[JS IR] Fix binary operator lookup in JsIrBackendContext

Previously, if multiple operators with the same name were defined in
a single class, we could look up neither of them (for example, the `Int`
class defines multiple `plus` operators, one for each primitive type
referenced on the RHS).

Now we can distinguish operator functions by their RHS type when
performing operator lookup in the backend.
This commit is contained in:
Sergej Jaskiewicz
2021-12-22 18:56:03 +03:00
committed by Space
parent 9547b0cae1
commit d8838f4e7b
2 changed files with 20 additions and 13 deletions
@@ -45,6 +45,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceMapNotNull
import org.jetbrains.kotlin.utils.addToStdlib.cast
class JsIrBackendContext(
val module: ModuleDescriptor,
@@ -161,7 +163,13 @@ class JsIrBackendContext(
return numbers + listOf(Name.identifier("String"), Name.identifier("Boolean"))
}
fun getOperatorByName(name: Name, type: IrSimpleType) = operatorMap[name]?.get(type.classifier)
fun getOperatorByName(name: Name, lhsType: IrSimpleType, rhsType: IrSimpleType?) =
operatorMap[name]?.get(lhsType.classifier)?.let { candidates ->
if (rhsType == null)
candidates.singleOrNull()
else
candidates.singleOrNull { it.owner.valueParameters[0].type.cast<IrSimpleType>().classifier == rhsType.classifier }
}
override val coroutineSymbols =
JsCommonCoroutineSymbols(symbolTable, module, this)
@@ -311,17 +319,16 @@ class JsIrBackendContext(
val klocalDelegateBuilder =
getFunctions(FqName("kotlin.js.getLocalDelegateReference")).single().let { symbolTable.referenceSimpleFunction(it) }
private fun referenceOperators(): Map<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> {
private fun referenceOperators(): Map<Name, Map<IrClassSymbol, Collection<IrSimpleFunctionSymbol>>> {
val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
return OperatorNames.ALL.map { name ->
// TODO to replace KotlinType with IrType we need right equals on IrType
name to primitiveIrSymbols.fold(mutableMapOf<IrClassifierSymbol, IrSimpleFunctionSymbol>()) { m, s ->
val function = s.owner.declarations.filterIsInstance<IrSimpleFunction>().singleOrNull { it.name == name }
function?.let { m.put(s, it.symbol) }
m
return OperatorNames.ALL.associateWith { name ->
primitiveIrSymbols.associateWith { classSymbol ->
classSymbol.owner.declarations
.filterIsInstanceMapNotNull<IrSimpleFunction, IrSimpleFunctionSymbol> { function ->
function.symbol.takeIf { function.name == name }
}
}
}.toMap()
}
}
private fun findProperty(memberScope: MemberScope, name: Name): List<PropertyDescriptor> =
@@ -16,7 +16,7 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
val symbols = context.ir.symbols
private fun buildBinaryOperator(name: Name, l: IrExpression, r: IrExpression): IrExpression {
val symbol = context.getOperatorByName(name, l.type as IrSimpleType)
val symbol = context.getOperatorByName(name, l.type as IrSimpleType, r.type as IrSimpleType)
return JsIrBuilder.buildCall(symbol!!).apply {
dispatchReceiver = l
putValueArgument(0, r)
@@ -24,7 +24,7 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
}
private fun buildUnaryOperator(name: Name, v: IrExpression): IrExpression {
val symbol = context.getOperatorByName(name, v.type as IrSimpleType)!!
val symbol = context.getOperatorByName(name, v.type as IrSimpleType, null)!!
return JsIrBuilder.buildCall(symbol).apply { dispatchReceiver = v }
}
@@ -45,4 +45,4 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
JsIrBuilder.buildIfElse(context.irBuiltIns.booleanType, l, r, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false))
fun oror(l: IrExpression, r: IrExpression) = // if (l) true else r
JsIrBuilder.buildIfElse(context.irBuiltIns.booleanType, l, JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true), r)
}
}