scala / scala3

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

assertion failed: `wildApprox` failed to remove uninstantiated B (should be a type error) #17305

Open bbarker opened 1 year ago

bbarker commented 1 year ago

Compiler version

3.3.0-RC3

Minimized code

Scastie link; same code:

import zio.*
import zio.test.*
import zio.test.Assertion.*
import zio.Duration

enum TimeUnit derives CanEqual:
  case Millis
  case Seconds

final case class Perf(
  point: Int,
  time: Duration,
  series: String = "",
  displayUnit: TimeUnit = TimeUnit.Seconds
) {
  def timeToDisplayUnit: Long = displayUnit match
    case TimeUnit.Millis  => time.toMillis
    case TimeUnit.Seconds => time.toSeconds

}

  def assertLessThanBenches(longTimeValues: Chunk[Long])(tol: Double)(perfs: Chunk[Perf]): TestResult =
    longTimeValues
      .zip(perfs)
      .foldLeft(assertTrue(true))((acc, ii) => acc && assert(ii._2.displayUnit)(isLessThanEqualTo(ii._1 * (1.0d + tol))))

Note the assertLessThanBenches has what should be a type error; the correct code is:

      .foldLeft(assertTrue(true))((acc, ii) => acc && assert(ii._2.timeToDisplayUnit.toDouble)(isLessThanEqualTo(ii._1 * (1.0d + tol))))

Output (click arrow to expand)

java.lang.AssertionError: assertion failed: `wildApprox` failed to remove uninstantiated B while compiling /tmp/scastie9219630149224372424/src/main/scala/main.scala

See also

https://github.com/lampepfl/dotty/issues/14145

jchyb commented 1 year ago

Hi! Thank you for filing the issue. It would be incredibly helpful if we could get a zero-dependency reproduction (without zio.* and others), allowing us to debug this more easily.

tusharmath commented 1 year ago

Facing a similar issue.

sergeda commented 1 year ago

Have the same issue when using ZIO Cli

andrzejressel commented 1 year ago

Minimized:

trait Wrapper[A1] {
  def use(a: A1 => Unit): Unit
}

trait Assertion[A2] {}

def hideTypeInOut[A3](
    c1: A3
)(using
    hider: HideAInOut[A3]
): Wrapper[hider.Out] = ???

def entryPoint(): Unit = {
  hideTypeInOut(1L)
    .use((pair) => myAssert(pair)(someAssertion(2)))
}

private def myAssert[A4](a: A4)(assertion: Assertion[A4]): Unit = ()

// This should be Unit or generic, but let compiler figure it out
private def someAssertion(i: Int): Assertion[Int] = ???

trait HideAInOut[-A] {
  type Out
  def get(left: A): Out
}

object HideAInOut {

  type Out[HideA, HideB] = HideAInOut[HideA] { type Out = HideB }

  given [ImplicitA]: HideAInOut.Out[ImplicitA, ImplicitA] =
    new HideAInOut[ImplicitA] {
      type Out = ImplicitA
      def get(left: ImplicitA): Out = left
    }
}

Error:

[error] java.lang.AssertionError: assertion failed: `wildApprox` failed to remove uninstantiated ImplicitA
[error] scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$collectParts$2$.traverse(Implicits.scala:621)
andrzejressel commented 1 year ago

So I see that wildApprox is never called and replacing:

            case t: TypeParamRef =>
              assert(!ctx.typerState.constraint.contains(t), i"`wildApprox` failed to remove uninstantiated $t")
              traverse(t.underlying)

with

            case t: TypeParamRef =>
              traverse(wildApprox(t))

works fine ...

-- [E007] Type Mismatch Error: test.scala:15:47 --------------------------------
15 |    .use((pair) => myAssert(pair)(someAssertion(2)))
   |                                  ^^^^^^^^^^^^^^^^
   |                                  Found:    Assertion[Int]
   |                                  Required: Assertion[Long]
   |
   | longer explanation available when compiling with `-explain`
pragmaxim commented 8 months ago

I have a repro, this is code with the error :

import zio.cli.*

object Cli {

  sealed trait Subcommand extends Product with Serializable
  object Subcommand {
    final case class Init(extraParameter: String, gpgId: String) extends Subcommand
  }

  val init =
    Command("init", Args.text("gpd-id"))
      .withHelp(HelpDoc.p("Init subcommand description"))
      .map(gpgId => Subcommand.Init(gpgId))

  val pass: Command[Subcommand] =
    Command("pass", Options.none, Args.none).subcommands(init)

}

And the reason is that .map(gpgId => Subcommand.Init(gpgId)) I supplied only one parameter in here ...

Scala : 3.3.1
openjdk version : "14.0.2" 2020-07-14
      "dev.zio"           %% "zio"              % "2.0.20",
      "dev.zio"           %% "zio-cli"          % "0.5.0",