[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
): ConeKotlinType? {
if (parameter == null) return null
if (parameter.returnTypeRef is FirILTTypeRefPlaceHolder && argument.resultType is FirResolvedTypeRef)
return argument.resultType.coneType
val parameterReturnTypeRef = parameter.returnTypeRef
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 expectedType = getExpectedTypeWithSAMConversion(session, argument, basicExpectedType, context) ?: basicExpectedType
return this.substitutor.substituteOrSelf(expectedType)
@@ -218,7 +218,9 @@ class IntegerOperatorsTypeUpdater(private val approximator: IntegerLiteralTypeAp
}
else -> {
val expectedType = when (argumentType.classId) {
StandardClassIds.Long -> argumentType
StandardClassIds.Long,
StandardClassIds.Float,
StandardClassIds.Double -> argumentType
else -> ConeIntegerLiteralTypeImpl.createType(StandardClassIds.Int)
}
functionCall.transformSingle(approximator, expectedType)
@@ -9,10 +9,7 @@ import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.contracts.impl.FirEmptyContractDescription
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
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.*
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirSimpleFunctionImpl
@@ -42,6 +39,7 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
companion object {
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 }
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 ->
name to FirNamedFunctionSymbol(CallableId(name)).apply {
createFirFunction(name, this).apply {
val valueParameterName = Name.identifier("arg")
valueParameters += buildValueParameter {
source = null
origin = FirDeclarationOrigin.Synthetic
session = this@FirIntegerLiteralTypeScope.session
returnTypeRef = FirILTTypeRefPlaceHolder(isUnsigned)
this.name = valueParameterName
symbol = FirVariableSymbol(valueParameterName)
defaultValue = null
isCrossinline = false
isNoinline = false
isVararg = false
valueParameters += createValueParameter(FirILTTypeRefPlaceHolder(isUnsigned))
}
}
}.toMap()
private val FLOATING_BINARY_OPERATOR_SYMBOLS = FLOATING_BINARY_OPERATOR_NAMES.map { name ->
name to listOf(session.builtinTypes.floatType, session.builtinTypes.doubleType).map { typeRef ->
FirNamedFunctionSymbol(CallableId(name)).apply {
createFirFunction(name, this, typeRef).apply {
valueParameters += createValueParameter(typeRef)
}
}
}
@@ -75,10 +71,14 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
}.toMap()
@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,
session,
FirILTTypeRefPlaceHolder(isUnsigned),
returnTypeRef,
receiverTypeRef = null,
ALL_OPERATORS.getValue(name),
FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL),
@@ -87,11 +87,29 @@ class FirIntegerLiteralTypeScope(private val session: FirSession, val isUnsigned
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) {
val symbol = BINARY_OPERATOR_SYMBOLS[name]
?: UNARY_OPERATOR_SYMBOLS[name]
?: return
UNARY_OPERATOR_SYMBOLS[name]?.let {
processor(it)
return
}
val symbol = BINARY_OPERATOR_SYMBOLS[name] ?: return
processor(symbol)
FLOATING_BINARY_OPERATOR_SYMBOLS[name]?.forEach(processor)
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
@@ -138,21 +156,21 @@ class FirIntegerOperator @FirImplementationDetail constructor(
annotations = mutableListOf(),
typeParameters = mutableListOf(),
) {
enum class Kind(val unary: Boolean, val operatorName: Name) {
PLUS(false, OperatorNameConventions.PLUS),
MINUS(false, OperatorNameConventions.MINUS),
TIMES(false, OperatorNameConventions.TIMES),
DIV(false, OperatorNameConventions.DIV),
REM(false, OperatorNameConventions.REM),
SHL(false, Name.identifier("shl")),
SHR(false, Name.identifier("shr")),
USHR(false, Name.identifier("ushr")),
XOR(false, Name.identifier("xor")),
AND(false, Name.identifier("and")),
OR(false, Name.identifier("or")),
UNARY_PLUS(true, OperatorNameConventions.UNARY_PLUS),
UNARY_MINUS(true, OperatorNameConventions.UNARY_MINUS),
INV(true, Name.identifier("inv"))
enum class Kind(val operatorName: Name, val unary: Boolean, val withFloatingRhs: Boolean) {
PLUS(OperatorNameConventions.PLUS, unary = false, withFloatingRhs = true),
MINUS(OperatorNameConventions.MINUS, unary = false, withFloatingRhs = true),
TIMES(OperatorNameConventions.TIMES, unary = false, withFloatingRhs = true),
DIV(OperatorNameConventions.DIV, unary = false, withFloatingRhs = true),
REM(OperatorNameConventions.REM, unary = false, withFloatingRhs = true),
SHL(Name.identifier("shl"), unary = false, withFloatingRhs = false),
SHR(Name.identifier("shr"), unary = false, withFloatingRhs = false),
USHR(Name.identifier("ushr"), unary = false, withFloatingRhs = false),
XOR(Name.identifier("xor"), unary = false, withFloatingRhs = false),
AND(Name.identifier("and"), unary = false, withFloatingRhs = false),
OR(Name.identifier("or"), unary = false, withFloatingRhs = false),
UNARY_PLUS(OperatorNameConventions.UNARY_PLUS, unary = true, withFloatingRhs = false),
UNARY_MINUS(OperatorNameConventions.UNARY_MINUS, unary = true, withFloatingRhs = false),
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_ES6
// 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 = {
<!INAPPLICABLE_CANDIDATE!>foo<!>(1)
}
return 1 - "1"
return 1 <!NONE_APPLICABLE!>-<!> "1"
}
class A() {
@@ -4,5 +4,5 @@ fun bar() {
// See exception in KT-13421
fun foo() {
42 and false
}
42 <!INAPPLICABLE_CANDIDATE!>and<!> false
}
@@ -12,9 +12,9 @@ class B {
fun test() {
with(B()) {
with(A()) {
<!INAPPLICABLE_CANDIDATE!>takeString<!>(1 % "")
takeString(1 % "")
}
}
}
fun takeString(s: String) {}
fun takeString(s: String) {}
@@ -84,8 +84,8 @@ class Case3 {
}
fun case() {
<!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!>
<!DEBUG_INFO_EXPRESSION_TYPE("ILT: 0")!>1+"1"<!>
<!DEBUG_INFO_CALL("fqName: testPackCase3.Case3.Companion.plus; typeCall: operator extension function")!>1+"1"<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>1+"1"<!>
}
}
@@ -95,15 +95,15 @@ fun case3(case: Case3) {
//(1.1) return type is String
<!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_EXPRESSION_TYPE("kotlin.Int")!>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.String")!>1+"1"<!> }
case.let { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> }
case.let { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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.String")!>1+"1"<!> }
case.also { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> }
case.also { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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.String")!>1+"1"<!> }
case.run { <!DEBUG_INFO_CALL("fqName: <local>.plus; typeCall: function")!>1+"1"<!> }
case.run { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int")!>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.String")!>1+"1"<!> }
}