From 130d4e113559a97e5c2dae4f80bd6a9429cef68b Mon Sep 17 00:00:00 2001 From: Douglas Creager Date: Mon, 28 Jul 2025 12:09:54 -0400 Subject: [PATCH] [ty] Don't panic with argument that doesn't actually implement Iterable (#19602) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This eliminates the panic reported in https://github.com/astral-sh/ty/issues/909, though it doesn't address the underlying cause, which is that we aren't yet checking the types of the fields of a protocol when checking whether a class implements the protocol. And in particular, if a class explictly opts out of iteration via ```py class NotIterable: __iter__ = None ``` we currently treat that as "having an `__iter__`" member, and therefore implementing `Iterable`. Note that the assumption that was in the comment before is still correct: call binding will have already checked that the argument satisfies `Iterable`, and so it shouldn't be an error to iterate over said argument. But arguably, the new logic in this PR is a better way to discharge that assumption — instead of panicking if we happen to be wrong, fall back on an unknown iteration result. --- crates/ty_python_semantic/src/types/call/bind.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/ty_python_semantic/src/types/call/bind.rs b/crates/ty_python_semantic/src/types/call/bind.rs index f9d770c845..32dc8ad258 100644 --- a/crates/ty_python_semantic/src/types/call/bind.rs +++ b/crates/ty_python_semantic/src/types/call/bind.rs @@ -1026,10 +1026,14 @@ impl<'db> Bindings<'db> { // `tuple(range(42))` => `tuple[int, ...]` // BUT `tuple((1, 2))` => `tuple[Literal[1], Literal[2]]` rather than `tuple[Literal[1, 2], ...]` if let [Some(argument)] = overload.parameter_types() { - let tuple_spec = argument.try_iterate(db).expect( - "try_iterate() should not fail on a type \ - assignable to `Iterable`", - ); + let Ok(tuple_spec) = argument.try_iterate(db) else { + tracing::debug!( + "type" = %argument.display(db), + "try_iterate() should not fail on a type \ + assignable to `Iterable`", + ); + continue; + }; overload.set_return_type(Type::tuple(TupleType::new( db, tuple_spec.as_ref(),