Skip to content

Optimise simple tuple extraction #23224

@noti0na1

Description

@noti0na1
Member

Compiler version

3.7.2-RC1-bin-20250520-baac46c-NIGHTLY-git-baac46c

Minimized example

class Test:
  def f1: (Int, Int) = (1, 2)

  def test1 =
    val (a, b) = f1
    a + b

Output

After typer: scala compile --server=false -S 3.nightly -Xprint:typer tuples.scala

package <empty> {
  class Test() extends Object() {
    def f1: Tuple2[Int, Int] = Tuple2.apply[Int, Int](1, 2)
    def test1: Int =
      {
        val $1$: (Int, Int) =
          this.f1:(Int, Int) @unchecked match 
            {
              case Tuple2.unapply[Int, Int](a @ _, b @ _) =>
                Tuple2.apply[Int, Int](a, b)
            }
        val a: Int = $1$._1
        val b: Int = $1$._2
        a + b
      }
  }
}

After genBCode: scala compile --server=false -S 3.nightly -Xprint:genBCode tuples.scala

package <empty> {
  @SourceFile("tuples.scala") class Test extends Object {
    def <init>(): Unit =
      {
        super()
        ()
      }
    def f1(): Tuple2 = new Tuple2$mcII$sp(1, 2)
    def test1(): Int =
      {
        val $1$: Tuple2 =
          matchResult1[Tuple2]: 
            {
              case val x1: Tuple2 = this.f1():Tuple2
              if x1 ne null then
                {
                  case val a: Int = x1._1$mcI$sp()
                  case val b: Int = x1._2$mcI$sp()
                  return[matchResult1] new Tuple2$mcII$sp(a, b)
                }
               else ()
              throw new MatchError(x1)
            }
        val a: Int = $1$._1$mcI$sp()
        val b: Int = $1$._2$mcI$sp()
        a + b
      }
  }
}

Expectation

Calling _i on the tuple directly:

val $1$: (Int, Int) = this.f1:(Int, Int)
val a: Int = $1$._1
val b: Int = $1$._2
a + b

Activity

added
stat:needs triageEvery issue needs to have an "area" and "itype" label
area:desugarDesugaring happens after parsing but before typing, see desugar.scala
and removed
stat:needs triageEvery issue needs to have an "area" and "itype" label
on May 21, 2025
noti0na1

noti0na1 commented on May 21, 2025

@noti0na1
MemberAuthor

When typing a PatDef(mods, pats, tpt, rhs), instead of passing to desuger directly, we type check rhs first.

In makePatDef, we update tupleOptimizable, and we will apply optimisation if:

  • all branches are both tuples of arity N (tuple literals or tuple types)
  • pat is a tuple of N variables or wildcard patterns like (x1, x2, ..., xN)
self-assigned this
on Jun 13, 2025
added a commit that references this issue on Jul 11, 2025
6f35f4a
added this to the 3.7.3 milestone on Jul 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:desugarDesugaring happens after parsing but before typing, see desugar.scalaitype:performance

Type

No type

Projects

No projects

Relationships

None yet

    Development

    Participants

    @noti0na1@WojciechMazur

    Issue actions

      Optimise simple tuple extraction · Issue #23224 · scala/scala3