Skip to content

Constraint resolution failing for match type argument #6505

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
nicolasstucki opened this issue May 14, 2019 · 5 comments · Fixed by #14850
Closed

Constraint resolution failing for match type argument #6505

nicolasstucki opened this issue May 14, 2019 · 5 comments · Fixed by #14850

Comments

@nicolasstucki
Copy link
Contributor

class Foo {

  type E[X]

  def i: Int = ???
  def e: E[Int] = ???

  // Transforms `(T1, ... Tn)` into `(E[T1], ..., E[Tn])`
  type F[T <: Tuple] <: Tuple = T match {
    case Unit => Unit
    case h *: t => E[h] *: F[t]
  }

  def foo1[Args <: Tuple](args: Args, args2: F[Args]): Unit = ()

  foo1((i, i), (e, e)) // fails
  foo1((i, i), (e, e): F[(Int, Int)]) // fails

}

fails with

-- [E007] Type Mismatch Error: Foo.scala:16:15 ---------------------------------
16 |  foo1((i, i), (e, e)) // fails
   |               ^^^^^^
   |Found:    (Foo.this.E[Int], Foo.this.E[Int])
   |Required: Foo.this.F[Args]
   |
   |where:    Args is a type variable with constraint >: (Int, Int) and <: Tuple
-- [E007] Type Mismatch Error: Foo.scala:17:15 ---------------------------------
17 |  foo1((i, i), (e, e): F[(Int, Int)]) // fails
   |               ^^^^^^^^^^^^^^^^^^^^^
   |Found:    Foo.this.E[Int] *: Foo.this.E[Int] *: Foo.this.F[Unit]
   |Required: Foo.this.F[Args]
   |
   |where:    Args is a type variable with constraint >: (Int, Int) and <: Tuple

where Args should be inferred as (Int, Int).

@nicolasstucki
Copy link
Contributor Author

Same happens for

class Foo {

  type E[X]

  def i: Int = ???
  def e: E[Int] = ???

  // Transforms `(T1, ... Tn)` into `(E[T1], ..., E[Tn])`
  type F[T <: Tuple] <: Tuple = T match {
    case Unit => Unit
    case h *: t => E[h] *: F[t]
  }

  def foo2[Args <: Tuple, Args2 >: F[Args] <: F[Args]](args: Args, args2: Args2): Unit = ()

  foo2((i, i), (e, e)) // fails

  // all these work
  foo2[(Int, Int), F[(Int, Int)]]((i, i), (e, e))
  foo2[(Int, Int), F[(Int, Int)]]((i, i), (e, e))
  foo2[(Int, Int), F[Int *: Int *: Unit]]((i, i), (e, e))
  foo2[(Int, Int), (E[Int], E[Int])]((i, i), (e, e))
  foo2[(Int, Int), E[Int] *: E[Int] *: Unit]((i, i), (e, e))

}

which fails with

-- [E007] Type Mismatch Error: Foo.scala:16:15 ---------------------------------
16 |  foo2((i, i), (e, e)) // fails
   |               ^^^^^^
   |Found:    (Foo.this.E[Int], Foo.this.E[Int])
   |Required: Foo.this.F[Args]
   |
   |where:    Args is a type variable with constraint >: (Int, Int) and <: Tuple

@odersky
Copy link
Contributor

odersky commented May 15, 2019

These are problems of type inference, since the argument to the match type is not instantiated at the point where the typecheck is made. For comparison, this works:

  foo1[(Int, Int)]((i, i), (e, e))

On the other hand, this does not work either:

  def foo2[Args <: Tuple](args: Args)(args2: F[Args]): Unit = ()
  foo2(i, i)(e, e) // fails

One would hope that the first application to (i, i) instantiates Args so that the second application can pass. But that's not the case. Args is only instantiated on demand, and we do not recognize the demand here.

@milessabin
Copy link
Contributor

I have something very similar working very nicely here,

type LiftP[F[_], T] <: Tuple = T match {
  case Unit => Unit
  case a *: b => F[a] *: LiftP[F, b]
}

As far as I can see the only difference is that in this case the applied type constructor is a parameter whereas in your case it's closed over?

Parenthetically, I'd like to recommend dropping redundant argument bounds like <: Tuple ... they're very noisy and propagate all the way through the call chain. IMO that outweighs any advantages they might have in terms of improved error messages.

@odersky
Copy link
Contributor

odersky commented Mar 6, 2020

It looks difficult to me how improve on the status quo here.

@odersky
Copy link
Contributor

odersky commented Apr 5, 2022

This seems to work now.

odersky added a commit to dotty-staging/dotty that referenced this issue Apr 5, 2022
odersky added a commit to dotty-staging/dotty that referenced this issue Apr 5, 2022
odersky added a commit to dotty-staging/dotty that referenced this issue Apr 5, 2022
odersky added a commit that referenced this issue Apr 5, 2022
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