Skip to content

Ycheck fail when mapping Option on Tuple #14351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Sporarum opened this issue Jan 25, 2022 · 2 comments · Fixed by #17215
Closed

Ycheck fail when mapping Option on Tuple #14351

Sporarum opened this issue Jan 25, 2022 · 2 comments · Fixed by #17215

Comments

@Sporarum
Copy link
Contributor

Compiler version

tasty-core / scalaVersion
        3.1.1-RC2
scala3-sbt-bridge / scalaVersion
        3.1.1-RC2
scala3-interfaces / scalaVersion
        3.1.1-RC2
scala3-compiler / scalaVersion
        3.1.1-RC2
scala3-library / scalaVersion
        3.1.1-RC2
scalaVersion
        3.1.1-RC2

Minimized code

val p: (Option[Int], Option[String]) = (1,"foo").map([T] => (x: T) => Option.apply[T](x))

(works correctly with a 1-Tuple, like 1 *: EmptyTuple)

Output

When running scalac <file>:

[success] Total time: 4 s, completed 25 janv. 2022 à 22:29:17

When running scalac -Ycheck:all <file>:

checking tests\pos\mapOnPair.scala after phase typer
exception while typing val p: Tuple2[Option[Int], Option[String]] =
  Tuple2.apply[Int, String](1, "foo").map[Option](
    {
      final class $anon() extends Object(), PolyFunction {
        def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
      }
      new $anon():([T] => (T) => Option[T])
    }
  ) of class class dotty.tools.dotc.ast.Trees$ValDef # -1
exception while typing final module class mapOnPair1() extends Object() { this: mapOnPair1.type =>
  val p: Tuple2[Option[Int], Option[String]] =
    Tuple2.apply[Int, String](1, "foo").map[Option](
      {
        final class $anon() extends Object(), PolyFunction {
          def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
        }
        new $anon():([T] => (T) => Option[T])
      }
    )
} of class class dotty.tools.dotc.ast.Trees$TypeDef # -1
exception while typing package <empty> {
  final lazy module val mapOnPair1: mapOnPair1 = new mapOnPair1()
  final module class mapOnPair1() extends Object() { this: mapOnPair1.type =>
    val p: Tuple2[Option[Int], Option[String]] =
      Tuple2.apply[Int, String](1, "foo").map[Option](
        {
          final class $anon() extends Object(), PolyFunction {
            def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
          }
          new $anon():([T] => (T) => Option[T])
        }
      )
  }
} of class class dotty.tools.dotc.ast.Trees$PackageDef # -1
*** error while checking tests\pos\mapOnPair.scala after phase typer ***
exception occurred while compiling tests\pos\mapOnPair.scala
Exception in thread "main" java.lang.AssertionError: assertion failed: Types differ
Original type : Option[Int] *: Nothing *: EmptyTuple
After checking: (Int, String) match {
  case EmptyTuple => EmptyTuple
  case h *: t => Option[h] *: scala.Tuple.Map[t, Option]
} <: Tuple
Original tree : Tuple2.apply[Int, String](1, "foo").map[Option](
  {
    final class $anon() extends Object(), PolyFunction {
      def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
    }
    new $anon():([T] => (T) => Option[T])
  }
)
After checking: Tuple2.apply[Int, String](1, "foo").map[Option](
  {
    final class $anon() extends Object(), PolyFunction {
      def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
    }
    new $anon():([T] => (T) => Option[T])
  }
)
Why different :
             Subtype trace:
 } <: Tuple  <:  Option[Int] *: Nothing *: EmptyTupleion]
    ==> Option[Int] *: Option[String] *: EmptyTuple  <:  Option[Int] *: Nothing *: EmptyTuple
      ==> scala.type  <:  scala.type
      <== scala.type  <:  scala.type = true
      ==> Option[Int]  <:  Option[Int]
        ==> Option[Int]  <:  Option[Int]
        <== Option[Int]  <:  Option[Int] = true
      <== Option[Int]  <:  Option[Int] = true
      ==> Option[String] *: EmptyTuple  <:  Nothing *: EmptyTuple
        ==> scala.type  <:  scala.type
        <== scala.type  <:  scala.type = true
        ==> Option[String]  <:  Nothing
        <== Option[String]  <:  Nothing = false
      <== Option[String] *: EmptyTuple  <:  Nothing *: EmptyTuple = false
    <== Option[Int] *: Option[String] *: EmptyTuple  <:  Option[Int] *: Nothing *: EmptyTuple = false
 } <: Tuple  <:  Option[Int] *: Nothing *: EmptyTuple = false while compiling tests\pos\mapOnPair.scala
java.lang.AssertionError: assertion failed: Types differ
Original type : Option[Int] *: Nothing *: EmptyTuple
After checking: (Int, String) match {
  case EmptyTuple => EmptyTuple
  case h *: t => Option[h] *: scala.Tuple.Map[t, Option]
} <: Tuple
Original tree : Tuple2.apply[Int, String](1, "foo").map[Option](
  {
    final class $anon() extends Object(), PolyFunction {
      def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
    }
    new $anon():([T] => (T) => Option[T])
  }
)
After checking: Tuple2.apply[Int, String](1, "foo").map[Option](
  {
    final class $anon() extends Object(), PolyFunction {
      def apply[T >: Nothing <: Any](x: T): Option[T] = Option.apply[T](x)
    }
    new $anon():([T] => (T) => Option[T])
  }
)
Why different :
             Subtype trace:
 } <: Tuple  <:  Option[Int] *: Nothing *: EmptyTupleion]
    ==> Option[Int] *: Option[String] *: EmptyTuple  <:  Option[Int] *: Nothing *: EmptyTuple
      ==> scala.type  <:  scala.type
      <== scala.type  <:  scala.type = true
      ==> Option[Int]  <:  Option[Int]
        ==> Option[Int]  <:  Option[Int]
        <== Option[Int]  <:  Option[Int] = true
      <== Option[Int]  <:  Option[Int] = true
      ==> Option[String] *: EmptyTuple  <:  Nothing *: EmptyTuple
        ==> scala.type  <:  scala.type
        <== scala.type  <:  scala.type = true
        ==> Option[String]  <:  Nothing
        <== Option[String]  <:  Nothing = false
      <== Option[String] *: EmptyTuple  <:  Nothing *: EmptyTuple = false
    <== Option[Int] *: Option[String] *: EmptyTuple  <:  Option[Int] *: Nothing *: EmptyTuple = false
 } <: Tuple  <:  Option[Int] *: Nothing *: EmptyTuple = false
        at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:339)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2937)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2941)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:310)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3057)
        at dotty.tools.dotc.typer.Typer.typedValDef(Typer.scala:2192)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2783)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2871)
        at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:326)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2937)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2941)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:310)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2963)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3013)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:549)
        at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2454)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedClassDef(TreeChecker.scala:484)
        at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:2797)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2801)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2871)
        at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:326)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2937)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2941)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:310)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:2963)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3013)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedStats(TreeChecker.scala:549)
        at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2581)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedPackageDef(TreeChecker.scala:575)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2842)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2872)
        at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:121)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typedUnadapted(TreeChecker.scala:326)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2937)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2941)
        at dotty.tools.dotc.transform.TreeChecker$Checker.typed(TreeChecker.scala:310)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3057)
        at dotty.tools.dotc.transform.TreeChecker.check(TreeChecker.scala:144)
        at dotty.tools.dotc.transform.TreeChecker.run(TreeChecker.scala:111)
        at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:308)
        at scala.collection.immutable.List.map(List.scala:246)
        at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:309)
        at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:259)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
        at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1328)
        at dotty.tools.dotc.Run.runPhases$1(Run.scala:270)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:278)
        at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
        at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:68)
        at dotty.tools.dotc.Run.compileUnits(Run.scala:287)
        at dotty.tools.dotc.Run.compileSources(Run.scala:220)
        at dotty.tools.dotc.Run.compile(Run.scala:204)
        at dotty.tools.dotc.Driver.doCompile(Driver.scala:39)
        at dotty.tools.dotc.Driver.process(Driver.scala:199)
        at dotty.tools.dotc.Driver.process(Driver.scala:167)
        at dotty.tools.dotc.Driver.process(Driver.scala:179)
        at dotty.tools.dotc.Driver.main(Driver.scala:209)
        at dotty.tools.dotc.Main.main(Main.scala)

Expectation

Ycheck should probably succeed, given the code can even execute:
https://scastie.scala-lang.org/xHL4deBNRwaCvqAn71H5og

@nicolasstucki
Copy link
Contributor

Workarround

- val p: (Option[Int], Option[String]) = (1,"foo").map([T] => (x: T) => Option.apply[T](x))
+ val p: (Option[Int], Option[String]) = (1,"foo").map[Option]([T] => (x: T) => Option.apply[T](x))

@nicolasstucki nicolasstucki removed the stat:needs triage Every issue needs to have an "area" and "itype" label label Jan 27, 2022
@nicolasstucki
Copy link
Contributor

It is strange that the first time we type check it we get

Original type : Option[Int] *: Nothing *: EmptyTuple

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants