Skip to content
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

Singleton inference failure when used in same file #11982

Closed
valencik opened this issue Apr 4, 2021 · 3 comments · Fixed by #13780 or #15423
Closed

Singleton inference failure when used in same file #11982

valencik opened this issue Apr 4, 2021 · 3 comments · Fixed by #13780 or #15423
Assignees
Labels
area:match-types itype:bug itype:soundness Soundness bug (it lets us compile code that crashes at runtime with a ClassCastException)
Milestone

Comments

@valencik
Copy link
Contributor

valencik commented Apr 4, 2021

Compiler version

3.0.0-RC2

Minimized code

The following compiles fine on it's own:

package tuplefun
object Unpair {

  def pair[A, B](using a: ValueOf[A], b: ValueOf[B]): Tuple2[A, B] =
    (a.value, b.value)

  def unpair[X <: Tuple2[?, ?]](
      using a: ValueOf[Tuple.Head[X]],
            b: ValueOf[Tuple.Head[Tuple.Tail[X]]]
  ): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] =
    type AA = Tuple.Head[X]
    type BB = Tuple.Head[Tuple.Tail[X]]
    pair[AA, BB](using a, b)
}

However, attempts to use unpair within the same file fail to compile, see the following scastie for an example:
https://scastie.scala-lang.org/wa8mgjM9TPOY2trROxRWXg

Everything compiles and works if we move UnpairApp, shown in above scastie link and below, to a new file.

object UnpairApp {
  import Unpair._

  type Tshape = ("msg", 42)

  // the following won't compile when in the same file as Unpair
  val p1: ("msg", 42) = unpair[Tshape] // error: No singleton value available for Any

  @main def pairHello: Unit =
    assert(p1 == ("msg", 42))
    println(p1)
}

Additionally if one loads the console in sbt and imports unpair things work:

scala> import tuplefun.Unpair.unpair

scala> type T = ("msg", 42)
// defined alias type T = ("msg", 42)

scala> unpair[T]                   
val res0: ("msg", 42) = (msg,42)

Expectation

UnpairApp and/or usage of unpair should compile whether defined in the same file or a separate file from Unpair

What are you doing?

If curious, the motivation that lead me here was trying to call a function of the form def func[A, B] when what I have is a type alias type T = Tuple2[A, B] and I do not want to spell out the types again.

@nicolasstucki
Copy link
Contributor

Minimized

object Unpair {
  def unpair[X <: Tuple2[?, ?]](a: ValueOf[Tuple.Head[X]]): Unit = ???
  unpair[("msg", 42)](summon[ValueOf["msg"]])
}

@OlivierBlanvillain
Copy link
Contributor

I'm not sure about the original example, but in Nico's minimization I don't think we can do better without existential types. If you give the first ? a name, things start to work as expected, but type inference won't do this on its own:

object Unpair {
  def unpair[A, X <: Tuple2[A, ?]](a: ValueOf[Tuple.Head[X]]): Unit = ???
  unpair["msg", ("msg", 42)](summon[ValueOf["msg"]])
}

@OlivierBlanvillain
Copy link
Contributor

OlivierBlanvillain commented May 20, 2021

I couldn't reproduce the issue with same file vs different files:

Reproduced as follows: (works under separate compilation, but breaks when put in a single file)

$ cat tests/pos/11982/1.scala
package tuplefun

object Unpair {

 def pair[A, B](using a: ValueOf[A], b: ValueOf[B]): Tuple2[A, B] =
   (a.value, b.value)

 def unpair[X <: Tuple2[?, ?]](
     using a: ValueOf[Tuple.Head[X]],
           b: ValueOf[Tuple.Head[Tuple.Tail[X]]]
 ): Tuple2[Tuple.Head[X], Tuple.Head[Tuple.Tail[X]]] =
   type AA = Tuple.Head[X]
   type BB = Tuple.Head[Tuple.Tail[X]]
   pair[AA, BB](using a, b)
}

$ cat tests/pos/11982/2.scala
package tuplefun

object UnpairApp {
 import Unpair._

 type Tshape = ("msg", 42)
 val p1: ("msg", 42) = unpair[Tshape]

 @main def pairHello: Unit =
   assert(p1 == ("msg", 42))
   println(p1)
}

$ echo 11982 >> compiler/test/dotc/pos-test-pickling.blacklist

$ sbt "testCompilation 11982"
...
[success] Total time: 3 s, completed Aug 4, 2021 12:45:51 PM

OlivierBlanvillain added a commit to dotty-staging/dotty that referenced this issue Oct 20, 2021
Fix scala#11982 and the associated soundness problem. The issue with the
behavior on master arises from the fact that type binder of match types
might change as context gets more precise, which results in a single
match type reducing in two different ways. This issue comes from the
fact that subtyping looks into base types, and is thus able to match a
type such as `T <: Tuple2[Int, Int]` against a pattern `case Tuple2[a,
b]`, even if the best solutions for `a` and `b` in the current context
are not guaranteed to be the best solution in more precise contexts
(such as at call site in the added test case).
OlivierBlanvillain added a commit to dotty-staging/dotty that referenced this issue Oct 20, 2021
Fix scala#11982 and the associated soundness problem. The issue with the
behavior on master arises from the fact that type binder of match types
might change as context gets more precise, which results in a single
match type reducing in two different ways. This issue comes from the
fact that subtyping looks into base types, and is thus able to match a
type such as `T <: Tuple2[Int, Int]` against a pattern `case Tuple2[a,
b]`, even if the best solutions for `a` and `b` in the current context
are not guaranteed to be the best solution in more precise contexts
(such as at call site in the added test case).
OlivierBlanvillain added a commit to dotty-staging/dotty that referenced this issue Mar 30, 2022
Fix scala#11982 and the associated soundness problem. The issue with the
behavior on master arises from the fact that type binder of match types
might change as context gets more precise, which results in a single
match type reducing in two different ways. This issue comes from the
fact that subtyping looks into base types, and is thus able to match a
type such as `T <: Tuple2[Int, Int]` against a pattern `case Tuple2[a,
b]`, even if the best solutions for `a` and `b` in the current context
are not guaranteed to be the best solution in more precise contexts
(such as at call site in the added test case).
odersky added a commit to dotty-staging/dotty that referenced this issue May 31, 2022
scala#13780 caused several regressions and I think it is too restrictive as a fix.
I am reverting it an re-opening the original scala#11982 issue.

It would be good to get to the bottom of what the soundness problem hinted at
in scala#11982 is, and what a fix should be. As it stands scala#11982 is not obviously
a soundness problem but a separate compilation problem.
@odersky odersky reopened this May 31, 2022
odersky added a commit to dotty-staging/dotty that referenced this issue May 31, 2022
scala#13780 caused several regressions and I think it is too restrictive as a fix.
I am reverting it an re-opening the original scala#11982 issue.

It would be good to get to the bottom of what the soundness problem hinted at
in scala#11982 is, and what a fix should be. As it stands scala#11982 is not obviously
a soundness problem but a separate compilation problem.
odersky added a commit to dotty-staging/dotty that referenced this issue May 31, 2022
scala#13780 caused several regressions and I think it is too restrictive as a fix.
I am reverting it an re-opening the original scala#11982 issue.

It would be good to get to the bottom of what the soundness problem hinted at
in scala#11982 is, and what a fix should be. As it stands scala#11982 is not obviously
a soundness problem but a separate compilation problem.
@smarter smarter added the itype:soundness Soundness bug (it lets us compile code that crashes at runtime with a ClassCastException) label May 31, 2022
odersky added a commit to dotty-staging/dotty that referenced this issue Jun 12, 2022
Take up scala#13780 again, but refine it so that abstract types are allowed in match type
reduction as long as they uniquely instantiate type parameters of the type pattern.

Fixes scala#11982
Kordyjan pushed a commit to dotty-staging/dotty that referenced this issue Jun 22, 2022
Take up scala#13780 again, but refine it so that abstract types are allowed in match type
reduction as long as they uniquely instantiate type parameters of the type pattern.

Fixes scala#11982
bishabosha pushed a commit to dotty-staging/dotty that referenced this issue Oct 18, 2022
scala#13780 caused several regressions and I think it is too restrictive as a fix.
I am reverting it an re-opening the original scala#11982 issue.

It would be good to get to the bottom of what the soundness problem hinted at
in scala#11982 is, and what a fix should be. As it stands scala#11982 is not obviously
a soundness problem but a separate compilation problem.
bishabosha pushed a commit to dotty-staging/dotty that referenced this issue Oct 18, 2022
Take up scala#13780 again, but refine it so that abstract types are allowed in match type
reduction as long as they uniquely instantiate type parameters of the type pattern.

Fixes scala#11982
@Kordyjan Kordyjan added this to the 3.2.1 milestone Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:match-types itype:bug itype:soundness Soundness bug (it lets us compile code that crashes at runtime with a ClassCastException)
Projects
None yet
6 participants