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

String interpolation followed by a dot is missing string literals #15514

Closed
tgodzik opened this issue Jun 23, 2022 · 9 comments · Fixed by #15524
Closed

String interpolation followed by a dot is missing string literals #15514

tgodzik opened this issue Jun 23, 2022 · 9 comments · Fixed by #15524

Comments

@tgodzik
Copy link
Contributor

tgodzik commented Jun 23, 2022

Compiler version

3.2.0-RC1

Minimized code

object Main {
 s"Hello $Main.toStr!"
}

Output

This is the tree representing the string interpolation:

 Select(
    qualifier = Apply(
      fun = Select(
        qualifier = Apply(
          fun = Select(
            qualifier = Select(
              qualifier = Select(qualifier = Ident(name = _root_), name = scala),
              name = StringContext
            ),
            name = apply
          ),
          args = List(
            Typed(
              expr = SeqLiteral(
                elems = List(Literal(const = ( = "Hello "))),
                elemtpt = ...
              ),
              tpt = ...
            )
          )
        ),
        name = s
      ),
      args = List(
        ...
      )
    ),
    name = <error>
  ),

Notice it only contains "Hello " literal.

Expectation

 Select(
    qualifier = Apply(
      fun = Select(
        qualifier = Apply(
          fun = Select(
            qualifier = Select(
              qualifier = Select(qualifier = Ident(name = _root_), name = scala),
              name = StringContext
            ),
            name = apply
          ),
          args = List(
            Typed(
              expr = SeqLiteral(
                 elems = List(Literal(const = ( = "Hello ")), Literal(const = ( = ".toStr!")))
                elemtpt = ...
              ),
              tpt = ...
            )
          )
        ),
        name = s
      ),
      args = List(
        ...
      )
    ),
    name = <error>
  ),

The main part is elems = List(Literal(const = ( = "Hello ")), Literal(const = ( = ".toStr!")))

@tgodzik tgodzik added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Jun 23, 2022
@som-snytt
Copy link
Contributor

Remarkably,

scala> object Main { def m = s"Hello $Main.toStr!" }
// defined object Main

scala> Main.m
val res0: String = Hello [email protected]!

@odersky
Copy link
Contributor

odersky commented Jun 24, 2022

I also don't see yet what is wrong here. There is no error reported and it generates the correct code.

@som-snytt
Copy link
Contributor

I took a look and will follow up. The dot is tokenized FSR after self type looks ahead, maybe something to do with string interpolation as two tokens, the part and the embedded ident.

@som-snytt
Copy link
Contributor

Probably this edge case results from a tweak to lookahead #14562

My proposed fix is defensive. I'll consider whether it's possible to tweak scanning the interpolation instead.

@odersky
Copy link
Contributor

odersky commented Jun 24, 2022

I still don't understand what is wrong.

@som-snytt
Copy link
Contributor

som-snytt commented Jun 24, 2022

I was about to comment on the mechanics, which were challenging enough that I hadn't taken a global view yet.

Calling lookahead at INTERPOLATIONID populates current token at STRINGPART and next at IDENT, but reset makes current INTERPOLATIONID and next at STRINGPART, so IDENT is dropped. getNextToken winds up with last STRINGPART, so when it sees the dot it takes it as DOT. Again, it's only with the interpolation in "self-type position".

It works either to avoid lookahead in that case, or resort to LookaheadScanner.

I'll look at whether producing STRINGPART can be less eager in producing the next IDENT. One idea is that if it's done in postProcess, then lookahead won't do it, much like fusion of case class.

@odersky
Copy link
Contributor

odersky commented Jun 24, 2022

I mean globally rather than the mechanics. It does produce produce the correct string, no?

@Kordyjan Kordyjan added area:transform and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jun 24, 2022
@som-snytt
Copy link
Contributor

som-snytt commented Jun 24, 2022

It looks like I edited my previous comment. I'll show the spurious syntax error in a minute after a recompile. Maybe a couple of minutes.

I was about to go read some early morning headlines.

The unexpected token is DOT. Sorry, Dotty.

[success] Total time: 190 s (03:10), completed Jun 24, 2022, 5:18:21 AM
Welcome to Scala 3.2.1-RC1-bin-SNAPSHOT-git-327ecc2 (17.0.2, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> object Main { s"Hello $Main.toStr!" }
-- [E016] Syntax Error: ------------------------------------------------------------------------------------------------
1 |object Main { s"Hello $Main.toStr!" }
  |                           ^
  |                           Error in interpolated string: identifier or block expected
  |
  | longer explanation available when compiling with `-explain`
-- [E040] Syntax Error: ------------------------------------------------------------------------------------------------
1 |object Main { s"Hello $Main.toStr!" }
  |                            ^
  |                            an identifier expected, but string literal found

scala>

@odersky
Copy link
Contributor

odersky commented Jun 24, 2022

Ah, now I get it. I tried with normal console but that was still 3.1.3.

odersky added a commit to dotty-staging/dotty that referenced this issue Jun 25, 2022
There was a missing set of parentheses in parser which caused a lookahead
from INTERPOLATIONID, which should be illegal, since the lookahead then
migth set the next TokenData which is subsequently overwritten by reset.

We now demand that lookahead cannot be called if the current token is
a INTERPOLATIONID.

There were two many variants `lookahead` in the Scanner, which only differered
in camelCase or not. Rename one to`peekAhead` to make the code clearer.
@odersky odersky linked a pull request Jun 25, 2022 that will close this issue
odersky added a commit that referenced this issue Jun 27, 2022
@Kordyjan Kordyjan added this to the 3.2.1 milestone Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants