Skip to content
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

REPL gives stack overflow during too eager syntax highlighting, e.g. when multiplying string #16904

Closed
bjornregnell opened this issue Feb 13, 2023 · 20 comments · Fixed by #19836
Assignees
Labels
area:repl itype:bug regression This worked in a previous version but doesn't anymore
Milestone

Comments

@bjornregnell
Copy link
Contributor

Compiler version

3.3.0-RC2

Minimized code

$ scala-cli repl -S 3.3.0-RC2
Welcome to Scala 3.3.0-RC2 (17.0.4.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                                                                                       
scala> "works fine" * 100
val res0: String = works fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks fineworks ...
                                                                                                                                                                       
scala> "works not fine"* 1000
Exception in thread "main" java.lang.StackOverflowError
    at dotty.tools.dotc.ast.untpd$UntypedTreeAccumulator.foldMoreCases(untpd.scala:799)
    at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1641)
    at dotty.tools.dotc.ast.untpd$UntypedTreeTraverser.traverseChildren(untpd.scala:809)
    at dotty.tools.dotc.printing.SyntaxHighlighting$TreeHighlighter$2$.traverse(SyntaxHighlighting.scala:123)
    at dotty.tools.dotc.ast.untpd$UntypedTreeTraverser.apply(untpd.scala:808)
    at dotty.tools.dotc.ast.untpd$UntypedTreeTraverser.apply(untpd.scala:808)
 

Expectation

Should work and not give stack overflow (as in e.g. 2.13)

@bjornregnell bjornregnell added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 13, 2023
@bjornregnell bjornregnell changed the title REPL gives stack overflow when multiplyin string REPL gives stack overflow when multiplying string Feb 13, 2023
@som-snytt
Copy link
Contributor

This is the highlight of my day.

@mpilquist
Copy link
Contributor

Note this isn't unique to string multiplication - it's a bug in syntax highlighting of very long strings.

@som-snytt
Copy link
Contributor

som-snytt commented Feb 14, 2023

it's not trying to highlight a string but a huge infix expression.

val res0: String = works fineworks fineworks

The fix is to put the string in quotes for parsing, as in scala/scala#8885

Then, to pun further, the fix is in.

image

I was curious about ellipsis output:

image

ending in the ellipsis, so it must abort highlighting on parse error.

@WojciechMazur
Copy link
Contributor

Bisect points to 1475a6f

@WojciechMazur WojciechMazur added area:repl regression This worked in a previous version but doesn't anymore and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Feb 14, 2023
@prolativ
Copy link
Contributor

It looks like the problem is that the limit of characters used for truncation got raised from 1000 to 50000. I think we should make the default 1000 again (3000 seem to work for me but I'm not sure if this would work universally). If users wanted to have a higher limit, they could use the setting explicitly now.
CC @mpollmeier

@mpollmeier
Copy link
Contributor

Sure we can change the default back to 1000, but that's only covering the underlying issue, doesn't it?
As @mpilquist mentioned, it's a bug in the syntax highlighting. So if users configure a higher limit for their session, they're still going to run into this...

@som-snytt
Copy link
Contributor

My point was ignored.

This is already wrong color, string would be red:

image

It's parsing that text to know how to colorize it, and works fineworks fineworks is an infix expression, not a string.

There are other workarounds besides putting quotes around the string, namely, not attempting to highlight the RHS or using the type to pick a color.

@bjornregnell
Copy link
Contributor Author

bjornregnell commented Feb 14, 2023

Why is the interior of a string syntax highlighted in the first place? It is just a string... (sorry if I'm missing something here and asking a strange question)

@bjornregnell
Copy link
Contributor Author

bjornregnell commented Feb 14, 2023

I mean: this is the algorithm that I (perhaps simplistically) assumed:

  • val replInput: String = """"works fine" * 1000"""
  • val code: FancyAST = intepret(replInput)
  • aha code is just a string (although loooong), so no further highlighting is necessary and just print (parts of) it

(But again, I am perhaps missing something obvious... )

@prolativ
Copy link
Contributor

Oh, right, the fact that printed string literals are trying to be highlighted like code seems to be the core problem here

@som-snytt
Copy link
Contributor

Another good example where the color is nonsensical:

image

@bjornregnell bjornregnell changed the title REPL gives stack overflow when multiplying string REPL gives stack overflow during too eager syntax highlighting, e.g. when multiplying string Feb 14, 2023
@bjornregnell
Copy link
Contributor Author

Syntax highlighting of parts of the hash code seems all too eager. Maybe that's another bug?

@SethTisue
Copy link
Member

SethTisue commented Mar 24, 2023

the fact that printed string literals are trying to be highlighted like code seems to be the core problem here

agree. (and with Bjorn's remark also, which shows that the problem isn't limited to string literals.)

I'm going to optimistically label this with “spree”, since the issue shouldn't require tearing up much of the REPL code? I hope?

@mpollmeier
Copy link
Contributor

Apart from the rendering being buggy, a major problem is that the rendering first transforms the results into a String (i.e. throwing away all type information), and then trying to colorise that String.

The type information is useful not only for less-buggy rendering and coloring, but also allows us to enrich the output with product labels etc. Here's an RFC that demonstrates one way to fix things, by using pprint: #17624

@mbovel mbovel removed the Spree Suitable for a future Spree label Feb 19, 2024
@mbovel
Copy link
Member

mbovel commented Feb 19, 2024

Similar issue: #18596.

Not sure if there are some other bugs at hand here, but isn't it unavoidable that the highlighter crashes on too deeply nested expressions?

Should we just catch StackOverflows and report an error? Or should we not highlight strings larger than some threshold?

@bjornregnell
Copy link
Contributor Author

Refraining from highlighting beyond some threshold is good I think. Better to be robust and not crash.

@som-snytt
Copy link
Contributor

Or just display strings in quotes like everyone asks for & has received PRs for.

@mbovel
Copy link
Member

mbovel commented Feb 19, 2024

Or just display strings in quotes like everyone asks for & has received PRs for.

I couldn't agree more. Why don't we have quotes yet; were there prior discussions about this?

However that would not solve the general problem of stackoverflows when highlighting deeply nested expression. I guess we can get the same problem without strings.

@som-snytt
Copy link
Contributor

I haven't finished my second cup of coffee to answer what complex thing it knows how to render. Huge case classes? I did already do wordle etc.

scala> val x = 42 * 2
val x: Int = 84

scala> case class C(i: Int, j: Int)
// defined case class C

scala> C(42*2, 27)
val res0: C = C(84,27)

The reason to highlight as code is that it is trying to render something code-like, but the RHS is just a value that is rendered. Oh, large collections is an obvious example of potentially large rendering. But that is "long" and not "deep". The other would be parse trees as deeply nested case classes, if people do that in REPL.

@mbovel
Copy link
Member

mbovel commented Feb 19, 2024

The other would be parse trees as deeply nested case classes, if people do that in REPL.

Indeed. I tried it and actually got a stack overflow in the parser already. We could also safe-guard it.

➜  ~/dotty git:(mb/refinements) scala-cli repl -S "3.3.2" --jvm 17
Welcome to Scala 3.3.2 (17.0.6, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                     
scala> case class Tree(left: Tree, right: Tree)
// defined case class Tree
                                                                                                     
scala> def deepTree(depth: Int): Tree = if depth == 0 then null else Tree(null, deepTree(depth - 1))
def deepTree(depth: Int): Tree
                                                                                                     
scala> deepTree(300)
Exception in thread "main" java.lang.StackOverflowError
	at dotty.tools.dotc.parsing.Scanners$Region.toList(Scanners.scala:1618)
	at dotty.tools.dotc.parsing.Scanners$Region.toList(Scanners.scala:1618)
	at dotty.tools.dotc.parsing.Scanners$Region.toList(Scanners.scala:1618)
        ...

@hamzaremmal hamzaremmal assigned mbovel and unassigned Florian3k Feb 27, 2024
@Kordyjan Kordyjan added this to the 3.4.2 milestone Mar 28, 2024
@Kordyjan Kordyjan modified the milestones: 3.4.2, 3.5.0 May 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:repl itype:bug regression This worked in a previous version but doesn't anymore
Projects
None yet
Development

Successfully merging a pull request may close this issue.