Skip to content

Conversation

@Lluc24
Copy link
Contributor

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

@Lluc24Lluc24 changed the title Fix inconsistent typeSize for TupleN vs nested pairsFix inconsistent typeSize calculation for TupleN vs recursive pair encodingsDec 13, 2025
Previously, `typeSize` reported different values for standard `TupleN` types (e.g., `(A, B)`) compared to their equivalent recursive pair encodings (e.g., `A *: B *: EmptyTuple`). This discrepancy occurred because `TupleN` is a flat `AppliedType`, while the nested encoding forms a deeper tree structure. This patch modifies `TypeSizeAccumulator` to canonicalize `TupleN` types into their recursive `*:` representation before calculating the size. This ensures that the size metric is consistent regardless of whether the tuple is represented syntactically or structurally. This change is verified by a new unit test in `TypesTest`, which confirms that both `Tuple3[Int, Boolean, Double]` and its recursive equivalent `Int *: Boolean *: Double *: EmptyTuple` now yield identical `typeSize` values. Fixesscala#24730
@Lluc24Lluc24force-pushed the i24730-TupleN-wrong-typeSize branch from cd3a120 to dca3ea1CompareDecember 13, 2025 14:01
@mbovel
Copy link
Member

We could maybe use normalizedTupleType here:

/** If this is a generic tuple type with arity <= MaxTupleArity, return the
* corresponding TupleN type, otherwise return this.
*/
defnormalizedTupleType(usingContext):Type=
if self.isGenericTuple then
self.tupleElementTypes match
caseSome(elems) if elems.size <=Definitions.MaxTupleArity=> defn.tupleType(elems)
case _ => self
else
self

Comment on lines 7137 to 7138
valtpNorm= tp.tryNormalize
if tpNorm.exists then apply(n, tpNorm)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
valtpNorm= tp.tryNormalize
if tpNorm.existsthen apply(n, tpNorm)
valtpNorm= tp.normalized.normalizedTupleType
if tpNorm ne tpthen apply(n, tpNorm)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Different type sizes for TupleN vs nested pairs encoding

2 participants

@Lluc24@mbovel