Description
A fully minimized version of code to duplicate the problem can be found in the comment below by Symon R..
Compiler version
scala 3.2.1 (older too) and nightly 3.3....
Minimized code
The code that does not compile is on this onepage branch of a repo specially for this Dotty issue. There is now only one file to look at: RDF.scala.
The code is duplicated in full here:
import scala.util.Try
trait RDF:
rdf =>
type R = rdf.type
type Node <: Matchable
type URI <: Node
given rops: ROps[R]
end RDF
object RDF:
type Node[R <: RDF] = R match
case GetNode[n] => Matchable //n & rNode[R]
type URI[R <: RDF] <: Node[R] = R match
case GetURI[u] => u & Node[R]
private type GetNode[N] = RDF { type Node = N }
private type GetURI[U] = RDF { type URI = U }
end RDF
trait ROps[R <: RDF]:
def mkUri(str: String): Try[RDF.URI[R]]
def auth(uri: RDF.URI[R]): Try[String]
object TraitTypes:
trait Node:
def value: String
trait Uri extends Node
def mkUri(u: String): Uri =
new Uri { def value = u }
object TraitRDF extends RDF:
import TraitTypes as tz
override opaque type Node <: Matchable = tz.Node
override opaque type URI <: Node = tz.Uri
given rops: ROps[R] with
override def mkUri(str: String): Try[RDF.URI[R]] = Try(tz.mkUri(str))
override def auth(uri: RDF.URI[R]): Try[String] =
Try(java.net.URI.create(uri.value).getAuthority())
end TraitRDF
class Test[R <: RDF](using rops: ROps[R]):
import rops.given
lazy val uriT: Try[RDF.URI[R]] = rops.mkUri("https://bblfish.net/#i")
lazy val x: String = "uri authority=" + uriT.map(u => rops.auth(u))
@main def run =
val test = Test[TraitRDF.type]
println(test.x)
Output
The compilation error can be seen in the github actions failing check here.
But I could not get the -explain
flag to work with scala-cli
.
Running it on the command line one gets the full error explantion. (After setting the env variables
below
export JAVA_HOME=/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home
export SCALA_HOME=/usr/local/scala/scala3-3.2.1
The following command
sh bin/clean
sh bin/compileScala
-- Error: scala/RDF.scala:44:8 -------------------------------------------------
44 | given rops: ROps[R] with
| ^
|object creation impossible, since def auth(uri: RDF.URI[R]): util.Try[String] in trait ROps is not defined
|(Note that
| parameter RDF.URI[R] in def auth(uri: RDF.URI[R]): util.Try[String] in trait ROps does not match
| parameter TraitTypes.Uri & Matchable in override def auth(uri: TraitTypes.Uri & Matchable): util.Try[String] in object rops in object TraitRDF
| )
-- [E038] Declaration Error: scala/RDF.scala:46:17 -----------------------------
46 | override def auth(uri: RDF.URI[R]): Try[String] =
| ^
| method auth has a different signature than the overridden declaration
|----------------------------------------------------------------------------
| Explanation (enabled by `-explain`)
|- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| There must be a non-final field or method with the name auth and the
| same parameter list in a super class of object rops to override it.
|
| override def auth(uri: TraitTypes.Uri & Matchable): util.Try[String]
|
| The super classes of object rops contain the following members
| named auth:
| def auth(uri: RDF.URI[TraitRDF.R]): util.Try[String]
----------------------------------------------------------------------------
But the compiler only has a problem when the URI is implemented in terms of a trait, not when it is implemented in terms of a class.
Expectation
The expectation is that it should work with traits as well as with classes.
A fix is to change the trait Uri
to a class Uri
as in the commit that lead to the onepage-works branch commit as shown in this minimal diff:
The problem is that it is not always possible use classes only and not traits. A major RDF library RDF4J uses traits for its RDF model, such as IRI.