Skip to content

Commit 232835a

Browse files
committed
Fix patterns containing wildcards; enhance test
1 parent 0d93a82 commit 232835a

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,13 +1489,18 @@ object desugar {
14891489
case _ => -1
14901490
}
14911491

1492+
val nonWildcardVars = pat match {
1493+
case Tuple(pats) => pats.filterNot(isWildcardPattern).length
1494+
case _ => -1
1495+
}
1496+
14921497
val isMatchingTuple: Tree => Boolean = {
14931498
case Tuple(es) => varTuplePatternArity == es.length && !hasNamedArg(es)
14941499
case _ => false
14951500
}
14961501

14971502
// We can only optimize `val pat = if (...) e1 else e2` if:
1498-
// - `e1` and `e2` are both tuples of arity N
1503+
// - `e1` and `e2` are both literal tuples of arity N
14991504
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
15001505
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
15011506

@@ -1504,7 +1509,7 @@ object desugar {
15041509
case _ => false
15051510

15061511
val vars =
1507-
if (tupleOptimizable) // include `_`
1512+
if varTuplePatternArity > 0 && nonWildcardVars > 1 then // include `_`
15081513
pat match
15091514
case Tuple(pats) => pats.map { case id: Ident => id -> TypeTree() }
15101515
else
@@ -1522,7 +1527,7 @@ object desugar {
15221527
if tupleOptimizable then rhs
15231528
else
15241529
val caseDef =
1525-
if varTuplePatternArity >= 0 && ids.length > 1 then
1530+
if varTuplePatternArity > 0 && ids.length > 1 then
15261531
// If the pattern contains only simple variables or wildcards,
15271532
// we don't need to create a new tuple.
15281533
// If there is only one variable (ids.length == 1),

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>
207207
case _ => false
208208
}
209209

210+
/** Is tree a wildcard pattern? Not including `x @ _` */
211+
def isWildcardPattern(pat: Tree): Boolean = unsplice(pat) match {
212+
case x: Ident => x.name == nme.WILDCARD && !isBackquoted(x)
213+
case _ => false
214+
}
215+
210216
/** The first constructor definition in `stats` */
211217
def firstConstructor(stats: List[Tree]): Tree = stats match {
212218
case (meth: DefDef) :: _ if meth.name.isConstructorName => meth

tests/pos/simple-tuple-extract.scala

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11

22
class Test:
3-
def f1: (Int, Int, Int) = (1, 2, 3)
4-
def f2: (x: Int, y: Int) = (3, 4)
3+
def f1: (Int, String, AnyRef) = (1, "2", "3")
4+
def f2: (x: Int, y: String) = (0, "y")
55

66
def test1 =
77
val (a, b, c) = f1
88
// Desugared to:
9-
// val $2$: (Int, Int, Int) =
10-
// this.f1:(Int, Int, Int) @unchecked match
9+
// val $2$: (Int, String, AnyRef) =
10+
// this.f1:(Int, String, AnyRef) @unchecked match
1111
// {
12-
// case $1$ @ Tuple3.unapply[Int, Int, Int](_, _, _) =>
13-
// $1$:(Int, Int, Int)
12+
// case $1$ @ Tuple3.unapply[Int, String, Object](_, _, _) =>
13+
// $1$:(Int, String, AnyRef)
1414
// }
1515
// val a: Int = $2$._1
16-
// val b: Int = $2$._2
17-
// val c: Int = $2$._3
18-
a + b + c
16+
// val b: String = $2$._2
17+
// val c: AnyRef = $2$._3
18+
a + b.length() + c.toString.length()
1919

2020
def test2 =
21-
val (_, d, e) = f1
22-
e + e
21+
val (_, b, c) = f1
22+
b.length() + c.toString.length()
23+
24+
val (a2, _, c2) = f1
25+
a2 + c2.toString.length()
2326

2427
def test3 =
25-
val (_, f, _) = f1
26-
f + f
28+
val (_, b, _) = f1
29+
b.length() + 1
2730

2831
def test4 =
2932
val (x, y) = f2
30-
x + y
33+
x + y.length()
3134

3235
def test5 =
33-
val (_, a) = f2
34-
a + a
36+
val (_, b) = f2
37+
b.length() + 1

0 commit comments

Comments
 (0)