Skip to content

Commit 2b8e12a

Browse files
Update the TastyFormat for matches with sub-cases (#23851)
2 parents e449935 + d9e11f6 commit 2b8e12a

File tree

5 files changed

+18
-11
lines changed

5 files changed

+18
-11
lines changed

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ class TreePickler(pickler: TastyPickler, attributes: Attributes) {
590590
if (tree.isInline)
591591
if (selector.isEmpty) writeByte(IMPLICIT)
592592
else { writeByte(INLINE); pickleTree(selector) }
593-
else if tree.isSubMatch then { writeByte(LAZY); pickleTree(selector) }
593+
else if tree.isSubMatch then { writeByte(SUBMATCH); pickleTree(selector) }
594594
else pickleTree(selector)
595595
tree.cases.foreach(pickleTree)
596596
}

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1551,7 +1551,7 @@ class TreeUnpickler(reader: TastyReader,
15511551
readByte()
15521552
InlineMatch(readTree(), readCases(end))
15531553
}
1554-
else if nextByte == LAZY then // similarly to InlineMatch we use an arbitrary Cat.1 tag
1554+
else if nextByte == SUBMATCH then
15551555
readByte()
15561556
SubMatch(readTree(), readCases(end))
15571557
else Match(readTree(), readCases(end)))

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,6 +3171,7 @@ object Parsers {
31713171
val t = inSepRegion(InCase)(postfixExpr(Location.InGuard))
31723172
t.asSubMatch
31733173
case other =>
3174+
// the guard is reinterpreted as a sub-match when there is no leading IF or ARROW token
31743175
val t = grd1.asSubMatch
31753176
grd1 = EmptyTree
31763177
t

docs/_docs/reference/experimental/sub-cases.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ e.g., `case Some(x) => x.version match ...`.
3636
If none of the sub-cases succeed, then control flow returns to the outer match expression and proceeds as though the current case had not matched.
3737
For example, `Some(Document("...", Version.Stable(2, 1)))` matches the first pattern, but none of its sub-cases, and we therefore obtain the result `"unsupported"`.
3838

39-
More generally, sub-matches also allow:
40-
- Arbitrary nesting, e.g. sub-sub-matches are supported.
41-
- Interleaved boolean guards, e.g. `case Some(x: Int) if x != 0 if x match ...`.
42-
- Interleaving pattern extractors and computations for the scrutinees of sub-matches.
43-
4439

4540
## Motivation
4641

@@ -62,11 +57,21 @@ def version(d: Option[Document]) = d match
6257
case _ => "unsupported"
6358
```
6459

60+
## Details
6561

62+
Sub-cases allow:
63+
- Arbitrary nesting, e.g. sub-sub-matches are supported.
64+
- Interleaving boolean guards, e.g. `case Some(x: Int) if x != 0 if x match ...`.
65+
- Interleaving pattern extractors and computations for the scrutinees of sub-matches.
6666

67+
Sub-cases are supported for:
68+
- match clauses
69+
- catch clauses
70+
- partial functions
6771

72+
Similarly to catch clauses, match expressions with a single case can now be written on single line (without braces),
73+
e.g., `Some(1) match case Some(x) => x`.
6874

75+
Exhaustivity and reachability checking conservatively assume the sub-cases to be partial, similarly boolean guards.
6976

70-
71-
72-
77+
A sub-match is inlined iff the outer match is inlined, with the same semantics as the usual match expressions.

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Standard-Section: "ASTs" TopLevelStat*
104104
INLINED Length expr_Term call_Term? ValOrDefDef* -- Inlined code from call, with given body `expr` and given bindings
105105
LAMBDA Length meth_Term target_Type? -- Closure over method `f` of type `target` (omitted id `target` is a function type)
106106
IF Length [INLINE] cond_Term then_Term else_Term -- inline? if cond then thenPart else elsePart
107-
MATCH Length (IMPLICIT | [INLINE] sel_Term) CaseDef* -- (inline? sel | implicit) match caseDefs
107+
MATCH Length (IMPLICIT | [INLINE | SUBMATCH] sel_Term) CaseDef* -- ((inline | if)? sel | implicit) match caseDefs
108108
TRY Length expr_Term CaseDef* finalizer_Term? -- try expr catch {casdeDef} (finally finalizer)?
109109
RETURN Length meth_ASTRef expr_Term? -- return expr?, `methASTRef` is method from which is returned
110110
WHILE Length cond_Term body_Term -- while cond do body
@@ -511,6 +511,7 @@ object TastyFormat {
511511
final val EMPTYCLAUSE = 45
512512
final val SPLITCLAUSE = 46
513513
final val TRACKED = 47
514+
final val SUBMATCH = 48 // experimental.subCases
514515

515516
// Tree Cat. 2: tag Nat
516517
final val firstNatTreeTag = SHAREDterm

0 commit comments

Comments
 (0)