Backend support for function expression
This commit is contained in:
@@ -41,6 +41,11 @@ public class CodegenStatementVisitor extends JetVisitor<StackValue, StackValue>
|
|||||||
return codegen.generateTryExpression(expression, true);
|
return codegen.generateTryExpression(expression, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data) {
|
||||||
|
return codegen.visitNamedFunction(function, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue data) {
|
public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue data) {
|
||||||
return codegen.generateWhenExpression(expression, true);
|
return codegen.generateWhenExpression(expression, true);
|
||||||
|
|||||||
@@ -1346,6 +1346,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data) {
|
public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data) {
|
||||||
|
return visitNamedFunction(function, data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data, boolean isStatement) {
|
||||||
assert data == StackValue.none();
|
assert data == StackValue.none();
|
||||||
|
|
||||||
if (JetPsiUtil.isScriptDeclaration(function)) {
|
if (JetPsiUtil.isScriptDeclaration(function)) {
|
||||||
@@ -1353,11 +1357,16 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
}
|
}
|
||||||
|
|
||||||
StackValue closure = genClosure(function, null, KotlinSyntheticClass.Kind.LOCAL_FUNCTION);
|
StackValue closure = genClosure(function, null, KotlinSyntheticClass.Kind.LOCAL_FUNCTION);
|
||||||
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function);
|
if (isStatement) {
|
||||||
int index = lookupLocalIndex(descriptor);
|
DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function);
|
||||||
closure.put(OBJECT_TYPE, v);
|
int index = lookupLocalIndex(descriptor);
|
||||||
v.store(index, OBJECT_TYPE);
|
closure.put(OBJECT_TYPE, v);
|
||||||
return StackValue.none();
|
v.store(index, OBJECT_TYPE);
|
||||||
|
return StackValue.none();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return closure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -621,9 +621,6 @@ public class JetTypeMapper {
|
|||||||
|
|
||||||
return isAccessor ? "access$" + accessorName : accessorName;
|
return isAccessor ? "access$" + accessorName : accessorName;
|
||||||
}
|
}
|
||||||
else if (isLocalNamedFun(descriptor)) {
|
|
||||||
return "invoke";
|
|
||||||
}
|
|
||||||
else if (descriptor instanceof AnonymousFunctionDescriptor) {
|
else if (descriptor instanceof AnonymousFunctionDescriptor) {
|
||||||
PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor);
|
PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor);
|
||||||
if (element instanceof JetFunctionLiteral) {
|
if (element instanceof JetFunctionLiteral) {
|
||||||
@@ -638,6 +635,9 @@ public class JetTypeMapper {
|
|||||||
|
|
||||||
return "invoke";
|
return "invoke";
|
||||||
}
|
}
|
||||||
|
else if (isLocalFunOrLambda(descriptor)) {
|
||||||
|
return "invoke";
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return descriptor.getName().asString();
|
return descriptor.getName().asString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
fun Any.foo1() : ()-> String {
|
val foo1 = fun Any.(): String {
|
||||||
return { "239" + this }
|
return "239" + this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Int.foo2() : (i : Int) -> Int {
|
val foo2 = fun Int.(i : Int) : Int = this + i
|
||||||
return { x -> x + this }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fooT1<T>(t : T) = { t.toString() }
|
fun <T> fooT1() = fun (t : T) = t.toString()
|
||||||
|
|
||||||
fun fooT2<T>(t: T) = { (x:T) -> t.toString() + x.toString() }
|
annotation class A
|
||||||
|
|
||||||
fun box() : String {
|
fun box() : String {
|
||||||
if( (10.foo1())() != "23910") return "foo1 fail"
|
if(10.foo1() != "23910") return "foo1 fail"
|
||||||
if( (10.foo2())(1) != 11 ) return "foo2 fail"
|
if(10.foo2(1) != 11) return "foo2 fail"
|
||||||
|
|
||||||
if(1.{Int.() -> this + 1}() != 2) return "test 3 failed";
|
if(1.(fun Int.() = this + 1)() != 2) return "test 3 failed";
|
||||||
if( {1}() != 1) return "test 4 failed";
|
if( (fun () = 1)() != 1) return "test 4 failed";
|
||||||
if( {(x : Int) -> x}(1) != 1) return "test 5 failed";
|
if( (fun (i: Int) = i)(1) != 1) return "test 5 failed";
|
||||||
if( 1.{Int.(x : Int) -> x + this}(1) != 2) return "test 6 failed";
|
if( 1.(fun Int.(i: Int) = i + this)(1) != 2) return "test 6 failed";
|
||||||
if( 1.({Int.() -> this})() != 1) return "test 7 failed";
|
if( (fooT1<String>()("mama")) != "mama") return "test 7 failed";
|
||||||
if( (fooT1<String>("mama"))() != "mama") return "test 8 failed";
|
|
||||||
if( (fooT2<String>("mama"))("papa") != "mamapapa") return "test 9 failed";
|
val a = [A] fun Int.() = this + 1 //
|
||||||
return "OK"
|
if (1.a() != 2) return "test 8 failed"
|
||||||
|
val b = ( fun Int.() = this + 1)
|
||||||
|
if (1.a() != 2) return "test 9 failed"
|
||||||
|
val c = (@c fun Int.() = this + 1)
|
||||||
|
if (1.a() != 2) return "test 10 failed"
|
||||||
|
|
||||||
|
val d = @d fun (): Int { return@d 4}
|
||||||
|
if (d() != 4) return "test 11 failed"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
val foo1 = fun Any.name(): String {
|
||||||
|
return "239" + this
|
||||||
|
}
|
||||||
|
|
||||||
|
val foo2 = fun Int.name(i : Int) : Int = this + i
|
||||||
|
|
||||||
|
fun <T> fooT1() = fun name(t : T) = t.toString()
|
||||||
|
|
||||||
|
annotation class A
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
if(10.foo1() != "23910") return "foo1 fail"
|
||||||
|
if(10.foo2(1) != 11) return "foo2 fail"
|
||||||
|
|
||||||
|
if(1.(fun Int.name() = this + 1)() != 2) return "test 3 failed";
|
||||||
|
if( (fun name() = 1)() != 1) return "test 4 failed";
|
||||||
|
if( (fun name(i: Int) = i)(1) != 1) return "test 5 failed";
|
||||||
|
if( 1.(fun Int.name(i: Int) = i + this)(1) != 2) return "test 6 failed";
|
||||||
|
if( (fooT1<String>()("mama")) != "mama") return "test 7 failed";
|
||||||
|
|
||||||
|
val a = [A] fun Int.name() = this + 1 // name
|
||||||
|
if (1.a() != 2) return "test 8 failed"
|
||||||
|
val b = ( fun Int.name() = this + 1)
|
||||||
|
if (1.a() != 2) return "test 9 failed"
|
||||||
|
val c = (@c fun Int.name() = this + 1)
|
||||||
|
if (1.a() != 2) return "test 10 failed"
|
||||||
|
|
||||||
|
val d = fun name(): Int { return@name 4}
|
||||||
|
if (d() != 4) return "test 11 failed"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
fun Any.foo1() : ()-> String {
|
||||||
|
return { "239" + this }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Int.foo2() : (i : Int) -> Int {
|
||||||
|
return { x -> x + this }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fooT1<T>(t : T) = { t.toString() }
|
||||||
|
|
||||||
|
fun fooT2<T>(t: T) = { (x:T) -> t.toString() + x.toString() }
|
||||||
|
|
||||||
|
fun box() : String {
|
||||||
|
if( (10.foo1())() != "23910") return "foo1 fail"
|
||||||
|
if( (10.foo2())(1) != 11 ) return "foo2 fail"
|
||||||
|
|
||||||
|
if(1.{Int.() -> this + 1}() != 2) return "test 3 failed";
|
||||||
|
if( {1}() != 1) return "test 4 failed";
|
||||||
|
if( {(x : Int) -> x}(1) != 1) return "test 5 failed";
|
||||||
|
if( 1.{Int.(x : Int) -> x + this}(1) != 2) return "test 6 failed";
|
||||||
|
if( 1.({Int.() -> this})() != 1) return "test 7 failed";
|
||||||
|
if( (fooT1<String>("mama"))() != "mama") return "test 8 failed";
|
||||||
|
if( (fooT2<String>("mama"))("papa") != "mamapapa") return "test 9 failed";
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
val property = fun () {}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val javaClass = property.javaClass
|
||||||
|
|
||||||
|
val enclosingMethod = javaClass.getEnclosingMethod()
|
||||||
|
if (enclosingMethod != null) return "method: $enclosingMethod"
|
||||||
|
|
||||||
|
val enclosingClass = javaClass.getEnclosingClass()!!.getName()
|
||||||
|
if (!enclosingClass.startsWith("_DefaultPackage") || !enclosingClass.contains("functionExpressionInProperty")) return "enclosing class: $enclosingClass"
|
||||||
|
|
||||||
|
val declaringClass = javaClass.getDeclaringClass()
|
||||||
|
if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
val property = fun name() {}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val javaClass = property.javaClass
|
||||||
|
|
||||||
|
val enclosingMethod = javaClass.getEnclosingMethod()
|
||||||
|
if (enclosingMethod != null) return "method: $enclosingMethod"
|
||||||
|
|
||||||
|
val enclosingClass = javaClass.getEnclosingClass()!!.getName()
|
||||||
|
if (!enclosingClass.startsWith("_DefaultPackage") || !enclosingClass.contains("namedFunctionExpressionInProperty")) return "enclosing class: $enclosingClass"
|
||||||
|
|
||||||
|
val declaringClass = javaClass.getDeclaringClass()
|
||||||
|
if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+12
@@ -3698,6 +3698,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionExpressionWithName.kt")
|
||||||
|
public void testFunctionExpressionWithName() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionExpressionWithName.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionLiteralExpression.kt")
|
||||||
|
public void testFunctionLiteralExpression() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionLiteralExpression.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("functionNtoString.kt")
|
@TestMetadata("functionNtoString.kt")
|
||||||
public void testFunctionNtoString() throws Exception {
|
public void testFunctionNtoString() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionNtoString.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionNtoString.kt");
|
||||||
|
|||||||
+12
@@ -2590,6 +2590,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib(fileName);
|
doTestWithStdlib(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("functionExpressionInProperty.kt")
|
||||||
|
public void testFunctionExpressionInProperty() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/functionExpressionInProperty.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt6368.kt")
|
@TestMetadata("kt6368.kt")
|
||||||
public void testKt6368() throws Exception {
|
public void testKt6368() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/kt6368.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/kt6368.kt");
|
||||||
@@ -2704,6 +2710,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
doTestWithStdlib(fileName);
|
doTestWithStdlib(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("namedFunctionExpressionInProperty.kt")
|
||||||
|
public void testNamedFunctionExpressionInProperty() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/namedFunctionExpressionInProperty.kt");
|
||||||
|
doTestWithStdlib(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("objectInLambda.kt")
|
@TestMetadata("objectInLambda.kt")
|
||||||
public void testObjectInLambda() throws Exception {
|
public void testObjectInLambda() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/objectInLambda.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/objectInLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user