-
Notifications
You must be signed in to change notification settings - Fork 21
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
Anonymous type function is accepted as higher-kinded parameter type, but does not unify with it #5075
Comments
Imported From: https://issues.scala-lang.org/browse/SI-5075?orig=1
|
@retronym said: So probably a duplicate of #2712, although Adriaan will be the final arbiter of that. trait TypeWithHKParam[D[_]]
def function[D[_]](t: TypeWithHKParam[D]) = 1
function(null: TypeWithHKParam[Option]) //okay
//Does not compile
function(null: TypeWithHKParam[({type l[a] = (Int, a)})#l]) Very nicely reported bug, BTW. |
@Blaisorblade said: |
@adriaanm said: |
seems unlikely to progress in Scala 2 |
Hold your horses ... this is actually fixed I would guess by the SI-2712 fix. I think you're being a bit too free with "unlikely to progress in Scala 2". |
PR adding a test confirming the fix here: scala/scala#6366. |
Fixing 2712 does not fix this, because "Scalac does not have to synthesize a type function, but it is handed to it on a plate and it must just be kind-checked and the kind compared with the desired one" as @Blaisorblade says, which is not what happens with You can see this by using scala> val param: TypeWithHigherKindParam[PartialApply1Of2[Tuple2, Int]#Apply] = null
param: TypeWithHigherKindParam[[B](Int, B)] = null
scala> function(param)
res2: Int = 1
scala> val param: TypeWithHigherKindParam[PartialApply1Of2[Tuple2, Int]#Flip] = null
param: TypeWithHigherKindParam[[B](B, Int)] = null
scala> function(param)
<console>:14: error: no type parameters for method function: (t: TypeWithHigherKindParam[D])Int exist so that it can be applied to arguments (TypeWithHigherKindParam[[B](B, Int)])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : TypeWithHigherKindParam[[B](B, Int)]
required: TypeWithHigherKindParam[?D]
function(param)
^
<console>:14: error: type mismatch;
found : TypeWithHigherKindParam[[B](B, Int)]
required: TypeWithHigherKindParam[D]
function(param)
^
scala> function[PartialApply1Of2[Tuple2, Int]#Flip](param)
res4: Int = 1 |
What's more annoying is that inference here would rely on not dealiasing too much, while other inference issues would be fixed by dealiasing more. Which is impossible to balance. It'd be more principled to use some
so that any amount of dealiasing couldn't change the result of type inference—the user has to explicitly coerce between the newtype and its implementation. It's as if you had aliases and a way of telling when the typechecker should unfold the alias (and replace it by its definition) and refold it (and replace the definition by the alias). That would demand better value types—maybe opaque types could handle this? But since the typechecker can see the implementation of an opaque type (supposedly), it's not obvious they could be used to control inference. Overall, compared to Haskell, it's cool that you can write out type lambdas and pass them explicitly (and we should retain that possibility), but we know that inferring them robustly in general doesn't work. Partial-unification approaches the Haskell approach but still infers type lambdas, unlike Haskell, causing this problem. |
@Blaisorblade I agree on all points. I don't know Dotty very well, but it looks to me that type aliases there are type lambdas under the hood. How does it deal with the conflicting needs to expand / not expand for the sake of unification? Also I am really excited to have newtypes or whatever we choose to call them in Scala, but in this specific case we don't ever need a value of that type. Workaround today: trait PartialApply1Of2[T[_, _], A] {
type Apply[B] >: T[A, B] <: T[A, B]
type Flip[B] >: T[B, A] <: T[B, A]
} |
Type aliases are still aliases — it's just that some aliases are to lambdas, so
Well, the function call would just use the type, but at some point the code does manipulate actual instances of the type (in non-minimized applications). It's fun this workaround might work, but at least in DOT (and I suspect in Dotty) |
That's definitely an improvement. In Scala 2 there is
Ah, I was under the impression that you would only use it as a type lambda.
Bug or feature 🤔 |
Caveat: I'm still a PL guy who understands DOT and is learning the real thing, so expect mistakes.
Makes sense for the theory, couldn't point to any downside, if it knows the difference when talking to the user? |
Test to close scala/bug#5075.
- this fails because the TC parameter should be a type member to avoid scala/bug#5075 but it is not
* equalz Scalatest matcher in new daml-lf/scalatest-tools library * equalz typing tests * a 'should' replacing design * a 'MatcherFactory1' design - this fails because the TC parameter should be a type member to avoid scala/bug#5075 but it is not * MatcherFactory1 with chained Lub+Equal typeclass - requires partial-unification at point of use, which is not great * LubEqual's extra tparam is probably unneeded * better LtEqual * demonstrate that HK LubEqual's resolve with DMT should + MatcherFactory * remove unneeded 3rd param from LubEqual, again * update dependency specs and license headers * allow use with should, shouldNot in some cases, preserving the shouldx/shouldNotx alternatives * move Equalz to libs-scala/scalatest-utils * rename bzl targets and place in com.daml.scalatest package * add scalatest-utils to release * move *SpecCheckLaws, Unnatural to scalatest-utils * missed scalacheck dep in scalatest-utils * downstreams of *SpecCheckLaws now get them from scalatest-utils * test equal-types case as well * update LF documentation CHANGELOG_BEGIN CHANGELOG_END * whitespace error
I attached a minimal example reproducing the bug. Compiling it and checking the error messages might be faster than reading my description, but I still include a walkthrough of the bug. Suppose we have the following definitions (the values are irrelevant as you might verify, only the argument types count):
where PartialApply1Of2#Apply is a type function (it comes from Scalaz, is included in the attachment). Let's apply function to param:
So, type inference cannot figure out the needed parameter. However, the error message hints that unification has the right inputs and is simply failing:
?D was declared as D[_] and has thus kind * -> * (in Haskell notation), like [B](Int, B), so unification should easily succeed.
Moreover, when making function implicit, I'd expect the compiler to be able to use it (as in the example) - that's (a reduced version of) my original use case, actually. More complex tests can be found commented out in the attachment.
FYI, I retested this also on a (hopefully) more recent version, getting the same results (plus extra unrelated warnings).
It was yesterday's HEAD of scala-virtualized (git://github.com/TiarkRompf/scala-virtualized.git), branch virtualized-master, commit 158bc26c7bf9552c99eba00690b15f5d351abfb6 (which seems to have last resynced to scala on this commit: scala/scala@b0d5648).
The text was updated successfully, but these errors were encountered: