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

Surprising parsing behaviour for objects ending with _ #16072

Open
keynmol opened this issue Sep 19, 2022 · 9 comments
Open

Surprising parsing behaviour for objects ending with _ #16072

keynmol opened this issue Sep 19, 2022 · 9 comments

Comments

@keynmol
Copy link
Contributor

keynmol commented Sep 19, 2022

Objects ending with _ that have a body are parsed in a surprising way.
I only narrowed it down accidentally, but the symptoms were lots of compiler errors because of the defs I expected to be in the companion actually being at top level.

Compiler version

3.2.0

Minimized code

You can see how Hello_: is defined instead, and x is treated as a top-level definition

object Hello_:
  def x = 1

object `Byte_`:
  def x = 1

@main def hello = 
  println(Byte_)
  println(Hello_:)
  println(x)

Output

This parsing warning is the only indication that helped me figure out that something was off:

[warn] ./test.scala:2:3: Line is indented too far to the right, or a `{` or `:` is missing
[warn]   def x = 1
[warn]   ^

Expectation

The code either parses correctly, or fails to parse, or gives a meaningful warning

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

That's a pretty good warning. Luckily everyone always compiles with -Werror. But this is a longstanding issue. It leads to folks always adding a space before their punctuation.

scala> def _greeting_: String = "hello"
-- [E040] Syntax Error: ------------------------------------------------------------------------------------------------
1 |def _greeting_: String = "hello"
  |                ^^^^^^
  |                '=' expected, but identifier found

Here, we want to write _greeting_ for emphasis! greeting, Earthling!

@WojciechMazur WojciechMazur added area:parser and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Sep 19, 2022
@prolativ
Copy link
Contributor

I think the only thing we could do here is to improve the warning/error message.
According to the language specification a sequence of alphanumeric characters directly followed by an underscore and a sequence of operator-like characters is treated as one identifier, so

object Hello_:

is equivalent to

object `Hello_:`

and not

object `Hello_`:

@abgruszecki
Copy link
Contributor

It feels like the warning is a warning because we thought that indenting too much is harmless, but here the indentation is evidently misleading. One of the basic reasons we went for indentation-based syntax is to prevent misleading indentation, so I think we should emit an error here. @odersky what do you think about this?

@odersky
Copy link
Contributor

odersky commented Sep 20, 2022

There are other situations where you might want this. Example:

  val mainDef = ...
     val mainDef_subSef1 = ...
     ...
     val mainDef_subDefN = ...

(this pattern is used a lot in Definitions.scala).

Or:

def foo = 
  val x = 2
    x
  + y
  + z

@Kordyjan Kordyjan added this to the Future versions milestone Dec 12, 2022
@odersky
Copy link
Contributor

odersky commented Dec 14, 2022

Without a clear idea how this should be improved there's nothing to do. So far I have not seen anything.

@odersky odersky removed this from the Future versions milestone Dec 14, 2022
@som-snytt
Copy link
Contributor

Relatedly, #10671

I tried just checking ahead from objectDef or classDef when name.endsWith(":"), as the suspicious case is easy to test for. I'll see if the carets line up.

Maybe it's worth the effort because "colon fusion" f_: is a language characteristic.

@som-snytt
Copy link
Contributor

I see on my local branch the carets did not line up. (Trailing comments, etc.)

On discord, the problem of "accidental fusion of colon" came up again, in the context that it is not only accidental but surprising, the way a banana peel is not surprising when someone slips on it, unless one has no experience with them.

Has no one ever proposed allowing (some subset of) trailing colon opchars only for operators, which are encouraged for infix? That sounds draconian. Perhaps a deprecation under -source:future if lacking infix.

@abgruszecki
Copy link
Contributor

Ok. So this issue happens because the users end the object's name with an underscore and they accidentally "fuse" the colon. How about we just refuse to compile objects with such names, unless they are quoted? We could emit an error early during the parsing stage.

Example of the problematic scenario:

object Hello_:
  def x = 1

The user wanted to name the object Hello_ and accidentally created an object named Hello_: instead. So: we refuse to compile this code (b/c the object's name ends in _: without being quoted) and emit an error together with an explanation.

Example of fixed code:

object `Hello_:`
  def x = 1

Now it should be clear to the user what the object's name actually is.

Thoughts?

@som-snytt
Copy link
Contributor

it's not more restrictive than

➜  ~ scala -deprecation
Welcome to Scala 3.2.2 (19, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> {
     | object :: :
     |   def f = 42
     | }
1 warning found
-- Deprecation Warning: ------------------------------------------------------------------------------------------------
2 |object :: :
  |          ^
  |          `:` after symbolic operator is deprecated; use backticks around operator instead
// defined object ::

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants