[FIR JS] KT-57200: Allow dynamic varargs
^KT-57200 Fixed
This commit is contained in:
committed by
Space Team
parent
5d664aac92
commit
b385d787cc
-30
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
|
||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -239,35 +238,6 @@ object ConeTypeCompatibilityChecker {
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the upper bounds as [ConeClassLikeType].
|
||||
*/
|
||||
private fun ConeKotlinType?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return when (this) {
|
||||
is ConeErrorType -> emptySet() // Ignore error types
|
||||
is ConeLookupTagBasedType -> when (this) {
|
||||
is ConeClassLikeType -> setOf(this)
|
||||
is ConeTypeVariableType -> {
|
||||
(lookupTag.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol.collectUpperBounds()
|
||||
}
|
||||
is ConeTypeParameterType -> lookupTag.typeParameterSymbol.collectUpperBounds()
|
||||
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
|
||||
}
|
||||
is ConeDefinitelyNotNullType -> original.collectUpperBounds()
|
||||
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectUpperBounds() }.toSet()
|
||||
is ConeFlexibleType -> upperBound.collectUpperBounds()
|
||||
is ConeCapturedType -> constructor.supertypes?.flatMap { it.collectUpperBounds() }?.toSet().orEmpty()
|
||||
is ConeIntegerConstantOperatorType -> setOf(getApproximatedType())
|
||||
is ConeStubType, is ConeIntegerLiteralConstantType -> throw IllegalStateException("$this should not reach here")
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return resolvedBounds.flatMap { it.coneType.collectUpperBounds() }.toSet()
|
||||
}
|
||||
|
||||
private fun ConeKotlinType?.collectLowerBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return when (this) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
@@ -732,3 +733,37 @@ fun FirElement.isLhsOfAssignment(context: CheckerContext): Boolean {
|
||||
val lastQualified = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull { it != this } ?: return false
|
||||
return lastQualified is FirVariableAssignment && lastQualified.lValue == this
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the upper bounds as [ConeClassLikeType].
|
||||
*/
|
||||
fun ConeKotlinType?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return when (this) {
|
||||
is ConeErrorType -> emptySet() // Ignore error types
|
||||
is ConeLookupTagBasedType -> when (this) {
|
||||
is ConeClassLikeType -> setOf(this)
|
||||
is ConeTypeVariableType -> {
|
||||
(lookupTag.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol.collectUpperBounds()
|
||||
}
|
||||
is ConeTypeParameterType -> lookupTag.typeParameterSymbol.collectUpperBounds()
|
||||
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
|
||||
}
|
||||
is ConeDefinitelyNotNullType -> original.collectUpperBounds()
|
||||
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectUpperBounds() }.toSet()
|
||||
is ConeFlexibleType -> upperBound.collectUpperBounds()
|
||||
is ConeCapturedType -> constructor.supertypes?.flatMap { it.collectUpperBounds() }?.toSet().orEmpty()
|
||||
is ConeIntegerConstantOperatorType -> setOf(getApproximatedType())
|
||||
is ConeStubType, is ConeIntegerLiteralConstantType -> throw IllegalStateException("$this should not reach here")
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return resolvedBounds.flatMap { it.coneType.collectUpperBounds() }.toSet()
|
||||
}
|
||||
|
||||
fun ConeKotlinType.leastUpperBound(session: FirSession): ConeKotlinType {
|
||||
val upperBounds = collectUpperBounds().takeIf { it.isNotEmpty() } ?: return session.builtinTypes.nullableAnyType.type
|
||||
return ConeTypeIntersector.intersectTypes(session.typeContext, upperBounds)
|
||||
}
|
||||
|
||||
+6
-3
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isValueClass
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.leastUpperBound
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.valOrVarKeyword
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
@@ -25,7 +26,6 @@ import org.jetbrains.kotlin.fir.references.toResolvedValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
object FirFunctionParameterChecker : FirFunctionChecker() {
|
||||
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -61,10 +61,13 @@ object FirFunctionParameterChecker : FirFunctionChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
val nullableNothingType = context.session.builtinTypes.nullableNothingType.coneType
|
||||
for (varargParameter in varargParameters) {
|
||||
val varargParameterType = varargParameter.returnTypeRef.coneType.arrayElementType() ?: continue
|
||||
if (AbstractTypeChecker.isSubtypeOf(context.session.typeContext, varargParameterType, nullableNothingType) ||
|
||||
// LUB is checked to ensure varargParameterType may
|
||||
// never be anything except `Nothing` or `Nothing?`
|
||||
// in case it is a complex type that quantifies
|
||||
// over many other types.
|
||||
if (varargParameterType.leastUpperBound(context.session).isNothingOrNullableNothing ||
|
||||
(varargParameterType.isValueClass(context.session) && !varargParameterType.isUnsignedTypeOrNullableUnsignedType)
|
||||
// Note: comparing with FE1.0, we skip checking if the type is not primitive because primitive types are not inline. That
|
||||
// is any primitive values are already allowed by the inline check.
|
||||
|
||||
@@ -19,11 +19,12 @@ val ConeKotlinType.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, fa
|
||||
val ConeKotlinType.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true)
|
||||
val ConeKotlinType.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
||||
val ConeKotlinType.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
||||
val ConeKotlinType.isNothingOrNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, null)
|
||||
|
||||
val ConeKotlinType.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||
val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, true)
|
||||
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Boolean))
|
||||
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, null)
|
||||
|
||||
val ConeKotlinType.isChar: Boolean get() = isBuiltinType(StandardClassIds.Char, false)
|
||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||
|
||||
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
object ConeTypeIntersector {
|
||||
fun intersectTypes(
|
||||
context: ConeInferenceContext,
|
||||
types: List<ConeKotlinType>
|
||||
types: Collection<ConeKotlinType>
|
||||
): ConeKotlinType {
|
||||
when (types.size) {
|
||||
0 -> error("Expected some types")
|
||||
|
||||
+4
-4
@@ -1,18 +1,18 @@
|
||||
// SKIP_TXT
|
||||
|
||||
fun case_1(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_1(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf(null) + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_2(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_2(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf<Nothing>() + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_3(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_3(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf(1) + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_4(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_4(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf<Any?>() + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1,18 +1,18 @@
|
||||
// SKIP_TXT
|
||||
|
||||
fun case_1(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_1(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf(null) + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_2(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_2(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf<Nothing>() + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_3(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_3(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf(1) + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
fun case_4(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> args: dynamic) {
|
||||
fun case_4(vararg args: dynamic) {
|
||||
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf<Any?>() + args<!>).toTypedArray()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// !MARK_DYNAMIC_CALLS
|
||||
|
||||
fun test() {
|
||||
v()
|
||||
v(1)
|
||||
v(1, "")
|
||||
}
|
||||
|
||||
fun v(<!FORBIDDEN_VARARG_PARAMETER_TYPE!>vararg<!> d: dynamic) {
|
||||
for (dd in d) {
|
||||
dd.<!DEBUG_INFO_DYNAMIC!>foo<!>()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !MARK_DYNAMIC_CALLS
|
||||
|
||||
fun test() {
|
||||
|
||||
Reference in New Issue
Block a user