scalatags icon indicating copy to clipboard operation
scalatags copied to clipboard

Example doesn't work in Scala 3 with latest versions and sbt

Open yatesco opened this issue 3 years ago • 4 comments

Hi there - I copied your example from cask/scalatags but used the latest versions and Scala 3 and I'm getting a spurious error:

Found:    scalatags.Text.all.html.Self
Required: scalatags.text.Frag

The following import might make progress towards fixing the problem:

  import sourcecode.Text.generate


      html(

build.sbt:

val scala3Version = "3.1.0"

lazy val root = project
  .in(file("."))
  .settings(
    name := "Pride and Joy",
    version := "0.1.0-SNAPSHOT",

    scalaVersion := scala3Version,

    libraryDependencies += "com.lihaoyi" % "cask_3" % "0.8.0",
    libraryDependencies += "com.lihaoyi" % "requests_3" % "0.7.0",
    libraryDependencies += "com.lihaoyi" % "scalatags_3" % "0.11.0",
    libraryDependencies += "com.lihaoyi" % "utest_3" % "0.7.10" % "test",
    libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % "test",
  )

src/main/scala/Main:

//package app
import scalatags.Text.all._

object Main extends cask.MainRoutes{
  @cask.get("/")
  def hello() = {
    doctype("html")(
      html(
        body(
          h1("Hello World"),
          p("I am cow")
        )
      )
    )
  }

  initialize()
}

Is this something obvious, or should I stick with the older versions used in the demo?

Thanks!

yatesco avatar Dec 14 '21 22:12 yatesco

I have also encountered this problem and it seems to be a regression in scalatags because it works fine on 2.13.x versions but not on 3.x.x versions. It seems that the protected[this] qualifier is no longer permitted in Scala 3 which might be related to this problem. From my admittedly limited time of debugging, the Self type inside scalatags.Text.TypedTag has issues with variance which is getting ignored by the @uncheckedVariance annotation. For Scala 2, the scalatags.text.TagFactory#tag function used to create tags such as html, a and so forth refines to ConcreteHtmlTag[String] but in Scala 3, it refines into <tag-name>.Self where <tag-name> is the name of a tag like html or a. This results in the type checking error that you have seen where Self cannot be resolved to text.Frag.

Since doctype is only present in the text packages, I do not think that this issue occurs in the js-dom packages however everything else related to variance most likely does...but I am not fully sure. Here is a slightly smaller reproducible example using mill as the build tool:

build.sc

import mill._
import mill.scalalib._

object example extends ScalaModule {
  // Replace this with Scala 2 or Scala 3 to view the difference.
  override def scalaVersion = "3.0.2"
  override def scalacOptions = T {
    super.scalacOptions() ++
      if (isScala3(scalaVersion)) {
        Seq("-explain")
      } else {
        Seq()
      }
  } 
  override def ivyDeps = T {
    super.ivyDeps() ++ Agg(
      ivy"com.lihaoyi::scalatags:0.11.0"
    )
  }
}

example/src/Example.scala

package example

import scalatags.Text.all._

object Example {
  def main(args: Array[String]): Unit =
    println("hello world")

  // Fails in Scala 3.
  def example() =
    doctype("html")(
      html()
    )
}

seoethereal avatar Dec 16 '21 19:12 seoethereal

(nice reduction and investigation - thanks)

yatesco avatar Dec 16 '21 22:12 yatesco

Could you work around it by using asInstanceOf?

edwardcwang avatar Apr 14 '22 00:04 edwardcwang

@edwardcwang sorry for the late reply but from what I remember, asInstanceOf worked in some places but it does not work as general solution. I only managed to realise that annotating the types explicitly worked because of some trial and error.

seoethereal avatar May 23 '22 17:05 seoethereal