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);
}
@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")
public void testExtensionLambda() throws Exception {
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 java.util.ArrayList
public fun addReceiverToArgs(receiver: JsExpression, arguments: List<JsExpression>): List<JsExpression> {
if (arguments.isEmpty())
return SmartList(receiver)
val argumentList = ArrayList<JsExpression>(1 + arguments.size())
argumentList.add(receiver)
argumentList.addAll(arguments)
return argumentList
public fun CallArgumentTranslator.ArgumentsInfo.argsWithReceiver(receiver: JsExpression): List<JsExpression> {
val allArguments = ArrayList<JsExpression>(1 + reifiedArguments.size() + valueArguments.size())
allArguments.addAll(reifiedArguments)
allArguments.add(receiver)
allArguments.addAll(valueArguments)
return allArguments
}
// call may be native and|or with spreadOperator
object DefaultFunctionCallCase : FunctionCallCase {
// TODO: refactor after fix ArgumentsInfo - duplicate code
@@ -118,13 +115,13 @@ object DefaultFunctionCallCase : FunctionCallCase {
functionRef
}
return JsInvocation(referenceToCall, addReceiverToArgs(extensionReceiver!!, argumentsInfo.translateArguments))
return JsInvocation(referenceToCall, argumentsInfo.argsWithReceiver(extensionReceiver!!))
}
override fun FunctionCallInfo.bothReceivers(): JsExpression {
// TODO: think about crazy case: spreadOperator + native
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)
*/
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
val prototypeClass = JsNameRef(Namer.getPrototypeName(), dispatchReceiver!!)
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) {
public data class ArgumentsInfo(
public val translateArguments: List<JsExpression>,
public val valueArguments: List<JsExpression>,
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 {
HAS_EMPTY_EXPRESSION_ARGUMENT
@@ -349,5 +353,5 @@ private fun Map<TypeParameterDescriptor, JetType>.addReifiedTypeArgsTo(
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"
}