@@ -178,7 +178,7 @@ open class KotlinFileExtractor(
178178 val parentId =
179179 if (parent.isAnonymousObject) {
180180 @Suppress(" UNCHECKED_CAST" )
181- useAnonymousClass(c ).javaResult.id as Label <out DbClass >
181+ useAnonymousClass(parent ).javaResult.id as Label <out DbClass >
182182 } else {
183183 useClassInstance(parent, listOf ()).typeResult.id
184184 }
@@ -260,12 +260,11 @@ open class KotlinFileExtractor(
260260 }
261261
262262 private fun extractValueParameter (vp : IrValueParameter , parent : Label <out DbCallable >, idx : Int ): TypeResults {
263- return extractValueParameter(useValueParameter(vp), vp.type, vp.name.asString(), vp , parent, idx)
263+ return extractValueParameter(useValueParameter(vp), vp.type, vp.name.asString(), tw.getLocation(vp) , parent, idx)
264264 }
265265
266- private fun extractValueParameter (id : Label <out DbParam >, t : IrType , name : String , loc : IrElement , parent : Label <out DbCallable >, idx : Int ): TypeResults {
266+ private fun extractValueParameter (id : Label <out DbParam >, t : IrType , name : String , locId : Label < DbLocation > , parent : Label <out DbCallable >, idx : Int ): TypeResults {
267267 val type = useType(t)
268- val locId = tw.getLocation(loc)
269268 tw.writeParams(id, type.javaResult.id, type.kotlinResult.id, idx, parent, id)
270269 tw.writeHasLocation(id, locId)
271270 tw.writeParamName(id, name)
@@ -721,6 +720,15 @@ open class KotlinFileExtractor(
721720 tw.writeStatementEnclosingExpr(idNewexpr, enclosingStmt)
722721 tw.writeCallableBinding(idNewexpr, ids.constructor )
723722
723+ @Suppress(" UNCHECKED_CAST" )
724+ tw.writeIsAnonymClass(ids.type.javaResult.id as Label <DbClass >, idNewexpr)
725+
726+ val typeAccessId = tw.getFreshIdLabel<DbUnannotatedtypeaccess >()
727+ val anyType = useType(pluginContext.irBuiltIns.anyType)
728+ tw.writeExprs_unannotatedtypeaccess(typeAccessId, anyType.javaResult.id, anyType.kotlinResult.id, idNewexpr, - 3 )
729+ tw.writeCallableEnclosingExpr(typeAccessId, callable)
730+ tw.writeStatementEnclosingExpr(typeAccessId, enclosingStmt)
731+
724732 } else {
725733 val methodId = useFunction<DbMethod >(callTarget)
726734 tw.writeCallableBinding(id, methodId)
@@ -1644,68 +1652,166 @@ open class KotlinFileExtractor(
16441652 functionN(pluginContext)(parameters.size).typeWith(types)
16451653 }
16461654
1655+ val lambdaType = pluginContext.referenceClass(FqName (" kotlin.jvm.internal.Lambda" ))!! .typeWith()
1656+ /*
1657+ * Extract generated class:
1658+ * ```
1659+ * class C : kotlin.jvm.internal.Lambda, kotlin.FunctionI<T0,T1, ... TI, R> {
1660+ * constructor() { super(I); }
1661+ * fun invoke(a0:T0, a1:T1, ... aI: TI): R { ... }
1662+ * }
1663+ * ```
1664+ * or in case of big arity lambdas
1665+ * ```
1666+ * class C : kotlin.jvm.internal.Lambda, kotlin.FunctionN<R> {
1667+ * constructor() { super(I); }
1668+ * fun invoke(a0:T0, a1:T1, ... aI: TI): R { ... }
1669+ * fun invoke(vararg args: Any?): R {
1670+ * return invoke(args[0] as T0, args[1] as T1, ..., args[I] as TI)
1671+ * }
1672+ * }
1673+ * ```
1674+ * */
16471675 extractGeneratedClass(
16481676 e.function, // We're adding this function as a member, and changing its name to `invoke` to implement `kotlin.FunctionX<,,,>.invoke(,,)`
1649- listOf (
1650- pluginContext.referenceClass(FqName (" kotlin.jvm.internal.Lambda" ))!! .typeWith(),
1651- fnInterface),
1677+ listOf (lambdaType, fnInterface),
16521678 listOf (e.function.valueParameters.size.toIrConst(pluginContext.irBuiltIns.intType, e.startOffset, e.endOffset)))
16531679
1654- val objectType = useType(pluginContext.irBuiltIns.anyNType).javaResult.id
1655-
1656- // Only add bridge method if its signature is different from the lambda function
1657- if (! types.all { useType(it).javaResult.id == objectType } ||
1658- types.size > BuiltInFunctionArity .BIG_ARITY ) {
1659-
1660- val methodId = tw.getFreshIdLabel<DbMethod >()
1661-
1662- val paramTypes =
1663- if (types.size > BuiltInFunctionArity .BIG_ARITY ) {
1664- // signature is `Object invoke(Object[] p)`
1665- listOf (extractValueParameter(tw.getFreshIdLabel(), pluginContext.irBuiltIns.arrayClass.typeWith(pluginContext.irBuiltIns.anyNType), " p" , e, methodId, 0 ))
1666- } else {
1667- // signature is `Object invoke(Object p0, Object p1, ..., Object pN)`
1668- parameters.mapIndexed { i, _ ->
1669- extractValueParameter(tw.getFreshIdLabel(), pluginContext.irBuiltIns.anyNType, " p$i " , e, methodId, i)
1670- }
1671- }
1680+ if (types.size > BuiltInFunctionArity .BIG_ARITY ) {
1681+ implementFunctionNInvoke(e.function, ids, locId, parameters)
16721682
1673- val paramsSignature = paramTypes.joinToString(separator = " ," , prefix = " (" , postfix = " )" ) { it.javaResult.signature!! }
1674-
1675- val returnType = useType(pluginContext.irBuiltIns.anyNType, TypeContext .RETURN )
1676- val shortName = OperatorNameConventions .INVOKE .asString()
1677- @Suppress(" UNCHECKED_CAST" )
1678- tw.writeMethods(methodId, shortName, " $shortName$paramsSignature " , returnType.javaResult.id, returnType.kotlinResult.id, ids.type.javaResult.id as Label <out DbReftype >, methodId)
1679- tw.writeHasLocation(methodId, locId)
1680-
1681- // TODO:
1682- // - Add body of bridge method, which calls `e.function`:
1683- // ```
1684- // public int invoke(int i, Object j, String k) { return 5; }
1685- // public Object invoke(Object p0, Object p1, Object p2) {
1686- // return invoke((int)p0, (Object)p1, (String)p2);
1687- // or
1688- // invoke((int)p0, (Object)p1, (String)p2);
1689- // return kotlin.Unit.INSTANCE
1690- // }
1691- // ```
1683+ // todo: which method should be returned in `LambdaExpr.asMethod()`?
16921684 }
16931685
16941686 val exprParent = parent.expr(e, callable)
1687+ val idLambdaExpr = tw.getFreshIdLabel<DbLambdaexpr >()
1688+ tw.writeExprs_lambdaexpr(idLambdaExpr, ids.type.javaResult.id, ids.type.kotlinResult.id, exprParent.parent, exprParent.idx)
1689+ tw.writeHasLocation(idLambdaExpr, locId)
1690+ tw.writeCallableEnclosingExpr(idLambdaExpr, callable)
1691+ tw.writeStatementEnclosingExpr(idLambdaExpr, exprParent.enclosingStmt)
1692+ tw.writeCallableBinding(idLambdaExpr, ids.constructor )
1693+
1694+ val typeAccessId = tw.getFreshIdLabel<DbUnannotatedtypeaccess >()
1695+ // todo: in Java, we're accessing the base functional interface type.
1696+ val typeAccessType = useType(lambdaType)
1697+ tw.writeExprs_unannotatedtypeaccess(typeAccessId, typeAccessType.javaResult.id, typeAccessType.kotlinResult.id, idLambdaExpr, - 3 )
1698+ tw.writeCallableEnclosingExpr(typeAccessId, callable)
1699+ tw.writeStatementEnclosingExpr(typeAccessId, exprParent.enclosingStmt)
1700+
1701+ // todo: fix hard coded block body of lambda
1702+ tw.writeLambdaKind(idLambdaExpr, 1 )
16951703
1696- val idNewexpr = tw.getFreshIdLabel<DbNewexpr >()
1697- tw.writeExprs_newexpr(idNewexpr, ids.type.javaResult.id, ids.type.kotlinResult.id, exprParent.parent, exprParent.idx)
1698- tw.writeHasLocation(idNewexpr, locId)
1699- tw.writeCallableEnclosingExpr(idNewexpr, callable)
1700- tw.writeStatementEnclosingExpr(idNewexpr, exprParent.enclosingStmt)
1701- tw.writeCallableBinding(idNewexpr, ids.constructor )
1704+ @Suppress(" UNCHECKED_CAST" )
1705+ tw.writeIsAnonymClass(ids.type.javaResult.id as Label <DbClass >, idLambdaExpr)
17021706 }
17031707 else -> {
17041708 logger.warnElement(Severity .ErrorSevere , " Unrecognised IrExpression: " + e.javaClass, e)
17051709 }
17061710 }
17071711 }
17081712
1713+ /*
1714+ * This function generates an implementation for `fun kotlin.FunctionN<R>.invoke(vararg args: Any?): R`
1715+ *
1716+ * The following body is added:
1717+ * ```
1718+ * fun invoke(vararg args: Any?): R {
1719+ * return invoke(args[0] as T0, args[1] as T1, ..., args[I] as TI)
1720+ * }
1721+ * ```
1722+ * */
1723+ private fun implementFunctionNInvoke (
1724+ lambda : IrFunction ,
1725+ ids : LocalFunctionLabels ,
1726+ locId : Label <DbLocation >,
1727+ parameters : List <IrValueParameter >
1728+ ) {
1729+ val methodId = tw.getFreshIdLabel<DbMethod >()
1730+
1731+ val argsParamId = tw.getFreshIdLabel<DbParam >()
1732+ val argsParamType = pluginContext.irBuiltIns.arrayClass.typeWith(pluginContext.irBuiltIns.anyNType)
1733+ val paramType = extractValueParameter(argsParamId, argsParamType, " args" , locId, methodId, 0 )
1734+
1735+ val paramsSignature = " (${paramType.javaResult.signature!! } )"
1736+
1737+ val returnType = useType(lambda.returnType, TypeContext .RETURN )
1738+ val shortName = OperatorNameConventions .INVOKE .asString()
1739+ @Suppress(" UNCHECKED_CAST" )
1740+ tw.writeMethods(methodId, shortName, " $shortName$paramsSignature " , returnType.javaResult.id, returnType.kotlinResult.id, ids.type.javaResult.id as Label <out DbReftype >, methodId)
1741+ tw.writeHasLocation(methodId, locId)
1742+
1743+ // Block
1744+ val blockId = tw.getFreshIdLabel<DbBlock >()
1745+ tw.writeStmts_block(blockId, methodId, 0 , methodId)
1746+ tw.writeHasLocation(blockId, locId)
1747+
1748+ // Return
1749+ val retId = tw.getFreshIdLabel<DbReturnstmt >()
1750+ tw.writeStmts_returnstmt(retId, blockId, 0 , methodId)
1751+ tw.writeHasLocation(retId, locId)
1752+
1753+ fun extractCommonExpr (id : Label <out DbExpr >) {
1754+ tw.writeHasLocation(id, locId)
1755+ tw.writeCallableEnclosingExpr(id, methodId)
1756+ tw.writeStatementEnclosingExpr(id, retId)
1757+ }
1758+
1759+ // Call to original `invoke`:
1760+ val callId = tw.getFreshIdLabel<DbMethodaccess >()
1761+ val callType = useType(lambda.returnType)
1762+ tw.writeExprs_methodaccess(callId, callType.javaResult.id, callType.kotlinResult.id, retId, 0 )
1763+ extractCommonExpr(callId)
1764+ val calledMethodId = useFunction<DbMethod >(lambda)
1765+ tw.writeCallableBinding(callId, calledMethodId)
1766+
1767+ // this access
1768+ val thisId = tw.getFreshIdLabel<DbThisaccess >()
1769+ tw.writeExprs_thisaccess(thisId, ids.type.javaResult.id, ids.type.kotlinResult.id, callId, - 1 )
1770+ extractCommonExpr(thisId)
1771+
1772+ // parameters
1773+ val intType = useType(pluginContext.irBuiltIns.intType)
1774+ val argsType = useType(argsParamType)
1775+ val anyNType = useType(pluginContext.irBuiltIns.anyNType)
1776+
1777+ val func =
1778+ pluginContext.irBuiltIns.arrayClass.owner.declarations.find { it is IrFunction && it.name.asString() == " get" }
1779+
1780+ @Suppress(" UNCHECKED_CAST" )
1781+ val arrayGetMethodId = useFunction<DbMethod >(func as IrFunction )
1782+
1783+ for ((pIdx, p) in parameters.withIndex()) {
1784+ // `args[i] as Ti` is generated below for each parameter
1785+
1786+ // cast
1787+ val castId = tw.getFreshIdLabel<DbCastexpr >()
1788+ val type = useType(p.type)
1789+ tw.writeExprs_castexpr(castId, type.javaResult.id, type.kotlinResult.id, callId, pIdx)
1790+ extractCommonExpr(castId)
1791+
1792+ // type access
1793+ extractTypeAccess(p.type, locId, methodId, castId, 0 , retId)
1794+
1795+ // element access: `args.get(i)`
1796+ val getCallId = tw.getFreshIdLabel<DbMethodaccess >()
1797+ tw.writeExprs_methodaccess(getCallId, anyNType.javaResult.id, anyNType.kotlinResult.id, castId, 1 )
1798+ extractCommonExpr(getCallId)
1799+ tw.writeCallableBinding(getCallId, arrayGetMethodId)
1800+
1801+ // parameter access:
1802+ val argsAccessId = tw.getFreshIdLabel<DbVaraccess >()
1803+ tw.writeExprs_varaccess(argsAccessId, argsType.javaResult.id, argsType.kotlinResult.id, getCallId, - 1 )
1804+ extractCommonExpr(argsAccessId)
1805+ tw.writeVariableBinding(argsAccessId, argsParamId)
1806+
1807+ // index access:
1808+ val indexId = tw.getFreshIdLabel<DbIntegerliteral >()
1809+ tw.writeExprs_integerliteral(indexId, intType.javaResult.id, intType.kotlinResult.id, getCallId, pIdx)
1810+ extractCommonExpr(indexId)
1811+ tw.writeNamestrings(pIdx.toString(), pIdx.toString(), indexId)
1812+ }
1813+ }
1814+
17091815 fun extractVarargElement (e : IrVarargElement , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , enclosingStmt : Label <out DbStmt >) {
17101816 when (e) {
17111817 is IrExpression -> {
@@ -1717,19 +1823,22 @@ open class KotlinFileExtractor(
17171823 }
17181824 }
17191825
1720- fun extractTypeAccess (t : IrType , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , elementForLocation : IrElement , enclosingStmt : Label <out DbStmt >) {
1826+ private fun extractTypeAccess (t : IrType , location : Label < DbLocation >, callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , enclosingStmt : Label <out DbStmt >) {
17211827 // TODO: elementForLocation allows us to give some sort of
17221828 // location, but a proper location for the type access will
17231829 // require upstream changes
17241830 val type = useType(t)
17251831 val id = tw.getFreshIdLabel<DbUnannotatedtypeaccess >()
17261832 tw.writeExprs_unannotatedtypeaccess(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
1727- val locId = tw.getLocation(elementForLocation)
1728- tw.writeHasLocation(id, locId)
1833+ tw.writeHasLocation(id, location)
17291834 tw.writeCallableEnclosingExpr(id, callable)
17301835 tw.writeStatementEnclosingExpr(id, enclosingStmt)
17311836 }
17321837
1838+ private fun extractTypeAccess (t : IrType , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , elementForLocation : IrElement , enclosingStmt : Label <out DbStmt >) {
1839+ extractTypeAccess(t, tw.getLocation(elementForLocation), callable, parent, idx, enclosingStmt)
1840+ }
1841+
17331842 fun extractTypeOperatorCall (e : IrTypeOperatorCall , callable : Label <out DbCallable >, parent : Label <out DbExprparent >, idx : Int , enclosingStmt : Label <out DbStmt >) {
17341843 when (e.operator ) {
17351844 IrTypeOperator .CAST -> {
@@ -1867,7 +1976,7 @@ open class KotlinFileExtractor(
18671976
18681977 // Super call
18691978 val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt >()
1870- tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0 , ids.function )
1979+ tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0 , ids.constructor )
18711980 for (i in 0 until superConstructorArgs.size) {
18721981 val arg = superConstructorArgs[i]
18731982 extractExpressionExpr(arg, ids.constructor , superCallId, i, superCallId)
@@ -1885,6 +1994,34 @@ open class KotlinFileExtractor(
18851994 addModifiers(id, " public" , " static" , " final" )
18861995 extractClassSupertypes(superTypes, listOf (), id)
18871996
1997+ var parent: IrDeclarationParent ? = localFunction.parent
1998+ while (parent != null ) {
1999+ // todo: merge this with the implementation in `extractClassSource`
2000+ if (parent is IrClass ) {
2001+ val parentId =
2002+ if (parent.isAnonymousObject) {
2003+ @Suppress(" UNCHECKED_CAST" )
2004+ useAnonymousClass(parent).javaResult.id as Label <out DbClass >
2005+ } else {
2006+ useClassInstance(parent, listOf ()).typeResult.id
2007+ }
2008+ tw.writeEnclInReftype(id, parentId)
2009+
2010+ break
2011+ }
2012+
2013+ if (parent is IrFile ) {
2014+ if (this is KotlinSourceFileExtractor && this .file == localFunction.fileOrNull) {
2015+ tw.writeEnclInReftype(id, this .fileClass)
2016+ } else {
2017+ logger.warn(Severity .ErrorSevere , " Unexpected file parent found" )
2018+ }
2019+ break
2020+ }
2021+
2022+ parent = (parent as ? IrDeclaration )?.parent
2023+ }
2024+
18882025 return id
18892026 }
18902027}
0 commit comments