bug icon indicating copy to clipboard operation
bug copied to clipboard

Strange type inference involving "with" when code is used from a library

Open jdrphillips opened this issue 5 years ago • 5 comments

reproduction steps

using Scala (2.12.11, 2.13.4),

The following code defined inside a library:

trait OtherType
class Foo {
  def bar[T](t: T): T with OtherType = ???
}

The following code in an application using the library:

val g1: Int with OtherType = new Foo().bar(5)
val g2: Int with OtherType = new Foo().bar[Int](5)

problem

g1 does not compile. It has the error:

[error]  found   : Int(5)
[error]  required: OtherType with Int

g2 compiles just fine.

However - if Foo is defined inside the same application as g1 and g2, they both compile.

I would expect both g1 and g2 to compile whether Foo comes from a library or application code.

jdrphillips avatar Jan 13 '21 15:01 jdrphillips

Dale and I took a quick look at this. Either the pickle is wrong, or the pickle is right but is unpickled incorrectly, or... something truly weird is happening.

So if someone wants to look into this, those are the hypotheses to pursue, in order.

SethTisue avatar Apr 16 '21 15:04 SethTisue

Not sure whether to "help wanted" this one. On the one hand, the minimization is small and doesn't involve obscure language features, so that makes it feel like we ought to fix it. On the other hand, presumably it's been broken forever and nobody noticed.

SethTisue avatar Apr 16 '21 15:04 SethTisue

I find it very surprising. As far as I'm aware, our use-case is exactly the same as shapeless' @@ tags, which boil down to an alias of with. I think I remember reproducing this issue with shapeless tags too but not 100% sure.

This bug really limits the abstraction you can do over with and @@, I'd be surprised if no one has ever noticed before. But clearly no one has ever reported it!

jdrphillips avatar Apr 16 '21 16:04 jdrphillips

Let's "help wanted" it since it would definitely be great if a volunteer at least dug into it far enough that we understand what's going on better inside the compiler here. Then we'd have some idea of whether it's an easy fix or not.

SethTisue avatar Apr 16 '21 16:04 SethTisue

Let's "help wanted" it since it would definitely be great if a volunteer at least dug into it far enough that we understand what's going on better inside the compiler here. Then we'd have some idea of whether it's an easy fix or not.

I'm interested in this, but don't know how to fix it. This is the second similar problem I've seen recently (and one I forgot.)

Strangely enough, I also reproduced it in sandbox mode, val g1: Int with OtherType = new Foo().bar(5) and got the wrong type when folding the constants, ending up with val g1: Int with OtherType = new Foo().bar[T](5). https://github.com/scala/scala/blob/3faf9a98282a2f06219fd0b05b7fede2ab8fb326/src/compiler/scala/tools/nsc/typechecker/Typers.scala#L3822

My test:


  val g1: Int with OtherType = new Foo().bar(5) // tpe check failed,  : Int <:< Int with OtherType => it's false
  val g2: Int with OtherType = new Foo().bar[Int](5) // tpe check passed : Int <:< Int

  val g3 = new Foo().bar(5) // tpe check passed : Int <:< ?
  val g4 = new Foo().bar[Int](5) // tpe check passed : Int <:< ?

For ConstantType, is it feasible to judge only one of the parents of the RefinedType by <:<?

jxnu-liguobin avatar Sep 26 '22 11:09 jxnu-liguobin