Skip to content

Commit 402be90

Browse files
authored
Fix inconsistent typeSize calculation for TupleN vs recursive pair encodings (#24743)
Currently, `typeSize` reports inconsistent values for standard tuple types (e.g., `(A, B)`) compared to their semantically equivalent recursive pair encodings (e.g., `A *: B *: EmptyTuple`). This discrepancy arises because `TupleN` is represented as a flat `AppliedType`, whereas the nested encoding forms a deeper tree structure. As `typeSize` is often used as a heuristic for complexity or optimization limits, this inconsistency can lead to divergent behavior in the compiler depending on how a tuple is represented syntactically. This PR modifies `TypeSizeAccumulator` to canonicalize `TupleN` types into their recursive `*:` representation before calculating their size. This ensures that the size metric is consistent regardless of whether the tuple is represented as a flat `AppliedType` or a nested structural type. I have added a new unit test in `TypesTest` that asserts `Tuple3[Int, Boolean, Double]` and `Int *: Boolean *: Double *: EmptyTuple` both yield identical `typeSize` equal to 3. Thanks to @mbovel for providing the unit test that effectively reproduces this issue and validates the fix. Fixes #24730
2 parents 837607b + b290509 commit 402be90

File tree

3 files changed

+22
-2
lines changed

3 files changed

+22
-2
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7125,6 +7125,8 @@ object Types extends TypeUtils {
71257125
var seen = util.HashSet[Type](initialCapacity = 8)
71267126
def apply(n: Int, tp: Type): Int =
71277127
tp match {
7128+
case tp: AppliedType if defn.isTupleNType(tp) =>
7129+
foldOver(n + 1, tp.toNestedPairs)
71287130
case tp: AppliedType =>
71297131
val tpNorm = tp.tryNormalize
71307132
if tpNorm.exists then apply(n, tpNorm)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package dotty.tools.dotc.core
2+
3+
import dotty.tools.DottyTest
4+
import dotty.tools.dotc.core.Symbols.defn
5+
import dotty.tools.dotc.core.TypeOps
6+
7+
import org.junit.Test
8+
import org.junit.Assert.assertEquals
9+
10+
class TypesTest extends DottyTest:
11+
12+
@Test def tuple3TypeSize =
13+
val tpe = defn.TupleType(3).nn.appliedTo(List(defn.IntType, defn.BooleanType, defn.DoubleType))
14+
assertEquals(3, tpe.typeSize)
15+
16+
@Test def tuple3ConsTypeSize =
17+
val tpe = TypeOps.nestedPairs(List(defn.IntType, defn.BooleanType, defn.DoubleType))
18+
assertEquals(3, tpe.typeSize)

compiler/test/dotty/tools/dotc/typer/DivergenceChecker.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ class DivergenceCheckerTests extends DottyTest {
5050
1,
5151
1,
5252
1,
53-
3,
54-
5
53+
4,
54+
6
5555
)
5656

5757
tpes.lazyZip(expectedSizes).lazyZip(expectedCoveringSets).foreach {

0 commit comments

Comments
 (0)