[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.declarations.fullyExpandedClass
|
||||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
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.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -239,35 +238,6 @@ object ConeTypeCompatibilityChecker {
|
|||||||
return null
|
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> {
|
private fun ConeKotlinType?.collectLowerBounds(): Set<ConeClassLikeType> {
|
||||||
if (this == null) return emptySet()
|
if (this == null) return emptySet()
|
||||||
return when (this) {
|
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.resolve.providers.symbolProvider
|
||||||
import org.jetbrains.kotlin.fir.scopes.*
|
import org.jetbrains.kotlin.fir.scopes.*
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.multipleDelegatesWithTheSameSignature
|
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.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
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
|
val lastQualified = context.qualifiedAccessOrAssignmentsOrAnnotationCalls.lastOrNull { it != this } ?: return false
|
||||||
return lastQualified is FirVariableAssignment && lastQualified.lValue == this
|
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.FirElement
|
||||||
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.isValueClass
|
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.checkers.valOrVarKeyword
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
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.symbols.SymbolInternals
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
|
|
||||||
object FirFunctionParameterChecker : FirFunctionChecker() {
|
object FirFunctionParameterChecker : FirFunctionChecker() {
|
||||||
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
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) {
|
for (varargParameter in varargParameters) {
|
||||||
val varargParameterType = varargParameter.returnTypeRef.coneType.arrayElementType() ?: continue
|
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)
|
(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
|
// 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.
|
// 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.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true)
|
||||||
val ConeKotlinType.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
val ConeKotlinType.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
||||||
val ConeKotlinType.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
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.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||||
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||||
val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, true)
|
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.isChar: Boolean get() = isBuiltinType(StandardClassIds.Char, false)
|
||||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|||||||
object ConeTypeIntersector {
|
object ConeTypeIntersector {
|
||||||
fun intersectTypes(
|
fun intersectTypes(
|
||||||
context: ConeInferenceContext,
|
context: ConeInferenceContext,
|
||||||
types: List<ConeKotlinType>
|
types: Collection<ConeKotlinType>
|
||||||
): ConeKotlinType {
|
): ConeKotlinType {
|
||||||
when (types.size) {
|
when (types.size) {
|
||||||
0 -> error("Expected some types")
|
0 -> error("Expected some types")
|
||||||
|
|||||||
+4
-4
@@ -1,18 +1,18 @@
|
|||||||
// SKIP_TXT
|
// 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()
|
(<!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()
|
(<!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()
|
(<!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()
|
(<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.collections.List<kotlin.Nothing..kotlin.Any?!>")!>listOf<Any?>() + args<!>).toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,18 +1,18 @@
|
|||||||
// SKIP_TXT
|
// 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()
|
(<!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()
|
(<!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()
|
(<!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()
|
(<!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
|
// !MARK_DYNAMIC_CALLS
|
||||||
|
|
||||||
fun test() {
|
fun test() {
|
||||||
|
|||||||
Reference in New Issue
Block a user