@@ -116,59 +116,72 @@ We also improved the `find references` functionality. It is more robust and much
116
116
117
117
Try it out in [ Visual Studio Code] ( http://dotty.epfl.ch/docs/usage/ide-support.html ) !
118
118
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)
123
120
121
+ Consider the following implementation of an evaluator for a very simple
122
+ language containing only integer literals (` Lit ` ) and pairs (` Pair ` ):
124
123
``` 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
+ }
131
140
```
132
141
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:
137
145
138
146
``` 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 )]
155
150
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))
159
159
}
160
160
```
161
161
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 xample 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.
172
185
173
186
## Trying out Dotty
174
187
### Scastie
0 commit comments