JS: support reified usage in extension functions

This commit is contained in:
Alexey Tsvetkov
2015-05-06 17:23:21 +03:00
parent 79ab47d374
commit 818b197169
4 changed files with 41 additions and 17 deletions
@@ -41,6 +41,12 @@ public class ReifiedTestGenerated extends AbstractReifiedTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("extensionFun.kt")
public void testExtensionFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/reified/cases/extensionFun.kt");
doTest(fileName);
}
@TestMetadata("extensionLambda.kt") @TestMetadata("extensionLambda.kt")
public void testExtensionLambda() throws Exception { public void testExtensionLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/reified/cases/extensionLambda.kt"); String fileName = JetTestUtils.navigationMetadata("js/js.translator/testData/reified/cases/extensionLambda.kt");
@@ -36,17 +36,14 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
import java.util.ArrayList import java.util.ArrayList
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> { public fun CallArgumentTranslator.ArgumentsInfo.argsWithReceiver(receiver: JsExpression): List<JsExpression> {
if (arguments.isEmpty()) val allArguments = ArrayList<JsExpression>(1 + reifiedArguments.size() + valueArguments.size())
return SmartList(receiver) allArguments.addAll(reifiedArguments)
allArguments.add(receiver)
val argumentList = ArrayList<JsExpression>(1 + arguments.size()) allArguments.addAll(valueArguments)
argumentList.add(receiver) return allArguments
argumentList.addAll(arguments)
return argumentList
} }
// call may be native and|or with spreadOperator // call may be native and|or with spreadOperator
object DefaultFunctionCallCase : FunctionCallCase { object DefaultFunctionCallCase : FunctionCallCase {
// TODO: refactor after fix ArgumentsInfo - duplicate code // TODO: refactor after fix ArgumentsInfo - duplicate code
@@ -118,13 +115,13 @@ object DefaultFunctionCallCase : FunctionCallCase {
functionRef functionRef
} }
return JsInvocation(referenceToCall, addReceiverToArgs(extensionReceiver!!, argumentsInfo.translateArguments)) return JsInvocation(referenceToCall, argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
override fun FunctionCallInfo.bothReceivers(): JsExpression { override fun FunctionCallInfo.bothReceivers(): JsExpression {
// TODO: think about crazy case: spreadOperator + native // TODO: think about crazy case: spreadOperator + native
val functionRef = JsNameRef(functionName, dispatchReceiver!!) val functionRef = JsNameRef(functionName, dispatchReceiver!!)
return JsInvocation(functionRef, addReceiverToArgs(extensionReceiver!!, argumentsInfo.translateArguments)) return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
} }
@@ -200,7 +197,7 @@ object InvokeIntrinsic : FunctionCallCase {
* extLambda.call(obj, some, args) * extLambda.call(obj, some, args)
*/ */
override fun FunctionCallInfo.bothReceivers(): JsExpression { override fun FunctionCallInfo.bothReceivers(): JsExpression {
return JsInvocation(Namer.getFunctionCallRef(dispatchReceiver!!), addReceiverToArgs(extensionReceiver!!, argumentsInfo.translateArguments)) return JsInvocation(Namer.getFunctionCallRef(dispatchReceiver!!), argumentsInfo.argsWithReceiver(extensionReceiver!!))
} }
} }
@@ -227,7 +224,7 @@ object SuperCallCase : FunctionCallCase {
// TODO: spread operator // TODO: spread operator
val prototypeClass = JsNameRef(Namer.getPrototypeName(), dispatchReceiver!!) val prototypeClass = JsNameRef(Namer.getPrototypeName(), dispatchReceiver!!)
val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass)) val functionRef = Namer.getFunctionCallRef(JsNameRef(functionName, prototypeClass))
return JsInvocation(functionRef, addReceiverToArgs(JsLiteral.THIS, argumentsInfo.translateArguments)) return JsInvocation(functionRef, argumentsInfo.argsWithReceiver(JsLiteral.THIS))
} }
} }
@@ -45,10 +45,14 @@ public class CallArgumentTranslator private (
) : AbstractTranslator(context) { ) : AbstractTranslator(context) {
public data class ArgumentsInfo( public data class ArgumentsInfo(
public val translateArguments: List<JsExpression>, public val valueArguments: List<JsExpression>,
public val hasSpreadOperator: Boolean, public val hasSpreadOperator: Boolean,
public val cachedReceiver: TemporaryConstVariable? public val cachedReceiver: TemporaryConstVariable?,
) public val reifiedArguments: List<JsExpression> = listOf()
) {
public val translateArguments: List<JsExpression>
get() = reifiedArguments + valueArguments
}
private enum class ArgumentsKind { private enum class ArgumentsKind {
HAS_EMPTY_EXPRESSION_ARGUMENT HAS_EMPTY_EXPRESSION_ARGUMENT
@@ -349,5 +353,5 @@ private fun Map<TypeParameterDescriptor, JetType>.addReifiedTypeArgsTo(
reifiedTypeArguments.add(isCheckCallable) reifiedTypeArguments.add(isCheckCallable)
} }
return info.copy(translateArguments = reifiedTypeArguments + info.translateArguments) return info.copy(reifiedArguments = reifiedTypeArguments)
} }
@@ -0,0 +1,17 @@
package foo
// CHECK_NOT_CALLED: canBeCastedTo
open class A
class B
class C : A()
inline fun Any.canBeCastedTo<reified T>(): Boolean = this is T
fun box(): String {
assertEquals(true, A().canBeCastedTo<A>(), "A().canBeCastedTo<A>()")
assertEquals(false, A().canBeCastedTo<B>(), "A().canBeCastedTo<B>()")
assertEquals(true, C().canBeCastedTo<A>(), "C().canBeCastedTo<A>()")
return "OK"
}