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

Code before:
                        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 if is_definitely_not_iterable(argument) {
                                // For non-iterable arguments like numbers, booleans, None, etc.,
                                // we can't assume truthiness. For example, tuple(0) raises TypeError.
                                Self::Unknown
                            } else if matches!(argument, Expr::StringLiteral(_)) {
                                // For strings, tuple("") creates an empty tuple which is falsy,
                                // but tuple("a") creates a non-empty tuple which is truthy.
                                // However, we can't assume truthiness matches because:
                                // - tuple("") is falsy (empty tuple), but "" is also falsy
                                // - The issue is that we conflate truthiness with non-emptiness
                                // - For SIM222/SIM223, we should be conservative and return Unknown
                                //   to avoid false positives
                                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,
        }
    }

Review comment (suggestion):
I think we can omit this branch. `Self::from_expr` should already work correctly for string literals. The problem in the issue is for t-strings, among other types, which behave differently.

Removing this also fixes the pytest snapshot, which I think was a true positive.

Code after:
                                | Expr::BooleanLiteral(_)
                                | Expr::NoneLiteral(_)
                                | Expr::EllipsisLiteral(_)
                                | Expr::TString(_)
                                | Expr::Lambda(_)
                                | Expr::Generator(_) => Self::Unknown,
                                // Recurse for all other types - collections, comprehensions, variables, etc.
                                // StringLiteral, FString, and BytesLiteral recurse because Self::from_expr
                                // correctly handles their truthiness (checking if empty or not).
                                _ => 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,
        }
    }
}

/// Returns `true` if the expression definitely resolves to a non-empty string, when used as an
/// f-string expression, or `false` if the expression may resolve to an empty string.
fn is_non_empty_f_string(expr: &ast::ExprFString) -> bool {
    fn inner(expr: &Expr) -> bool {
        match expr {
            // When stringified, these expressions are always non-empty.
            Expr::Lambda(_) => true,
            Expr::Dict(_) => true,
            Expr::Set(_) => true,
            Expr::ListComp(_) => true,
            Expr::SetComp(_) => true,
            Expr::DictComp(_) => true,
            Expr::Compare(_) => true,
            Expr::NumberLiteral(_) => true,
            Expr::BooleanLiteral(_) => true,
            Expr::NoneLiteral(_) => true,