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
A match type reduces to one of its right-hand sides, depending on a scrutinee type. Example:
6
+
A match type reduces to one of its right-hand sides, depending on the type of
7
+
its scrutinee. For example:
7
8
8
9
```scala
9
10
typeElem[X] =Xmatch {
@@ -22,16 +23,17 @@ Elem[List[Float]] =:= Float
22
23
Elem[Nil.type] =:=Nothing
23
24
```
24
25
25
-
Here `=:=` is understood to mean that left and right hand sides are mutually subtypes of each other.
26
+
Here `=:=` is understood to mean that left and right hand sides are mutually
27
+
subtypes of each other.
26
28
27
29
In general, a match type is of the form
28
30
29
31
```scala
30
32
Smatch { P1=>T1 ... Pn=>Tn }
31
33
```
32
34
33
-
where `S`, `T1`, ..., `Tn` are types and `P1`, ..., `Pn` are type patterns. Type variables
34
-
in patterns start as usual with a lower case letter.
35
+
where `S`, `T1`, ..., `Tn` are types and `P1`, ..., `Pn` are type patterns. Type
36
+
variables in patterns start with a lower case letter, as usual.
35
37
36
38
Match types can form part of recursive type definitions. Example:
37
39
@@ -53,11 +55,16 @@ type Concat[Xs <: Tuple, +Ys <: Tuple] <: Tuple = Xs match {
53
55
}
54
56
```
55
57
56
-
In this definition, every instance of `Concat[A, B]`, whether reducible or not, is known to be a subtype of `Tuple`. This is necessary to make the recursive invocation `x *: Concat[xs, Ys]` type check, since `*:` demands a `Tuple` as its right operand.
58
+
In this definition, every instance of `Concat[A, B]`, whether reducible or not,
59
+
is known to be a subtype of `Tuple`. This is necessary to make the recursive
60
+
invocation `x *: Concat[xs, Ys]` type check, since `*:` demands a `Tuple` as its
61
+
right operand.
57
62
58
-
## Dependent typing
63
+
## Dependent Typing
59
64
60
-
Match types can be used to define dependently type methods. For instance, here is value level counterpart to the`LeafElem` defined above (note the use of the match type as return type):
65
+
Match types can be used to define dependently typed methods. For instance, here
66
+
is the value level counterpart to the `LeafElem` type defined above (note the
67
+
use of the match type as the return type):
61
68
62
69
```scala
63
70
defleafElem[X](x: X):LeafElem[X] = x match {
@@ -68,12 +75,16 @@ def leafElem[X](x: X): LeafElem[X] = x match {
68
75
}
69
76
```
70
77
71
-
This special mode of typing for match expressions is only used when the following conditions are met:
78
+
This special mode of typing for match expressions is only used when the
79
+
following conditions are met:
72
80
73
81
1. The match expression patterns do not have guards
74
-
2. The match expression scrutinee's type is a subtype of the match type scrutinee's type
82
+
2. The match expression scrutinee's type is a subtype of the match type
83
+
scrutinee's type
75
84
3. The match expression and the match type have the same number of cases
76
-
4. The match expression patterns are all [Typed Patterns](https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#typed-patterns), and these types are `=:=` to their corresponding type patterns in the match type
85
+
4. The match expression patterns are all [Typed Patterns](https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#typed-patterns),
86
+
and these types are `=:=` to their corresponding type patterns in the match
87
+
type
77
88
78
89
## Representation of Match Types
79
90
@@ -86,77 +97,102 @@ is `Match(S, C1, ..., Cn) <: B` where each case `Ci` is of the form
86
97
[Xs] =>> P => T
87
98
```
88
99
89
-
Here, `[Xs]` is a type parameter clause of the variables bound in pattern `Pi`. If there are no bound type variables in a case, the type parameter clause is omitted and only the function type `P => T` is kept. So each case is either a unary function type or a type lambda over a unary function type.
100
+
Here, `[Xs]` is a type parameter clause of the variables bound in pattern `Pi`.
101
+
If there are no bound type variables in a case, the type parameter clause is
102
+
omitted and only the function type `P => T` is kept. So each case is either a
103
+
unary function type or a type lambda over a unary function type.
90
104
91
-
`B` is the declared upper bound of the match type, or `Any` if no such bound is given.
92
-
We will leave it out in places where it does not matter for the discussion. Scrutinee, bound and pattern types must be first-order types.
105
+
`B` is the declared upper bound of the match type, or `Any` if no such bound is
106
+
given. We will leave it out in places where it does not matter for the
107
+
discussion. The scrutinee, bound, and pattern types must all be first-order
108
+
types.
93
109
94
-
## Match type reduction
110
+
## Match Type Reduction
95
111
96
-
Match type reduction follows the semantics of match expression, that is, a match type of the form `S match { P1 => T1 ... Pn => Tn }` reduces to `Ti` if and only if `s: S match { _: P1 => T1 ... _: Pn => Tn }` evaluates to a value of type `Ti` for all `s: S`.
112
+
Match type reduction follows the semantics of match expressions, that is, a
113
+
match type of the form `S match { P1 => T1 ... Pn => Tn }` reduces to `Ti` if
114
+
and only if `s: S match { _: P1 => T1 ... _: Pn => Tn }` evaluates to a value of
115
+
type `Ti` for all `s: S`.
97
116
98
117
The compiler implements the following reduction algorithm:
99
118
100
-
- If the scrutinee type `S` is an empty set of values (such as `Nothing` or `String & Int`), do not reduce.
119
+
- If the scrutinee type `S` is an empty set of values (such as `Nothing` or
120
+
`String & Int`), do not reduce.
101
121
- Sequentially consider each pattern `Pi`
102
122
- If `S <: Pi` reduce to `Ti`.
103
-
- Otherwise, try constructing a proof that `S` and `Pi` are disjoint, or, in other words, that no value `s` of type `S` is also of type `Pi`.
104
-
- If such proof is found, proceed to the next case (`Pi+1`), otherwise, do not reduce.
123
+
- Otherwise, try constructing a proof that `S` and `Pi` are disjoint, or, in
124
+
other words, that no value `s` of type `S` is also of type `Pi`.
125
+
- If such proof is found, proceed to the next case (`Pi+1`), otherwise, do
126
+
not reduce.
105
127
106
128
Disjointness proofs rely on the following properties of Scala types:
107
129
108
130
1. Single inheritance of classes
109
131
2. Final classes cannot be extended
110
132
3. Constant types with distinct values are nonintersecting
111
133
112
-
Type parameters in patterns are minimally instantiated when computing `S <: Pi`. An instantiation `Is` is _minimal_ for `Xs` if all type variables in `Xs` that appear covariantly and nonvariantly in `Is` are as small as possible and all type variables in `Xs` that appear contravariantly in `Is` are as large as possible. Here, "small" and "large" are understood with respect to `<:`.
134
+
Type parameters in patterns are minimally instantiated when computing `S <: Pi`.
135
+
An instantiation `Is` is _minimal_ for `Xs` if all type variables in `Xs` that
136
+
appear covariantly and nonvariantly in `Is` are as small as possible and all
137
+
type variables in `Xs` that appear contravariantly in `Is` are as large as
138
+
possible. Here, "small" and "large" are understood with respect to `<:`.
113
139
114
-
For simplicity, we have omitted constraint handling so far. The full formulation of subtyping tests describes them as a function from a constraint and a pair of types to either _success_ and a new constraint or _failure_. In the context of reduction, the subtyping test `S <: [Xs := Is] P` is understood to leave the bounds of all variables in the input constraint unchanged, i.e. existing variables in the constraint cannot be instantiated by matching the scrutinee against the patterns.
140
+
For simplicity, we have omitted constraint handling so far. The full formulation
141
+
of subtyping tests describes them as a function from a constraint and a pair of
142
+
types to either _success_ and a new constraint or _failure_. In the context of
143
+
reduction, the subtyping test `S <: [Xs := Is] P` is understood to leave the
144
+
bounds of all variables in the input constraint unchanged, i.e. existing
145
+
variables in the constraint cannot be instantiated by matching the scrutinee
146
+
against the patterns.
115
147
116
148
## Subtyping Rules for Match Types
117
149
118
-
The following rules apply to match types. For simplicity, we omit environments and constraints.
150
+
The following rules apply to match types. For simplicity, we omit environments
151
+
and constraints.
119
152
120
-
The first rule is a structural comparison between two match types:
153
+
1.The first rule is a structural comparison between two match types:
121
154
122
-
```
123
-
S match { P1 => T1 ... Pm => Tm } <: T match { Q1 => U1 ... Qn => Un }
124
-
```
155
+
```
156
+
S match { P1 => T1 ... Pm => Tm } <: T match { Q1 => U1 ... Qn => Un }
157
+
```
125
158
126
-
if
159
+
if
127
160
128
-
```
129
-
S =:= T, m >= n, Pi =:= Qi and Ti <: Ui for i in 1..n
130
-
```
161
+
```
162
+
S =:= T, m >= n, Pi =:= Qi and Ti <: Ui for i in 1..n
163
+
```
131
164
132
-
I.e. scrutinees and patterns must be equal and the corresponding bodies must be subtypes. No case re-ordering is allowed, but the subtype can have more cases than the supertype.
165
+
I.e. scrutinees and patterns must be equal and the corresponding bodies must
166
+
be subtypes. No case re-ordering is allowed, but the subtype can have more
167
+
cases than the supertype.
133
168
134
-
The second rule states that a match type and its redux are mutual subtypes
169
+
2.The second rule states that a match type and its redux are mutual subtypes.
135
170
136
-
```
137
-
S match { P1 => T1 ... Pn => Tn } <: U
138
-
U <: S match { P1 => T1 ... Pn => Tn }
139
-
```
171
+
```
172
+
S match { P1 => T1 ... Pn => Tn } <: U
173
+
U <: S match { P1 => T1 ... Pn => Tn }
174
+
```
140
175
141
-
if
176
+
if
142
177
143
-
```
144
-
S match { P1 => T1 ... Pn => Tn } reduces-to U
145
-
```
178
+
```
179
+
S match { P1 => T1 ... Pn => Tn } reduces-to U
180
+
```
146
181
147
-
The third rule states that a match type conforms to its upper bound:
182
+
3.The third rule states that a match type conforms to its upper bound:
148
183
149
-
```
150
-
(S match { P1 => T1 ... Pn => Tn } <: B) <: B
151
-
```
184
+
```
185
+
(S match { P1 => T1 ... Pn => Tn } <: B) <: B
186
+
```
152
187
153
188
## Termination
154
189
155
190
Match type definitions can be recursive, which means that it's possible to run
156
191
into an infinite loop while reducing match types.
157
192
158
-
Since reduction is linked to subtyping, we already have a cycle detection mechanism in place.
159
-
So the following will already give a reasonable error message:
193
+
Since reduction is linked to subtyping, we already have a cycle detection
194
+
mechanism in place. As a result, the following will already give a reasonable
195
+
error message:
160
196
161
197
```scala
162
198
typeL[X] =Xmatch {
@@ -176,26 +212,38 @@ def g[X]: L[X] = ???
176
212
| subtype LazyRef(Test.L[Int]) <:<Int
177
213
```
178
214
179
-
Internally, `dotc` detects these cycles by turning selected stackoverflows
180
-
into type errors. If there is a stackoverflow during subtyping, the exception
181
-
will be caught and turned into a compile-time error that indicates a trace of
182
-
the subtype tests that caused the overflow without showing a full stacktrace.
215
+
Internally, `dotc` detects these cycles by turning selected stack overflows into
216
+
type errors. If there is a stack overflow during subtyping, the exception will
217
+
be caught and turned into a compile-time error that indicates a trace of the
218
+
subtype tests that caused the overflow without showing a full stack trace.
183
219
184
220
## Variance Laws for Match Types
221
+
NOTE: This section does not reflect the current implementation.
185
222
186
-
Within a match type `Match(S, Cs) <: B`, all occurrences of type variables count as covariant. By the nature of the cases `Ci` this means that occurrences in pattern position are contravarant (since patterns are represented as function type arguments).
223
+
Within a match type `Match(S, Cs) <: B`, all occurrences of type variables count
224
+
as covariant. By the nature of the cases `Ci` this means that occurrences in
225
+
pattern position are contravarant (since patterns are represented as function
226
+
type arguments).
187
227
188
228
## Related Work
189
229
190
-
Match types have similarities with [closed type families](https://wiki.haskell.org/GHC/Type_families) in Haskell. Some differences are:
230
+
Match types have similarities with
231
+
[closed type families](https://wiki.haskell.org/GHC/Type_families) in Haskell.
232
+
Some differences are:
191
233
192
-
- Subtyping instead of type equalities.
193
-
- 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.
234
+
- Subtyping instead of type equalities.
235
+
- Match type reduction does not tighten the underlying constraint, whereas type
236
+
family reduction does unify. This difference in approach mirrors the
237
+
difference between local type inference in Scala and global type inference in
238
+
Haskell.
194
239
195
-
Match types are also similar to Typescript's [conditional types](https://github.com/Microsoft/TypeScript/pull/21316). The main differences here are:
240
+
Match types are also similar to Typescript's
241
+
[conditional types](https://github.com/Microsoft/TypeScript/pull/21316). The
242
+
main differences here are:
196
243
197
-
- Conditional types only reduce if scrutinee and pattern are ground, whereas
198
-
match types also work for type parameters and abstract types.
244
+
- Conditional types only reduce if both the scrutinee and pattern are ground,
245
+
whereas match types also work for type parameters and abstract types.
199
246
- Match types can bind variables in type patterns.
200
247
- Match types support direct recursion.
201
248
- Conditional types distribute through union types.
0 commit comments