{"action":"opened","issue":{"url":"https://api.github.com/repos/scala/bug/issues/10750","repository_url":"https://api.github.com/repos/scala/bug","labels_url":"https://api.github.com/repos/scala/bug/issues/10750/labels{/name}","comments_url":"https://api.github.com/repos/scala/bug/issues/10750/comments","events_url":"https://api.github.com/repos/scala/bug/issues/10750/events","html_url":"https://github.com/scala/bug/issues/10750","id":300508960,"number":10750,"title":"Inconsistent type inference","user":{"login":"carymrobbins","id":3103764,"avatar_url":"https://avatars0.githubusercontent.com/u/3103764?v=4","gravatar_id":"","url":"https://api.github.com/users/carymrobbins","html_url":"https://github.com/carymrobbins","followers_url":"https://api.github.com/users/carymrobbins/followers","following_url":"https://api.github.com/users/carymrobbins/following{/other_user}","gists_url":"https://api.github.com/users/carymrobbins/gists{/gist_id}","starred_url":"https://api.github.com/users/carymrobbins/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/carymrobbins/subscriptions","organizations_url":"https://api.github.com/users/carymrobbins/orgs","repos_url":"https://api.github.com/users/carymrobbins/repos","events_url":"https://api.github.com/users/carymrobbins/events{/privacy}","received_events_url":"https://api.github.com/users/carymrobbins/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-02-27T06:31:10Z","updated_at":"2018-02-27T06:31:10Z","closed_at":null,"author_association":"NONE","body":"In the following code we see that scalac will infer the return type of a method (even though it is annotated explicitly) differently depending on the context. This is confirmed using `reify`.\r\n\r\nIf the `Nel.of` method is used in the same scope in which the `type Nel` is defined, the compiler will infer the return type of `Nel.of` to be (even though it is annotated as `Nel[A]`) -\r\n\r\n`java.lang.Object{type Nel$newtype} with Context1.Nel.Tag[Int]`\r\n\r\nHowever, if used in a different scope, its type is inferred as `Nel[A]`\r\n\r\nThe problem with this is that it prevents implicit resolution from working properly. If we define an instance for `Monad[Nel]`, the implicit won't be properly resolved for a value of the expanded type `java.lang.Object{type Nel$newtype} with Context1.Nel.Tag[Int]`. We can get around this by using type ascription, explicitly typing the value as `Nel[Int]`; however, this is far from ideal and leads to confusion.\r\n\r\nAnother oddity is that `Nel.apply` _always_ seems to be inferred correctly as `Nel[A]`, both in the scope in which it is defined or otherwise. Not sure if this means that the varargs parameters of `Nel.of` might have something to do with it.\r\n\r\nThis was discovered when using the `@newtype` macro annotation from the [newtype 0.2.1](https://github.com/estatico/scala-newtype/) library. I have demonstrated this problem with the expanded code for convenience.\r\n\r\nReproduced in a Scastie sandbox here - https://scastie.scala-lang.org/aE2tQcAzT8aU9JGZ9lug9g\r\n\r\nUncomment the code in `Context1.example1()` to reproduce the compiler error.\r\n\r\n```scala\r\nimport cats._\r\nimport cats.implicits._\r\nimport io.estatico.newtype.ops._\r\nimport io.estatico.newtype.macros.newtype\r\nimport scala.reflect.runtime.universe.reify\r\n\r\nobject Context1 {\r\n\r\n  // The following is the macro application which reproduces this issue\r\n  // @newtype class Nel[A](val toList: List[A]) {\r\n  //   def head: A = toList.head\r\n  //   def tail: List[A] = toList.tail\r\n  //   def iterator: Iterator[A] = toList.iterator\r\n  // }\r\n  // object Nel {\r\n  //   def apply[A](head: A, tail: List[A]): Nel[A] = (head +: tail).coerce\r\n  //   def of[A](head: A, tail: A*): Nel[A] = apply(head, tail.toList)\r\n  //   implicit def show[A](implicit A: Show[A]): Show[Nel[A]] = new Show[Nel[A]] {\r\n  //     def show(nel: Nel[A]): String = \"Nel(\" + nel.iterator.map(A.show).mkString(\",\") + \")\"\r\n  //   }\r\n  //   implicit def monoid[A]: Monoid[Nel[A]] = deriving\r\n  //   implicit val monad: Monad[Nel] = derivingK\r\n  // }\r\n\r\n  // Code above generates something semantically equivalent to the following\r\n  // The issue can be reproduced using either the macro or expanded implementation\r\n\ttype Nel[A] = Nel.Type[A]\r\n  object Nel {\r\n    def apply[A](head: A, tail: List[A]): Nel[A] = (head +: tail).asInstanceOf[Nel[A]]\r\n    def of[A](head: A, tail: A*): Nel[A] = apply(head, tail.toList)\r\n    implicit def show[A](implicit A: Show[A]): Show[Nel[A]] = new Show[Nel[A]] {\r\n      def show(nel: Nel[A]): String = \"Nel(\" + nel.iterator.map(A.show).mkString(\",\") + \")\"\r\n    }\r\n    implicit def monoid[A]: Monoid[Nel[A]] = deriving\r\n    implicit val monad: Monad[Nel] = derivingK\r\n    // Generated code\r\n    type Repr[A] = List[A]\r\n    type Base = { type Nel$newtype }\r\n    trait Tag[A]\r\n    type Type[A] = Base with Tag[A]\r\n    final implicit class Ops$newtype[A](val $this$: Type[A]) extends AnyVal {\r\n      def toList: List[A] = $this$.asInstanceOf[List[A]]\r\n      def head: A = toList.head\r\n      def tail: List[A] = toList.tail\r\n      def iterator: Iterator[A] = toList.iterator\r\n    }\r\n    def deriving[T[_], A](implicit ev: T[Repr[A]]): T[Type[A]] = ev.asInstanceOf[T[Type[A]]]\r\n    def derivingK[T[_[_]]](implicit ev: T[Repr]): T[Type] = ev.asInstanceOf[T[Type]]\r\n  }\r\n\r\n  def example1(): Unit = {\r\n    // COMPILE ERROR, seems to have to do with being used in the same object which defines Nel.\r\n    // val xs1 = for {\r\n    //   // value flatMap is not a member of Object{type Nel$newtype} with Example.Nel.Tag[Int]\r\n    //   x <- Nel.of(1, 2, 3) \r\n    //   // value map is not a member of Object{type Nel$newtype} with Example.Nel.Tag[Int]\r\n    //   y <- Nel.of(4, 5, 6)\r\n    // } yield x * y\r\n    //\r\n    //println(\"example1.xs1: \" + xs1)\r\n    \r\n    // For some reason, the inferred return type of Nel.of is\r\n    // java.lang.Object{type Nel$newtype} with Context1.Nel.Tag[Int]\r\n    println(\"example1: Nel.of(1, 2, 3): \" + reify(Nel.of(1, 2, 3)))\r\n  \r\n    // And the inferred return type of Nel.apply is\r\n    // Context1.Nel[Int]\r\n    println(\"example1: Nel.apply(1, List(2, 3)): \" + reify(Nel(1, List(2, 3))))\r\n\r\n    // Compiles with explicit annotation\r\n    val xs2 = for {\r\n      x <- Nel.of(1, 2, 3): Nel[Int]\r\n      y <- Nel.of(4, 5, 6): Nel[Int]\r\n    } yield x * y\r\n\r\n    println(\"example1.xs2: \" + xs2)\r\n\r\n    // Compiles with different object method\r\n    val xs3 = for {\r\n      x <- Nel(1, List(2, 3))\r\n      y <- Nel(4, List(5, 6))\r\n    } yield x * y\r\n\r\n    println(\"example1.xs3: \" + xs3)\r\n  }\r\n}\r\n\r\nobject Context2 {\r\n  import Context1.Nel\r\n\r\n  // This compiles even though it didn't in Context1\r\n  def example2(): Unit = {\r\n    val xs1 = for {\r\n      x <- Nel.of(1, 2, 3) \r\n      y <- Nel.of(4, 5, 6)\r\n    } yield x * y\r\n\r\n    println(\"example2.xs1: \" + xs1)\r\n    \r\n    // However, inferred return types are what we expect in Context2.\r\n    // Both Nel.of and Nel.apply both infer as Context1.Nel[Int] here.\r\n    println(\"example2: Nel.of(1, 2, 3): \" + reify(Nel.of(1, 2, 3)))\r\n    println(\"example2: Nel.apply(1, List(2, 3)): \" + reify(Nel(1, List(2, 3))))\r\n  }\r\n}\r\n\r\nobject Example {\r\n  def main(args: Array[String]): Unit = {\r\n    Context1.example1()\r\n    Context2.example2()\r\n  }\r\n}\r\n```"}}
{"actor":{"display_login":"carymrobbins"}}