[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:
+17
-10
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user