You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/docs/reference/match-types.md
+51-1
Original file line number
Diff line number
Diff line change
@@ -183,13 +183,63 @@ A complete defininition of when two patterns or types overlap still needs to be
183
183
The last rule in particular is needed to detect non-overlaps for cases where the scrutinee and the patterns are tuples. I.e. `(Int, String)` does not overlap `(Int, Int)` since
184
184
`String` does not overlap `Int`.
185
185
186
+
## Handling Termination
187
+
188
+
Match type definitions can be recursive, which raises the question whether and how to check
189
+
that reduction terminates. This is currently an open question. We should investigate whether
190
+
there are workable ways to enforce that recursion is primitive.
191
+
192
+
Note that, since reduction is linked to subtyping, we already have a cycle dectection mechanism in place.
193
+
So the following will already give a reasonable error message:
194
+
```scala
195
+
typeL[X] =Xmatch {
196
+
caseInt=>L[X]
197
+
}
198
+
defg[X]:L[X] =???
199
+
valx:Int= g[Int]
200
+
```
201
+
202
+
```
203
+
|
204
+
| ^^^^^^
205
+
| found: Test.L[Int]
206
+
| required: Int
207
+
```
208
+
209
+
The subtype cycle test can be circumvented by producing larger types in each recursive invocation, as in the following definitions:
210
+
```scala
211
+
typeLL[X] =Xmatch {
212
+
caseInt=>LL[LL[X]]
213
+
}
214
+
defgg[X]:LL[X] =???
215
+
```
216
+
In this case subtyping enters into an infinite recursion. This is not as bad as it looks, however, because
217
+
`dotc` turns selected stack overflows into type errors. If there is a stackoverflow during subtyping,
218
+
the exception will be caught and turned into a compile-time error that indicates
219
+
a trace of the subtype tests that caused the overflow without showing a full stacktrace.
220
+
Concretely:
221
+
```
222
+
| val xx: Int = gg[Int]
223
+
| ^
224
+
|Recursion limit exceeded.
225
+
|Maybe there is an illegal cyclic reference?
226
+
|If that's not the case, you could also try to increase the stacksize using the -Xss JVM option.
227
+
|A recurring operation is (inner to outer):
228
+
|
229
+
| subtype Test.LL[Int] <:< Int
230
+
| subtype Test.LL[Int] <:< Int
231
+
| ...
232
+
| subtype Test.LL[Int] <:< Int
233
+
```
234
+
(The actual error message shows some additional lines in the stacktrace).
235
+
186
236
## Related Work
187
237
188
238
Match types have similarities with [closed type families](https://wiki.haskell.org/GHC/Type_families) in Haskell. Some differences are:
189
239
190
240
- Subtyping instead of type equalities.
191
241
- Match type reduction does not tighten the underlying constraint, whereas type family reduction does unify. This difference in approach mirrors the difference between local type inference in Scala and global type inference in Haskell.
192
-
- No a-priory requirement that cases are non-overlapping. Uses parallel reduction
242
+
- No a-priori requirement that cases are non-overlapping. Uses parallel reduction
193
243
instead of always chosing a unique branch.
194
244
195
245
Match types are also similar to Typescript's [conditional types](https://github.com/Microsoft/TypeScript/pull/21316). The main differences here are:
0 commit comments