Skip to content

fix Preserve arity for tuple literals with * #2861#2888

Open
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2861
Open

fix Preserve arity for tuple literals with * #2861#2888
asukaminato0721 wants to merge 1 commit intofacebook:mainfrom
asukaminato0721:2861

Conversation

@asukaminato0721
Copy link
Contributor

Summary

Fixes #2861

special-casing tuple multiplication so known integer repeats preserve concrete tuple arity instead of falling through to the generic tuple[T, ...] stub.

respects the existing 256-element literal tuple cap by falling back once expansion would get too large.

Test Plan

add test

Copilot AI review requested due to automatic review settings March 24, 2026 10:19
@meta-cla meta-cla bot added the cla signed label Mar 24, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes type inference for tuple multiplication when the repeat count is a known integer literal, preserving concrete tuple arity (up to the existing 256-element expansion cap) instead of degrading to an unbounded tuple[T, ...].

Changes:

  • Add tuple-repeat inference for tuple * Literal[int] / Literal[int] * tuple, expanding concrete tuples when the resulting length stays within MAX_TUPLE_LENGTH.
  • Re-export the tuple literal expansion cap (MAX_TUPLE_LENGTH) for reuse in operator inference.
  • Add regression tests covering tuple repetition (including 0, negative, and overflow-to-fallback cases).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
pyrefly/lib/alt/operators.rs Adds try_tuple_repeat and wires it into * inference for tuples using literal repeat counts.
pyrefly/lib/alt/expr.rs Exposes MAX_TUPLE_LENGTH for cross-module use.
pyrefly/lib/test/tuple.rs Adds test coverage for tuple repetition type inference and the 256-element cap fallback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +300 to +302
Type::Literal(box Literal {
value: Lit::Int(n), ..
}) => n.as_i64(),
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

try_tuple_repeat only recognizes Literal[int] as the repeat count. In Python, bool is a subtype of int and tuple * True/False is valid; right now those cases will fall through to the generic __mul__ typing and won't preserve arity. Consider extracting the count via Literal.value.as_index_i64() (covers both Int and Bool) instead of matching only Lit::Int.

Suggested change
Type::Literal(box Literal {
value: Lit::Int(n), ..
}) => n.as_i64(),
Type::Literal(box Literal { value, .. }) => value.as_index_i64(),

Copilot uses AI. Check for mistakes.
Comment on lines 419 to +423
self.tuple_concat(l, r)
} else if x.op == Operator::Mult
&& let Some(result) = self.try_tuple_repeat(lhs, rhs)
{
result
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The tuple-repeat special case is implemented for normal binary * in binop_types, but *= goes through augassign_infer and currently has no analogous handling (unlike +=, which special-cases tuples). This can make x *= 2 produce a less precise type than x = x * 2 for tuples; consider adding a Operator::Mult branch in augassign_infer that reuses try_tuple_repeat.

Copilot uses AI. Check for mistakes.
}

static MAX_TUPLE_LENGTH: usize = 256;
pub(crate) static MAX_TUPLE_LENGTH: usize = 256;
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

MAX_TUPLE_LENGTH is a compile-time constant but is declared as a static and is now being re-exported for cross-module use. Elsewhere in the repo similar limits are typically const (e.g. pyrefly/lib/alt/answers_solver.rs:1979, pyrefly/lib/binding/scope.rs:519). Consider making this pub(crate) const MAX_TUPLE_LENGTH: usize = 256; to match that pattern and avoid introducing an addressable global unnecessarily.

Suggested change
pub(crate) static MAX_TUPLE_LENGTH: usize = 256;
pub(crate) const MAX_TUPLE_LENGTH: usize = 256;

Copilot uses AI. Check for mistakes.
@github-actions

This comment has been minimized.

@github-actions
Copy link

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Preserve arity for tuple literals with *

2 participants