diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c3682329cd68..3b4fc8a97d13 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -913,16 +913,34 @@ object desugar { case IdPattern(named, tpt) => derivedValDef(original, named, tpt, rhs, mods) case _ => - val rhsUnchecked = makeAnnotated("scala.unchecked", rhs) - val vars = getVariables(pat) + def isTuplePattern(arity: Int): Boolean = pat match { + case Tuple(pats) if pats.size == arity => + pats.forall(isVarPattern) + case _ => false + } val isMatchingTuple: Tree => Boolean = { - case Tuple(es) => es.length == vars.length + case Tuple(es) => isTuplePattern(es.length) case _ => false } + + // We can only optimize `val pat = if (...) e1 else e2` if: + // - `e1` and `e2` are both tuples of arity N + // - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)` + val tupleOptimizable = forallResults(rhs, isMatchingTuple) + + def rhsUnchecked = makeAnnotated("scala.unchecked", rhs) + val vars = + if (tupleOptimizable) // include `_` + pat match { + case Tuple(pats) => + pats.map { case id: Ident => id -> TypeTree() } + } + else getVariables(pat) // no `_` + val ids = for ((named, _) <- vars) yield Ident(named.name) val caseDef = CaseDef(pat, EmptyTree, makeTuple(ids)) val matchExpr = - if (forallResults(rhs, isMatchingTuple)) rhs + if (tupleOptimizable) rhs else Match(rhsUnchecked, caseDef :: Nil) vars match { case Nil => @@ -938,7 +956,7 @@ object desugar { .withSpan(pat.span.union(rhs.span)).withMods(patMods) def selector(n: Int) = Select(Ident(tmpName), nme.selectorName(n)) val restDefs = - for (((named, tpt), n) <- vars.zipWithIndex) + for (((named, tpt), n) <- vars.zipWithIndex if named.name != nme.WILDCARD) yield if (mods is Lazy) derivedDefDef(original, named, tpt, selector(n), mods &~ Lazy) else derivedValDef(original, named, tpt, selector(n), mods) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8985088ff2fb..f988ab7b7cd1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2405,7 +2405,7 @@ object Parsers { } makeConstructor(Nil, vparamss, rhs).withMods(mods).setComment(in.getDocComment(start)) } else { - val (leadingParamss: List[List[ValDef]], flags: FlagSet) = + val (leadingParamss, flags) = if (in.token == LPAREN) (paramClause(prefix = true) :: Nil, Method | Extension) else diff --git a/tests/neg/i4935.scala b/tests/neg/i4935.scala new file mode 100644 index 000000000000..29ccd3cb8ec5 --- /dev/null +++ b/tests/neg/i4935.scala @@ -0,0 +1,3 @@ +object Foo { + val (A, B) = () // error // error +} diff --git a/tests/run/i4935.scala b/tests/run/i4935.scala new file mode 100644 index 000000000000..6b3b1292c2ec --- /dev/null +++ b/tests/run/i4935.scala @@ -0,0 +1,5 @@ +object Test { + val (Some(a), b) = (Some(3), 6) + + def main(args: Array[String]) = assert(a == 3) +} diff --git a/tests/run/i4935b.scala b/tests/run/i4935b.scala new file mode 100644 index 000000000000..b1260107292f --- /dev/null +++ b/tests/run/i4935b.scala @@ -0,0 +1,5 @@ +object Test { + val (a, _, b) = (Some(3), 6, Some(9)) + + def main(args: Array[String]) = assert(a == Some(3) && b == Some(9)) +}