Skip to content

Type constructors of kind (*, *) -> * don't infer properly #9478

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
LukaJCB opened this issue Aug 1, 2020 · 0 comments
Closed

Type constructors of kind (*, *) -> * don't infer properly #9478

LukaJCB opened this issue Aug 1, 2020 · 0 comments

Comments

@LukaJCB
Copy link

LukaJCB commented Aug 1, 2020

Minimized code

class Foo[T[_, _], F[_], A, B](val fa: T[F[A], F[B]]) extends AnyVal

def x[T[_, _]](tmab: T[Either[Int, String], Either[Int, Int]]) = 
  new Foo(tmab)

Output

Found:    (tmab : T[Either[Int, String], Either[Int, Int]])
Required: T²[F[A], F[B]]

where:    A  is a type variable
          B  is a type variable
          F  is a type variable with constraint <: [_$14] =>> Any
          T  is a type in method x with bounds <: [_$15, _$16] =>> Any
          T² is a type variable with constraint <: [_$12, _$13] =>> Any

Expectation

This should compile fine and infer F as Either[Int, *], it compiles fine in Scala 2.

The larger context here is that in Cats we have a Bitraverse typeclass:

trait Bitraverse[F[_, _]] {
  def bisequence[G[_]: Applicative, A, B](fg: F[G[A], G[B]]): G[F[A, B]]
}

And the Ops for it stopped working in Dotty:

implicit class BitraverseOps[T[_, _], M[_], A, B](private val tmamb: T[M[A], M[B]]) extends AnyVal {
  def bisequence(implicit T: Bitraverse[T], P: Applicative[M]): M[T[A, B]] =
    T.bisequence(tmamb)
}

def x[T[_, _]: Bitraverse, B](tmab: T[Either[Int, String], Either[Int, Int]]) = 
  tmab.bisequence

[error] value bisequence is not a member of T[Either[Int, String], Either[Int, Int]], but could be made available as an extension method.

The following import might make progress towards fixing the problem:

  import collection.Searching.search



where:    T is a type in method x with bounds <: [_$9, _$10] =>> Any
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 10, 2020
So far, like Scala 2, given:

  Either[Int, String] <:< ?F[String]

we were able to infer:

  ?F >: [X] =>> Either[Int, X]

However, in the inverse situation:

  ?F[String] <:< Either[Int, String]

Scala 2, but not Dotty, was able to infer:

  ?F <: [X] =>> Either[Int, X]

This commit fixes this by generalizing the partial unification logic to
be run both in `compareAppliedType2` and `compareAppliedType1`, this
broke a few tests:
- In `anykind.scala`, `kinder1` and `kinder2` became ambiguous, this is
  fixed by moving `kinder2` in a lower priority base trait.
- One of the implicit search in tests/neg/i3452.scala now goes into an
  infinite loop, this seems to be the same issue as scala#9504, so I disabled
  it for now.
- shapeless in the community build now fails to compile:

```
-- Error: /home/smarter/opt/shapeless/modules/deriving/src/test/scala/shapeless3/deriving/adts.scala:30:64
30 |  sealed trait Opt[+A] derives Eq, Show, Read, Functor, EmptyK, Pure
   |                                                                ^
   | cannot reduce inline match with
   |  scrutinee:  compiletime.erasedValue[EmptyTuple.type] : EmptyTuple.type
   |  patterns :  case _:*:[a @ _, b @ _]
   | This location contains code that was inlined from kinds.scala:152
   | This location contains code that was inlined from kinds.scala:155
   | This location contains code that was inlined from kinds.scala:155
   | This location contains code that was inlined from kinds.scala:150
   | This location contains code that was inlined from type-classes.scala:345
   | This location contains code that was inlined from type-classes.scala:350
-- Error: /home/smarter/opt/shapeless/modules/deriving/src/test/scala/shapeless3/deriving/deriving.scala:163:24
163 |    val v1 = Pure[CList]
    |                        ^
    |no implicit argument of type shapeless3.deriving.Pure[shapeless3.deriving.adts.CList] was found for parameter ef of method apply in object Pure.
    |I found:
    |
    |    shapeless3.deriving.Pure.pureGenC[shapeless3.deriving.adts.CList](
    |      shapeless3.deriving.adts.CList.$asInstanceOf$[
    |
    |          (
    |            deriving.Mirror.Sum{
    |              Kind = shapeless3.deriving.K1.type;
    |                MirroredType[X] = shapeless3.deriving.adts.CList[X]
    |              ; MirroredElemTypes[_$23]
    |            }
    |           &
    |            scala.deriving.Mirror.Sum{
    |              MirroredMonoType = shapeless3.deriving.adts.CList[?];
    |                MirroredType[X] = shapeless3.deriving.adts.CList[X]
    |              ; MirroredLabel = ("CList" : String)
    |            }
    |          ){
    |            MirroredElemTypes[X] = (shapeless3.deriving.adts.CCons[X],
    |              shapeless3.deriving.adts.CNil.type
    |            ); MirroredElemLabels = (("CCons" : String), ("CNil" : String))
    |          }
    |
    |      ]
    |    )
    |
    |But method pureGenC in object Pure does not match type shapeless3.deriving.Pure[shapeless3.deriving.adts.CList].
```

As far as I can tell, this has to do with the following definition:

```
given pureGen[A[_]](using inst: K1.ProductInstances[Alt1.Of[Pure, EmptyK], A]) as Pure[A] =
```

Where:
```
trait Alt1[F[_[_]], G[_[_]], T[_]]
object Alt1 {
  type Of[F[_[_]], G[_[_]]] = [t[_]] =>> Alt1[F, G, t]
}
```

I wasn't able to really figure out what's going on but here are some
observations:
- Alt1.Of is a curried type lambda which is fairly unusual and could be
  mishandled by the compiler somehow.
- If I manually dealias `Alt1.Of[Pure, EmptyK]` to `[X[_]] =>>
  Alt1[Pure, EmptyK, X]`, then compilation fails on Dotty master but
  succeeds with this PR! However, some tests fail (for example, in
  `DerivationTests#data`, the result of `v0.gmapQ(ISB(23, "foo", true))`
  is a empty list somehow).
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 11, 2020
So far, like Scala 2, given:

  Either[Int, String] <:< ?F[String]

we were able to infer:

  ?F >: [X] =>> Either[Int, X]

However, in the inverse situation:

  ?F[String] <:< Either[Int, String]

Scala 2, but not Dotty, was able to infer:

  ?F <: [X] =>> Either[Int, X]

This commit fixes this by generalizing the partial unification logic to
be run both in `compareAppliedType2` and `compareAppliedType1`, this
broke a few tests:
- In `anykind.scala`, `kinder1` and `kinder2` became ambiguous, this is
  fixed by moving `kinder2` in a lower priority base trait.
- One of the implicit search in tests/neg/i3452.scala now goes into an
  infinite loop, this seems to be the same issue as scala#9504, so I disabled
  it for now.
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 11, 2020
So far, like Scala 2, given:

  Either[Int, String] <:< ?F[String]

we were able to infer:

  ?F >: [X] =>> Either[Int, X]

However, in the inverse situation:

  ?F[String] <:< Either[Int, String]

Scala 2, but not Dotty, was able to infer:

  ?F <: [X] =>> Either[Int, X]

This commit fixes this by generalizing the partial unification logic to
be run both in `compareAppliedType2` and `compareAppliedType1`, this
broke a few tests:
- In `anykind.scala`, `kinder1` and `kinder2` became ambiguous, this is
  fixed by moving `kinder2` in a lower priority base trait.
- One of the implicit search in tests/neg/i3452.scala now goes into an
  infinite loop, this seems to be the same issue as scala#9504, so I disabled
  it for now.
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 14, 2020
So far, like Scala 2, given:

  Either[Int, String] <:< ?F[String]

we were able to infer:

  ?F >: [X] =>> Either[Int, X]

However, in the inverse situation:

  ?F[String] <:< Either[Int, String]

Scala 2, but not Dotty, was able to infer:

  ?F <: [X] =>> Either[Int, X]

This commit fixes this by generalizing the partial unification logic to
be run both in `compareAppliedType2` and `compareAppliedType1`, this
broke a few tests:
- In `anykind.scala`, `kinder1` and `kinder2` became ambiguous, this is
  fixed by moving `kinder2` in a lower priority base trait.
- One of the implicit search in tests/neg/i3452.scala now goes into an
  infinite loop, I've disabled it for now.
smarter added a commit to dotty-staging/dotty that referenced this issue Aug 14, 2020
So far, like Scala 2, given:

  Either[Int, String] <:< ?F[String]

we were able to infer:

  ?F >: [X] =>> Either[Int, X]

However, in the inverse situation:

  ?F[String] <:< Either[Int, String]

Scala 2, but not Dotty, was able to infer:

  ?F <: [X] =>> Either[Int, X]

This commit fixes this by generalizing the partial unification logic to
be run both in `compareAppliedType2` and `compareAppliedType1`, this
broke a few tests:
- In `anykind.scala`, `kinder1` and `kinder2` became ambiguous, this is
  fixed by moving `kinder2` in a lower priority base trait.
- One of the implicit search in tests/neg/i3452.scala now goes into an
  infinite loop, I've disabled it for now. The issue seems to be related
  to by-name implicits as the divergence checker works when the by-name
  is removed from one of the implicit parameter, I've added the
  non-by-name version in the same file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants