-
Notifications
You must be signed in to change notification settings - Fork 1.1k
StackOverflow in dotc when returning/manipulating big Term/Expr #17218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I would say this one is on you. You're creating a huge code tree for apparently no good reason. IIUC, you are basically unrolling a loop. Unrolling a loop iteration more than a small power of two times (perhaps 8) is usually going to be detrimental to performance due to code cache misses and things like that. I suggest you only perform that kind of unrolling of the input string is small. |
This is an example. The "useful" code throwing this error is here. It's a type refinement system which checks whenever possible (and allowed) inputs/constraints at compile-time. The goal is to generate something like The weird thing is the fold/maps do not cause the error but returning the generated value does. Is there a workaround I can use? Note that quoting does not work too and throw the SO earlier in the |
The issue is that For example: def forallCharsImpl(expr: Expr[String], exprPredicate: Expr[Char => Boolean])(using Quotes): Expr[Boolean] =
import quotes.reflect.*
expr.value match
case Some(value) =>
val predicates: List[Expr[Boolean]] = value
.map(c => Literal(CharConstant(c)))
.map(c => Apply(Select.unique(exprPredicate.asTerm, "apply"), List(c)).asExprOf[Boolean])
.toList
all(predicates)
case None => ???
def all(predicates: List[Expr[Boolean]])(using Quotes): Expr[Boolean] =
predicates match
case Nil => Expr(true)
case x :: Nil => x
case x :: y :: Nil => '{ $x && $y }
case _ =>
val (left, right) = predicates.splitAt(predicates.length / 2)
all(List(all(left), all(right))) This does change the evaluation order of the |
If you want to make inline def forallChars(inline value: String, inline predicate: Char => Boolean): Boolean = ${forallCharsImpl('value, 'predicate)} You could also beta-reduce during macro expansion to allow further optimization .map(c => Expr.betaReduce(Apply(Select.unique(exprPredicate.asTerm, "apply"), List(c)).asExprOf[Boolean])) After this you may have |
Also seems that you do not need to use - c => Apply(Select.unique(exprPredicate.asTerm, "apply"), List(Literal(CharConstant(c)))).asExprOf[Boolean]
+ c => '{ $exprPredicate.appy(${Expr(c)}) } or just |
I discovered a bug that blocks beta-reduction of this example in some cases. See #17227. |
For my use case I cannot use quoting/splicing directly due to a wrong interaction with inline (I think I should minimize the example and maybe report it a day) but using beta reduction maybe I would no longer need to manipulate the Term AST. Also, does beta reduction works for custom traits/typeclasses? Anyway, thank for the explanations ! |
It works like a charm. I guess I can now close this issue. |
Uh oh!
There was an error while loading. Please reload this page.
Compiler version
3.2.0 and 3.3.0-RC3
Minimized code
test.sc
ScalaQuoted.scala
Output (click arrow to expand)
This code compiles but when I return the first expression (aka removing the
Expr(true)
as line 18):The compiler crashes with the following StackOverflowError:
Stacktrace
If I try to do something with the generated Term/Expr (like calling
show
), it crashes with the same error.The text was updated successfully, but these errors were encountered: