@@ -946,6 +946,113 @@ class TestBCode extends DottyBytecodeTest {
946946 }
947947 }
948948
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+
9491056 @ Test
9501057 def getClazz : Unit = {
9511058 val source = """
0 commit comments