Skip to content

Problem with Traits not being Matchable #16408

Closed
@bblfish

Description

@bblfish

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:

Screenshot 2022-12-19 at 21 04 36

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions