Repository: astral-sh/ruff
File: crates/ruff_python_ast/src/helpers.rs (Rust)

Code before:
                    .iter()
                    .all(|item| matches!(item, DictItem { key: None, .. }))
                {
                    // {**foo} / {**foo, **bar}
                    Self::Unknown
                } else {
                    Self::Truthy
                }
            }
            Expr::Call(ast::ExprCall {
                func, arguments, ..
            }) => {
                if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
                    if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
                        if arguments.is_empty() {
                            // Ex) `list()`
                            Self::Falsey
                        } else if arguments.args.len() == 1 && arguments.keywords.is_empty() {
                            // Ex) `list([1, 2, 3])`
                            // For tuple(generator), tuple(list_comp), tuple(set_comp), we can't
                            // determine statically if the result will be empty or not, so return Unknown.
                            // The generator/comprehension itself is truthy, but tuple(empty_generator)
                            // is falsy.
                            if matches!(
                                &arguments.args[0],
                                Expr::Generator(_) | Expr::ListComp(_) | Expr::SetComp(_)
                            ) {
                                Self::Unknown
                            } else {
                                Self::from_expr(&arguments.args[0], is_builtin)
                            }
                        } else {
                            Self::Unknown
                        }
                    } else {
                        Self::Unknown
                    }
                } else {
                    Self::Unknown
                }
            }
            _ => Self::Unknown,
        }
    }

    pub fn into_bool(self) -> Option<bool> {
        match self {
            Self::True | Self::Truthy => Some(true),
            Self::False | Self::Falsey => Some(false),
            Self::None => Some(false),
            Self::Unknown => None,

Review comment (suggestion):
I think this only needs to include `Generator`, not the comprehension types. Recursing into the `Self::from_expr` arm below should already return `Self::Unknown` for other comprehensions. Generators are the only special case on 1223, if I'm following correctly.

The last two new tests already suppress the rule, for example: https://play.ruff.rs/a211c51a-b6f3-4dae-b259-431a75788464

Code after:
                    .iter()
                    .all(|item| matches!(item, DictItem { key: None, .. }))
                {
                    // {**foo} / {**foo, **bar}
                    Self::Unknown
                } else {
                    Self::Truthy
                }
            }
            Expr::Call(ast::ExprCall {
                func, arguments, ..
            }) => {
                if let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() {
                    if is_iterable_initializer(id.as_str(), |id| is_builtin(id)) {
                        if arguments.is_empty() {
                            // Ex) `list()`
                            Self::Falsey
                        } else if let [argument] = &*arguments.args
                            && arguments.keywords.is_empty()
                        {
                            // Ex) `list([1, 2, 3])`
                            // For tuple(generator), we can't determine statically if the result will
                            // be empty or not, so return Unknown. The generator itself is truthy, but
                            // tuple(empty_generator) is falsy. ListComp and SetComp are handled by
                            // recursing into Self::from_expr below, which returns Unknown for them.
                            if argument.is_generator_expr() {
                                Self::Unknown
                            } else {
                                Self::from_expr(argument, is_builtin)
                            }
                        } else {
                            Self::Unknown
                        }
                    } else {
                        Self::Unknown
                    }
                } else {
                    Self::Unknown
                }
            }
            _ => Self::Unknown,
        }
    }

    pub fn into_bool(self) -> Option<bool> {
        match self {
            Self::True | Self::Truthy => Some(true),
            Self::False | Self::Falsey => Some(false),
            Self::None => Some(false),
            Self::Unknown => None,
        }