[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.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.isNullable import org.jetbrains.kotlin.types.isNullable
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceMapNotNull
import org.jetbrains.kotlin.utils.addToStdlib.cast
class JsIrBackendContext( class JsIrBackendContext(
val module: ModuleDescriptor, val module: ModuleDescriptor,
@@ -161,7 +163,13 @@ class JsIrBackendContext(
return numbers + listOf(Name.identifier("String"), Name.identifier("Boolean")) 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 = override val coroutineSymbols =
JsCommonCoroutineSymbols(symbolTable, module, this) JsCommonCoroutineSymbols(symbolTable, module, this)
@@ -311,17 +319,16 @@ class JsIrBackendContext(
val klocalDelegateBuilder = val klocalDelegateBuilder =
getFunctions(FqName("kotlin.js.getLocalDelegateReference")).single().let { symbolTable.referenceSimpleFunction(it) } 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 } val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
return OperatorNames.ALL.associateWith { name ->
return OperatorNames.ALL.map { name -> primitiveIrSymbols.associateWith { classSymbol ->
// TODO to replace KotlinType with IrType we need right equals on IrType classSymbol.owner.declarations
name to primitiveIrSymbols.fold(mutableMapOf<IrClassifierSymbol, IrSimpleFunctionSymbol>()) { m, s -> .filterIsInstanceMapNotNull<IrSimpleFunction, IrSimpleFunctionSymbol> { function ->
val function = s.owner.declarations.filterIsInstance<IrSimpleFunction>().singleOrNull { it.name == name } function.symbol.takeIf { function.name == name }
function?.let { m.put(s, it.symbol) } }
m
} }
}.toMap() }
} }
private fun findProperty(memberScope: MemberScope, name: Name): List<PropertyDescriptor> = private fun findProperty(memberScope: MemberScope, name: Name): List<PropertyDescriptor> =
@@ -16,7 +16,7 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
val symbols = context.ir.symbols val symbols = context.ir.symbols
private fun buildBinaryOperator(name: Name, l: IrExpression, r: IrExpression): IrExpression { 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 { return JsIrBuilder.buildCall(symbol!!).apply {
dispatchReceiver = l dispatchReceiver = l
putValueArgument(0, r) putValueArgument(0, r)
@@ -24,7 +24,7 @@ class JsIrArithBuilder(val context: JsIrBackendContext) {
} }
private fun buildUnaryOperator(name: Name, v: IrExpression): IrExpression { 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 } return JsIrBuilder.buildCall(symbol).apply { dispatchReceiver = v }
} }