Nonunified types in GADT pattern match
See original GitHub issueCompiler version
3.1.3
Minimized code
enum PingMessage[Response]:
case Ping(from: String) extends PingMessage[String]
val pongBehavior: [O] => (Unit, PingMessage[O]) => (Unit, O) = [O] =>
(state: Unit, msg: PingMessage[O]) =>
msg match
case PingMessage.Ping(from) => ((), s"Pong from $from")
Scastie: https://scastie.scala-lang.org/omCKwdwSQ2uGyiYSPRbOLQ
Output
Found: [O] => (Unit, PingMessage[O]) => (Unit, String)
Required: [O] => (Unit, PingMessage[O²]) => (Unit, O²)
where: O is a type variable
O² is a type variable
Expectation
Compiles successfully
Issue Analytics
- State:
- Created a year ago
- Comments:7 (3 by maintainers)
Top Results From Across the Web
Haskell pattern matching on GADTs with Data Kinds
I have found that I really like combining GADTs with Data Kinds, as it gives me further type safety than before (for most...
Read more >GADT pattern matching exhaustiveness - OCaml Discuss
I'm guessing that the type unification must have some module bounds. It can infer it correctly when all types are in the same...
Read more >6.4.8. Generalised Algebraic Data Types (GADTs) - Haskell.org
The key point about GADTs is that pattern matching causes type refinement. For example, in the right hand side of the equation.
Read more >Extensions to Type Classes and Pattern Match Checking
Generalised Algebraic Data Types (GADTs), pattern guards, en view patterns is het redeneren over pattern matching veel complexer geworden. Hoewel.
Read more >Complete and Decidable Type Inference for GADTs - Microsoft
Generalized Algebraic Data Types (GADTs) pose a particularly ... The key difficulty is that a GADT pattern match brings local type constraints into...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Again: keep an eye out for variance. If you switch to a covariant Option/Some instead of sticking to something invariant like PingMessage/Ping was, the behaviour is going to be different.
Dale and I have been looking at this further.
Our current hypothesis is that the root cause here is that when a polymorphic function literal is desugared, the result type of the
apply
method is always left blank and it’s up to type inference to fill it in.Desugar.scala
line 1734 creates thisDefDef
:where the
TypeTree()
is the missing result type of theapply
.Let’s return to Dale’s minimization. To keep this straight in your head, it’s helpful not to reuse the same type parameter name. So the minimization becomes:
line 1 is where we say what the expected type of the polymorphic function is, and that expected type includes the information that the body’s result type is
O1
.But when lines 2 and 3 are desugared, the desugaring includes
def apply(...) =
, whereas what we want isdef apply(...): O2 = ...
, since if we don’t putO2
there, inference putsString
there instead, which is wrong.So we’d need to take the expected type
[O1] => Option[O1] => O1
, extract the thirdO1
, replace all of the type parameters according to their indices so thatO1
becomesO2
, and then fill that in.