question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Weird macro recursive inline limit infinite loop bug/crash

See original GitHub issue

Maximal number of successive inlines exceeds when using Scala 3 Macros across various dependent files.

Compiler version

3.0.0-RC1

Minimized code

Please see attached sample zipped project. This issue only appears to surface when having definitions across multiple files. I currently found 3 workaround so far, but the underlying issue remains.

  1. If you either omit Transactions.scala and remove its reference, property in Chain.scala,
  2. Change Transaction to use derive instead, like
    case class Transaction( sender: Address, 
                            recipient: Address, 
                            value: Long) derives Codec.AsObject
    
  3. Group all the definitions in a single file as in here, it works too.

MacroBug.zip

To Reproduce:

  1. Unzip the file.
  2. Run sbt run in the directory.

Output

Without default flags
[error] -- Error: /Users/swoorup.joshi/IdeaProjects/temp/LBAbOJMVT1260OKUnBXuzw/src/main/scala/blockchain/Chain.scala:25:27
[error] 25 |given Encoder[ChainLink] = deriveEncoder[ChainLink]
[error]    |                           ^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |                     Maximal number of successive inlines (32) exceeded,
[error]    |                     Maybe this is caused by a recursive inline method?
[error]    |                     You can use -Xmax-inlines to change the limit.
[error]    | This location contains code that was inlined from Chain.scala:25
[error]    | This location contains code that was inlined from Derivation.scala:47
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from Derivation.scala:16
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:38
[error]    | This location contains code that was inlined from Derivation.scala:12
[error]    | This location contains code that was inlined from Derivation.scala:50
[error]    | This location contains code that was inlined from semiauto.scala:27
[error] one error found
[error] one error found

Using max inlines -Xmax-inlines 10000000 flag does not do any justice either, it runs into stack overflow.

With max inlines
java.lang.StackOverflowError while compiling /Users/swoorup.joshi/IdeaProjects/temp/LBAbOJMVT1260OKUnBXuzw/src/main/scala/blockchain/Chain.scala, /Users/swoorup.joshi/IdeaProjects/temp/LBAbOJMVT1260OKUnBX
uzw/src/main/scala/blockchain/Transaction.scala, /Users/swoorup.joshi/IdeaProjects/temp/LBAbOJMVT1260OKUnBXuzw/src/main/scala/main.scala
[error] ## Exception when compiling 3 sources to /Users/swoorup.joshi/IdeaProjects/temp/LBAbOJMVT1260OKUnBXuzw/target/scala-3.0.0-RC1/classes
[error] java.lang.StackOverflowError
[error] dotty.tools.dotc.ast.Positioned.sourcePos(Positioned.scala:52)
[error] dotty.tools.dotc.report$.recur$1(report.scala:119)
[error] dotty.tools.dotc.report$.recur$1(report.scala:119)
[error] dotty.tools.dotc.report$.recur$1(report.scala:119)
[error] dotty.tools.dotc.report$.recur$1(report.scala:119)

Expectation

[info] running Main
{
  "index" : 1,
  "proof" : 2,
  "previousHash" : "",
  "values" : [
  ],
  "timestamp" : 1615684763839
}

The same example in scastie works however, when everything is lumped together in a single file. https://scastie.scala-lang.org/LBAbOJMVT1260OKUnBXuzw

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
heksesangcommented, Mar 14, 2021

The zipped example works fine when:

  • You put each given in their respective companion object.
  • You declare given Encoder[Transaction] = blockchain.given_Encoder_Transaction in Chain.scala.
  • You replace the List[Transaction] with just Transaction.

Also, the Scastie breaks if you use two different packages to separate the definitions: https://scastie.scala-lang.org/heksesang/Vr8kHxhURgWxQBmGcxB9ww/6

Based on the observations above, I think the problem is most likely the same as https://github.com/lampepfl/dotty/issues/11538 and thus fixed in RC2.

The thing that breaks the derivation is the fact that there is a List[Transaction] coupled with the bug mentioned above. The implicit circe uses for Encoder[List[A]] requires an implicit Encoder[A]. When it looks for a Encoder[List[Transaction]], it uses this implicit, but because of it does not find an implicit Encoder[Transaction], the summonFrom defaults to trying to derive an Encoder[List[Transaction]], and that causes some infinite recursion.

If you create case class A(val i: Int), do not derive an Encoder[A], but try to call deriveEncoder[List[A]] you will see the same problem.

If my deductions are correct, this is not a dotty bug, but a circe bug.

0reactions
smartercommented, Mar 15, 2021

Sounds like we can close this then, thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Recursive macro makes infinite recursion - Stack Overflow
I changed the recursion_limit to 128 and higher, but the compiler error message just increase as well. Even when I call n!(0) it...
Read more >
High-order recursive macro to define several similar macro at ...
programming - High-order recursive macro to define several similar macro at once does infinite loop - TeX - LaTeX Stack Exchange. Stack ...
Read more >
https://sajtr.ga/FRI/Novo/2019-2020/UNI-2.letnik/P...
... report by Mark Shinwell) - PR#6564: infinite loop in Mtype.remove_aliases ... not terminating on some lazy values w/ recursive types (Xavier Leroy, ......
Read more >
ocaml-base-compiler.4.10.0/Changes - OCaml Docs - OCamlPro
46, provides a compatibility macro with the old name, but programs ... 1662, - #7847, #2019: Fix an infinite loop that could occur...
Read more >
By Thread - Linux-Kernel Archive
[patch] sched: fix macro -> inline function conversion bug Ingo Molnar (Mon Jul 03 ... Re: 2.6.17-mm one process gets stuck in infinite...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found