scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.88k stars 1.06k forks source link

Should Generate warnings when synchronized on `AnyVal` #17284

Closed He-Pin closed 1 year ago

He-Pin commented 1 year ago

Compiler version

3.2.2

Minimized code

1.synchronized{}

Output

image

Expectation

generate some warning as https://openjdk.org/jeps/390

liang3zy22 commented 1 year ago

This issue also exists with scala 2.13.10.

Screenshot 2023-04-17 at 15 43 11
som-snytt commented 1 year ago

That is due to boxing conversion.

g does not compile in Scala 2, but in Scala 3 is accepted, as though written A.synchronized.

class A(val s: String) extends AnyVal {
  //def f = eq("hello, world")  // missing argument list for method eq in object Predef

  def g = synchronized { println("hello, world") }
}

The error on f is charming. I was expecting it to use (Predef: AnyRef).eq and was hoping for a warning.

Since this ticket is an enhancement, I created a separate issue for the missing error.

scala-center-bot commented 1 year ago

This issue was picked for the Issue Spree No. 32 of 20 June 2023 which takes place in 7 days. @mbovel, @diogocanut, @jmesyou, @michaelpigg will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.

mbovel commented 1 year ago

See synchronized method documentation.

mbovel commented 1 year ago

I don't know good ressources about autoboxing in Scala, but the one for Java might be worth reading: https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html.

michaelpigg commented 1 year ago

It's not clear to me what phase of the compiler is relevant to this issue. I was thinking initially the parser, but maybe it's at erasure after the tree shows it converted to a BoxedUnit?

mbovel commented 1 year ago

@michaelpigg, sorry we missed you for this spree! The phase where we added the check is RefChecks: https://github.com/lampepfl/dotty/blob/main/compiler/src/dotty/tools/dotc/typer/RefChecks.scala. This phase runs after the parser and the typer, but before erasure. It's where we have most checks that are independent of parsing and typing.

To investigate this issue, we first created a test file at tests/neg/17284.scala with the following content:

def test = 451.synchronized {}

And then printed the AST after the typer using scalac -Xprint:typer tests/neg/17284.scala:

[[syntax trees at end of                     typer]] // tests/neg/17284.scala
package <empty> {
  final lazy module val 17284$package: 17284$package = new 17284$package()
  final module class 17284$package() extends Object() {
    this: 17284$package.type =>
    def test: Unit =
      int2Integer(451).synchronized[Unit](
        {
          ()
        }
      )
  }
}

We also used the -Yplain-printer flag to print the actual tree structure, not the pretty printed version scalac -Xprint:typer -Yplain-printer tests/neg/17284.scala:

[[syntax trees at end of                     typer]] // tests/neg/17284.scala
PackageDef(Ident(<empty>), List(
  ValDef(17284$package, Ident(17284$package$),
    Apply(Select(New(Ident(17284$package$)), <init>), List())),
  TypeDef(17284$package$,
    Template(DefDef(<init>, List(List()), TypeTree(), Thicket(List())),
      List(Apply(Select(New(TypeTree()), <init>), List())),
      ValDef(_, SingletonTypeTree(Ident(17284$package)), Thicket(List())), List(
      DefDef(test, List(), TypeTree(),
        Apply(
          TypeApply(
            Select(Apply(Ident(int2Integer), List(Literal(451))), synchronized)
              ,
          List(TypeTree())),
        List(Block(List(), Literal(()))))
      )
    ))
  )
))

And noted that the part we are interested in is Select(Apply(Ident(int2Integer), List(Literal(451))), synchronized).

More specifically, we're looking for pattern of the form Select(qualifier, name) where qualifier's type is a boxed class, and name is synchronized.

You can find the result of our work in #18021.

Don't hesitate to ask if you have questions! I hope to see you at the next Spree.

michaelpigg commented 1 year ago

Thanks for the explanation, @mbovel !