https://kotlinlang.org logo
#getting-started
Title
# getting-started
a

Adam S

11/30/2023, 9:33 AM
Why do I get 'A function is marked as tail-recursive but no tail calls are found' and 'Recursive call is not a tail call'? Is there a way to make this function work with tailrec?
Copy code
class Container(
    val name: String,
    val parent: Container?
)

// WARNING A function is marked as tail-recursive but no tail calls are found
tailrec fun Container.rootParent() : Container {
  return parent?.rootParent() // WARNING Recursive call is not a tail call
    ?: this
}
playground
k

Klitos Kyriacou

11/30/2023, 9:36 AM
This version doesn't warn about it not having tail recursion:
Copy code
tailrec fun Container.rootParent() : Container {
    if (parent == null) return this
    return parent.rootParent()
}
Your original version is directly equivalent to this, which also warns about tail recursion, even though it knows (and warns about) the condition
rp == null
always being false.
Copy code
tailrec fun Container.rootParent() : Container {
    if (parent == null) return this
    val rp = parent.rootParent()
    if (rp == null) return this
    return rp
}
Interestingly, this also issues the warning:
Copy code
tailrec fun Container.rootParent() : Container {
    if (parent == null) return this
    val rp = parent.rootParent()
    return rp
}
But if you remove the
val rp
and return directly, it doesn't give the warning. Seems like a limitation in the compiler's capabilities.
a

Adam S

11/30/2023, 11:43 AM
nice, thanks!
d

Daniel Pitts

11/30/2023, 5:18 PM
This also appears to work:
Copy code
tailrec fun Container.rootParent():Container = if (parent == null) this else parent.rootParent()
Ironically, IntelliJ tells me that it can be replaced with
parent?.rootParent() ?: this
, but then the warning happens.
Also, avoiding tailrec, this would work:
Copy code
fun Container.rootParent() = generateSequence(this) { it.parent }.last()
3 Views