[FIR] Fix processing integer operator calls for not integer types

This commit is contained in:
Dmitriy Novozhilov
2020-09-14 10:52:54 +03:00
parent def647c094
commit 535898c8a4
8 changed files with 75 additions and 55 deletions
@@ -346,8 +346,9 @@ private fun Candidate.prepareExpectedType(
context: ResolutionContext context: ResolutionContext
): ConeKotlinType? { ): ConeKotlinType? {
if (parameter == null) return null if (parameter == null) return null
if (parameter.returnTypeRef is FirILTTypeRefPlaceHolder && argument.resultType is FirResolvedTypeRef) val parameterReturnTypeRef = parameter.returnTypeRef
return argument.resultType.coneType if (parameterReturnTypeRef is FirILTTypeRefPlaceHolder && argument.resultType is FirResolvedTypeRef)
return argument.resultType.coneType.takeIf { it in parameterReturnTypeRef.type.possibleTypes } ?: session.builtinTypes.intType.type
val basicExpectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/) val basicExpectedType = argument.getExpectedType(session, parameter/*, LanguageVersionSettings*/)
val expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType, context) ?: basicExpectedType val expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType, context) ?: basicExpectedType
return this.substitutor.substituteOrSelf(expectedType) return this.substitutor.substituteOrSelf(expectedType)
@@ -218,7 +218,9 @@ class IntegerOperatorsTypeUpdater(private val approximator: IntegerLiteralTypeAp
} }
else -> { else -> {
val expectedType = when (argumentType.classId) { val expectedType = when (argumentType.classId) {
StandardClassIds.Long -> argumentType StandardClassIds.Long,
StandardClassIds.Float,
StandardClassIds.Double -> argumentType
else -> ConeIntegerLiteralTypeImpl.createType(StandardClassIds.Int) else -> ConeIntegerLiteralTypeImpl.createType(StandardClassIds.Int)
} }
functionCall.transformSingle(approximator, expectedType) functionCall.transformSingle(approximator, expectedType)
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirDeclarationStatus
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
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.impl.FirSimpleFunctionImpl import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
@@ -42,6 +39,7 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
companion object { companion object {
val BINARY_OPERATOR_NAMES = FirIntegerOperator.Kind.values().filterNot { it.unary }.map { it.operatorName } val BINARY_OPERATOR_NAMES = FirIntegerOperator.Kind.values().filterNot { it.unary }.map { it.operatorName }
val FLOATING_BINARY_OPERATOR_NAMES = FirIntegerOperator.Kind.values().filter { it.withFloatingRhs }.map { it.operatorName }
val UNARY_OPERATOR_NAMES = FirIntegerOperator.Kind.values().filter { it.unary }.map { it.operatorName } val UNARY_OPERATOR_NAMES = FirIntegerOperator.Kind.values().filter { it.unary }.map { it.operatorName }
private val ALL_OPERATORS = FirIntegerOperator.Kind.values().map { it.operatorName to it }.toMap() private val ALL_OPERATORS = FirIntegerOperator.Kind.values().map { it.operatorName to it }.toMap()
@@ -52,18 +50,16 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
private val BINARY_OPERATOR_SYMBOLS = BINARY_OPERATOR_NAMES.map { name -> private val BINARY_OPERATOR_SYMBOLS = BINARY_OPERATOR_NAMES.map { name ->
name to FirNamedFunctionSymbol(CallableId(name)).apply { name to FirNamedFunctionSymbol(CallableId(name)).apply {
createFirFunction(name, this).apply { createFirFunction(name, this).apply {
val valueParameterName = Name.identifier("arg") valueParameters += createValueParameter(FirILTTypeRefPlaceHolder(isUnsigned))
valueParameters += buildValueParameter { }
source = null }
origin = FirDeclarationOrigin.Synthetic }.toMap()
session = this@FirIntegerLiteralTypeScope.session
returnTypeRef = FirILTTypeRefPlaceHolder(isUnsigned) private val FLOATING_BINARY_OPERATOR_SYMBOLS = FLOATING_BINARY_OPERATOR_NAMES.map { name ->
this.name = valueParameterName name to listOf(session.builtinTypes.floatType, session.builtinTypes.doubleType).map { typeRef ->
symbol = FirVariableSymbol(valueParameterName) FirNamedFunctionSymbol(CallableId(name)).apply {
defaultValue = null createFirFunction(name, this, typeRef).apply {
isCrossinline = false valueParameters += createValueParameter(typeRef)
isNoinline = false
isVararg = false
} }
} }
} }
@@ -75,10 +71,14 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
}.toMap() }.toMap()
@OptIn(FirImplementationDetail::class) @OptIn(FirImplementationDetail::class)
private fun createFirFunction(name: Name, symbol: FirNamedFunctionSymbol): FirSimpleFunctionImpl = FirIntegerOperator( private fun createFirFunction(
name: Name,
symbol: FirNamedFunctionSymbol,
returnTypeRef: FirResolvedTypeRef = FirILTTypeRefPlaceHolder(isUnsigned)
): FirSimpleFunctionImpl = FirIntegerOperator(
source = null, source = null,
session, session,
FirILTTypeRefPlaceHolder(isUnsigned), returnTypeRef,
receiverTypeRef = null, receiverTypeRef = null,
ALL_OPERATORS.getValue(name), ALL_OPERATORS.getValue(name),
FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL), FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL),
@@ -87,11 +87,29 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
resolvePhase = FirResolvePhase.BODY_RESOLVE resolvePhase = FirResolvePhase.BODY_RESOLVE
} }
private fun createValueParameter(returnTypeRef: FirResolvedTypeRef): FirValueParameter {
return buildValueParameter {
source = null
origin = FirDeclarationOrigin.Synthetic
session = this@FirIntegerLiteralTypeScope.session
this.returnTypeRef = returnTypeRef
name = Name.identifier("arg")
symbol = FirVariableSymbol(name)
defaultValue = null
isCrossinline = false
isNoinline = false
isVararg = false
}
}
override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) { override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) {
val symbol = BINARY_OPERATOR_SYMBOLS[name] UNARY_OPERATOR_SYMBOLS[name]?.let {
?: UNARY_OPERATOR_SYMBOLS[name] processor(it)
?: return return
}
val symbol = BINARY_OPERATOR_SYMBOLS[name] ?: return
processor(symbol) processor(symbol)
FLOATING_BINARY_OPERATOR_SYMBOLS[name]?.forEach(processor)
} }
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) { override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
@@ -138,21 +156,21 @@ class FirIntegerOperator @FirImplementationDetail constructor(
annotations = mutableListOf(), annotations = mutableListOf(),
typeParameters = mutableListOf(), typeParameters = mutableListOf(),
) { ) {
enum class Kind(val unary: Boolean, val operatorName: Name) { enum class Kind(val operatorName: Name, val unary: Boolean, val withFloatingRhs: Boolean) {
PLUS(false, OperatorNameConventions.PLUS), PLUS(OperatorNameConventions.PLUS, unary = false, withFloatingRhs = true),
MINUS(false, OperatorNameConventions.MINUS), MINUS(OperatorNameConventions.MINUS, unary = false, withFloatingRhs = true),
TIMES(false, OperatorNameConventions.TIMES), TIMES(OperatorNameConventions.TIMES, unary = false, withFloatingRhs = true),
DIV(false, OperatorNameConventions.DIV), DIV(OperatorNameConventions.DIV, unary = false, withFloatingRhs = true),
REM(false, OperatorNameConventions.REM), REM(OperatorNameConventions.REM, unary = false, withFloatingRhs = true),
SHL(false, Name.identifier("shl")), SHL(Name.identifier("shl"), unary = false, withFloatingRhs = false),
SHR(false, Name.identifier("shr")), SHR(Name.identifier("shr"), unary = false, withFloatingRhs = false),
USHR(false, Name.identifier("ushr")), USHR(Name.identifier("ushr"), unary = false, withFloatingRhs = false),
XOR(false, Name.identifier("xor")), XOR(Name.identifier("xor"), unary = false, withFloatingRhs = false),
AND(false, Name.identifier("and")), AND(Name.identifier("and"), unary = false, withFloatingRhs = false),
OR(false, Name.identifier("or")), OR(Name.identifier("or"), unary = false, withFloatingRhs = false),
UNARY_PLUS(true, OperatorNameConventions.UNARY_PLUS), UNARY_PLUS(OperatorNameConventions.UNARY_PLUS, unary = true, withFloatingRhs = false),
UNARY_MINUS(true, OperatorNameConventions.UNARY_MINUS), UNARY_MINUS(OperatorNameConventions.UNARY_MINUS, unary = true, withFloatingRhs = false),
INV(true, Name.identifier("inv")) INV(Name.identifier("inv"), unary = true, withFloatingRhs = false),
} }
} }
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JS_IR // IGNORE_BACKEND: JS_IR
// IGNORE_BACKEND: JS_IR_ES6 // IGNORE_BACKEND: JS_IR_ES6
// TODO: muted automatically, investigate should it be ran for JS or not // TODO: muted automatically, investigate should it be ran for JS or not
+1 -1
View File
@@ -6,7 +6,7 @@ fun test() : Int {
val a : () -> Unit = { val a : () -> Unit = {
<!INAPPLICABLE_CANDIDATE!>foo<!>(1) <!INAPPLICABLE_CANDIDATE!>foo<!>(1)
} }
return 1 - "1" return 1 <!NONE_APPLICABLE!>-<!> "1"
} }
class A() { class A() {
@@ -4,5 +4,5 @@ fun bar() {
// See exception in KT-13421 // See exception in KT-13421
fun foo() { fun foo() {
42 and false 42 <!INAPPLICABLE_CANDIDATE!>and<!> false
} }
@@ -12,9 +12,9 @@ class B {
fun test() { fun test() {
with(B()) { with(B()) {
with(A()) { with(A()) {
<!INAPPLICABLE_CANDIDATE!>takeString<!>(1 % "") takeString(1 % "")
} }
} }
} }
fun takeString(s: String) {} fun takeString(s: String) {}
@@ -84,8 +84,8 @@ class Case3 {
} }
fun case() { fun case() {
<!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> <!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!>
<!DEBUG_INFO_EXPRESSION_TYPE("ILT: 0")!>1+"1"<!> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!>
} }
} }
@@ -95,15 +95,15 @@ fun case3(case: Case3) {
//(1.1) return type is String //(1.1) return type is String
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>case.boo+"1"<!> <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>case.boo+"1"<!>
case.apply { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> } case.apply { <!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!> }
case.apply { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>1+"1"<!> } case.apply { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!> }
case.let { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> } case.let { <!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!> }
case.let { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>1+"1"<!> } case.let { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!> }
case.also { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> } case.also { <!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!> }
case.also { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>1+"1"<!> } case.also { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!> }
case.run { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> } case.run { <!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!> }
case.run { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>1+"1"<!> } case.run { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!> }
} }