@@ -946,6 +946,113 @@ class TestBCode extends DottyBytecodeTest {
946
946
}
947
947
}
948
948
949
+ @ Test def i14773TailRecReuseParamSlots (): Unit = {
950
+ val source =
951
+ s """ class Foo {
952
+ | @scala.annotation.tailrec // explicit @tailrec here
953
+ | final def fact(n: Int, acc: Int): Int =
954
+ | if n == 0 then acc
955
+ | else fact(n - 1, acc * n)
956
+ |}
957
+ |
958
+ |class IntList(head: Int, tail: IntList | Null) {
959
+ | // implicit @tailrec
960
+ | final def sum(acc: Int): Int =
961
+ | val t = tail
962
+ | if t == null then acc + head
963
+ | else t.sum(acc + head)
964
+ |}
965
+ """ .stripMargin
966
+
967
+ checkBCode(source) { dir =>
968
+ // The mutable local vars for n and acc reuse the slots of the params n and acc
969
+
970
+ val fooClass = loadClassNode(dir.lookupName(" Foo.class" , directory = false ).input)
971
+ val factMeth = getMethod(fooClass, " fact" )
972
+
973
+ assertSameCode(factMeth, List (
974
+ VarOp (ALOAD , 0 ),
975
+ VarOp (ASTORE , 3 ),
976
+ VarOp (ILOAD , 2 ),
977
+ VarOp (ISTORE , 4 ),
978
+ VarOp (ILOAD , 1 ),
979
+ VarOp (ISTORE , 5 ),
980
+ Label (6 ),
981
+ VarOp (ILOAD , 5 ),
982
+ Op (ICONST_0 ),
983
+ Jump (IF_ICMPNE , Label (13 )),
984
+ VarOp (ILOAD , 4 ),
985
+ Jump (GOTO , Label (32 )),
986
+ Label (13 ),
987
+ VarOp (ALOAD , 3 ),
988
+ VarOp (ASTORE , 6 ),
989
+ VarOp (ILOAD , 5 ),
990
+ Op (ICONST_1 ),
991
+ Op (ISUB ),
992
+ VarOp (ISTORE , 7 ),
993
+ VarOp (ILOAD , 4 ),
994
+ VarOp (ILOAD , 5 ),
995
+ Op (IMUL ),
996
+ VarOp (ISTORE , 8 ),
997
+ VarOp (ALOAD , 6 ),
998
+ VarOp (ASTORE , 3 ),
999
+ VarOp (ILOAD , 7 ),
1000
+ VarOp (ISTORE , 5 ),
1001
+ VarOp (ILOAD , 8 ),
1002
+ VarOp (ISTORE , 4 ),
1003
+ Jump (GOTO , Label (35 )),
1004
+ Label (32 ),
1005
+ Op (IRETURN ),
1006
+ Label (35 ),
1007
+ Jump (GOTO , Label (6 )),
1008
+ Op (ATHROW ),
1009
+ Op (ATHROW ),
1010
+ ))
1011
+
1012
+ // The mutable local vars for this and acc reuse the slots of `this` and of the param acc
1013
+
1014
+ val intListClass = loadClassNode(dir.lookupName(" IntList.class" , directory = false ).input)
1015
+ val sumMeth = getMethod(intListClass, " sum" )
1016
+
1017
+ assertSameCode(sumMeth, List (
1018
+ VarOp (ALOAD , 0 ),
1019
+ VarOp (ASTORE , 2 ),
1020
+ VarOp (ILOAD , 1 ),
1021
+ VarOp (ISTORE , 3 ),
1022
+ Label (4 ),
1023
+ VarOp (ALOAD , 2 ),
1024
+ Field (GETFIELD , " IntList" , " tail" , " LIntList;" ),
1025
+ VarOp (ASTORE , 4 ),
1026
+ VarOp (ALOAD , 4 ),
1027
+ Jump (IFNONNULL , Label (16 )),
1028
+ VarOp (ILOAD , 3 ),
1029
+ VarOp (ALOAD , 2 ),
1030
+ Field (GETFIELD , " IntList" , " head" , " I" ),
1031
+ Op (IADD ),
1032
+ Jump (GOTO , Label (30 )),
1033
+ Label (16 ),
1034
+ VarOp (ALOAD , 4 ),
1035
+ VarOp (ASTORE , 5 ),
1036
+ VarOp (ILOAD , 3 ),
1037
+ VarOp (ALOAD , 2 ),
1038
+ Field (GETFIELD , " IntList" , " head" , " I" ),
1039
+ Op (IADD ),
1040
+ VarOp (ISTORE , 6 ),
1041
+ VarOp (ALOAD , 5 ),
1042
+ VarOp (ASTORE , 2 ),
1043
+ VarOp (ILOAD , 6 ),
1044
+ VarOp (ISTORE , 3 ),
1045
+ Jump (GOTO , Label (33 )),
1046
+ Label (30 ),
1047
+ Op (IRETURN ),
1048
+ Label (33 ),
1049
+ Jump (GOTO , Label (4 )),
1050
+ Op (ATHROW ),
1051
+ Op (ATHROW ),
1052
+ ))
1053
+ }
1054
+ }
1055
+
949
1056
@ Test
950
1057
def getClazz : Unit = {
951
1058
val source = """
0 commit comments