Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions pyrefly/lib/alt/class/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,13 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
}
None
}

/// Check if a class that inherits from tuple defines its own `__getitem__`,
/// which should take priority over tuple's special subscript handling.
pub fn class_overrides_tuple_getitem(&self, cls: &ClassType) -> bool {
if cls.class_object().is_builtin("tuple") {
return false;
}
/// Check whether tuple indexing should use tuple's special subscript handling
/// rather than a user-defined `__getitem__` override.
pub fn tuple_uses_builtin_getitem(&self, cls: &ClassType) -> bool {
self.get_non_synthesized_class_member_and_defining_class(
cls.class_object(),
&dunder::GETITEM,
)
.is_some_and(|member| !member.defining_class.is_builtin("tuple"))
.is_none_or(|member| member.defining_class.is_builtin("tuple"))
}
}
2 changes: 1 addition & 1 deletion pyrefly/lib/alt/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2237,7 +2237,7 @@ impl<'a, Ans: LookupAnswer> AnswersSolver<'a, Ans> {
}
Type::ClassType(ref cls) | Type::SelfType(ref cls)
if let Some(tuple) = self.as_tuple(cls)
&& !self.class_overrides_tuple_getitem(cls) =>
&& self.tuple_uses_builtin_getitem(cls) =>
{
self.infer_tuple_subscript(
tuple,
Expand Down
9 changes: 7 additions & 2 deletions pyrefly/lib/solver/subset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1484,8 +1484,13 @@ impl<'a, Ans: LookupAnswer> Subset<'a, Ans> {
metadata: _,
}),
) => {
self.is_subset_params(&l.params, &u.params)?;
self.is_subset_eq(&l.ret, &u.ret)
// Check returns before parameters so quantified vars in the target callable
// pick up their covariant lower bounds before contravariant parameter checks.
// This keeps cases like `math.gcd <: Callable[[T, T], T]` precise: `int`
// from the return type should win over the looser `SupportsIndex` parameter
// bound.
self.is_subset_eq(&l.ret, &u.ret)?;
self.is_subset_params(&l.params, &u.params)
}
(Type::TypedDict(TypedDict::Anonymous(got)), Type::TypedDict(want)) => {
self.is_subset_anonymous_typed_dict(got, want)
Expand Down
15 changes: 15 additions & 0 deletions pyrefly/lib/test/calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,21 @@ reduce(max, [1,2])
"#,
);

testcase!(
test_reduce_gcd_returns_int,
r#"
from functools import reduce
from math import gcd

def detect_indentation(values: list[int]) -> int:
try:
indentation = reduce(gcd, [v for v in values if not v % 2]) or 1
except TypeError:
indentation = 1
return indentation
"#,
);

testcase!(
test_union_with_type,
r#"
Expand Down
2 changes: 1 addition & 1 deletion pyrefly/lib/test/lsp/lsp_interaction/pytorch_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn test_pytorch_error_propagation_latency() {
};
// Use all available cores for realistic benchmarking
let mut interaction =
LspInteraction::new_with_args(args, NoTelemetry, Some(ThreadCount::AllThreads));
LspInteraction::new_with_args(args, NoTelemetry, Some(ThreadCount::AllThreads), None);
interaction.set_root(pytorch_root.clone());

interaction
Expand Down
4 changes: 2 additions & 2 deletions pyrefly/lib/test/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ testcase!(
from typing import assert_type

class Foo(tuple[int, ...]):
def __getitem__(self, name: str) -> int: # E: `Foo.__getitem__` has type
def __getitem__(self, name: str) -> int: # pyrefly: ignore [bad-override]
...

def test(foo: Foo) -> None:
Expand All @@ -575,7 +575,7 @@ testcase!(
from typing import assert_type

class Parent(tuple[int, ...]):
def __getitem__(self, name: str) -> int: # E: `Parent.__getitem__` has type
def __getitem__(self, name: str) -> int: # pyrefly: ignore [bad-override]
...

class Child(Parent):
Expand Down
Loading