Skip to content

Missing warning for Infinite recursive call in object #23277

Closed
@drewfeelsblue

Description

@drewfeelsblue

Compiler version

3.7.0

reproduced also for nightly version (currently 3.7.2-RC1-bin-20250527-2703b6b-NIGHTLY)

Minimized code

//> using scala 3.7.0

enum Test:
  case One
  case Two(i: Int)

object Test:
  object Two:
    def apply(i: Int): Test.Two = Test.Two(i)


object app extends App:
  Test.Two(1)

Output

run of above code snippet leads to "lock" (execution is stuck)

Expectation

I expected to see at least compiler warning for such code

Activity

som-snytt

som-snytt commented on May 28, 2025

@som-snytt
Contributor

enum is not involved, as the method recurses trivially.

It works as

def apply(i: Int): Test.Two = new Test.Two(i)

It's normal to write a custom apply method where one might be generated, such as in a case class companion.

The check in Scala 2 warns for only the most trivial definition:

warning: method g in object Test does nothing other than call itself recursively
  def g: Int = g
               ^
1 warning

Actually, Scala 3 makes an effort now:

7 |  def f(i: Int): Int = f(i)
  |  ^^^^^^^^^^^^^^^^^^^^^^^^^
  |  Infinite recursive call
8 |  def g: Int = g
  |  ^^^^^^^^^^^^^^
  |  Infinite recursive call
2 warnings found

The check in tailrec could be more expansive or forgiving:

    final module class Two() extends Object {
      def apply(i: Int): Test.Two =
        {
          var $this$tailLocal1: (Test.Two : Test.Two) = this
          while <empty> do
            tailLabel1[Unit]:
              return
                {
                  $this$tailLocal1 = Test.Two
                  (return[tailLabel1] ()):Test.Two
                }
        }
    }
    def f(i: Int): Int =
      {
        while <empty> do tailLabel2[Unit]: return (return[tailLabel2] ()):Int
      }

The usual observation is, "No one writes code like that, until they do." What does the A.I. say about it?

drewfeelsblue

drewfeelsblue commented on May 28, 2025

@drewfeelsblue
Author

ah, I see now, @som-snytt thank you for the reply

so

//> using scala 3.7.0

object Test {
  object Two {
    def apply(i: Int): Test.Two.type = Test.Two(i)
  }
}

object app extends App {
  Test.Two(1)
}

compiles just fine

while

//> using scala 3.7.0

object Test {
  object Two {
    def apply(i: Int): Two.type = Two(i)
  }
}

object app extends App {
  Test.Two(1)
}

warns about recursive call

[warn] Infinite recursive call
[warn]     def apply(i: Int): Two.type = Two(i)
[warn]     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
added
better-errorsIssues concerned with improving confusing/unhelpful diagnostic messages
and removed
stat:needs triageEvery issue needs to have an "area" and "itype" label
on May 28, 2025
som-snytt

som-snytt commented on May 28, 2025

@som-snytt
Contributor

The PR warns despite an assignment to this that is a stable (but impure) value; then avoids emitting the assignment for an object.

changed the title [-]Conflicting definitions lead to the endless run[/-] [+]Missing warning for Infinite recursive call in object[/+] on May 28, 2025
self-assigned this
on May 31, 2025
added a commit that references this issue on Jun 3, 2025
451cc74

3 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

    Development

    Participants

    @som-snytt@WojciechMazur@drewfeelsblue

    Issue actions

      Missing warning for Infinite recursive call in object · Issue #23277 · scala/scala3