scala / scala3

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

"error overriding method" error when compiling JOOQ generated model #16844

Open scf37 opened 1 year ago

scf37 commented 1 year ago

Compiler version

3.2.0+

before 3.2.0 - fails with "bad constant pool", fixed in 3.2.0

Minimized code

libraryDependencies += ("org.jooq" %% "jooq-scala" % "3.17.7").cross(CrossVersion.for3Use2_13)

import org.jooq.Field
import org.jooq.Record1
import org.jooq.Record6
import org.jooq.Row6
import org.jooq.impl.UpdatableRecordImpl

class ChatRecord extends UpdatableRecordImpl[ChatRecord](null) with Record6[Long, Long, Long, Boolean, Long, Long] {}

Scastie link: https://scastie.scala-lang.org/3ioAIaRaQJ282KS69KugxA

Output

error overriding method fieldsRow in trait Record6 of type (): org.jooq.Row6[Long, Long, Long, Boolean, Long, Long];
  method fieldsRow in class AbstractQualifiedRecord of type (): org.jooq.Row has incompatible type;
other members with override errors are:: method valuesRow, method with, method original

Expectation

Successful compilation

SethTisue commented 1 year ago

Is the problem reproducible without involving an external dependency?

scf37 commented 1 year ago

I tried to reproduce it by building similar hierarchy and overrides in Scala, unsuccessfully. Seems to be Java-related.

SethTisue commented 1 year ago

The compiler does need to treat Java-defined things specially in some respects, so it's a possible a minimal reproducer would need to include a Java source file as well as a Scala one.

SethTisue commented 1 year ago

Perhaps this is a scala.Long vs java.lang.Long, scala.Boolean vs java.lang.Boolean thing?

scf37 commented 1 year ago

Nope.

new UpdatableRecordImpl[Nothing](null) {} // error
new UpdatableRecordImpl[Nothing](null)  // okay
SethTisue commented 1 year ago

Scala 2.13.10 gives a very similar looking error on the same code

[error] ./S.scala:7:1: incompatible type in overriding
[error] def fieldsRow(): org.jooq.Row6[Long,Long,Long,Boolean,Long,Long] (defined in trait Record6)
[error]   with def fieldsRow(): org.jooq.Row (defined in class AbstractQualifiedRecord);
[error]  found   : (): org.jooq.Row
[error]  required: (): org.jooq.Row6[Long,Long,Long,Boolean,Long,Long];
[error]  other members with override errors are: valuesRow
[error] class ChatRecord extends UpdatableRecordImpl[ChatRecord](null) with Record6[Long, Long, Long, Boolean, Long, Long] {}

I don't think you've made a case that there is a Scala bug here. (Perhaps there is? It remains to be seen.)

Do you definitely believe there is a Scala bug here, and you believe you can substantiate that? Or did you just get an error message you don't really understand and you came to the bug tracker hoping for help...?

SethTisue commented 1 year ago

self-contained (except for the external dependency) reproducer using scala-cli:

//> using scala "2.13.10"
//> using lib "org.jooq:jooq-scala_2.13:3.17.8"

import org.jooq.Record6
import org.jooq.impl.UpdatableRecordImpl

class ChatRecord extends UpdatableRecordImpl[ChatRecord](null)
  with Record6[Long, Long, Long, Boolean, Long, Long] {}
scf37 commented 1 year ago

Do you definitely believe there is a Scala bug

Well, real JOOQ generated code compiles well on 2.x (including 2.13). Looking at the message, there is a problem in how scalac typechecks compiled Java bytecode. I believe java bytecode is correct since JOOQ is a popular project having 5.3k stars on github.

Since they do not support scala3 directly yet https://github.com/jOOQ/jOOQ/issues/12180 AND generated code needs some fixes before getting stuck on that error I think I'd give up on integrating JOOQ in scala3 project for now.

Attached is sbt project which compiles on 2.3.10 but fails on 3.2.2

jooq-test.tar.gz

SethTisue commented 1 year ago

I think I'd give up on integrating JOOQ in scala3 project for now

Okay. I'm closing this ticket, then, since we don't have solid evidence here that there is a bug in Scala 3. (We do have some circumstantial evidence that there could be...)

Perhaps someone else trying to make JOOQ work with Scala 3 will find this ticket and have additional insight or volunteer to find a self-contained reproducer and/or attempt to characterize the specific nature of the possible bug.

tpunder commented 11 months ago

@SethTisue I just ran into this issue. Here is a reproduction with no external dependencies: https://github.com/tpunder/scala3_jooq_bug_overriding

It works fine with Scala 2.12 and 2.13 but fails with Scala 3. The only Scala source file is:

package com.example

import org.jooq.Record
import org.jooq.impl.TableRecordImpl

// Works in Scala 2.12 and Scala 2.13 but is broken in Scala 3
class ExampleRecordScala extends TableRecordImpl[ExampleRecordScala] with Record {

}

The equivalent Java version works fine:

package com.example;

import org.jooq.Record;
import org.jooq.impl.TableRecordImpl;

// This works fine
class ExampleRecordJava extends TableRecordImpl<ExampleRecordJava> implements Record {

}
tpunder commented 10 months ago

Can this bug be re-opened? Or should I create a new bug?

tpunder commented 10 months ago

I've slightly simplified the Scala example in https://github.com/tpunder/scala3_jooq_bug_overriding to remove the with Record part:

package com.example

import org.jooq.impl.AbstractRoutine

// Works in Scala 2.12 and 2.13 but is broken in Scala 3
class MyRoutineScala extends AbstractRoutine[String] {

}

Also, here is the -explain output for Scala 3:

[info] compiling 1 Scala source and 6 Java sources to /Users/tim/code/personal/scala3_jooq_bug_overriding/target/scala-3.3.1/classes ...
[info] /Users/tim/code/personal/scala3_jooq_bug_overriding/src/main/java/org/jooq/impl/TableRecordImpl.java: TableRecordImpl.java uses unchecked or unsafe operations.
[info] /Users/tim/code/personal/scala3_jooq_bug_overriding/src/main/java/org/jooq/impl/TableRecordImpl.java: Recompile with -Xlint:unchecked for details.
[error] -- [E164] Declaration Error: /Users/tim/code/personal/scala3_jooq_bug_overriding/src/main/scala/com/example/ExampleRecordScala.scala:6:6
[error] 6 |class ExampleRecordScala extends TableRecordImpl[ExampleRecordScala] {
[error]   |      ^
[error]   |error overriding method with in trait TableRecord of type [T](x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala;
[error]   |  method with in class AbstractRecord of type [T](x$0: org.jooq.Field[T], x$1: T): org.jooq.Record has incompatible type
[error]   |-----------------------------------------------------------------------------
[error]   | Explanation (enabled by `-explain`)
[error]   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error]   | I tried to show that
[error]   |   [T](x$0: org.jooq.Field[T], x$1: T): org.jooq.Record
[error]   | conforms to
[error]   |   [T](x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala
[error]   | but the comparison trace ended with `false`:
[error]   |
[error]   |   ==> [T](x$0: org.jooq.Field[T], x$1: T): org.jooq.Record  <:  [T](x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala
[error]   |     ==> type bounds []  <:  type bounds [] in frozen constraint
[error]   |     <== type bounds []  <:  type bounds [] in frozen constraint = true
[error]   |     ==> (x$0: org.jooq.Field[T], x$1: T): org.jooq.Record  <:  (x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala
[error]   |       ==> org.jooq.Record  <:  com.example.ExampleRecordScala
[error]   |       <== org.jooq.Record  <:  com.example.ExampleRecordScala = false
[error]   |     <== (x$0: org.jooq.Field[T], x$1: T): org.jooq.Record  <:  (x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala = false
[error]   |   <== [T](x$0: org.jooq.Field[T], x$1: T): org.jooq.Record  <:  [T](x$0: org.jooq.Field[T], x$1: T): com.example.ExampleRecordScala = false
[error]   |
[error]   | The tests were made under the empty constraint
[error]    -----------------------------------------------------------------------------