@@ -116,59 +116,72 @@ We also improved the `find references` functionality. It is more robust and much
116116
117117Try it out in [ Visual Studio Code] ( http://dotty.epfl.ch/docs/usage/ide-support.html ) !
118118
119- ### Improvements in GADT type inference
120-
121- GADT typechecking is an advanced feature that got significantly improved in this
122- release. GADTs are case class hierarchies similar to this one:
119+ ### Better and safer types in pattern matching (improved GADT support)
123120
121+ Consider the following implementation of an evaluator for a very simple
122+ language containing only integer literals (` Lit ` ) and pairs (` Pair ` ):
124123``` scala
125- sealed trait Exp [T ]
126- case class IntLit (n : Int ) extends Exp [Int ]
127-
128- case class GenLit [T ](t : T ) extends Exp [T ]
129- case class Fun [S , T ](f : Exp [S ] => Exp [T ]) extends Exp [S => T ]
130- case class App [T , U ](f : Exp [T => U ], e : Exp [T ]) extends Exp [U ]
124+ sealed trait Exp
125+ case class Lit (value : Int ) extends Exp
126+ case class Pair (fst : Exp , snd : Exp ) extends Exp
127+
128+ object Evaluator {
129+ def eval (e : Exp ): Any = e match {
130+ case Lit (x) =>
131+ x
132+ case Pair (a, b) =>
133+ (eval(a), eval(b))
134+ }
135+ def main (args : Array [String ]): Unit = {
136+ println(eval(Lit (1 ))) // 1
137+ println(eval(Pair (Pair (Lit (1 ), Lit (2 )), Lit (3 )))) // ((1,2),3)
138+ }
139+ }
131140```
132141
133- where different constructors, such as ` IntLit ` and ` Fun ` , pass different type argument to the super
134- trait. Hence, typechecking a pattern match on ` v: Exp[T] ` requires special care. For instance, if
135- ` v = IntLit(5) ` then the typechecker must realize that ` T ` must be ` Int ` . This enables writing a
136- typed interpreter ` eval[T](e: Exp[T]): T ` , where say the ` IntLit ` branch can return an ` Int ` :
142+ This code is correct but it's not very type-safe since ` eval ` returns a value
143+ of type ` Any ` , we can do better by adding a type parameter to ` Exp ` that
144+ represents the result type of evaluating expression:
137145
138146``` scala
139- object Interpreter {
140- def eval [T ](e : Exp [T ]): T = e match {
141- case IntLit (n) => // Here T = Int and n: Int
142- n
143-
144- case gl : GenLit [_] => // Here in fact gl: GenLit[T]
145- // the next line was incorrectly allowed before the fix to https://github.com/lampepfl/dotty/issues/1754
146- // val gl1: GenLit[Nothing] = gl
147-
148- gl.t
149-
150- // The next cases triggered spurious warnings before the fix to
151- // https://github.com/lampepfl/dotty/issues/3666
152-
153- case f : Fun [s, t] => // Here T = s => t
154- (v : s) => eval(f.f(GenLit (v)))
147+ sealed trait Exp [T ]
148+ case class Lit (value : Int ) extends Exp [Int ]
149+ case class Pair [A , B ](fst : Exp [A ], snd : Exp [B ]) extends Exp [(A , B )]
155150
156- case App (f, e) => // Here f: Exp[s, T] and e: Exp[s]
157- eval(f)(eval(e))
158- }
151+ object Evaluator {
152+ def eval [T ](e : Exp [T ]): T = e match {
153+ case Lit (x) =>
154+ // In this case, T = Int
155+ x
156+ case Pair (a, b) =>
157+ // In this case, T = (A, B) where A is the type of a and B is the type of b
158+ (eval(a), eval(b))
159159}
160160```
161161
162- Scala 2 and Dotty have issues typechecking such interpreters.
163- In this release we fixed multiple bugs about GADT type checking and exhaustiveness checking, including
164- [ #3666 ] ( https://github.com/lampepfl/dotty/issues/3666 ) ,
165- [ #1754 ] ( https://github.com/lampepfl/dotty/issues/1754 ) ,
166- [ #3645 ] ( https://github.com/lampepfl/dotty/issues/3645 ) ,
167- [ #4030 ] ( https://github.com/lampepfl/dotty/issues/4030 ) .
168- Error messages are now more informative [ #3990 ] ( https://github.com/lampepfl/dotty/pull/3990 ) .
169-
170- Fixes to covariant GADTs ([ #3989 ] ( https://github.com/lampepfl/dotty/issues/3989 ) /
171- [ #4013 ] ( https://github.com/lampepfl/dotty/pull/4013 ) ) have been deferred to next release.
162+ Now the expression `Pair(Pair(Lit(1), Lit(2)), Lit(3)))` has type `Exp [((Int ,
163+ Int ), Int )]` and calling `eval` on it will return a value of type `((Int ,
164+ Int ), Int )` instead of `Any `.
165+
166+ Something subtle is going on in the definition of `eval` here : its result type
167+ is `T` which is a type parameter that could be instantiated to anything, and
168+ yet in the `Lit` case we are able to return a value of type `Int` , and in the
169+ `Pair` case a value of a tuple type . In each case the typechecker has been able
170+ to constrain the type of `T` through unification (e.g. if `e` matches `Lit(x)`
171+ then `Lit` is a subtype of `Exp[T]`, so `T` must be equal to `Int`). This is
172+ usually referred to as ** GADT support** in Scala since it closely mirrors the
173+ behavior of [Generalized Algebraic Data
174+ Types ](https:// en.wikipedia.org/ wiki/ Generalized_algebraic_data_type ) in
175+ Haskell and other languages.
176+
177+ GADTs have been a part of Scala for a long time, but in Dotty 0.7.0 - RC1 we
178+ significantly improved their implementation to catch more issues at
179+ compile- time. For example, writing `(eval(a), eval(a))` instead of `(eval(a),
180+ (eval(b)))` in the example above should be an error, but it was not caught by
181+ Scala 2 or previous versions of Dotty , whereas we now get a type mismatch error
182+ as expected. More work remains to be done to fix the remaining [GADT - related
183+ issues](https:// github.com/ lampepfl/ dotty/ issues? utf8=% E2 % 9C% 93 & q= is% 3Aissue+ is% 3Aopen+ gadt),
184+ but so far no show- stopper has been found.
172185
173186## Trying out Dotty
174187### Scastie
0 commit comments