E199: Tailrec Nested Call

E199: Tailrec Nested Call

이 경고는 @tailrec 메서드가 인라인되지 않은 내부 정의 안에서 재귀 호출을 포함할 때 발생해요.

출처: Scala 3 Reference

본문

꼬리 재귀 최적화는 메서드의 본문에서 직접적으로만 적용될 수 있어요. 내부 def를 통해 이루어지는 재귀 호출은 꼬리 재귀로 검증하거나 최적화할 수 없어요. 이 때문에 깊은 재귀 호출에서 스택 오버플로가 발생할 수 있어요.

예시 (Example)

import scala.annotation.tailrec

@tailrec
def countdown(n: Int): Unit =
  def helper(): Unit =
    countdown(n - 1)  // recursive call from inner def
  if n > 0 then helper()
  else countdown(n - 1)

에러 (Error)

-- [E199] Syntax Warning: example.scala:6:13 -----------------------------------
6 |    countdown(n - 1)  // recursive call from inner def
  |    ^^^^^^^^^^^^^^^^
  |The tail recursive def countdown contains a recursive call inside the non-inlined inner def helper
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  | Tail recursion is only validated and optimised directly in the definition.
  | Any calls to the recursive method via an inner def cannot be validated as
  | tail recursive, nor optimised if they are. To enable tail recursion from
  | inner calls, mark the inner def as inline.
   -----------------------------------------------------------------------------

해결 방법 (Solution)

내부 definline으로 표시해요.

import scala.annotation.tailrec

@tailrec
def countdown(n: Int): Unit =
  inline def helper(): Unit =
    countdown(n - 1)
  if n > 0 then helper()
  else countdown(n - 1)

아니면 중첩된 재귀 호출을 피하도록 코드를 재구성해요.

import scala.annotation.tailrec

@tailrec
def countdown(n: Int): Unit =
  if n > 0 then countdown(n - 1)