K2: expand type before isSomeType checks properly
Related to KT-60229
This commit is contained in:
committed by
Space Team
parent
51e8a72f47
commit
00b4ae6ae9
+2
-1
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.fir.psi
|
|||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
@@ -261,7 +262,7 @@ internal object FirReferenceResolveHelper {
|
|||||||
return buildList {
|
return buildList {
|
||||||
scope.processFunctionsByName(OperatorNameConventions.EQUALS) { functionSymbol ->
|
scope.processFunctionsByName(OperatorNameConventions.EQUALS) { functionSymbol ->
|
||||||
val parameterSymbol = functionSymbol.valueParameterSymbols.singleOrNull()
|
val parameterSymbol = functionSymbol.valueParameterSymbols.singleOrNull()
|
||||||
if (parameterSymbol != null && parameterSymbol.fir.returnTypeRef.isNullableAny) {
|
if (parameterSymbol != null && parameterSymbol.fir.returnTypeRef.coneType.fullyExpandedType(session).isNullableAny) {
|
||||||
add(functionSymbol.buildSymbol(symbolBuilder))
|
add(functionSymbol.buildSymbol(symbolBuilder))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtType
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.isNullableAny
|
import org.jetbrains.kotlin.fir.types.isNullableAny
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
|
import org.jetbrains.kotlin.fir.analysis.checkers.typeParameterSymbols
|
||||||
|
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [KtFirTypeParameterSymbolBase] provides shared implementations for [KtFirTypeParameterSymbol] and [KtFirPsiJavaTypeParameterSymbol].
|
* [KtFirTypeParameterSymbolBase] provides shared implementations for [KtFirTypeParameterSymbol] and [KtFirPsiJavaTypeParameterSymbol].
|
||||||
@@ -29,6 +30,7 @@ internal sealed class KtFirTypeParameterSymbolBase : KtTypeParameterSymbol(), Kt
|
|||||||
KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token)
|
KtFirAnnotationListForDeclaration.create(firSymbol, analysisSession.useSiteSession, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
override val upperBounds: List<KtType> by cached {
|
override val upperBounds: List<KtType> by cached {
|
||||||
firSymbol.resolvedBounds.mapNotNull { type ->
|
firSymbol.resolvedBounds.mapNotNull { type ->
|
||||||
if (type.isNullableAny) return@mapNotNull null
|
if (type.isNullableAny) return@mapNotNull null
|
||||||
|
|||||||
-1
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.fir.types.isArrayType
|
|||||||
import org.jetbrains.kotlin.fir.types.isString
|
import org.jetbrains.kotlin.fir.types.isString
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
|
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
|
||||||
import org.jetbrains.kotlin.ir.symbols.*
|
|
||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||||
import org.jetbrains.kotlin.modules.Module
|
import org.jetbrains.kotlin.modules.Module
|
||||||
import org.jetbrains.kotlin.modules.TargetId
|
import org.jetbrains.kotlin.modules.TargetId
|
||||||
|
|||||||
+1
-1
@@ -165,7 +165,7 @@ object FirRepeatableAnnotationChecker : FirBasicDeclarationChecker() {
|
|||||||
val valueParameterSymbols = containerCtor.valueParameterSymbols
|
val valueParameterSymbols = containerCtor.valueParameterSymbols
|
||||||
val parameterName = StandardClassIds.Annotations.ParameterNames.value
|
val parameterName = StandardClassIds.Annotations.ParameterNames.value
|
||||||
val value = valueParameterSymbols.find { it.name == parameterName }
|
val value = valueParameterSymbols.find { it.name == parameterName }
|
||||||
if (value == null || !value.resolvedReturnTypeRef.isArrayType ||
|
if (value == null || !value.resolvedReturnTypeRef.coneType.fullyExpandedType(context.session).isArrayType ||
|
||||||
value.resolvedReturnTypeRef.type.typeArguments.single().type != annotationClass.defaultType()
|
value.resolvedReturnTypeRef.type.typeArguments.single().type != annotationClass.defaultType()
|
||||||
) {
|
) {
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
|
|||||||
+2
-2
@@ -13,10 +13,10 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.isEquals
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.hasBody
|
import org.jetbrains.kotlin.fir.declarations.utils.hasBody
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
|
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.isEquals
|
|
||||||
import org.jetbrains.kotlin.name.CallableId
|
import org.jetbrains.kotlin.name.CallableId
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING
|
import org.jetbrains.kotlin.util.OperatorNameConventions.TO_STRING
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ object FirMethodOfAnyImplementedInInterfaceChecker : FirRegularClassChecker(), F
|
|||||||
(function.name == HASHCODE_NAME || function.name == TO_STRING)
|
(function.name == HASHCODE_NAME || function.name == TO_STRING)
|
||||||
) {
|
) {
|
||||||
methodOfAny = true
|
methodOfAny = true
|
||||||
} else if (function.isEquals()) {
|
} else if (function.isEquals(context.session)) {
|
||||||
methodOfAny = true
|
methodOfAny = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.fir.resolve.defaultType
|
|||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.isEquals
|
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
@@ -192,7 +191,7 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() -> {
|
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType(context.session) -> {
|
||||||
reporter.reportOn(
|
reporter.reportOn(
|
||||||
primaryConstructorParameter.returnTypeRef.source,
|
primaryConstructorParameter.returnTypeRef.source,
|
||||||
FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
|
FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
|
||||||
@@ -227,7 +226,7 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
if (it !is FirSimpleFunction) {
|
if (it !is FirSimpleFunction) {
|
||||||
return@forEach
|
return@forEach
|
||||||
}
|
}
|
||||||
if (it.isEquals()) equalsFromAnyOverriding = it
|
if (it.isEquals(context.session)) equalsFromAnyOverriding = it
|
||||||
if (it.isTypedEqualsInValueClass(context.session)) typedEquals = it
|
if (it.isTypedEqualsInValueClass(context.session)) typedEquals = it
|
||||||
}
|
}
|
||||||
equalsFromAnyOverriding to typedEquals
|
equalsFromAnyOverriding to typedEquals
|
||||||
@@ -268,8 +267,8 @@ object FirValueClassDeclarationChecker : FirRegularClassChecker() {
|
|||||||
return isVararg || !primaryConstructorProperty.isVal || isOpen
|
return isVararg || !primaryConstructorProperty.isVal || isOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirTypeRef.isInapplicableParameterType() =
|
private fun FirTypeRef.isInapplicableParameterType(session: FirSession): Boolean =
|
||||||
isUnit || isNothing
|
coneType.fullyExpandedType(session).let { it.isUnit || it.isNothing }
|
||||||
|
|
||||||
private fun ConeKotlinType.isGenericArrayOfTypeParameter(): Boolean {
|
private fun ConeKotlinType.isGenericArrayOfTypeParameter(): Boolean {
|
||||||
if (this.typeArguments.firstOrNull() is ConeStarProjection || !isPotentiallyArray())
|
if (this.typeArguments.firstOrNull() is ConeStarProjection || !isPotentiallyArray())
|
||||||
|
|||||||
+3
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.languageVersionSettings
|
|||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.fir.types.isArrayType
|
import org.jetbrains.kotlin.fir.types.isArrayType
|
||||||
|
|
||||||
@@ -50,6 +51,8 @@ object FirNamedVarargChecker : FirCallChecker() {
|
|||||||
val typeRef = argument.expression.typeRef
|
val typeRef = argument.expression.typeRef
|
||||||
if (typeRef is FirErrorTypeRef) return
|
if (typeRef is FirErrorTypeRef) return
|
||||||
if (argument.expression is FirArrayOfCall) return
|
if (argument.expression is FirArrayOfCall) return
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if (allowAssignArray && typeRef.isArrayType) return
|
if (allowAssignArray && typeRef.isArrayType) return
|
||||||
|
|
||||||
if (isAnnotation) {
|
if (isAnnotation) {
|
||||||
|
|||||||
+1
@@ -30,6 +30,7 @@ object FirNotNullAssertionChecker : FirCheckNotNullCallChecker() {
|
|||||||
}
|
}
|
||||||
// TODO: use of Unit is subject to change.
|
// TODO: use of Unit is subject to change.
|
||||||
// See BodyResolveComponents.typeForQualifier in ResolveUtils.kt which returns Unit for no value type.
|
// See BodyResolveComponents.typeForQualifier in ResolveUtils.kt which returns Unit for no value type.
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if (argument is FirResolvedQualifier && argument.typeRef.isUnit) {
|
if (argument is FirResolvedQualifier && argument.typeRef.isUnit) {
|
||||||
// Would be reported as NO_COMPANION_OBJECT
|
// Would be reported as NO_COMPANION_OBJECT
|
||||||
return
|
return
|
||||||
|
|||||||
+5
-1
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
|||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||||
import org.jetbrains.kotlin.fir.types.isUnit
|
import org.jetbrains.kotlin.fir.types.isUnit
|
||||||
|
|
||||||
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
|
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
|
||||||
@@ -26,8 +27,11 @@ object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
|
|||||||
if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return
|
if (lastQualifiedAccess?.explicitReceiver === expression || lastQualifiedAccess?.dispatchReceiver === expression) return
|
||||||
val lastGetClass = context.getClassCalls.lastOrNull()
|
val lastGetClass = context.getClassCalls.lastOrNull()
|
||||||
if (lastGetClass?.argument === expression) return
|
if (lastGetClass?.argument === expression) return
|
||||||
// Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below
|
|
||||||
|
// Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below in reportErrorOn
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if (!expression.typeRef.isUnit) return
|
if (!expression.typeRef.isUnit) return
|
||||||
|
|
||||||
expression.symbol.reportErrorOn(expression.source, context, reporter)
|
expression.symbol.reportErrorOn(expression.source, context, reporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -13,6 +13,8 @@ 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.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.fir.types.isUnit
|
import org.jetbrains.kotlin.fir.types.isUnit
|
||||||
|
|
||||||
object RedundantReturnUnitType : FirSimpleFunctionChecker() {
|
object RedundantReturnUnitType : FirSimpleFunctionChecker() {
|
||||||
@@ -23,7 +25,7 @@ object RedundantReturnUnitType : FirSimpleFunctionChecker() {
|
|||||||
if (declaration.source?.kind is KtFakeSourceElementKind) return
|
if (declaration.source?.kind is KtFakeSourceElementKind) return
|
||||||
if (returnType.annotations.isNotEmpty()) return
|
if (returnType.annotations.isNotEmpty()) return
|
||||||
|
|
||||||
if (returnType.isUnit) {
|
if (returnType.coneType.fullyExpandedType(context.session).isUnit) {
|
||||||
reporter.reportOn(declaration.returnTypeRef.source, FirErrors.REDUNDANT_RETURN_UNIT_TYPE, context)
|
reporter.reportOn(declaration.returnTypeRef.source, FirErrors.REDUNDANT_RETURN_UNIT_TYPE, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ val ConeKotlinType.isPrimitiveNumberOrNullableType: Boolean
|
|||||||
val ConeKotlinType.isArrayType: Boolean
|
val ConeKotlinType.isArrayType: Boolean
|
||||||
get() {
|
get() {
|
||||||
return isBuiltinType(StandardClassIds.Array, false) ||
|
return isBuiltinType(StandardClassIds.Array, false) ||
|
||||||
StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) }
|
StandardClassIds.primitiveArrayTypeByElementType.values.any { isBuiltinType(it, false) } ||
|
||||||
|
StandardClassIds.unsignedArrayTypeByElementType.values.any { isBuiltinType(it, false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as [KotlinBuiltIns#isNonPrimitiveArray]
|
// Same as [KotlinBuiltIns#isNonPrimitiveArray]
|
||||||
|
|||||||
+3
-1
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.FirContractDescriptionOwner
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||||
import org.jetbrains.kotlin.fir.types.isBoolean
|
import org.jetbrains.kotlin.fir.types.isBoolean
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
import org.jetbrains.kotlin.metadata.deserialization.isInstanceType
|
||||||
@@ -37,7 +38,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) :
|
|||||||
override fun extractVariable(
|
override fun extractVariable(
|
||||||
valueParameterIndex: Int,
|
valueParameterIndex: Int,
|
||||||
owner: FirContractDescriptionOwner
|
owner: FirContractDescriptionOwner
|
||||||
): KtValueParameterReference<ConeKotlinType, ConeDiagnostic>? {
|
): KtValueParameterReference<ConeKotlinType, ConeDiagnostic>? {
|
||||||
val name: String
|
val name: String
|
||||||
val ownerFunction = owner as FirSimpleFunction
|
val ownerFunction = owner as FirSimpleFunction
|
||||||
val typeRef = if (valueParameterIndex < 0) {
|
val typeRef = if (valueParameterIndex < 0) {
|
||||||
@@ -49,6 +50,7 @@ class FirContractDeserializer(private val c: FirDeserializationContext) :
|
|||||||
parameter.returnTypeRef
|
parameter.returnTypeRef
|
||||||
} ?: return null
|
} ?: return null
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
return if (!typeRef.isBoolean)
|
return if (!typeRef.isBoolean)
|
||||||
KtValueParameterReference(valueParameterIndex, name)
|
KtValueParameterReference(valueParameterIndex, name)
|
||||||
else
|
else
|
||||||
|
|||||||
+3
-3
@@ -196,8 +196,8 @@ internal object FirToConstantValueTransformer : FirDefaultVisitor<ConstantValue<
|
|||||||
functionCall: FirFunctionCall,
|
functionCall: FirFunctionCall,
|
||||||
data: FirToConstantValueTransformerData
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
if (functionCall.isArrayOfCall) {
|
if (functionCall.isArrayOfCall(data.session)) {
|
||||||
return FirArrayOfCallTransformer().transformFunctionCall(functionCall, null).accept(this, data)
|
return FirArrayOfCallTransformer().transformFunctionCall(functionCall, data.session).accept(this, data)
|
||||||
}
|
}
|
||||||
return visitQualifiedAccessExpression(functionCall, data)
|
return visitQualifiedAccessExpression(functionCall, data)
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ internal object FirToConstantValueChecker : FirDefaultVisitor<Boolean, FirSessio
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: FirSession): Boolean {
|
override fun visitFunctionCall(functionCall: FirFunctionCall, data: FirSession): Boolean {
|
||||||
if (functionCall.isArrayOfCall) return functionCall.arguments.all { it.accept(this, data) }
|
if (functionCall.isArrayOfCall(data)) return functionCall.arguments.all { it.accept(this, data) }
|
||||||
return visitQualifiedAccessExpression(functionCall, data)
|
return visitQualifiedAccessExpression(functionCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -364,6 +364,7 @@ internal class ClassMemberGenerator(
|
|||||||
* constructor() : this(10) // <---- this call, IrDelegatingConstructorCall
|
* constructor() : this(10) // <---- this call, IrDelegatingConstructorCall
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if ((constructor.isFromEnumClass || constructor.returnTypeRef.isEnum) && this.isSuper) {
|
if ((constructor.isFromEnumClass || constructor.returnTypeRef.isEnum) && this.isSuper) {
|
||||||
IrEnumConstructorCallImpl(
|
IrEnumConstructorCallImpl(
|
||||||
startOffset, endOffset,
|
startOffset, endOffset,
|
||||||
|
|||||||
+18
-17
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
|||||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.scopes.overriddenFunctions
|
import org.jetbrains.kotlin.fir.scopes.overriddenFunctions
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
@@ -45,7 +46,7 @@ object OperatorFunctionChecks {
|
|||||||
checkFor(
|
checkFor(
|
||||||
OperatorNameConventions.SET,
|
OperatorNameConventions.SET,
|
||||||
Checks.memberOrExtension, Checks.ValueParametersCount.atLeast(2),
|
Checks.memberOrExtension, Checks.ValueParametersCount.atLeast(2),
|
||||||
Checks.simple("last parameter should not have a default value or be a vararg") {
|
Checks.simple("last parameter should not have a default value or be a vararg") { it, _ ->
|
||||||
it.valueParameters.lastOrNull()?.let { param ->
|
it.valueParameters.lastOrNull()?.let { param ->
|
||||||
param.defaultValue == null && !param.isVararg
|
param.defaultValue == null && !param.isVararg
|
||||||
} == true
|
} == true
|
||||||
@@ -161,9 +162,9 @@ private abstract class Check {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private object Checks {
|
private object Checks {
|
||||||
fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check() {
|
fun simple(message: String, predicate: (FirSimpleFunction, FirSession) -> Boolean) = object : Check() {
|
||||||
override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? =
|
override fun check(function: FirSimpleFunction, session: FirSession, scopeSession: ScopeSession?): String? =
|
||||||
message.takeIf { !predicate(function) }
|
message.takeIf { !predicate(function, session) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun full(message: String, predicate: (FirSession, FirSimpleFunction) -> Boolean) = object : Check() {
|
fun full(message: String, predicate: (FirSession, FirSimpleFunction) -> Boolean) = object : Check() {
|
||||||
@@ -171,51 +172,51 @@ private object Checks {
|
|||||||
message.takeIf { !predicate(session, function) }
|
message.takeIf { !predicate(session, function) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val memberOrExtension = simple("must be a member or an extension function") {
|
val memberOrExtension = simple("must be a member or an extension function") { it, _ ->
|
||||||
it.dispatchReceiverType != null || it.receiverParameter != null
|
it.dispatchReceiverType != null || it.receiverParameter != null
|
||||||
}
|
}
|
||||||
|
|
||||||
val member = simple("must be a member function") {
|
val member = simple("must be a member function") { it, _ ->
|
||||||
it.dispatchReceiverType != null
|
it.dispatchReceiverType != null
|
||||||
}
|
}
|
||||||
|
|
||||||
val nonSuspend = simple("must not be suspend") {
|
val nonSuspend = simple("must not be suspend") { it, _ ->
|
||||||
!it.isSuspend
|
!it.isSuspend
|
||||||
}
|
}
|
||||||
|
|
||||||
object ValueParametersCount {
|
object ValueParametersCount {
|
||||||
fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) {
|
fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) { it, _ ->
|
||||||
it.valueParameters.size >= n
|
it.valueParameters.size >= n
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exactly(n: Int) = simple("must have exactly $n value parameters") {
|
fun exactly(n: Int) = simple("must have exactly $n value parameters") { it, _ ->
|
||||||
it.valueParameters.size == n
|
it.valueParameters.size == n
|
||||||
}
|
}
|
||||||
|
|
||||||
val single = simple("must have a single value parameter") {
|
val single = simple("must have a single value parameter") { it, _ ->
|
||||||
it.valueParameters.size == 1
|
it.valueParameters.size == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
val none = simple("must have no value parameters") {
|
val none = simple("must have no value parameters") { it, _ ->
|
||||||
it.valueParameters.isEmpty()
|
it.valueParameters.isEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Returns {
|
object Returns {
|
||||||
val boolean = simple("must return Boolean") {
|
val boolean = simple("must return Boolean") { it, session ->
|
||||||
it.returnTypeRef.isBoolean
|
it.returnTypeRef.coneType.fullyExpandedType(session).isBoolean
|
||||||
}
|
}
|
||||||
|
|
||||||
val int = simple("must return Int") {
|
val int = simple("must return Int") { it, session ->
|
||||||
it.returnTypeRef.isInt
|
it.returnTypeRef.coneType.fullyExpandedType(session).isInt
|
||||||
}
|
}
|
||||||
|
|
||||||
val unit = simple("must return Unit") {
|
val unit = simple("must return Unit") { it, session ->
|
||||||
it.returnTypeRef.isUnit
|
it.returnTypeRef.coneType.fullyExpandedType(session).isUnit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") {
|
val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") { it, _ ->
|
||||||
it.valueParameters.all { param ->
|
it.valueParameters.all { param ->
|
||||||
param.defaultValue == null && !param.isVararg
|
param.defaultValue == null && !param.isVararg
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-3
@@ -88,7 +88,10 @@ fun FirSimpleFunction.isTypedEqualsInValueClass(session: FirSession): Boolean =
|
|||||||
contextReceivers.isEmpty() && receiverParameter == null
|
contextReceivers.isEmpty() && receiverParameter == null
|
||||||
&& name == OperatorNameConventions.EQUALS
|
&& name == OperatorNameConventions.EQUALS
|
||||||
&& this@run.isInline && valueParameters.size == 1
|
&& this@run.isInline && valueParameters.size == 1
|
||||||
&& (returnTypeRef.isBoolean || returnTypeRef.isNothing)
|
&& returnTypeRef.coneType.fullyExpandedType(session).let {
|
||||||
&& valueParameters[0].returnTypeRef.coneType.let { it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection }
|
it.isBoolean || it.isNothing
|
||||||
|
} && valueParameters[0].returnTypeRef.coneType.let {
|
||||||
|
it is ConeClassLikeType && it.replaceArgumentsWithStarProjections() == valueClassStarProjection
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} ?: false
|
} == true
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
|
|||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
import org.jetbrains.kotlin.fir.types.isNullableAny
|
||||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
fun FirClass.constructors(session: FirSession): List<FirConstructorSymbol> {
|
fun FirClass.constructors(session: FirSession): List<FirConstructorSymbol> {
|
||||||
val result = mutableListOf<FirConstructorSymbol>()
|
val result = mutableListOf<FirConstructorSymbol>()
|
||||||
@@ -93,3 +95,12 @@ private fun FirFunction.containsDefaultValue(index: Int): Boolean = valueParamet
|
|||||||
|
|
||||||
fun FirFunction.itOrExpectHasDefaultParameterValue(index: Int): Boolean =
|
fun FirFunction.itOrExpectHasDefaultParameterValue(index: Int): Boolean =
|
||||||
containsDefaultValue(index) || symbol.getSingleExpectForActualOrNull()?.fir?.containsDefaultValue(index) == true
|
containsDefaultValue(index) || symbol.getSingleExpectForActualOrNull()?.fir?.containsDefaultValue(index) == true
|
||||||
|
|
||||||
|
fun FirSimpleFunction.isEquals(session: FirSession): Boolean {
|
||||||
|
if (name != OperatorNameConventions.EQUALS) return false
|
||||||
|
if (valueParameters.size != 1) return false
|
||||||
|
if (contextReceivers.isNotEmpty()) return false
|
||||||
|
if (receiverParameter != null) return false
|
||||||
|
val parameter = valueParameters.first()
|
||||||
|
return parameter.returnTypeRef.coneType.fullyExpandedType(session).isNullableAny
|
||||||
|
}
|
||||||
|
|||||||
+3
-2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.FirSimpleFunctionBuilder
|
|||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.isEquals
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
|
||||||
@@ -46,7 +47,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
|||||||
* This declared scope wrapper is created for data/value classes and provides Any method stubs, if necessary
|
* This declared scope wrapper is created for data/value classes and provides Any method stubs, if necessary
|
||||||
*/
|
*/
|
||||||
class FirClassAnySynthesizedMemberScope(
|
class FirClassAnySynthesizedMemberScope(
|
||||||
session: FirSession,
|
private val session: FirSession,
|
||||||
private val declaredMemberScope: FirContainingNamesAwareScope,
|
private val declaredMemberScope: FirContainingNamesAwareScope,
|
||||||
klass: FirRegularClass,
|
klass: FirRegularClass,
|
||||||
scopeSession: ScopeSession,
|
scopeSession: ScopeSession,
|
||||||
@@ -118,7 +119,7 @@ class FirClassAnySynthesizedMemberScope(
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
lazyResolveToPhase(FirResolvePhase.TYPES)
|
lazyResolveToPhase(FirResolvePhase.TYPES)
|
||||||
fir.isEquals()
|
fir.isEquals(session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,16 +54,17 @@ import kotlin.contracts.contract
|
|||||||
fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection<FirExpression>): Boolean =
|
fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection<FirExpression>): Boolean =
|
||||||
isLambda && returnStatements.any { it is FirUnitExpression }
|
isLambda && returnStatements.any { it is FirUnitExpression }
|
||||||
|
|
||||||
fun FirAnonymousFunction.addReturnToLastStatementIfNeeded() {
|
fun FirAnonymousFunction.addReturnToLastStatementIfNeeded(session: FirSession) {
|
||||||
// If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement.
|
// If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement.
|
||||||
// During conversion (to backend IR), the last expression will be coerced to Unit if needed.
|
// During conversion (to backend IR), the last expression will be coerced to Unit if needed.
|
||||||
if (returnTypeRef.isUnit) return
|
if (returnTypeRef.coneType.fullyExpandedType(session).isUnit) return
|
||||||
|
|
||||||
val body = this.body ?: return
|
val body = this.body ?: return
|
||||||
val lastStatement = body.statements.lastOrNull() as? FirExpression ?: return
|
val lastStatement = body.statements.lastOrNull() as? FirExpression ?: return
|
||||||
if (lastStatement is FirReturnExpression) return
|
if (lastStatement is FirReturnExpression) return
|
||||||
|
|
||||||
val returnType = (body.typeRef as? FirResolvedTypeRef) ?: return
|
val returnType = (body.typeRef as? FirResolvedTypeRef) ?: return
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if (returnType.isNothing) return
|
if (returnType.isNothing) return
|
||||||
|
|
||||||
val returnTarget = FirFunctionTarget(null, isLambda = isLambda).also { it.bind(this) }
|
val returnTarget = FirFunctionTarget(null, isLambda = isLambda).also { it.bind(this) }
|
||||||
|
|||||||
+9
-4
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
|||||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||||
import org.jetbrains.kotlin.fir.resolve.createFunctionType
|
import org.jetbrains.kotlin.fir.resolve.createFunctionType
|
||||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedCallableReferenceTarget
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnsupportedCallableReferenceTarget
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType
|
import org.jetbrains.kotlin.fir.resolve.inference.extractInputOutputTypesFromCallableReferenceExpectedType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
@@ -248,10 +249,14 @@ private fun BodyResolveComponents.getCallableReferenceAdaptation(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val coercionStrategy = if (returnExpectedType.isUnitOrFlexibleUnit && !function.returnTypeRef.isUnit)
|
val returnTypeRef = function.returnTypeRef
|
||||||
CoercionStrategy.COERCION_TO_UNIT
|
val coercionStrategy =
|
||||||
else
|
if (returnExpectedType.isUnitOrFlexibleUnit &&
|
||||||
CoercionStrategy.NO_COERCION
|
returnTypeRef.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session)?.isUnit != true
|
||||||
|
)
|
||||||
|
CoercionStrategy.COERCION_TO_UNIT
|
||||||
|
else
|
||||||
|
CoercionStrategy.NO_COERCION
|
||||||
|
|
||||||
val adaptedArguments = if (expectedType.isBaseTypeForNumberedReferenceTypes)
|
val adaptedArguments = if (expectedType.isBaseTypeForNumberedReferenceTypes)
|
||||||
emptyMap()
|
emptyMap()
|
||||||
|
|||||||
+2
-1
@@ -536,7 +536,7 @@ abstract class FirDataFlowAnalyzer(
|
|||||||
|
|
||||||
return session.declaredMemberScope(this, memberRequiredPhase = FirResolvePhase.STATUS)
|
return session.declaredMemberScope(this, memberRequiredPhase = FirResolvePhase.STATUS)
|
||||||
.getFunctions(OperatorNameConventions.EQUALS)
|
.getFunctions(OperatorNameConventions.EQUALS)
|
||||||
.any { it.fir.isEquals() }
|
.any { it.fir.isEquals(session) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------- Jump -----------------------------------
|
// ----------------------------------- Jump -----------------------------------
|
||||||
@@ -1107,6 +1107,7 @@ abstract class FirDataFlowAnalyzer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
fun exitElvis(elvisExpression: FirElvisExpression, isLhsNotNull: Boolean, callCompleted: Boolean) {
|
fun exitElvis(elvisExpression: FirElvisExpression, isLhsNotNull: Boolean, callCompleted: Boolean) {
|
||||||
val node = graphBuilder.exitElvis(isLhsNotNull, callCompleted)
|
val node = graphBuilder.exitElvis(isLhsNotNull, callCompleted)
|
||||||
node.mergeIncomingFlow { flow ->
|
node.mergeIncomingFlow { flow ->
|
||||||
|
|||||||
+5
@@ -1065,6 +1065,7 @@ class ControlFlowGraphBuilder {
|
|||||||
// it would be much easier if we could build calls after full completion only, at least for Nothing calls
|
// it would be much easier if we could build calls after full completion only, at least for Nothing calls
|
||||||
// KT-59726
|
// KT-59726
|
||||||
// @returns `true` if node actually returned Nothing
|
// @returns `true` if node actually returned Nothing
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
private fun completeFunctionCall(node: FunctionCallNode): Boolean {
|
private fun completeFunctionCall(node: FunctionCallNode): Boolean {
|
||||||
if (!node.fir.resultType.isNothing) return false
|
if (!node.fir.resultType.isNothing) return false
|
||||||
val stub = StubNode(node.owner, node.level)
|
val stub = StubNode(node.owner, node.level)
|
||||||
@@ -1082,6 +1083,7 @@ class ControlFlowGraphBuilder {
|
|||||||
|
|
||||||
// ----------------------------------- Resolvable call -----------------------------------
|
// ----------------------------------- Resolvable call -----------------------------------
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression): QualifiedAccessNode {
|
fun exitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression): QualifiedAccessNode {
|
||||||
val returnsNothing = qualifiedAccessExpression.resultType.isNothing
|
val returnsNothing = qualifiedAccessExpression.resultType.isNothing
|
||||||
val node = createQualifiedAccessNode(qualifiedAccessExpression)
|
val node = createQualifiedAccessNode(qualifiedAccessExpression)
|
||||||
@@ -1093,6 +1095,7 @@ class ControlFlowGraphBuilder {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
fun exitSmartCastExpression(smartCastExpression: FirSmartCastExpression): SmartCastExpressionExitNode {
|
fun exitSmartCastExpression(smartCastExpression: FirSmartCastExpression): SmartCastExpressionExitNode {
|
||||||
val returnsNothing = smartCastExpression.resultType.isNothing
|
val returnsNothing = smartCastExpression.resultType.isNothing
|
||||||
val node = createSmartCastExitNode(smartCastExpression)
|
val node = createSmartCastExitNode(smartCastExpression)
|
||||||
@@ -1126,6 +1129,7 @@ class ControlFlowGraphBuilder {
|
|||||||
return argumentListSplitNodes.pop()?.also { addNewSimpleNode(it) }
|
return argumentListSplitNodes.pop()?.also { addNewSimpleNode(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode {
|
fun exitFunctionCall(functionCall: FirFunctionCall, callCompleted: Boolean): FunctionCallNode {
|
||||||
val returnsNothing = functionCall.resultType.isNothing
|
val returnsNothing = functionCall.resultType.isNothing
|
||||||
val node = createFunctionCallNode(functionCall)
|
val node = createFunctionCallNode(functionCall)
|
||||||
@@ -1171,6 +1175,7 @@ class ControlFlowGraphBuilder {
|
|||||||
return createThrowExceptionNode(throwExpression).also { addNonSuccessfullyTerminatingNode(it) }
|
return createThrowExceptionNode(throwExpression).also { addNonSuccessfullyTerminatingNode(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode {
|
fun exitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, callCompleted: Boolean): CheckNotNullCallNode {
|
||||||
val node = createCheckNotNullCallNode(checkNotNullCall)
|
val node = createCheckNotNullCallNode(checkNotNullCall)
|
||||||
unifyDataFlowFromPostponedLambdas(node, callCompleted)
|
unifyDataFlowFromPostponedLambdas(node, callCompleted)
|
||||||
|
|||||||
+2
-2
@@ -249,7 +249,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enableArrayOfCallTransformation) {
|
if (enableArrayOfCallTransformation) {
|
||||||
return arrayOfCallTransformer.transformFunctionCall(result, null)
|
return arrayOfCallTransformer.transformFunctionCall(result, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -618,7 +618,7 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
session.lookupTracker?.recordTypeResolveAsLookup(result.typeRef, result.source, context.file.source)
|
session.lookupTracker?.recordTypeResolveAsLookup(result.typeRef, result.source, context.file.source)
|
||||||
}
|
}
|
||||||
// Have to delay this until the type is written to avoid adding a return if the type is Unit.
|
// Have to delay this until the type is written to avoid adding a return if the type is Unit.
|
||||||
result.addReturnToLastStatementIfNeeded()
|
result.addReturnToLastStatementIfNeeded(session)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -214,6 +214,7 @@ private object WhenOnNullableExhaustivenessChecker : WhenExhaustivenessChecker()
|
|||||||
private object ConditionChecker : AbstractConditionChecker<Flags>() {
|
private object ConditionChecker : AbstractConditionChecker<Flags>() {
|
||||||
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Flags) {
|
override fun visitEqualityOperatorCall(equalityOperatorCall: FirEqualityOperatorCall, data: Flags) {
|
||||||
val argument = equalityOperatorCall.arguments[1]
|
val argument = equalityOperatorCall.arguments[1]
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
if (argument.typeRef.isNullableNothing) {
|
if (argument.typeRef.isNullableNothing) {
|
||||||
data.containsNull = true
|
data.containsNull = true
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-14
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
package org.jetbrains.kotlin.fir.resolve.transformers.body.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
@@ -14,7 +15,10 @@ import org.jetbrains.kotlin.fir.expressions.builder.buildArrayOfCall
|
|||||||
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
import org.jetbrains.kotlin.fir.types.isArrayType
|
import org.jetbrains.kotlin.fir.types.isArrayType
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
||||||
|
|
||||||
@@ -23,9 +27,9 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer
|
|||||||
*
|
*
|
||||||
* Note that arrayOf() calls only in [FirAnnotation] or the default value of annotation constructor are transformed.
|
* Note that arrayOf() calls only in [FirAnnotation] or the default value of annotation constructor are transformed.
|
||||||
*/
|
*/
|
||||||
class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
|
class FirArrayOfCallTransformer : FirDefaultTransformer<FirSession>() {
|
||||||
private fun toArrayOfCall(functionCall: FirFunctionCall): FirArrayOfCall? {
|
private fun toArrayOfCall(functionCall: FirFunctionCall, session: FirSession): FirArrayOfCall? {
|
||||||
if (!functionCall.isArrayOfCall) return null
|
if (!functionCall.isArrayOfCall(session)) return null
|
||||||
if (functionCall.calleeReference !is FirResolvedNamedReference) return null
|
if (functionCall.calleeReference !is FirResolvedNamedReference) return null
|
||||||
return buildArrayOfCall {
|
return buildArrayOfCall {
|
||||||
source = functionCall.source
|
source = functionCall.source
|
||||||
@@ -42,25 +46,25 @@ class FirArrayOfCallTransformer : FirDefaultTransformer<Nothing?>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Nothing?): FirStatement {
|
override fun transformFunctionCall(functionCall: FirFunctionCall, data: FirSession): FirStatement {
|
||||||
functionCall.transformChildren(this, data)
|
functionCall.transformChildren(this, data)
|
||||||
return toArrayOfCall(functionCall) ?: functionCall
|
return toArrayOfCall(functionCall, data) ?: functionCall
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Nothing?): E {
|
override fun <E : FirElement> transformElement(element: E, data: FirSession): E {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
return (element.transformChildren(this, data) as E)
|
return (element.transformChildren(this, data) as E)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val FirFunctionCall.isArrayOfCall: Boolean
|
fun FirFunctionCall.isArrayOfCall(session: FirSession): Boolean {
|
||||||
get() {
|
val function: FirCallableDeclaration = getOriginalFunction() ?: return false
|
||||||
val function: FirCallableDeclaration = getOriginalFunction() ?: return false
|
val returnTypeRef = function.returnTypeRef
|
||||||
return function is FirSimpleFunction &&
|
return function is FirSimpleFunction &&
|
||||||
function.returnTypeRef.isArrayType &&
|
returnTypeRef.coneTypeSafe<ConeKotlinType>()?.fullyExpandedType(session)?.isArrayType == true &&
|
||||||
isArrayOf(function, arguments) &&
|
isArrayOf(function, arguments) &&
|
||||||
function.receiverParameter == null
|
function.receiverParameter == null
|
||||||
}
|
}
|
||||||
|
|
||||||
private val arrayOfNames = hashSetOf("kotlin/arrayOf") +
|
private val arrayOfNames = hashSetOf("kotlin/arrayOf") +
|
||||||
hashSetOf(
|
hashSetOf(
|
||||||
|
|||||||
+1
-1
@@ -860,7 +860,7 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
|
|
||||||
lambda.replaceTypeRef(lambda.constructFunctionTypeRef(session, resolvedLambdaAtom?.expectedFunctionTypeKind))
|
lambda.replaceTypeRef(lambda.constructFunctionTypeRef(session, resolvedLambdaAtom?.expectedFunctionTypeKind))
|
||||||
session.lookupTracker?.recordTypeResolveAsLookup(lambda.typeRef, lambda.source, context.file.source)
|
session.lookupTracker?.recordTypeResolveAsLookup(lambda.typeRef, lambda.source, context.file.source)
|
||||||
lambda.addReturnToLastStatementIfNeeded()
|
lambda.addReturnToLastStatementIfNeeded(session)
|
||||||
return lambda
|
return lambda
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -451,7 +451,7 @@ open class FirExpressionsResolveTransformer(transformer: FirAbstractBodyResolveT
|
|||||||
addReceiversFromExtensions(result)
|
addReceiversFromExtensions(result)
|
||||||
|
|
||||||
if (enableArrayOfCallTransformation) {
|
if (enableArrayOfCallTransformation) {
|
||||||
return arrayOfCallTransformer.transformFunctionCall(result, null)
|
return arrayOfCallTransformer.transformFunctionCall(result, session)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.resolve.dfa.PersistentFlow
|
|||||||
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
|
import org.jetbrains.kotlin.fir.resolve.dfa.controlFlowGraph
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNothingTypeRef
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNothingTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.isNothing
|
import org.jetbrains.kotlin.fir.types.isNothing
|
||||||
@@ -815,6 +816,8 @@ object FirStub : FirExpression() {
|
|||||||
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirExpression = this
|
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirExpression = this
|
||||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement = this
|
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement = this
|
||||||
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) { assert(newAnnotations.isEmpty()) }
|
override fun replaceAnnotations(newAnnotations: List<FirAnnotation>) { assert(newAnnotations.isEmpty()) }
|
||||||
|
|
||||||
|
@OptIn(UnexpandedTypeCheck::class)
|
||||||
override fun replaceTypeRef(newTypeRef: FirTypeRef) { assert(newTypeRef.isNothing) }
|
override fun replaceTypeRef(newTypeRef: FirTypeRef) { assert(newTypeRef.isNothing) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,12 +96,3 @@ val FirCallableSymbol<*>.isExtension: Boolean
|
|||||||
is FirProperty -> fir.receiverParameter != null
|
is FirProperty -> fir.receiverParameter != null
|
||||||
is FirVariable -> false
|
is FirVariable -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirSimpleFunction.isEquals(): Boolean {
|
|
||||||
if (name != OperatorNameConventions.EQUALS) return false
|
|
||||||
if (valueParameters.size != 1) return false
|
|
||||||
if (contextReceivers.isNotEmpty()) return false
|
|
||||||
if (receiverParameter != null) return false
|
|
||||||
val parameter = valueParameters.first()
|
|
||||||
return parameter.returnTypeRef.isNullableAny
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,15 +34,40 @@ val FirTypeRef.coneType: ConeKotlinType
|
|||||||
val FirTypeRef.coneTypeOrNull: ConeKotlinType?
|
val FirTypeRef.coneTypeOrNull: ConeKotlinType?
|
||||||
get() = coneTypeSafe()
|
get() = coneTypeSafe()
|
||||||
|
|
||||||
|
@RequiresOptIn(
|
||||||
|
"This type check never expands type aliases. Use with care (probably Ok for expression & constructor types). " +
|
||||||
|
"Generally this.coneType.fullyExpandedType(session).isSomeType is better"
|
||||||
|
)
|
||||||
|
annotation class UnexpandedTypeCheck
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, false)
|
val FirTypeRef.isAny: Boolean get() = isBuiltinType(StandardClassIds.Any, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true)
|
val FirTypeRef.isNullableAny: Boolean get() = isBuiltinType(StandardClassIds.Any, true)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
|
val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
val FirTypeRef.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||||
|
|
||||||
|
@UnexpandedTypeCheck
|
||||||
val FirTypeRef.isArrayType: Boolean
|
val FirTypeRef.isArrayType: Boolean
|
||||||
get() =
|
get() =
|
||||||
isBuiltinType(StandardClassIds.Array, false)
|
isBuiltinType(StandardClassIds.Array, false)
|
||||||
|
|||||||
Reference in New Issue
Block a user