//!
//! Take an AST and transform it into bytecode
//!
//! Inspirational code:
//!   <https://github.com/python/cpython/blob/main/Python/compile.c>
//!   <https://github.com/micropython/micropython/blob/master/py/compile.c>

// spell-checker:ignore starunpack subscripter

#![deny(clippy::cast_possible_truncation)]

use crate::{
    IndexMap, IndexSet, ToPythonName, ast_constant_value_to_constant_data,
    error::{CodegenError, CodegenErrorType, InternalError},
    ir::{self, Block, BlockIdx, Blocks},
    preprocess,
    symboltable::{self, CompilerScope, Symbol, SymbolFlags, SymbolScope, SymbolTable},
    unparse::UnparseExpr,
};
use alloc::borrow::Cow;
use core::{mem, slice};
use malachite_bigint::BigInt;
use num_complex::Complex;
use num_traits::{Num, ToPrimitive, Zero};
use ruff_python_ast as ast;
use ruff_text_size::{Ranged, TextRange, TextSize};
use rustpython_compiler_core::{
    Mode, OneIndexed, PositionEncoding, SourceFile, SourceLocation,
    bytecode::{
        self, AnyInstruction, AnyOpcode, Arg as OpArgMarker, BinaryOperator, BuildSliceArgCount,
        CodeObject, ComparisonOperator, ConstantData, ConvertValueOparg, Instruction,
        IntrinsicFunction1, Invert, LoadAttr, LoadSuperAttr, OpArg, OpArgType, PseudoInstruction,
        SpecialMethod, UnpackExArgs, oparg,
    },
};
use rustpython_literal::{
    complex as literal_complex,
    escape::{AsciiEscape, UnicodeEscape},
    float as literal_float,
};
use rustpython_wtf8::Wtf8Buf;

/// Extension trait for `ast::Expr` to add constant checking methods
trait ExprExt {
    /// Returns true if the expression is a constant literal with no side effects.
    fn is_constant(&self) -> bool;
}

impl ExprExt for ast::Expr {
    fn is_constant(&self) -> bool {
        matches!(
            self,
            Self::NumberLiteral(_)
                | Self::StringLiteral(_)
                | Self::BytesLiteral(_)
                | Self::Constant(_)
                | Self::NoneLiteral(_)
                | Self::BooleanLiteral(_)
                | Self::EllipsisLiteral(_)
        )
    }
}

const CO_MAXBLOCKS: usize = 21;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FBlockType {
    WhileLoop,
    ForLoop,
    TryExcept,
    FinallyTry,
    FinallyEnd,
    With,
    AsyncWith,
    HandlerCleanup,
    PopValue,
    ExceptionHandler,
    ExceptionGroupHandler,
    AsyncComprehensionGenerator,
    StopIteration,
}

/// Stores additional data for fblock unwinding
// fb_datum
#[derive(Debug, Clone)]
pub enum FBlockDatum {
    None,
    /// For FinallyTry: stores the finally body statements to compile during unwind
    FinallyBody(Vec<ast::Stmt>),
    /// For HandlerCleanup: stores the exception variable name (e.g., "e" in "except X as e")
    ExceptionName(String),
}

/// Type of super() call optimization detected by can_optimize_super_call()
#[derive(Debug, Clone)]
enum SuperCallType<'a> {
    /// super(class, self) - explicit 2-argument form
    TwoArg {
        class_arg: &'a ast::Expr,
        self_arg: &'a ast::Expr,
    },
    /// super() - implicit 0-argument form (uses __class__ cell)
    ZeroArg,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum BuiltinGeneratorCallKind {
    Tuple,
    All,
    Any,
}

#[derive(Debug, Clone)]
pub struct FBlockInfo {
    pub fb_type: FBlockType,
    // CPython _PyCompile_FBlockInfo stores jump_target_label values here.
    pub(crate) fb_block: ir::InstructionSequenceLabel,
    // CPython's optional type-specific exit or cleanup jump_target_label.
    pub(crate) fb_exit: ir::InstructionSequenceLabel,
    pub fb_range: TextRange,
    // additional data for fblock unwinding
    pub fb_datum: FBlockDatum,
}

pub(crate) type InternalResult<T> = Result<T, InternalError>;
type CompileResult<T> = Result<T, CodegenError>;
pub type SyntaxWarningHandler<'a> =
    dyn FnMut(SourceLocation, String) -> Result<(), CodegenError> + 'a;

fn warn_ast_preprocess_syntax(
    source_file: &SourceFile,
    handler: &mut SyntaxWarningHandler<'_>,
    range: TextRange,
    message: String,
) -> CompileResult<()> {
    let location = source_file
        .to_source_code()
        .source_location(range.start(), PositionEncoding::Utf8);
    handler(location, message)
}

fn checked_future_features(
    ast: &ruff_python_ast::Mod,
    source_file: &SourceFile,
) -> CompileResult<bytecode::CodeFlags> {
    preprocess::checked_future_features(ast).map_err(|err| {
        let location = source_file
            .to_source_code()
            .source_location(err.range.start(), PositionEncoding::Utf8);
        let error = match err.kind {
            preprocess::FutureFeatureErrorKind::InvalidFeature(feature) => {
                CodegenErrorType::InvalidFutureFeature(feature)
            }
            preprocess::FutureFeatureErrorKind::InvalidBraces => {
                CodegenErrorType::InvalidFutureBraces
            }
        };
        CodegenError {
            location: Some(location),
            error,
            source_path: source_file.name().to_owned(),
        }
    })
}

#[derive(PartialEq, Eq, Clone, Copy)]
enum NameUsage {
    Load,
    Store,
    Delete,
}
/// Main structure holding the state of compilation.
struct Compiler<'a> {
    code_stack: Vec<ir::CodeInfo>,
    symbol_table_stack: Vec<SymbolTable>,
    source_file: SourceFile,
    // current_source_location: SourceLocation,
    current_source_range: TextRange,
    done_with_future_stmts: DoneWithFuture,
    future_features: bytecode::CodeFlags,
    future_annotations: bool,
    ctx: CompileContext,
    opts: CompileOpts,
    in_annotation: bool,
    /// True when compiling in "single" (interactive) mode.
    /// Expression statements at module scope emit CALL_INTRINSIC_1(Print).
    interactive: bool,
    /// Counter for dead-code elimination during constant folding.
    /// When > 0, the compiler walks AST (consuming sub_tables) but emits no bytecode.
    /// Mirrors CPython's `c_do_not_emit_bytecode`.
    do_not_emit_bytecode: u32,
    /// Mirrors `c_disable_warning` while compiling FINALLY_END copies.
    disable_warning: u32,
    syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
}

#[derive(Clone, Copy)]
enum DoneWithFuture {
    No,
    DoneWithDoc,
    Yes,
}

/// A Python `__future__` feature flag imported via `from __future__ import <feature>`.
///
/// # See Also
///
/// - [Python documentation on `__future__`](https://docs.python.org/3.14/library/__future__.html)
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FutureFeature {
    /// ```py
    /// from __future__ import absolute_import
    /// ```
    AbsoluteImport,

    /// ```py
    /// from __future__ import annotations
    /// ```
    Annotations,

    /// ```py
    /// from __future__ import barry_as_FLUFL
    /// ```
    BarryAsFLUFL,

    /// ```py
    /// from __future__ import braces
    /// ```
    Braces,

    /// ```py
    /// from __future__ import division
    /// ```
    Division,

    /// ```py
    /// from __future__ import generator_stop
    /// ```
    GeneratorStop,

    /// ```py
    /// from __future__ import generators
    /// ```
    Generators,

    /// ```py
    /// from __future__ import nested_scopes
    /// ```
    NestedScopes,

    /// ```py
    /// from __future__ import print_function
    /// ```
    PrintFunction,

    /// ```py
    /// from __future__ import unicode_literals
    /// ```
    UnicodeLiterals,

    /// ```py
    /// from __future__ import with_statement
    /// ```
    WithStatement,
}

impl TryFrom<&str> for FutureFeature {
    type Error = String;

    fn try_from(name: &str) -> Result<Self, Self::Error> {
        Ok(match name {
            "absolute_import" => Self::AbsoluteImport,
            "annotations" => Self::Annotations,
            "barry_as_FLUFL" => Self::BarryAsFLUFL,
            "braces" => Self::Braces,
            "division" => Self::Division,
            "generator_stop" => Self::GeneratorStop,
            "generators" => Self::Generators,
            "nested_scopes" => Self::NestedScopes,
            "print_function" => Self::PrintFunction,
            "unicode_literals" => Self::UnicodeLiterals,
            "with_statement" => Self::WithStatement,
            _ => return Err(name.into()),
        })
    }
}

#[derive(Clone, Copy)]
enum ComprehensionSymbolSource {
    Child,
    Inlined,
}

#[derive(Clone, Copy)]
struct SymbolTableCursors {
    sub_table: usize,
    hidden_annotation_block: usize,
    inlined_comprehension_block: usize,
}

#[derive(Clone, Debug)]
pub struct CompileOpts {
    /// How optimized the bytecode output should be; any optimize > 0 does
    /// not emit assert statements
    pub optimize: u8,
    /// Include column info in bytecode (-X no_debug_ranges disables)
    pub debug_ranges: bool,
    /// Maximum decimal integer literal digits, matching sys.int_info/default.
    pub int_max_str_digits: usize,
    /// Allow module-level await/async-for/async-with, matching PyCF_ALLOW_TOP_LEVEL_AWAIT.
    pub allow_top_level_await: bool,
    /// Future compiler flags passed explicitly to compile(), matching cf_flags merge.
    pub future_features: bytecode::CodeFlags,
    /// Keep single-input blocks incomplete until a terminating newline is seen.
    pub dont_imply_dedent: bool,
    /// Recursion limit used by compiler tree walks, matching Py_EnterRecursiveCall.
    pub recursion_limit: usize,
}

impl Default for CompileOpts {
    fn default() -> Self {
        Self {
            optimize: 0,
            debug_ranges: true,
            int_max_str_digits: 4300,
            allow_top_level_await: false,
            future_features: bytecode::CodeFlags::empty(),
            dont_imply_dedent: false,
            recursion_limit: 1000,
        }
    }
}

#[derive(Debug, Clone, Copy)]
struct CompileContext {
    in_class: bool,
    func: FunctionContext,
    /// True if we're anywhere inside an async function (even inside nested comprehensions)
    in_async_scope: bool,
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum FunctionContext {
    NoFunction,
    Function,
    AsyncFunction,
}

impl CompileContext {
    fn in_func(self) -> bool {
        self.func != FunctionContext::NoFunction
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum ComprehensionType {
    Generator,
    List,
    Set,
    Dict,
}

#[derive(Debug, Clone, Copy)]
enum ComprehensionLoopControl {
    Iteration {
        loop_block: BlockIdx,
        if_cleanup_block: BlockIdx,
        after_block: BlockIdx,
        backedge_range: TextRange,
        is_async: bool,
        end_async_for_target: BlockIdx,
    },
    IfCleanupOnly {
        if_cleanup_block: BlockIdx,
    },
}

fn validate_duplicate_params(params: &ast::Parameters) -> Result<(), CodegenErrorType> {
    let mut seen_params = IndexSet::default();
    for param in params {
        let param_name = param.name().as_str();
        if !seen_params.insert(param_name) {
            return Err(CodegenErrorType::SyntaxError(format!(
                r#"Duplicate parameter "{param_name}""#
            )));
        }
    }

    Ok(())
}

/// Compile an Mod produced from ruff parser
pub fn compile_top(
    ast: ruff_python_ast::Mod,
    source_file: SourceFile,
    mode: Mode,
    opts: CompileOpts,
) -> CompileResult<CodeObject> {
    compile_top_with_syntax_warning_handler(ast, source_file, mode, opts, None)
}

pub fn compile_top_with_syntax_warning_handler<'a>(
    mut ast: ruff_python_ast::Mod,
    source_file: SourceFile,
    mode: Mode,
    mut opts: CompileOpts,
    mut syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
) -> CompileResult<CodeObject> {
    opts.future_features |= checked_future_features(&ast, &source_file)?;
    let future_annotations = opts
        .future_features
        .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
    if let Some(handler) = syntax_warning_handler.as_deref_mut() {
        preprocess::warn_control_flow_in_finally(&ast, |range, message| {
            warn_ast_preprocess_syntax(&source_file, handler, range, message)
        })?;
    }
    if matches!(mode, Mode::Single)
        && let ruff_python_ast::Mod::Module(module) = &mut ast
    {
        preprocess::preprocess_statements(
            &mut module.body,
            opts.optimize,
            future_annotations,
            false,
        );
    } else {
        preprocess::preprocess_mod(&mut ast, opts.optimize, future_annotations, false);
    }
    match ast {
        ruff_python_ast::Mod::Module(module) => match mode {
            Mode::Exec | Mode::Eval => compile_program_with_syntax_warning_handler(
                &module,
                source_file,
                opts,
                syntax_warning_handler,
            ),
            Mode::Single => compile_program_single_with_syntax_warning_handler(
                &module,
                source_file,
                opts,
                syntax_warning_handler,
            ),
            Mode::BlockExpr => compile_block_expression_with_syntax_warning_handler(
                &module,
                source_file,
                opts,
                syntax_warning_handler,
            ),
        },
        ruff_python_ast::Mod::Expression(expr) => compile_expression_with_syntax_warning_handler(
            &expr,
            source_file,
            opts,
            syntax_warning_handler,
        ),
    }
}

/// Compile a standard Python program to bytecode
pub fn compile_program(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
) -> CompileResult<CodeObject> {
    compile_program_with_syntax_warning_handler(ast, source_file, opts, None)
}

fn scan_module_symbols(
    ast: &ast::ModModule,
    source_file: &SourceFile,
    opts: &CompileOpts,
) -> CompileResult<SymbolTable> {
    SymbolTable::scan_program_with_options(
        ast,
        source_file.clone(),
        opts.allow_top_level_await,
        opts.future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS),
        opts.recursion_limit,
    )
    .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
}

fn scan_expr_symbols(
    ast: &ast::ModExpression,
    source_file: &SourceFile,
    opts: &CompileOpts,
) -> CompileResult<SymbolTable> {
    SymbolTable::scan_expr_with_options(
        ast,
        source_file.clone(),
        opts.allow_top_level_await,
        opts.future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS),
        opts.recursion_limit,
    )
    .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
}

fn compile_program_with_syntax_warning_handler<'a>(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
    syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
) -> CompileResult<CodeObject> {
    let symbol_table = scan_module_symbols(ast, &source_file, &opts)?;
    let mut compiler = Compiler::new_with_syntax_warning_handler(
        opts,
        source_file,
        "<module>",
        syntax_warning_handler,
    );
    compiler.compile_program(ast, symbol_table)?;
    let code = compiler.exit_scope();
    trace!("Compilation completed: {code:?}");
    Ok(code)
}

/// Compile a Python program to bytecode for the context of a REPL
pub fn compile_program_single(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
) -> CompileResult<CodeObject> {
    compile_program_single_with_syntax_warning_handler(ast, source_file, opts, None)
}

fn compile_program_single_with_syntax_warning_handler<'a>(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
    syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
) -> CompileResult<CodeObject> {
    let symbol_table = scan_module_symbols(ast, &source_file, &opts)?;
    let mut compiler = Compiler::new_with_syntax_warning_handler(
        opts,
        source_file,
        "<module>",
        syntax_warning_handler,
    );
    compiler.compile_program_single(&ast.body, symbol_table)?;
    let code = compiler.exit_scope();
    trace!("Compilation completed: {code:?}");
    Ok(code)
}

pub fn compile_block_expression(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
) -> CompileResult<CodeObject> {
    compile_block_expression_with_syntax_warning_handler(ast, source_file, opts, None)
}

fn compile_block_expression_with_syntax_warning_handler<'a>(
    ast: &ast::ModModule,
    source_file: SourceFile,
    opts: CompileOpts,
    syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
) -> CompileResult<CodeObject> {
    let symbol_table = scan_module_symbols(ast, &source_file, &opts)?;
    let mut compiler = Compiler::new_with_syntax_warning_handler(
        opts,
        source_file,
        "<module>",
        syntax_warning_handler,
    );
    compiler.compile_block_expr(&ast.body, symbol_table)?;
    let code = compiler.exit_scope();
    trace!("Compilation completed: {code:?}");
    Ok(code)
}

pub fn compile_expression(
    ast: &ast::ModExpression,
    source_file: SourceFile,
    opts: CompileOpts,
) -> CompileResult<CodeObject> {
    compile_expression_with_syntax_warning_handler(ast, source_file, opts, None)
}

fn compile_expression_with_syntax_warning_handler<'a>(
    ast: &ast::ModExpression,
    source_file: SourceFile,
    opts: CompileOpts,
    syntax_warning_handler: Option<&'a mut SyntaxWarningHandler<'a>>,
) -> CompileResult<CodeObject> {
    let symbol_table = scan_expr_symbols(ast, &source_file, &opts)?;
    let mut compiler = Compiler::new_with_syntax_warning_handler(
        opts,
        source_file,
        "<module>",
        syntax_warning_handler,
    );
    compiler.compile_eval(ast, symbol_table)?;
    let code = compiler.exit_scope();
    Ok(code)
}

macro_rules! emit {
    // Struct variant with single identifier (e.g., Foo::A { arg })
    ($c:expr, $enum:ident :: $op:ident { $arg:ident $(,)? } $(,)?) => {
        $c.emit_arg($arg, |x| $enum::$op { $arg: x })
    };

    // Struct variant with explicit value (e.g., Foo::A { arg: 42 })
    ($c:expr, $enum:ident :: $op:ident { $arg:ident : $arg_val:expr $(,)? } $(,)?) => {
        $c.emit_arg($arg_val, |x| $enum::$op { $arg: x })
    };

    // Tuple variant (e.g., Foo::B(42)). Should never be reached, here for validation.
    ($c:expr, $enum:ident :: $op:ident($arg_val:expr $(,)? ) $(,)?) => {
        panic!("No instruction should be defined as `Instruction::Foo(value)` use `Instruction::Foo { x: value }` instead")
    };

    // No-arg variant (e.g., Foo::C)
    ($c:expr, $enum:ident :: $op:ident $(,)?) => {
        $c.emit_no_arg($enum::$op)
    };
}

fn eprint_location(zelf: &Compiler<'_>) {
    let start = zelf
        .source_file
        .to_source_code()
        .source_location(zelf.current_source_range.start(), PositionEncoding::Utf8);
    let end = zelf
        .source_file
        .to_source_code()
        .source_location(zelf.current_source_range.end(), PositionEncoding::Utf8);
    eprintln!(
        "LOCATION: {} from {}:{} to {}:{}",
        zelf.source_file.name(),
        start.line,
        start.character_offset,
        end.line,
        end.character_offset
    );
}

/// Better traceback for internal error
#[track_caller]
fn unwrap_internal<T>(zelf: &Compiler<'_>, r: InternalResult<T>) -> T {
    if let Err(ref r_err) = r {
        eprintln!("=== CODEGEN PANIC INFO ===");
        eprintln!("This IS an internal error: {r_err}");
        eprint_location(zelf);
        eprintln!("=== END PANIC INFO ===");
    }
    r.unwrap()
}

fn compiler_unwrap_option<T>(zelf: &Compiler<'_>, o: Option<T>) -> T {
    if o.is_none() {
        eprintln!("=== CODEGEN PANIC INFO ===");
        eprintln!("This IS an internal error, an option was unwrapped during codegen");
        eprint_location(zelf);
        eprintln!("=== END PANIC INFO ===");
    }
    o.unwrap()
}

// fn compiler_result_unwrap<T, E: core::fmt::Debug>(zelf: &Compiler, result: Result<T, E>) -> T {
//     if result.is_err() {
//         eprintln!("=== CODEGEN PANIC INFO ===");
//         eprintln!("This IS an internal error, an result was unwrapped during codegen");
//         eprint_location(zelf);
//         eprintln!("=== END PANIC INFO ===");
//     }
//     result.unwrap()
// }

/// The pattern context holds information about captured names and jump targets.
#[derive(Clone)]
pub struct PatternContext {
    /// A list of names captured by the pattern.
    pub stores: Vec<String>,
    /// If false, then any name captures against our subject will raise.
    pub allow_irrefutable: bool,
    /// A list of jump target labels used on pattern failure.
    pub fail_pop: Vec<BlockIdx>,
    /// The number of items on top of the stack that should remain.
    pub on_top: usize,
}

impl Default for PatternContext {
    fn default() -> Self {
        Self::new()
    }
}

impl PatternContext {
    #[must_use]
    pub const fn new() -> Self {
        Self {
            stores: Vec::new(),
            allow_irrefutable: false,
            fail_pop: Vec::new(),
            on_top: 0,
        }
    }

    #[must_use]
    pub fn fail_pop_size(&self) -> usize {
        self.fail_pop.len()
    }
}

#[derive(Clone, Copy, Eq, PartialEq)]
enum JumpOp {
    Jump,
    PopJumpIfFalse,
}

/// Type of collection to build in starunpack_helper
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum CollectionType {
    Tuple,
    List,
    Set,
}

#[derive(Clone, Copy, Eq, PartialEq)]
enum InferredType {
    Tuple,
    List,
    Dict,
    Set,
    FrozenSet,
    Generator,
    Function,
    Template,
    Str,
    Bytes,
    Int,
    Float,
    Complex,
    Bool,
    NoneType,
    Ellipsis,
    Slice,
}

impl InferredType {
    const fn name(self) -> &'static str {
        match self {
            Self::Tuple => "tuple",
            Self::List => "list",
            Self::Dict => "dict",
            Self::Set => "set",
            Self::FrozenSet => "frozenset",
            Self::Generator => "generator",
            Self::Function => "function",
            Self::Template => "string.templatelib.Template",
            Self::Str => "str",
            Self::Bytes => "bytes",
            Self::Int => "int",
            Self::Float => "float",
            Self::Complex => "complex",
            Self::Bool => "bool",
            Self::NoneType => "NoneType",
            Self::Ellipsis => "ellipsis",
            Self::Slice => "slice",
        }
    }

    const fn is_long_subclass(self) -> bool {
        matches!(self, Self::Int | Self::Bool)
    }
}

const STACK_USE_GUIDELINE: u32 = 30;

impl<'warnings> Compiler<'warnings> {
    fn constant_truthiness(constant: &ConstantData) -> bool {
        match constant {
            ConstantData::Tuple { elements } | ConstantData::Frozenset { elements } => {
                !elements.is_empty()
            }
            ConstantData::Integer { value } => !value.is_zero(),
            ConstantData::Float { value } => *value != 0.0,
            ConstantData::Complex { value } => value.re != 0.0 || value.im != 0.0,
            ConstantData::Boolean { value } => *value,
            ConstantData::Str { value } => !value.is_empty(),
            ConstantData::Bytes { value } => !value.is_empty(),
            ConstantData::Code { .. } | ConstantData::Slice { .. } | ConstantData::Ellipsis => true,
            ConstantData::None => false,
        }
    }

    fn infer_type_constant(constant: &ConstantData) -> Option<InferredType> {
        match constant {
            ConstantData::Tuple { .. } => Some(InferredType::Tuple),
            ConstantData::Frozenset { .. } => Some(InferredType::FrozenSet),
            ConstantData::Integer { .. } => Some(InferredType::Int),
            ConstantData::Float { .. } => Some(InferredType::Float),
            ConstantData::Complex { .. } => Some(InferredType::Complex),
            ConstantData::Boolean { .. } => Some(InferredType::Bool),
            ConstantData::Str { .. } => Some(InferredType::Str),
            ConstantData::Bytes { .. } => Some(InferredType::Bytes),
            ConstantData::None => Some(InferredType::NoneType),
            ConstantData::Ellipsis => Some(InferredType::Ellipsis),
            ConstantData::Slice { .. } => Some(InferredType::Slice),
            ConstantData::Code { .. } => None,
        }
    }

    fn infer_type(&self, expr: &ast::Expr) -> Option<InferredType> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Self::infer_type_constant(&constant);
        }
        match expr {
            ast::Expr::Tuple(_) => Some(InferredType::Tuple),
            ast::Expr::List(_) | ast::Expr::ListComp(_) => Some(InferredType::List),
            ast::Expr::Dict(_) | ast::Expr::DictComp(_) => Some(InferredType::Dict),
            ast::Expr::Set(_) | ast::Expr::SetComp(_) => Some(InferredType::Set),
            ast::Expr::Generator(_) => Some(InferredType::Generator),
            ast::Expr::Lambda(_) => Some(InferredType::Function),
            ast::Expr::TString(_) => Some(InferredType::Template),
            ast::Expr::FString(_) | ast::Expr::StringLiteral(_) => Some(InferredType::Str),
            ast::Expr::BytesLiteral(_) => Some(InferredType::Bytes),
            ast::Expr::NumberLiteral(number) => match number.value {
                ast::Number::Int(_) => Some(InferredType::Int),
                ast::Number::Float(_) => Some(InferredType::Float),
                ast::Number::Complex { .. } => Some(InferredType::Complex),
            },
            ast::Expr::BooleanLiteral(_) => Some(InferredType::Bool),
            ast::Expr::NoneLiteral(_) => Some(InferredType::NoneType),
            ast::Expr::EllipsisLiteral(_) => Some(InferredType::Ellipsis),
            ast::Expr::Slice(_) => Some(InferredType::Slice),
            _ => None,
        }
    }

    fn is_constant_expr(&self, expr: &ast::Expr) -> bool {
        if self.ast_constant_value(expr).is_some() {
            return true;
        }
        matches!(
            expr,
            ast::Expr::StringLiteral(_)
                | ast::Expr::BytesLiteral(_)
                | ast::Expr::NumberLiteral(_)
                | ast::Expr::BooleanLiteral(_)
                | ast::Expr::NoneLiteral(_)
                | ast::Expr::EllipsisLiteral(_)
        )
    }

    fn is_constant_slice(&self, slice: &ast::Expr) -> bool {
        match slice {
            ast::Expr::Slice(s) => {
                let lower_const = s.lower.is_none()
                    || s.lower.as_deref().is_some_and(|e| self.is_constant_expr(e));
                let upper_const = s.upper.is_none()
                    || s.upper.as_deref().is_some_and(|e| self.is_constant_expr(e));
                let step_const =
                    s.step.is_none() || s.step.as_deref().is_some_and(|e| self.is_constant_expr(e));
                lower_const && upper_const && step_const
            }
            _ => false,
        }
    }

    fn should_apply_two_element_slice_optimization(&self, slice: &ast::Expr) -> bool {
        !self.is_constant_slice(slice) && matches!(slice, ast::Expr::Slice(s) if s.step.is_none())
    }

    fn check_is_arg(&self, expr: &ast::Expr) -> bool {
        if let Some(constant) = self.ast_constant_value(expr) {
            return matches!(
                constant,
                ConstantData::None | ConstantData::Boolean { .. } | ConstantData::Ellipsis
            );
        }
        if let ast::Expr::Tuple(tuple) = expr {
            return !tuple.elts.iter().all(|expr| self.is_constant_expr(expr));
        }
        if !self.is_constant_expr(expr) {
            return true;
        }
        matches!(
            expr,
            ast::Expr::NoneLiteral(_)
                | ast::Expr::BooleanLiteral(_)
                | ast::Expr::EllipsisLiteral(_)
        )
    }

    fn warn_syntax(&mut self, range: TextRange, message: String) -> CompileResult<()> {
        if self.disable_warning > 0 {
            return Ok(());
        }
        let Some(handler) = self.syntax_warning_handler.as_deref_mut() else {
            return Ok(());
        };
        let location = self
            .source_file
            .to_source_code()
            .source_location(range.start(), PositionEncoding::Utf8);
        handler(location, message)
    }

    fn check_caller(&mut self, func: &ast::Expr) -> CompileResult<()> {
        let warns = self.ast_constant_value(func).is_some()
            || matches!(
                func,
                ast::Expr::StringLiteral(_)
                    | ast::Expr::BytesLiteral(_)
                    | ast::Expr::NumberLiteral(_)
                    | ast::Expr::BooleanLiteral(_)
                    | ast::Expr::NoneLiteral(_)
                    | ast::Expr::EllipsisLiteral(_)
                    | ast::Expr::Tuple(_)
                    | ast::Expr::List(_)
                    | ast::Expr::ListComp(_)
                    | ast::Expr::Dict(_)
                    | ast::Expr::DictComp(_)
                    | ast::Expr::Set(_)
                    | ast::Expr::SetComp(_)
                    | ast::Expr::Generator(_)
                    | ast::Expr::FString(_)
                    | ast::Expr::TString(_)
            );
        if warns && let Some(inferred) = self.infer_type(func) {
            self.warn_syntax(
                func.range(),
                format!(
                    "'{}' object is not callable; perhaps you missed a comma?",
                    inferred.name()
                ),
            )?;
        }
        Ok(())
    }

    fn check_compare(
        &mut self,
        range: TextRange,
        left: &ast::Expr,
        ops: &[ast::CmpOp],
        comparators: &[ast::Expr],
    ) -> CompileResult<()> {
        let mut left_is_arg = self.check_is_arg(left);
        let mut left_expr = left;
        for (op, right_expr) in ops.iter().zip(comparators.iter()) {
            let right_is_arg = self.check_is_arg(right_expr);
            if matches!(op, ast::CmpOp::Is | ast::CmpOp::IsNot) && (!right_is_arg || !left_is_arg) {
                let literal = if !left_is_arg { left_expr } else { right_expr };
                if let Some(inferred) = self.infer_type(literal) {
                    let is_op = matches!(op, ast::CmpOp::Is);
                    let op = if is_op { "\"is\"" } else { "\"is not\"" };
                    let replacement = if is_op { "==" } else { "!=" };
                    self.warn_syntax(
                        range,
                        format!(
                            "{op} with '{}' literal. Did you mean \"{replacement}\"?",
                            inferred.name()
                        ),
                    )?;
                    return Ok(());
                }
            }
            left_is_arg = right_is_arg;
            left_expr = right_expr;
        }
        Ok(())
    }

    fn constant_warns_as_subscripter(constant: &ConstantData) -> bool {
        matches!(
            constant,
            ConstantData::None
                | ConstantData::Ellipsis
                | ConstantData::Integer { .. }
                | ConstantData::Float { .. }
                | ConstantData::Complex { .. }
                | ConstantData::Boolean { .. }
                | ConstantData::Frozenset { .. }
        )
    }

    fn check_subscripter(&mut self, value: &ast::Expr) -> CompileResult<()> {
        let warns = self
            .ast_constant_value(value)
            .is_some_and(|constant| Self::constant_warns_as_subscripter(&constant))
            || matches!(
                value,
                ast::Expr::NoneLiteral(_)
                    | ast::Expr::EllipsisLiteral(_)
                    | ast::Expr::NumberLiteral(_)
                    | ast::Expr::BooleanLiteral(_)
                    | ast::Expr::Set(_)
                    | ast::Expr::SetComp(_)
                    | ast::Expr::Generator(_)
                    | ast::Expr::TString(_)
                    | ast::Expr::Lambda(_)
            );
        if warns && let Some(inferred) = self.infer_type(value) {
            self.warn_syntax(
                value.range(),
                format!(
                    "'{}' object is not subscriptable; perhaps you missed a comma?",
                    inferred.name()
                ),
            )?;
        }
        Ok(())
    }

    fn check_index(&mut self, value: &ast::Expr, slice: &ast::Expr) -> CompileResult<()> {
        let Some(index_type) = self.infer_type(slice) else {
            return Ok(());
        };
        if index_type.is_long_subclass() || index_type == InferredType::Slice {
            return Ok(());
        }

        let constant_warns = self.ast_constant_value(value).is_some_and(|constant| {
            matches!(
                constant,
                ConstantData::Str { .. } | ConstantData::Bytes { .. } | ConstantData::Tuple { .. }
            )
        });
        let warns = constant_warns
            || matches!(
                value,
                ast::Expr::StringLiteral(_)
                    | ast::Expr::BytesLiteral(_)
                    | ast::Expr::Tuple(_)
                    | ast::Expr::List(_)
                    | ast::Expr::ListComp(_)
                    | ast::Expr::FString(_)
            );
        if warns && let Some(value_type) = self.infer_type(value) {
            self.warn_syntax(
                value.range(),
                format!(
                    "{} indices must be integers or slices, not {}; perhaps you missed a comma?",
                    value_type.name(),
                    index_type.name()
                ),
            )?;
        }
        Ok(())
    }

    fn check_assert(&mut self, assert_stmt: &ast::StmtAssert) -> CompileResult<()> {
        let warns = match &*assert_stmt.test {
            ast::Expr::Tuple(tuple) => !tuple.elts.is_empty(),
            _ => matches!(
                self.ast_constant_value(&assert_stmt.test),
                Some(ConstantData::Tuple { ref elements }) if !elements.is_empty()
            ),
        };
        if warns {
            self.warn_syntax(
                assert_stmt.range,
                "assertion is always true, perhaps remove parentheses?".to_owned(),
            )?;
        }
        Ok(())
    }

    fn new_with_syntax_warning_handler(
        opts: CompileOpts,
        source_file: SourceFile,
        code_name: &str,
        syntax_warning_handler: Option<&'warnings mut SyntaxWarningHandler<'warnings>>,
    ) -> Self {
        let module_code = ir::CodeInfo {
            // CPython convention: top-level module / interactive /
            // expression code does not carry CO_NEWLOCALS or CO_OPTIMIZED.
            // (See `Python/compile.c compiler_enter_scope` for module
            // scope.)  This matches the per-scope mapping at
            // enter_scope::CompilerScope::Module below, which also returns
            // empty flags.  frame.rs:725-731 then binds locals to globals
            // for module/REPL frames whose `scope.locals` is None - the
            // correct semantics for `exec(code, globals)` and module init.
            flags: bytecode::CodeFlags::empty(),
            source_path: source_file.name().to_owned(),
            private: None,
            blocks: Blocks::from([Block::default()]),
            current_block: BlockIdx::new(0),
            instr_sequence: ir::InstructionSequence::new(),
            instr_sequence_label_map: ir::InstructionSequenceLabelMap::new(),
            annotations_instr_sequence: None,
            metadata: ir::CodeUnitMetadata {
                name: code_name.to_string(),
                qualname: Some(code_name.to_string()),
                consts: Default::default(),
                names: IndexSet::default(),
                varnames: IndexSet::default(),
                cellvars: IndexSet::default(),
                freevars: IndexSet::default(),
                fast_hidden: IndexMap::default(),
                fast_hidden_final: IndexSet::default(),
                argcount: 0,
                posonlyargcount: 0,
                kwonlyargcount: 0,
                firstlineno: OneIndexed::MIN,
            },
            static_attributes: None,
            in_inlined_comp: false,
            fblock: Vec::with_capacity(CO_MAXBLOCKS),
            symbol_table_index: 0, // Module is always the first symbol table
            nparams: 0,
            in_conditional_block: 0,
            next_conditional_annotation_index: 0,
        };
        Self {
            code_stack: vec![module_code],
            symbol_table_stack: Vec::new(),
            source_file,
            // current_source_location: SourceLocation::default(),
            current_source_range: TextRange::default(),
            done_with_future_stmts: DoneWithFuture::No,
            future_features: opts.future_features,
            future_annotations: false,
            ctx: CompileContext {
                in_class: false,
                func: FunctionContext::NoFunction,
                in_async_scope: false,
            },
            opts,
            in_annotation: false,
            interactive: false,
            do_not_emit_bytecode: 0,
            disable_warning: 0,
            syntax_warning_handler,
        }
    }

    fn compile_module_annotation_setup_sequence(
        &mut self,
        body: &[ast::Stmt],
        loc: TextRange,
    ) -> CompileResult<()> {
        let (
            saved_blocks,
            saved_current_block,
            saved_instr_sequence,
            saved_instr_sequence_label_map,
            saved_annotations_instr_sequence,
        ) = {
            let code = self.current_code_info();

            (
                mem::replace(&mut code.blocks, Blocks::from([Block::default()])),
                mem::replace(&mut code.current_block, BlockIdx::new(0)),
                mem::replace(&mut code.instr_sequence, ir::InstructionSequence::new()),
                mem::replace(
                    &mut code.instr_sequence_label_map,
                    ir::InstructionSequenceLabelMap::new(),
                ),
                code.annotations_instr_sequence.take(),
            )
        };

        let result = self.compile_module_annotate(body, Some(loc));

        {
            let code = self.current_code_info();
            code.blocks = saved_blocks;
            let annotations_instr_sequence =
                mem::replace(&mut code.instr_sequence, saved_instr_sequence);
            code.current_block = saved_current_block;
            code.instr_sequence_label_map = saved_instr_sequence_label_map;
            debug_assert!(saved_annotations_instr_sequence.is_none());
            if matches!(result, Ok(true)) {
                code.annotations_instr_sequence = Some(annotations_instr_sequence);
            } else {
                code.annotations_instr_sequence = saved_annotations_instr_sequence;
            }
        };

        result.map(|_| ())
    }

    /// Compile just start and stop of a slice (for BINARY_SLICE/STORE_SLICE)
    // = codegen_slice_two_parts
    fn compile_slice_two_parts(&mut self, s: &ast::ExprSlice) -> CompileResult<()> {
        // Compile lower (or None)
        if let Some(lower) = &s.lower {
            self.compile_expression(lower)?;
        } else {
            self.set_source_range(s.range);
            self.emit_load_const(ConstantData::None);
        }

        // Compile upper (or None)
        if let Some(upper) = &s.upper {
            self.compile_expression(upper)?;
        } else {
            self.set_source_range(s.range);
            self.emit_load_const(ConstantData::None);
        }

        Ok(())
    }
    /// Compile a subscript expression
    // = compiler_subscript
    fn compile_subscript(
        &mut self,
        value: &ast::Expr,
        slice: &ast::Expr,
        ctx: ast::ExprContext,
    ) -> CompileResult<()> {
        // Save full subscript expression range (set by compile_expression before this call)
        let subscript_range = self.current_source_range;
        if matches!(ctx, ast::ExprContext::Load) {
            self.check_subscripter(value)?;
            self.check_index(value, slice)?;
        }

        // VISIT(c, expr, e->v.Subscript.value)
        self.compile_expression(value)?;

        // Handle two-element non-constant slice with BINARY_SLICE/STORE_SLICE
        let use_slice_opt = matches!(ctx, ast::ExprContext::Load | ast::ExprContext::Store)
            && self.should_apply_two_element_slice_optimization(slice);
        if use_slice_opt {
            match slice {
                ast::Expr::Slice(s) => self.compile_slice_two_parts(s)?,
                _ => unreachable!(
                    "should_use_slice_optimization should only return true for ast::Expr::Slice"
                ),
            };
        } else {
            // VISIT(c, expr, e->v.Subscript.slice)
            self.compile_expression(slice)?;
        }

        // Restore full subscript expression range before emitting
        self.set_source_range(subscript_range);

        match (use_slice_opt, ctx) {
            (true, ast::ExprContext::Load) => emit!(self, Instruction::BinarySlice),
            (true, ast::ExprContext::Store) => emit!(self, Instruction::StoreSlice),
            (true, _) => unreachable!(),
            (false, ast::ExprContext::Load) => emit!(
                self,
                Instruction::BinaryOp {
                    op: BinaryOperator::Subscr
                }
            ),
            (false, ast::ExprContext::Store) => emit!(self, Instruction::StoreSubscr),
            (false, ast::ExprContext::Del) => emit!(self, Instruction::DeleteSubscr),
            (false, ast::ExprContext::Invalid) => {
                return Err(self.error(CodegenErrorType::SyntaxError(
                    "Invalid expression context".to_owned(),
                )));
            }
        }

        Ok(())
    }

    /// Helper function for compiling tuples/lists/sets with starred expressions
    ///
    /// ast::Parameters:
    /// - elts: The elements to compile
    /// - pushed: Number of items already on the stack
    /// - collection_type: What type of collection to build (tuple, list, set)
    ///
    // = starunpack_helper in compile.c
    fn starunpack_helper_impl(
        &mut self,
        elts: &[ast::Expr],
        injected_arg: Option<&str>,
        pushed: u32,
        collection_type: CollectionType,
    ) -> CompileResult<()> {
        let collection_range = self.current_source_range;
        let n = elts.len().to_u32();
        let seen_star = elts.iter().any(|e| matches!(e, ast::Expr::Starred(_)));

        let injected_count = u32::from(injected_arg.is_some());
        let big = n + pushed + injected_count > STACK_USE_GUIDELINE;

        // Constant collections are not folded here: the late flowgraph
        // optimization passes introduce tuple-backed constants after their
        // operands have first been emitted, matching the constant ordering.

        // If no stars and not too big, compile all elements and build once
        if !seen_star && !big {
            for elt in elts {
                self.compile_expression(elt)?;
            }
            if let Some(injected_arg) = injected_arg {
                self.set_source_range(collection_range);
                self.load_name(injected_arg)?;
            }
            let total_size = n + injected_count + pushed;
            self.set_source_range(collection_range);
            match collection_type {
                CollectionType::List => {
                    emit!(self, Instruction::BuildList { count: total_size });
                }
                CollectionType::Set => {
                    emit!(self, Instruction::BuildSet { count: total_size });
                }
                CollectionType::Tuple => {
                    emit!(self, Instruction::BuildTuple { count: total_size });
                }
            }
            return Ok(());
        }

        // Has stars or too big: use streaming approach.
        let mut sequence_built = false;
        let mut i = 0u32;

        if big {
            self.set_source_range(collection_range);
            match collection_type {
                CollectionType::List => {
                    emit!(self, Instruction::BuildList { count: pushed });
                    sequence_built = true;
                }
                CollectionType::Set => {
                    emit!(self, Instruction::BuildSet { count: pushed });
                    sequence_built = true;
                }
                CollectionType::Tuple => {
                    emit!(self, Instruction::BuildList { count: pushed });
                    sequence_built = true;
                }
            }
        }

        for elt in elts {
            if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = elt {
                // When we hit first star, build sequence with elements so far
                if !sequence_built {
                    self.set_source_range(collection_range);
                    match collection_type {
                        CollectionType::List => {
                            emit!(self, Instruction::BuildList { count: i + pushed });
                        }
                        CollectionType::Set => {
                            emit!(self, Instruction::BuildSet { count: i + pushed });
                        }
                        CollectionType::Tuple => {
                            emit!(self, Instruction::BuildList { count: i + pushed });
                        }
                    }
                    sequence_built = true;
                }

                // Compile the starred expression and extend
                self.compile_expression(value)?;
                self.set_source_range(collection_range);
                match collection_type {
                    CollectionType::List => {
                        emit!(self, Instruction::ListExtend { i: 1 });
                    }
                    CollectionType::Set => {
                        emit!(self, Instruction::SetUpdate { i: 1 });
                    }
                    CollectionType::Tuple => {
                        emit!(self, Instruction::ListExtend { i: 1 });
                    }
                }
            } else {
                // Non-starred element
                self.compile_expression(elt)?;

                if sequence_built {
                    // Sequence already exists, append to it
                    self.set_source_range(collection_range);
                    match collection_type {
                        CollectionType::List => {
                            emit!(self, Instruction::ListAppend { i: 1 });
                        }
                        CollectionType::Set => {
                            emit!(self, Instruction::SetAdd { i: 1 });
                        }
                        CollectionType::Tuple => {
                            emit!(self, Instruction::ListAppend { i: 1 });
                        }
                    }
                } else {
                    // Still collecting elements before first star
                    i += 1;
                }
            }
        }

        debug_assert!(sequence_built);
        if let Some(injected_arg) = injected_arg {
            self.set_source_range(collection_range);
            self.load_name(injected_arg)?;
            self.set_source_range(collection_range);
            match collection_type {
                CollectionType::List | CollectionType::Tuple => {
                    emit!(self, Instruction::ListAppend { i: 1 });
                }
                CollectionType::Set => {
                    emit!(self, Instruction::SetAdd { i: 1 });
                }
            }
        }

        if collection_type == CollectionType::Tuple {
            self.set_source_range(collection_range);
            emit!(
                self,
                Instruction::CallIntrinsic1 {
                    func: IntrinsicFunction1::ListToTuple
                }
            );
        }

        Ok(())
    }

    fn starunpack_helper(
        &mut self,
        elts: &[ast::Expr],
        pushed: u32,
        collection_type: CollectionType,
    ) -> CompileResult<()> {
        self.starunpack_helper_impl(elts, None, pushed, collection_type)
    }

    fn error(&mut self, error: CodegenErrorType) -> CodegenError {
        self.error_ranged(error, self.current_source_range)
    }

    fn error_ranged(&mut self, error: CodegenErrorType, range: TextRange) -> CodegenError {
        let location = self
            .source_file
            .to_source_code()
            .source_location(range.start(), PositionEncoding::Utf8);
        CodegenError {
            error,
            location: Some(location),
            source_path: self.source_file.name().to_owned(),
        }
    }

    fn error_optional_range(
        &mut self,
        error: CodegenErrorType,
        range: Option<TextRange>,
    ) -> CodegenError {
        match range {
            Some(range) => self.error_ranged(error, range),
            None => CodegenError {
                error,
                location: None,
                source_path: self.source_file.name().to_owned(),
            },
        }
    }

    /// Get the SymbolTable for the current scope.
    fn current_symbol_table(&self) -> &SymbolTable {
        self.symbol_table_stack
            .last()
            .expect("symbol_table_stack is empty! This is a compiler bug.")
    }

    fn has_enclosing_non_module_code_scope(&self) -> bool {
        self.code_stack.len() > 1
    }

    /// Match CPython's `is_import_originated()`: only imports recorded in the
    /// module-level symbol table suppress method-call optimization.
    fn is_name_imported(&self, name: &str) -> bool {
        self.symbol_table_stack
            .first()
            .and_then(|table| table.symbols.get(name))
            .is_some_and(|sym| sym.flags.contains(SymbolFlags::DEF_IMPORT))
    }

    /// Get the cell-relative index of a free variable.
    /// Returns ncells + freevar_idx. Fixed up to localsplus index during finalize.
    fn get_free_var_index(&mut self, name: &str) -> oparg::VarNum {
        let info = self.code_stack.last_mut().unwrap();
        let idx = info
            .metadata
            .freevars
            .get_index_of(name)
            .unwrap_or_else(|| info.metadata.freevars.insert_full(name.to_owned()).0);
        (idx + info.metadata.cellvars.len()).to_u32().into()
    }

    /// Get the cell-relative index of a cell variable.
    /// Returns cellvar_idx. Fixed up to localsplus index during finalize.
    fn get_cell_var_index(&mut self, name: &str) -> oparg::VarNum {
        let info = self.code_stack.last_mut().unwrap();
        let idx = info
            .metadata
            .cellvars
            .get_index_of(name)
            .unwrap_or_else(|| info.metadata.cellvars.insert_full(name.to_owned()).0);
        idx.to_u32().into()
    }

    /// Get the index of a local variable.
    fn get_local_var_index(&mut self, name: &str) -> oparg::VarNum {
        let info = self.code_stack.last_mut().unwrap();
        let idx = info
            .metadata
            .varnames
            .get_index_of(name)
            .unwrap_or_else(|| info.metadata.varnames.insert_full(name.to_owned()).0);
        idx.to_u32().into()
    }

    /// Get the index of a global name.
    fn get_global_name_index(&mut self, name: &str) -> u32 {
        let info = self.code_stack.last_mut().unwrap();
        let idx = info
            .metadata
            .names
            .get_index_of(name)
            .unwrap_or_else(|| info.metadata.names.insert_full(name.to_owned()).0);
        idx.to_u32()
    }

    /// Push the next symbol table on to the stack
    fn push_symbol_table(&mut self) -> CompileResult<&SymbolTable> {
        // Look up the next table contained in the scope of the current table
        let current_table = self
            .symbol_table_stack
            .last_mut()
            .expect("no current symbol table");

        if current_table.next_sub_table >= current_table.sub_tables.len() {
            let name = current_table.name.clone();
            let typ = current_table.typ;
            return Err(self.error(CodegenErrorType::SyntaxError(format!(
                "no symbol table available in {name} (type: {typ:?})"
            ))));
        }

        while current_table.next_sub_table < current_table.sub_tables.len()
            && current_table.sub_tables[current_table.next_sub_table].typ
                == CompilerScope::Annotation
        {
            current_table.next_sub_table += 1;
        }
        if current_table.next_sub_table >= current_table.sub_tables.len() {
            let name = current_table.name.clone();
            let typ = current_table.typ;
            return Err(self.error(CodegenErrorType::SyntaxError(format!(
                "no symbol table available in {name} (type: {typ:?})"
            ))));
        }

        let idx = current_table.next_sub_table;
        current_table.next_sub_table += 1;
        let table = current_table.sub_tables[idx].clone();

        // Push the next table onto the stack
        self.symbol_table_stack.push(table);
        Ok(self.current_symbol_table())
    }

    fn push_symbol_table_matching(
        &mut self,
        typ: CompilerScope,
        table_name: &str,
    ) -> CompileResult<&SymbolTable> {
        let current_table = self
            .symbol_table_stack
            .last_mut()
            .expect("no current symbol table");

        while current_table.next_sub_table < current_table.sub_tables.len()
            && current_table.sub_tables[current_table.next_sub_table].typ
                == CompilerScope::Annotation
        {
            current_table.next_sub_table += 1;
        }

        let start = current_table.next_sub_table;
        let Some(idx) = current_table.sub_tables[start..]
            .iter()
            .position(|table| table.typ == typ && table.name == table_name)
            .map(|idx| start + idx)
        else {
            let name = current_table.name.clone();
            let current_typ = current_table.typ;
            return Err(self.error(CodegenErrorType::SyntaxError(format!(
                "no matching symbol table {table_name} ({typ:?}) available in {name} (type: {current_typ:?})"
            ))));
        };

        let table = current_table.sub_tables[idx].clone();
        current_table.next_sub_table = idx + 1;
        self.symbol_table_stack.push(table);
        Ok(self.current_symbol_table())
    }

    /// Push the function annotation symbol table.
    /// Signature annotation blocks are stored in st_blocks keyed by the
    /// arguments AST node. Without future annotations they are also children;
    /// with future annotations they are hidden from children and consumed here.
    fn push_annotation_symbol_table(&mut self) -> bool {
        let Some(annotation_table) = ({
            let current_table = self
                .symbol_table_stack
                .last_mut()
                .expect("no current symbol table");

            let next_idx = current_table.next_sub_table;
            if next_idx < current_table.sub_tables.len()
                && current_table.sub_tables[next_idx].typ == CompilerScope::Annotation
            {
                let next_table = current_table.sub_tables[next_idx].clone();
                current_table.next_sub_table += 1;
                Some(next_table)
            } else if current_table.next_hidden_annotation_block
                < current_table.hidden_annotation_blocks.len()
            {
                let idx = current_table.next_hidden_annotation_block;
                current_table.next_hidden_annotation_block += 1;
                Some(current_table.hidden_annotation_blocks[idx].clone())
            } else {
                None
            }
        }) else {
            return false;
        };

        self.symbol_table_stack.push(annotation_table);
        true
    }

    fn next_function_annotation_symbol_table_uses_annotations(&self) -> bool {
        let current_table = self
            .symbol_table_stack
            .last()
            .expect("no current symbol table");
        let next_idx = current_table.next_sub_table;
        if next_idx < current_table.sub_tables.len()
            && current_table.sub_tables[next_idx].typ == CompilerScope::Annotation
        {
            return current_table.sub_tables[next_idx].annotations_used;
        }

        let hidden_idx = current_table.next_hidden_annotation_block;
        current_table
            .hidden_annotation_blocks
            .get(hidden_idx)
            .is_some_and(|table| table.annotations_used)
    }

    /// Push the annotation symbol table for module/class level annotations
    /// This takes annotation_block from the current symbol table (not sub_tables)
    fn push_current_annotation_symbol_table(&mut self) -> bool {
        let current_table = self
            .symbol_table_stack
            .last_mut()
            .expect("no current symbol table");

        // For modules/classes, annotation_block is directly in the current table
        if let Some(annotation_block) = current_table.annotation_block.take() {
            self.symbol_table_stack.push(*annotation_block);
            true
        } else {
            false
        }
    }

    /// Pop the annotation symbol table.
    fn pop_annotation_symbol_table(&mut self) {
        self.symbol_table_stack.pop().expect("compiler bug");
    }

    /// Pop the current symbol table off the stack
    fn pop_symbol_table(&mut self) -> SymbolTable {
        self.symbol_table_stack.pop().expect("compiler bug")
    }

    /// Check if a super() call can be optimized
    /// Returns Some(SuperCallType) if optimization is possible, None otherwise
    fn can_optimize_super_call<'a>(
        &self,
        value: &'a ast::Expr,
        attr: &str,
    ) -> Option<SuperCallType<'a>> {
        // 1. value must be a Call expression
        let ast::Expr::Call(ast::ExprCall {
            func, arguments, ..
        }) = value
        else {
            return None;
        };

        // 2. func must be Name("super")
        let ast::Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
            return None;
        };
        if id.as_str() != "super" {
            return None;
        }

        // 3. attr must not be "__class__"
        if attr == "__class__" {
            return None;
        }

        // 4. No keyword arguments
        if !arguments.keywords.is_empty() {
            return None;
        }

        // 5. "super" must be GlobalImplicit in the current scope.
        let table = self.current_symbol_table();
        if let Some(symbol) = table.lookup("super")
            && symbol.scope != SymbolScope::GlobalImplicit
        {
            return None;
        }
        // Then check the top-level scope and reject any statically
        // visible symbol for "super", not just local bindings.
        if let Some(top_table) = self.symbol_table_stack.first()
            && top_table.lookup("super").is_some()
        {
            return None;
        }

        // 6. Check argument pattern
        let args = &arguments.args;

        // No starred expressions allowed
        if args.iter().any(|arg| matches!(arg, ast::Expr::Starred(_))) {
            return None;
        }

        match args.len() {
            2 => {
                // 2-arg: super(class, self)
                Some(SuperCallType::TwoArg {
                    class_arg: &args[0],
                    self_arg: &args[1],
                })
            }
            0 => {
                // 0-arg: super() - need __class__ cell and first parameter
                // Enclosing function should have at least one positional argument
                let info = self.code_stack.last()?;
                if info.metadata.argcount == 0 && info.metadata.posonlyargcount == 0 {
                    return None;
                }

                // Check if __class__ is available as a cell/free variable
                // The scope must be Free (from enclosing class) or have DEF_FREE_CLASS flag
                {
                    let symbol = table.lookup("__class__")?;
                    if symbol.scope != SymbolScope::Free
                        && !symbol.flags.contains(SymbolFlags::DEF_FREE_CLASS)
                    {
                        return None;
                    }
                }

                Some(SuperCallType::ZeroArg)
            }
            _ => None, // 1 or 3+ args - not optimizable
        }
    }

    /// Load arguments for super() optimization onto the stack
    /// Stack result: [global_super, class, self]
    fn load_args_for_super(
        &mut self,
        super_type: &SuperCallType<'_>,
        super_name_range: TextRange,
        super_call_range: TextRange,
    ) -> CompileResult<()> {
        // 1. Load global super
        self.set_source_range(super_name_range);
        self.compile_name("super", NameUsage::Load)?;

        match super_type {
            SuperCallType::TwoArg {
                class_arg,
                self_arg,
            } => {
                // 2-arg: load provided arguments
                self.compile_expression(class_arg)?;
                self.compile_expression(self_arg)?;
            }
            SuperCallType::ZeroArg => {
                // 0-arg: load __class__ cell and first parameter
                // Load __class__ from cell/free variable
                self.set_source_range(super_call_range);
                let scope = self.get_ref_type("__class__").map_err(|e| self.error(e))?;
                let idx = match scope {
                    SymbolScope::Cell => self.get_cell_var_index("__class__"),
                    SymbolScope::Free => self.get_free_var_index("__class__"),
                    _ => {
                        return Err(self.error(CodegenErrorType::SyntaxError(
                            "super(): __class__ cell not found".to_owned(),
                        )));
                    }
                };
                emit!(self, Instruction::LoadDeref { i: idx });

                // Load first parameter (typically 'self').
                // Safety: can_optimize_super_call() ensures argcount > 0, and
                // parameters are always added to varnames first (see symboltable.rs).
                let first_param = {
                    let info = self.code_stack.last().unwrap();
                    info.metadata.varnames.first().cloned()
                };
                let first_param = first_param.ok_or_else(|| {
                    self.error(CodegenErrorType::SyntaxError(
                        "super(): no arguments and no first parameter".to_owned(),
                    ))
                })?;
                self.set_source_range(super_call_range);
                self.compile_name(&first_param, NameUsage::Load)?;
            }
        }
        Ok(())
    }

    /// Check if this is an inlined comprehension context (PEP 709).
    /// Generator expressions are never inlined.
    fn is_inlined_comprehension_context(
        &self,
        comprehension_type: ComprehensionType,
        comp_table: &SymbolTable,
    ) -> bool {
        if comprehension_type == ComprehensionType::Generator {
            return false;
        }
        comp_table.comp_inlined
    }

    /// Enter a new scope
    // = compiler_enter_scope
    fn enter_scope(
        &mut self,
        name: &str,
        scope_type: CompilerScope,
        key: usize, // Symbol table stack index used like CPython's scope key.
        lineno: u32,
    ) -> CompileResult<()> {
        // Allocate a new compiler unit

        // In Rust, we'll create the structure directly
        let source_path = self.source_file.name().to_owned();

        // Lookup symbol table entry using key (_PySymtable_Lookup)
        let ste = match self.symbol_table_stack.get(key) {
            Some(v) => v,
            None => {
                return Err(self.error(CodegenErrorType::SyntaxError(
                    "unknown symbol table entry".to_owned(),
                )));
            }
        };

        // Use varnames from symbol table (already collected in definition order)
        let varname_cache: IndexSet<String> = ste.varnames.iter().cloned().collect();
        let nparams = ste.varnames.len();

        // Build cellvars using dictbytype (CELL scope or COMP_CELL flag, sorted)
        let mut cellvar_cache = IndexSet::default();
        let mut cell_names: Vec<_> = ste
            .symbols
            .iter()
            .filter(|(_, s)| {
                s.scope == SymbolScope::Cell || s.flags.contains(SymbolFlags::DEF_COMP_CELL)
            })
            .map(|(name, _)| name.clone())
            .collect();
        cell_names.sort();
        for name in cell_names {
            cellvar_cache.insert(name);
        }

        // Handle implicit __class__ cell if needed
        if ste.needs_class_closure {
            // Cook up an implicit __class__ cell
            debug_assert_eq!(scope_type, CompilerScope::Class);
            cellvar_cache.insert("__class__".to_string());
        }

        // Handle implicit __classdict__ cell if needed
        if ste.needs_classdict {
            // Cook up an implicit __classdict__ cell
            debug_assert_eq!(scope_type, CompilerScope::Class);
            cellvar_cache.insert("__classdict__".to_string());
        }

        // Handle implicit __conditional_annotations__ cell if needed.
        if Self::scope_needs_conditional_annotations_cell(ste) {
            cellvar_cache.insert("__conditional_annotations__".to_string());
        }

        // Build freevars using dictbytype (FREE scope, offset by cellvars size)
        let mut freevar_cache = IndexSet::default();
        let annotation_free_names: IndexSet<String> = ste
            .annotation_block
            .as_ref()
            .map(|annotation| {
                annotation
                    .symbols
                    .iter()
                    .filter(|(_, s)| s.scope == SymbolScope::Free)
                    .map(|(name, _)| name.clone())
                    .collect()
            })
            .unwrap_or_default();
        let mut free_names: Vec<_> = ste
            .symbols
            .iter()
            .filter(|(_, s)| {
                s.scope == SymbolScope::Free
                    || (scope_type != CompilerScope::Class
                        && s.flags.contains(SymbolFlags::DEF_FREE_CLASS))
                    || (scope_type == CompilerScope::Class
                        && s.flags.contains(SymbolFlags::DEF_FREE_CLASS)
                        && self.has_enclosing_non_module_code_scope())
            })
            .filter(|(name, symbol)| {
                if !matches!(
                    scope_type,
                    CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda
                ) {
                    return true;
                }
                !(annotation_free_names.contains(*name) && symbol.flags.is_empty())
            })
            .map(|(name, _)| name.clone())
            .collect();
        free_names.sort();
        for name in free_names {
            freevar_cache.insert(name);
        }

        // Initialize u_metadata fields
        let (mut flags, posonlyarg_count, arg_count, kwonlyarg_count) = match scope_type {
            CompilerScope::Module => (bytecode::CodeFlags::empty(), 0, 0, 0),
            CompilerScope::Class => (bytecode::CodeFlags::empty(), 0, 0, 0),
            CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda => (
                bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
                0, // Will be set later in enter_function
                0, // Will be set later in enter_function
                0, // Will be set later in enter_function
            ),
            CompilerScope::Comprehension => (
                bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
                0,
                1, // comprehensions take one argument (.0)
                0,
            ),
            CompilerScope::TypeParams => (
                bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
                0,
                0,
                0,
            ),
            CompilerScope::Annotation => (
                bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
                1, // format is positional-only
                0,
                0,
            ),
            CompilerScope::TypeAlias | CompilerScope::TypeVariable => (
                bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
                1, // format is positional-only
                0,
                0,
            ),
        };

        if ste.is_method {
            flags |= bytecode::CodeFlags::METHOD;
        }

        // CPython sets CO_NESTED from symtable's ste_nested, not merely
        // from lexical depth: module-level class methods are CO_METHOD but
        // not CO_NESTED.
        let mut flags = if ste.is_nested
            && matches!(
                scope_type,
                CompilerScope::Function
                    | CompilerScope::AsyncFunction
                    | CompilerScope::Lambda
                    | CompilerScope::Comprehension
                    | CompilerScope::Annotation
                    | CompilerScope::TypeAlias
                    | CompilerScope::TypeVariable
                    | CompilerScope::TypeParams
            ) {
            flags | bytecode::CodeFlags::NESTED
        } else {
            flags
        };
        flags |= self.future_features;

        // Get private name from parent scope
        let private = if !self.code_stack.is_empty() {
            self.code_stack.last().unwrap().private.clone()
        } else {
            None
        };

        // Create the new compilation unit
        let code_info = ir::CodeInfo {
            flags,
            source_path,
            private,
            blocks: Blocks::from([Block::default()]),
            current_block: BlockIdx::new(0),
            instr_sequence: ir::InstructionSequence::new(),
            instr_sequence_label_map: ir::InstructionSequenceLabelMap::new(),
            annotations_instr_sequence: None,
            metadata: ir::CodeUnitMetadata {
                name: name.to_owned(),
                qualname: None, // Will be set below
                consts: Default::default(),
                names: IndexSet::default(),
                varnames: varname_cache,
                cellvars: cellvar_cache,
                freevars: freevar_cache,
                fast_hidden: IndexMap::default(),
                fast_hidden_final: IndexSet::default(),
                argcount: arg_count,
                posonlyargcount: posonlyarg_count,
                kwonlyargcount: kwonlyarg_count,
                firstlineno: OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN),
            },
            static_attributes: if scope_type == CompilerScope::Class {
                Some(IndexSet::default())
            } else {
                None
            },
            in_inlined_comp: false,
            fblock: Vec::with_capacity(CO_MAXBLOCKS),
            symbol_table_index: key,
            nparams,
            in_conditional_block: 0,
            next_conditional_annotation_index: 0,
        };

        // Push the old compiler unit on the stack (like PyCapsule)
        // This happens before setting qualname
        self.code_stack.push(code_info);

        // Set qualname after pushing (uses compiler_set_qualname logic)
        if scope_type != CompilerScope::Module {
            self.set_qualname();
        }

        // Emit RESUME (handles async preamble and module lineno 0)
        // CPython: LOCATION(lineno, lineno, 0, 0), then loc.lineno = 0 for module
        self.emit_resume_for_scope(scope_type, lineno);

        Ok(())
    }

    /// Emit RESUME instruction with proper handling for module lineno.
    /// codegen_enter_scope equivalent for RESUME emission.
    fn emit_resume_for_scope(&mut self, scope_type: CompilerScope, lineno: u32) {
        // CPython: LOCATION(lineno, lineno, 0, 0)
        // Module scope: loc.lineno = 0 (before the first line)
        let lineno_override = if scope_type == CompilerScope::Module {
            Some(0)
        } else {
            None
        };

        // Use lineno for location (col = 0 as in CPython)
        let location = SourceLocation {
            line: OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN),
            character_offset: OneIndexed::MIN, // col = 0
        };
        let end_location = location; // end_lineno = lineno, end_col = 0
        let except_handler = None;

        self.cpython_cfg_builder_addop(ir::InstructionInfo {
            instr: Instruction::Resume {
                context: OpArgMarker::marker(),
            }
            .into(),
            arg: OpArg::new(oparg::ResumeLocation::AtFuncStart.into()),
            target: BlockIdx::NULL,
            location,
            end_location,
            except_handler,
            lineno_override,
        });
    }

    fn push_output(
        &mut self,
        flags: bytecode::CodeFlags,
        posonlyarg_count: u32,
        arg_count: u32,
        kwonlyarg_count: u32,
        obj_name: &str,
    ) -> CompileResult<()> {
        // First push the symbol table
        let table = self.push_symbol_table()?;
        let scope_type = table.typ;

        // The key is the current position in the symbol table stack
        let key = self.symbol_table_stack.len() - 1;

        // Get the line number
        let lineno = self.get_source_line_number().get();

        // Call enter_scope which does most of the work
        self.enter_scope(obj_name, scope_type, key, lineno.to_u32())?;

        // Override the values that push_output sets explicitly
        // enter_scope sets default values based on scope_type, but push_output
        // allows callers to specify exact values
        if let Some(info) = self.code_stack.last_mut() {
            // Preserve flags computed from the symbol-table context.
            info.flags = flags
                | (info.flags
                    & (bytecode::CodeFlags::NESTED
                        | bytecode::CodeFlags::METHOD
                        | bytecode::CodeFlags::FUTURE_DIVISION
                        | bytecode::CodeFlags::FUTURE_ABSOLUTE_IMPORT
                        | bytecode::CodeFlags::FUTURE_WITH_STATEMENT
                        | bytecode::CodeFlags::FUTURE_PRINT_FUNCTION
                        | bytecode::CodeFlags::FUTURE_UNICODE_LITERALS
                        | bytecode::CodeFlags::FUTURE_GENERATOR_STOP
                        | bytecode::CodeFlags::FUTURE_ANNOTATIONS));
            info.metadata.argcount = arg_count;
            info.metadata.posonlyargcount = posonlyarg_count;
            info.metadata.kwonlyargcount = kwonlyarg_count;
        }
        Ok(())
    }

    // compiler_exit_scope
    fn exit_scope(&mut self) -> CodeObject {
        self.pop_symbol_table();
        // Various scopes can have sub_tables:
        // - ast::TypeParams scope can have sub_tables (the function body's symbol table)
        // - Module scope can have sub_tables (for TypeAlias scopes, nested functions, classes)
        // - Function scope can have sub_tables (for nested functions, classes)
        // - Class scope can have sub_tables (for nested classes, methods)

        let pop = self.code_stack.pop();
        let stack_top = compiler_unwrap_option(self, pop);
        // No parent scope stack to maintain
        unwrap_internal(self, stack_top.finalize_code(&self.opts))
    }

    fn expose_annotation_format_parameter(code: &mut CodeObject) {
        if let Some(first) = code.varnames.first_mut() {
            *first = String::from("format");
        }
    }

    /// Exit a function signature annotation scope.
    fn exit_annotation_scope(&mut self, saved_ctx: CompileContext) -> CodeObject {
        self.pop_annotation_symbol_table();
        self.ctx = saved_ctx;
        let pop = self.code_stack.pop();
        let stack_top = compiler_unwrap_option(self, pop);
        let mut code = unwrap_internal(self, stack_top.finalize_code(&self.opts));
        Self::expose_annotation_format_parameter(&mut code);
        code
    }

    /// Enter a function signature annotation scope.
    /// Returns None if no matching annotation symbol table exists.
    /// On success, returns the saved CompileContext to pass to exit_annotation_scope.
    fn enter_annotation_scope(
        &mut self,
        _func_name: &str,
        loc: TextRange,
    ) -> CompileResult<Option<CompileContext>> {
        if !self.push_annotation_symbol_table() {
            return Ok(None);
        }

        // Annotation scopes are never async (even inside async functions)
        let saved_ctx = self.ctx;
        self.ctx = CompileContext {
            in_class: saved_ctx.in_class,
            func: FunctionContext::Function,
            in_async_scope: false,
        };

        self.set_source_range(loc);
        let key = self.symbol_table_stack.len() - 1;
        let lineno = self.get_source_line_number().get();
        self.enter_scope(
            "__annotate__",
            CompilerScope::Annotation,
            key,
            lineno.to_u32(),
        )?;

        // Keep the internal ".format" name; exit_annotation_scope()
        // renames it to "format" on the final code object.
        self.current_code_info()
            .metadata
            .varnames
            .insert(".format".to_owned());

        // Emit format validation: if format > VALUE_WITH_FAKE_GLOBALS: raise NotImplementedError
        // VALUE_WITH_FAKE_GLOBALS = 2 (from annotationlib.Format)
        self.emit_format_validation();

        Ok(Some(saved_ctx))
    }

    /// Emit format parameter validation for annotation scope
    /// if format > VALUE_WITH_FAKE_GLOBALS (2): raise NotImplementedError
    fn emit_format_validation(&mut self) {
        // Load format parameter (first local variable, index 0)
        emit!(
            self,
            Instruction::LoadFast {
                var_num: oparg::VarNum::from_u32(0)
            }
        );

        // Load VALUE_WITH_FAKE_GLOBALS constant (2)
        self.emit_load_const(ConstantData::Integer { value: 2.into() });

        // Compare: format > 2
        emit!(
            self,
            Instruction::CompareOp {
                opname: ComparisonOperator::Greater
            }
        );

        // Jump to body if format <= 2 (comparison is false)
        let body_block = self.new_block();
        emit!(self, Instruction::PopJumpIfFalse { delta: body_block });

        // Raise NotImplementedError
        emit!(
            self,
            Instruction::LoadCommonConstant {
                idx: bytecode::CommonConstant::NotImplementedError
            }
        );
        emit!(
            self,
            Instruction::RaiseVarargs {
                argc: bytecode::RaiseKind::Raise
            }
        );

        // Body label - continue with annotation evaluation
        self.use_cpython_label_block(body_block);
    }

    /// CPython `_PyCompile_PushFBlock()`: store the active label targets on the
    /// fblock stack.
    fn push_fblock_labels(
        &mut self,
        fb_type: FBlockType,
        fb_block: ir::InstructionSequenceLabel,
        fb_exit: ir::InstructionSequenceLabel,
        fb_datum: FBlockDatum,
    ) -> CompileResult<()> {
        let fb_range = self.current_source_range;
        if self.current_code_info().fblock.len() >= CO_MAXBLOCKS {
            return Err(self.error(CodegenErrorType::SyntaxError(
                "too many statically nested blocks".to_owned(),
            )));
        }
        if matches!(fb_type, FBlockType::FinallyEnd) {
            self.disable_warning += 1;
        }
        let code = self.current_code_info();
        code.fblock.push(FBlockInfo {
            fb_type,
            fb_block,
            fb_exit,
            fb_range,
            fb_datum,
        });
        Ok(())
    }

    /// CPython `_PyCompile_PopFBlock()`: assert the popped type and label.
    fn pop_fblock_label(
        &mut self,
        expected_type: FBlockType,
        expected_block: ir::InstructionSequenceLabel,
    ) -> FBlockInfo {
        let fblock = {
            let code = self.current_code_info();
            code.fblock.pop().expect("fblock stack underflow")
        };
        debug_assert_eq!(fblock.fb_type, expected_type);
        debug_assert_eq!(
            fblock.fb_block, expected_block,
            "CPython _PyCompile_PopFBlock asserts the popped fb_block label"
        );
        if matches!(expected_type, FBlockType::FinallyEnd) {
            self.disable_warning -= 1;
        }
        fblock
    }

    /// `_PyCompile_PushFBlock()` call used by
    /// `codegen_unwind_fblock_stack()` to restore the copied fblock after
    /// recursive unwinding.
    fn restore_fblock_info(&mut self, fblock: FBlockInfo) -> CompileResult<()> {
        let FBlockInfo {
            fb_type,
            fb_block,
            fb_exit,
            fb_range,
            fb_datum,
        } = fblock;
        let code = self.current_code_info();
        if code.fblock.len() >= CO_MAXBLOCKS {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError("too many statically nested blocks".to_owned()),
                fb_range,
            ));
        }
        code.fblock.push(FBlockInfo {
            fb_type,
            fb_block,
            fb_exit,
            fb_range,
            fb_datum,
        });
        Ok(())
    }

    fn set_unwind_source_range(&mut self, loc: Option<TextRange>) {
        if let Some(range) = loc {
            self.set_source_range(range);
        }
    }

    fn mark_unwind_no_location(&mut self, loc: Option<TextRange>) {
        if loc.is_none() {
            self.set_no_location();
        }
    }

    /// Unwind a single fblock, emitting cleanup code
    /// preserve_tos: if true, preserve the top of stack (e.g., return value)
    fn unwind_fblock(
        &mut self,
        info: &FBlockInfo,
        preserve_tos: bool,
        loc: &mut Option<TextRange>,
    ) -> CompileResult<()> {
        match info.fb_type {
            FBlockType::WhileLoop
            | FBlockType::ExceptionHandler
            | FBlockType::ExceptionGroupHandler
            | FBlockType::AsyncComprehensionGenerator
            | FBlockType::StopIteration => {
                // No cleanup needed
            }

            FBlockType::ForLoop => {
                // When returning from a for-loop, CPython swaps the preserved
                // value with the iterator and uses POP_TOP for loop cleanup.
                if preserve_tos {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 });
                    self.mark_unwind_no_location(*loc);
                }
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopTop);
                self.mark_unwind_no_location(*loc);
            }

            FBlockType::TryExcept => {
                self.set_unwind_source_range(*loc);
                emit!(self, PseudoInstruction::PopBlock);
                self.mark_unwind_no_location(*loc);
            }

            FBlockType::FinallyTry => {
                // codegen_unwind_fblock(FINALLY_TRY)
                self.set_unwind_source_range(*loc);
                emit!(self, PseudoInstruction::PopBlock);
                self.mark_unwind_no_location(*loc);

                if preserve_tos {
                    self.push_fblock_labels(
                        FBlockType::PopValue,
                        ir::InstructionSequenceLabel::NO_LABEL,
                        ir::InstructionSequenceLabel::NO_LABEL,
                        FBlockDatum::None,
                    )?;
                }

                if let FBlockDatum::FinallyBody(ref body) = info.fb_datum {
                    self.compile_statements(body)?;
                }

                if preserve_tos {
                    self.pop_fblock_label(
                        FBlockType::PopValue,
                        ir::InstructionSequenceLabel::NO_LABEL,
                    );
                }

                *loc = None;
            }

            FBlockType::FinallyEnd => {
                // codegen_unwind_fblock(FINALLY_END)
                if preserve_tos {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 });
                    self.mark_unwind_no_location(*loc);
                }
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopTop); // exc_value
                self.mark_unwind_no_location(*loc);
                if preserve_tos {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 });
                    self.mark_unwind_no_location(*loc);
                }
                self.set_unwind_source_range(*loc);
                emit!(self, PseudoInstruction::PopBlock);
                self.mark_unwind_no_location(*loc);
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopExcept);
                self.mark_unwind_no_location(*loc);
            }

            FBlockType::With | FBlockType::AsyncWith => {
                // Stack: [..., exit_func, self_exit, return_value (if preserve_tos)]
                // CPython codegen_unwind_fblock() assigns *ploc = info->fb_loc
                // for WITH/ASYNC_WITH cleanup and then makes following unwind
                // instructions artificial with *ploc = NO_LOCATION.
                *loc = Some(info.fb_range);
                self.set_unwind_source_range(*loc);
                emit!(self, PseudoInstruction::PopBlock);

                if preserve_tos {
                    // Rotate return value below the exit pair
                    // [exit_func, self_exit, value] → [value, exit_func, self_exit]
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 3 }); // [value, self_exit, exit_func]
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 }); // [value, exit_func, self_exit]
                }

                self.set_unwind_source_range(*loc);
                self.compile_call_exit_with_nones();

                // For async with, await the result
                if matches!(info.fb_type, FBlockType::AsyncWith) {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::GetAwaitable { r#where: 2 });
                    self.set_unwind_source_range(*loc);
                    self.emit_load_const(ConstantData::None);
                    let _ = self.compile_yield_from_sequence(true);
                }

                // Pop the __exit__ result
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopTop);
                *loc = None;
            }

            FBlockType::HandlerCleanup => {
                // codegen_unwind_fblock(HANDLER_CLEANUP)
                if let FBlockDatum::ExceptionName(_) = info.fb_datum {
                    // Named handler: PopBlock for inner SETUP_CLEANUP
                    self.set_unwind_source_range(*loc);
                    emit!(self, PseudoInstruction::PopBlock);
                    self.mark_unwind_no_location(*loc);
                }
                if preserve_tos {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 });
                    self.mark_unwind_no_location(*loc);
                }
                // PopBlock for outer SETUP_CLEANUP (ExceptionHandler)
                self.set_unwind_source_range(*loc);
                emit!(self, PseudoInstruction::PopBlock);
                self.mark_unwind_no_location(*loc);
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopExcept);
                self.mark_unwind_no_location(*loc);

                // If there's an exception name, clean it up
                if let FBlockDatum::ExceptionName(ref name) = info.fb_datum {
                    self.set_unwind_source_range(*loc);
                    self.emit_load_const(ConstantData::None);
                    self.mark_unwind_no_location(*loc);
                    self.set_unwind_source_range(*loc);
                    self.store_name(name)?;
                    self.mark_unwind_no_location(*loc);
                    self.set_unwind_source_range(*loc);
                    self.compile_name(name, NameUsage::Delete)?;
                    self.mark_unwind_no_location(*loc);
                }
            }

            FBlockType::PopValue => {
                if preserve_tos {
                    self.set_unwind_source_range(*loc);
                    emit!(self, Instruction::Swap { i: 2 });
                    self.mark_unwind_no_location(*loc);
                }
                self.set_unwind_source_range(*loc);
                emit!(self, Instruction::PopTop);
                self.mark_unwind_no_location(*loc);
            }
        }
        Ok(())
    }

    /// Unwind the fblock stack, emitting cleanup code for each block
    /// preserve_tos: if true, preserve the top of stack (e.g., return value)
    /// stop_at_loop: if true, stop when encountering a loop (for break/continue)
    fn unwind_fblock_stack(
        &mut self,
        preserve_tos: bool,
        stop_at_loop: bool,
    ) -> CompileResult<Option<TextRange>> {
        let (unwind_loc, _loop_fblock) =
            self.unwind_fblock_stack_with_loop(preserve_tos, stop_at_loop)?;
        Ok(unwind_loc)
    }

    /// CPython `codegen_unwind_fblock_stack()`: unwind frame blocks and, when
    /// requested by break/continue codegen, return the first loop fblock instead
    /// of unwinding it.
    fn unwind_fblock_stack_with_loop(
        &mut self,
        preserve_tos: bool,
        stop_at_loop: bool,
    ) -> CompileResult<(Option<TextRange>, Option<FBlockInfo>)> {
        let mut unwind_loc = Some(self.current_source_range);
        let loop_fblock =
            self.unwind_fblock_stack_inner(preserve_tos, stop_at_loop, &mut unwind_loc)?;
        Ok((unwind_loc, loop_fblock))
    }

    fn unwind_fblock_stack_inner(
        &mut self,
        preserve_tos: bool,
        stop_at_loop: bool,
        unwind_loc: &mut Option<TextRange>,
    ) -> CompileResult<Option<FBlockInfo>> {
        let Some(top) = self.current_code_info().fblock.last().cloned() else {
            return Ok(None);
        };
        if matches!(top.fb_type, FBlockType::ExceptionGroupHandler) {
            return Err(self.error_optional_range(
                CodegenErrorType::BreakContinueReturnInExceptStar,
                *unwind_loc,
            ));
        }
        if stop_at_loop && matches!(top.fb_type, FBlockType::WhileLoop | FBlockType::ForLoop) {
            return Ok(Some(top));
        }

        let copy = self
            .current_code_info()
            .fblock
            .pop()
            .expect("fblock stack underflow");
        self.unwind_fblock(&copy, preserve_tos, unwind_loc)?;
        let loop_fblock = self.unwind_fblock_stack_inner(preserve_tos, stop_at_loop, unwind_loc)?;
        self.restore_fblock_info(copy)?;
        Ok(loop_fblock)
    }

    // could take impl Into<Cow<str>>, but everything is borrowed from ast structs; we never
    // actually have a `String` to pass
    fn name(&mut self, name: &str) -> bytecode::NameIdx {
        self._name_inner(name, |i| &mut i.metadata.names)
    }

    fn varname(&mut self, name: &str) -> oparg::VarNum {
        // NOTE: __debug__ checks are now handled in symboltable phase
        oparg::VarNum::from_u32(self._name_inner(name, |i| &mut i.metadata.varnames))
    }

    fn _name_inner(
        &mut self,
        name: &str,
        cache: impl FnOnce(&mut ir::CodeInfo) -> &mut IndexSet<String>,
    ) -> u32 {
        let name = self.mangle(name);
        let cache = cache(self.current_code_info());
        cache
            .get_index_of(name.as_ref())
            .unwrap_or_else(|| cache.insert_full(name.into_owned()).0)
            .to_u32()
    }

    /// Set the qualified name for the current code object
    // = compiler_set_qualname
    fn set_qualname(&mut self) -> String {
        let qualname = self.make_qualname();
        self.current_code_info().metadata.qualname = Some(qualname.clone());
        qualname
    }
    fn make_qualname(&mut self) -> String {
        let stack_size = self.code_stack.len();
        assert!(stack_size >= 1);

        let current_obj_name = self.current_code_info().metadata.name.clone();

        // If we're at the module level (stack_size == 1), qualname is just the name
        if stack_size <= 1 {
            return current_obj_name;
        }

        // Check parent scope
        let mut parent_idx = stack_size - 2;
        let mut parent = &self.code_stack[parent_idx];

        let mut parent_scope = self
            .symbol_table_stack
            .get(parent_idx)
            .map(|table| table.typ);

        // CPython skips both generic-parameter scopes and annotation scopes
        // when building qualnames for the contained function/class code object.
        if matches!(
            parent_scope,
            Some(
                CompilerScope::TypeParams
                    | CompilerScope::Annotation
                    | CompilerScope::TypeAlias
                    | CompilerScope::TypeVariable,
            )
        ) || parent.metadata.name.starts_with("<generic parameters of ")
        {
            if stack_size == 2 {
                // If we're immediately within the module, qualname is just the name
                return current_obj_name;
            }
            // Use grandparent
            parent_idx = stack_size - 3;
            parent = &self.code_stack[parent_idx];
            parent_scope = self
                .symbol_table_stack
                .get(parent_idx)
                .map(|table| table.typ);
        }

        // Check if this is a global class/function.
        // CPython compiler_set_qualname() only applies this GLOBAL_EXPLICIT
        // shortcut to function, async-function, and class scopes. Annotation
        // scopes, including type-alias value scopes, still inherit the parent
        // function's .<locals> qualname.
        let mut force_global = false;
        let current_scope = self
            .code_stack
            .last()
            .map(|code| self.symbol_table_stack[code.symbol_table_index].typ);
        if matches!(
            current_scope,
            Some(CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Class)
        ) {
            if stack_size > self.symbol_table_stack.len() {
                // We might be in a situation where symbol table isn't pushed yet
                // In this case, check the parent symbol table
                if let Some(parent_table) = self.symbol_table_stack.last()
                    && let Some(symbol) = parent_table.lookup(&current_obj_name)
                    && symbol.scope == SymbolScope::GlobalExplicit
                {
                    force_global = true;
                }
            } else if let Some(_current_table) = self.symbol_table_stack.last() {
                // Mangle the name if necessary (for private names in classes)
                let mangled_name = self.mangle(&current_obj_name);

                // Look up in parent symbol table to check scope
                if self.symbol_table_stack.len() >= 2 {
                    let parent_table = &self.symbol_table_stack[self.symbol_table_stack.len() - 2];
                    if let Some(symbol) = parent_table.lookup(&mangled_name)
                        && symbol.scope == SymbolScope::GlobalExplicit
                    {
                        force_global = true;
                    }
                }
            }
        }

        // Build the qualified name
        if force_global {
            // For global symbols, qualname is just the name
            current_obj_name
        } else {
            // Check parent scope type
            let parent_obj_name = &parent.metadata.name;

            // Determine if parent is a function-like scope
            let is_function_parent = matches!(
                parent_scope,
                Some(
                    CompilerScope::Function | CompilerScope::AsyncFunction | CompilerScope::Lambda
                )
            );

            if is_function_parent {
                // For functions, append .<locals> to parent qualname
                // Use parent's qualname if available, otherwise use parent_obj_name
                let parent_qualname = parent.metadata.qualname.as_ref().unwrap_or(parent_obj_name);
                format!("{parent_qualname}.<locals>.{current_obj_name}")
            } else {
                // For classes and other scopes, use parent's qualname directly
                // Use parent's qualname if available, otherwise use parent_obj_name
                let parent_qualname = parent.metadata.qualname.as_ref().unwrap_or(parent_obj_name);
                if parent_qualname == "<module>" {
                    // Module level, just use the name
                    current_obj_name
                } else {
                    // Concatenate parent qualname with current name
                    format!("{parent_qualname}.{current_obj_name}")
                }
            }
        }
    }

    fn compile_program(
        &mut self,
        body: &ast::ModModule,
        symbol_table: SymbolTable,
    ) -> CompileResult<()> {
        let size_before = self.code_stack.len();
        // Set future_annotations from symbol table (detected during symbol table scan)
        self.future_annotations = symbol_table.future_annotations;
        let future_features = self.future_features;
        self.current_code_info().flags |= future_features;
        if self.future_annotations {
            self.future_features
                .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        }
        if symbol_table.is_coroutine {
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::COROUTINE);
        }

        // Module-level __conditional_annotations__ cell
        let has_module_cond_ann = Self::scope_needs_conditional_annotations_cell(&symbol_table);
        if has_module_cond_ann {
            self.current_code_info()
                .metadata
                .cellvars
                .insert("__conditional_annotations__".to_string());
        }

        self.symbol_table_stack.push(symbol_table);

        self.emit_resume_for_scope(CompilerScope::Module, 1);
        emit!(self, PseudoInstruction::AnnotationsPlaceholder);

        let (doc, statements) = split_doc_with_range(&body.body, &self.opts);
        let module_start_loc = self.module_start_location(&body.body);
        let annotations_used = self.current_symbol_table().annotations_used;
        // Handle annotation bookkeeping before the docstring assignment, as
        // codegen_body() does after _PyCodegen_Module() inserts the prefix set.
        if Self::scope_needs_conditional_annotations_cell(self.current_symbol_table()) {
            self.set_source_range(module_start_loc);
            emit!(self, Instruction::BuildSet { count: 0 });
            self.store_name("__conditional_annotations__")?;
        }

        if self.future_annotations && annotations_used {
            self.set_source_range(module_start_loc);
            emit!(self, Instruction::SetupAnnotations);
        }

        if let Some((value, range)) = doc {
            let saved_range = self.current_source_range;
            self.set_source_range(range);
            self.emit_load_const(ConstantData::Str {
                value: value.into(),
            });
            let doc = self.name("__doc__");
            emit!(self, Instruction::StoreName { namei: doc });
            self.set_no_location();
            self.set_source_range(saved_range);
        }

        // Compile all statements
        self.compile_statements(statements)?;

        if annotations_used && !self.future_annotations {
            self.compile_module_annotation_setup_sequence(statements, module_start_loc)?;
        }

        assert_eq!(self.code_stack.len(), size_before);

        // Match _PyCodegen_AddReturnAtEnd(): implicit scope epilogues start
        // without a source location and receive one later via CFG line
        // propagation.
        self.emit_return_const_no_location(ConstantData::None);
        Ok(())
    }

    fn compile_program_single(
        &mut self,
        body: &[ast::Stmt],
        symbol_table: SymbolTable,
    ) -> CompileResult<()> {
        self.interactive = true;
        // Set future_annotations from symbol table (detected during symbol table scan)
        self.future_annotations = symbol_table.future_annotations;
        let future_features = self.future_features;
        self.current_code_info().flags |= future_features;
        if self.future_annotations {
            self.future_features
                .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        }
        if symbol_table.is_coroutine {
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::COROUTINE);
        }
        self.symbol_table_stack.push(symbol_table);
        let module_start_loc = self.module_start_location(body);

        self.emit_resume_for_scope(CompilerScope::Module, 1);
        emit!(self, PseudoInstruction::AnnotationsPlaceholder);

        let annotations_used = self.current_symbol_table().annotations_used;
        // Handle annotations based on future_annotations flag
        if self.current_symbol_table().has_conditional_annotations {
            self.set_source_range(module_start_loc);
            emit!(self, Instruction::BuildSet { count: 0 });
            self.store_name("__conditional_annotations__")?;
        }

        if self.future_annotations && annotations_used {
            self.set_source_range(module_start_loc);
            // PEP 563: Initialize __annotations__ dict
            emit!(self, Instruction::SetupAnnotations);
        }

        self.compile_statements(body)?;

        if annotations_used && !self.future_annotations {
            self.compile_module_annotation_setup_sequence(body, module_start_loc)?;
        }

        self.emit_return_const_no_location(ConstantData::None);
        Ok(())
    }

    fn compile_block_expr(
        &mut self,
        body: &[ast::Stmt],
        symbol_table: SymbolTable,
    ) -> CompileResult<()> {
        let future_features = self.future_features;
        self.current_code_info().flags |= future_features;
        if symbol_table.is_coroutine {
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::COROUTINE);
        }
        self.symbol_table_stack.push(symbol_table);
        self.emit_resume_for_scope(CompilerScope::Module, 1);

        if let Some((last_statement, statements)) = body.split_last() {
            self.compile_statements(statements)?;
            match last_statement {
                ast::Stmt::Expr(ast::StmtExpr { value, .. }) => {
                    self.compile_expression(value)?;
                }
                ast::Stmt::FunctionDef(ast::StmtFunctionDef {
                    name,
                    parameters,
                    body,
                    decorator_list,
                    returns,
                    type_params,
                    is_async,
                    ..
                }) => {
                    validate_duplicate_params(parameters).map_err(|e| self.error(e))?;
                    self.compile_function_def(
                        name.as_str(),
                        parameters,
                        body,
                        decorator_list,
                        returns.as_deref(),
                        *is_async,
                        type_params.as_deref(),
                        true,
                    )?;
                }
                ast::Stmt::ClassDef(ast::StmtClassDef {
                    name,
                    body,
                    decorator_list,
                    type_params,
                    arguments,
                    ..
                }) => {
                    self.compile_class_def(
                        name.as_str(),
                        body,
                        decorator_list,
                        type_params.as_deref(),
                        arguments.as_deref(),
                        true,
                    )?;
                }
                _ => {
                    self.compile_statement(last_statement)?;
                    self.emit_load_const(ConstantData::None);
                }
            }
        } else {
            self.emit_load_const(ConstantData::None);
        }
        self.emit_return_value();

        Ok(())
    }

    // Compile statement in eval mode:
    fn compile_eval(
        &mut self,
        expression: &ast::ModExpression,
        symbol_table: SymbolTable,
    ) -> CompileResult<()> {
        let future_features = self.future_features;
        self.current_code_info().flags |= future_features;
        if symbol_table.is_coroutine {
            self.current_code_info()
                .flags
                .insert(bytecode::CodeFlags::COROUTINE);
        }
        self.symbol_table_stack.push(symbol_table);
        self.emit_resume_for_scope(CompilerScope::Module, 1);

        self.compile_expression(&expression.body)?;
        self.emit_return_value();
        Ok(())
    }

    fn compile_statements(&mut self, statements: &[ast::Stmt]) -> CompileResult<()> {
        for statement in statements {
            self.compile_statement(statement)?;
        }
        Ok(())
    }

    fn compile_with_body_statements(&mut self, statements: &[ast::Stmt]) -> CompileResult<()> {
        for statement in statements {
            self.compile_statement(statement)?;
        }
        Ok(())
    }

    /// CPython `codegen_call_exit_with_nones()`.
    fn compile_call_exit_with_nones(&mut self) {
        self.emit_load_const(ConstantData::None);
        self.emit_load_const(ConstantData::None);
        self.emit_load_const(ConstantData::None);
        emit!(self, Instruction::Call { argc: 3 });
    }

    /// CPython `codegen_with_except_finish()`.
    fn compile_with_except_finish(&mut self, cleanup_block: BlockIdx) {
        let suppress_block = self.new_block();

        emit!(self, Instruction::ToBool);
        self.set_no_location();
        emit!(
            self,
            Instruction::PopJumpIfTrue {
                delta: suppress_block
            }
        );
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 2 });
        self.set_no_location();

        self.use_cpython_label_block(suppress_block);
        emit!(self, Instruction::PopTop);
        self.set_no_location();
        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::PopTop);
        self.set_no_location();
        emit!(self, Instruction::PopTop);
        self.set_no_location();
        emit!(self, Instruction::PopTop);
        self.set_no_location();
        let exit_block = self.new_block();
        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: exit_block }
        );
        self.set_no_location();

        self.use_cpython_label_block(cleanup_block);
        emit!(self, Instruction::Copy { i: 3 });
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 1 });
        self.set_no_location();

        self.use_cpython_label_block(exit_block);
    }

    fn compile_loop_body_statements(&mut self, statements: &[ast::Stmt]) -> CompileResult<()> {
        self.compile_statements(statements)
    }

    fn scope_needs_conditional_annotations_cell(symbol_table: &SymbolTable) -> bool {
        match symbol_table.typ {
            CompilerScope::Module | CompilerScope::Class => {
                symbol_table.has_conditional_annotations
            }
            _ => false,
        }
    }

    fn load_name(&mut self, name: &str) -> CompileResult<()> {
        self.compile_name(name, NameUsage::Load)
    }

    fn store_name(&mut self, name: &str) -> CompileResult<()> {
        self.compile_name(name, NameUsage::Store)
    }

    fn emit_no_location_exception_name_cleanup(&mut self, name: &str) -> CompileResult<()> {
        // CPython codegen_try_except() emits `name = None; del name`
        // with NO_LOCATION for `except ... as name` cleanup.
        self.emit_load_const(ConstantData::None);
        self.set_no_location();
        self.store_name(name)?;
        self.set_no_location();
        self.compile_name(name, NameUsage::Delete)?;
        self.set_no_location();
        Ok(())
    }

    fn mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
        // Use private from current code unit for name mangling
        let private = self
            .code_stack
            .last()
            .and_then(|info| info.private.as_deref());
        let mangled_names = self.current_symbol_table().mangled_names.as_ref();
        symboltable::maybe_mangle_name(private, mangled_names, name)
    }

    fn module_name_declared_global_in_nested_scope(table: &SymbolTable, name: &str) -> bool {
        table.sub_tables.iter().any(|subtable| {
            (!subtable.comp_inlined
                && subtable
                    .lookup(name)
                    .is_some_and(|symbol| symbol.scope == SymbolScope::GlobalExplicit))
                || Self::module_name_declared_global_in_nested_scope(subtable, name)
        })
    }

    // = compiler_nameop
    fn compile_name(&mut self, name: &str, usage: NameUsage) -> CompileResult<()> {
        enum NameOp {
            Fast,
            Global,
            Deref,
            Name,
            DictOrGlobals, // PEP 649: can_see_class_scope
        }

        let name = self.mangle(name);

        // Special handling for __debug__
        if NameUsage::Load == usage && name == "__debug__" {
            self.emit_load_const(ConstantData::Boolean {
                value: self.opts.optimize == 0,
            });
            return Ok(());
        }

        // Determine the operation type based on symbol scope
        let is_function_like = self.ctx.in_func();

        // Look up the symbol, handling ast::TypeParams and Annotation scopes specially
        let (symbol_scope, can_see_class_scope, class_declared_global) = {
            let current_idx = self.symbol_table_stack.len() - 1;
            let current_table = &self.symbol_table_stack[current_idx];
            let is_typeparams = current_table.typ == CompilerScope::TypeParams;
            let is_annotation = matches!(
                current_table.typ,
                CompilerScope::Annotation | CompilerScope::TypeAlias | CompilerScope::TypeVariable
            );
            let can_see_class = current_table.can_see_class_scope;

            // First try to find in current table
            let symbol = current_table.lookup(name.as_ref());

            // If not found and we're in ast::TypeParams or Annotation scope, try parent scope
            let symbol = if symbol.is_none() && (is_typeparams || is_annotation) {
                self.symbol_table_stack
                    .get(self.symbol_table_stack.len() - 2) // Try to get parent index
                    .expect("Symbol has no parent! This is a compiler bug.")
                    .lookup(name.as_ref())
            } else {
                symbol
            };
            let class_declared_global = can_see_class
                && self.symbol_table_stack[..current_idx]
                    .iter()
                    .rev()
                    .find(|table| table.typ == CompilerScope::Class)
                    .and_then(|table| table.lookup(name.as_ref()))
                    .is_some_and(|symbol| symbol.flags.contains(SymbolFlags::DEF_GLOBAL));

            (
                symbol.map(|s| s.scope),
                can_see_class,
                class_declared_global,
            )
        };

        // Special handling for class scope implicit cell variables
        // These are treated as Cell even if not explicitly marked in symbol table
        // __class__ and __classdict__: only LOAD uses Cell (stores go to class namespace)
        // __conditional_annotations__: both LOAD and STORE use Cell (it's a mutable set
        // that the annotation scope accesses through the closure)
        let symbol_scope = {
            let current_table = self.current_symbol_table();
            if current_table.typ == CompilerScope::Class
                && !self.current_code_info().in_inlined_comp
                && ((usage == NameUsage::Load
                    && (name == "__class__"
                        || name == "__classdict__"
                        || name == "__conditional_annotations__"))
                    || (name == "__conditional_annotations__" && usage == NameUsage::Store))
            {
                Some(SymbolScope::Cell)
            } else {
                symbol_scope
            }
        };

        // In annotation or type params scope, missing symbols are treated as global implicit
        // This allows referencing global names like Union, Optional, etc. that are imported
        // at module level but not explicitly bound in the function scope
        let actual_scope = match symbol_scope {
            Some(scope) => scope,
            None => {
                let current_table = self.current_symbol_table();
                if matches!(
                    current_table.typ,
                    CompilerScope::Annotation
                        | CompilerScope::TypeAlias
                        | CompilerScope::TypeVariable
                        | CompilerScope::TypeParams
                ) {
                    SymbolScope::GlobalImplicit
                } else if matches!(
                    name.as_ref(),
                    "__name__"
                        | "__module__"
                        | "__qualname__"
                        | "__firstlineno__"
                        | "__doc__"
                        | "__static_attributes__"
                        | "__classdictcell__"
                        | "__classcell__"
                ) {
                    SymbolScope::Unknown
                } else {
                    return Err(self.error(CodegenErrorType::SyntaxError(format!(
                        "the symbol '{name}' must be present in the symbol table"
                    ))));
                }
            }
        };

        let module_global_from_nested_scope = {
            let current_table = self.current_symbol_table();
            current_table.typ == CompilerScope::Module
                && Self::module_name_declared_global_in_nested_scope(current_table, name.as_ref())
        };

        // Determine operation type based on scope
        let op_type = match actual_scope {
            SymbolScope::Free => NameOp::Deref,
            SymbolScope::Cell => NameOp::Deref,
            SymbolScope::Local => {
                if module_global_from_nested_scope {
                    NameOp::Global
                } else if is_function_like
                    || self
                        .current_code_info()
                        .metadata
                        .fast_hidden
                        .get(name.as_ref())
                        .is_some_and(|&hidden| hidden)
                {
                    NameOp::Fast
                } else {
                    NameOp::Name
                }
            }
            SymbolScope::GlobalImplicit => {
                // PEP 649: In annotation scope with class visibility, use DictOrGlobals
                // to check classdict first before globals
                if class_declared_global {
                    NameOp::Global
                } else if can_see_class_scope && usage == NameUsage::Load {
                    NameOp::DictOrGlobals
                } else if is_function_like {
                    NameOp::Global
                } else {
                    NameOp::Name
                }
            }
            SymbolScope::GlobalExplicit => {
                // A global declared in the owning class body must bypass the
                // classdict, but an explicit global inherited from an outer
                // function still participates in DictOrGlobals lookup.
                if can_see_class_scope && !class_declared_global && usage == NameUsage::Load {
                    NameOp::DictOrGlobals
                } else {
                    NameOp::Global
                }
            }
            SymbolScope::Unknown => {
                if module_global_from_nested_scope {
                    NameOp::Global
                } else {
                    NameOp::Name
                }
            }
        };

        // Generate appropriate instructions based on operation type
        match op_type {
            NameOp::Deref => {
                let i = match actual_scope {
                    SymbolScope::Free => self.get_free_var_index(&name),
                    SymbolScope::Cell => self.get_cell_var_index(&name),
                    _ => unreachable!("Invalid scope for Deref operation"),
                };

                match usage {
                    NameUsage::Load => {
                        // ClassBlock (not inlined comp): LOAD_LOCALS first, then LOAD_FROM_DICT_OR_DEREF
                        if self.ctx.in_class
                            && !self.ctx.in_func()
                            && !self.current_code_info().in_inlined_comp
                        {
                            emit!(self, Instruction::LoadLocals);
                            emit!(self, Instruction::LoadFromDictOrDeref { i });
                        // can_see_class_scope: LOAD_DEREF(__classdict__) first
                        } else if can_see_class_scope {
                            let classdict_idx = self.get_free_var_index("__classdict__");
                            emit!(self, Instruction::LoadDeref { i: classdict_idx });
                            emit!(self, Instruction::LoadFromDictOrDeref { i });
                        } else {
                            emit!(self, Instruction::LoadDeref { i });
                        }
                    }
                    NameUsage::Store => emit!(self, Instruction::StoreDeref { i }),
                    NameUsage::Delete => emit!(self, Instruction::DeleteDeref { i }),
                };
            }
            NameOp::Fast => {
                let var_num = self.get_local_var_index(&name);
                match usage {
                    NameUsage::Load => emit!(self, Instruction::LoadFast { var_num }),
                    NameUsage::Store => emit!(self, Instruction::StoreFast { var_num }),
                    NameUsage::Delete => emit!(self, Instruction::DeleteFast { var_num }),
                };
            }
            NameOp::Global => {
                let namei = self.get_global_name_index(&name);
                match usage {
                    NameUsage::Load => {
                        self.emit_load_global(namei, false);
                        return Ok(());
                    }
                    NameUsage::Store => emit!(self, Instruction::StoreGlobal { namei }),
                    NameUsage::Delete => emit!(self, Instruction::DeleteGlobal { namei }),
                };
            }
            NameOp::Name => {
                let namei = self.get_global_name_index(&name);
                match usage {
                    NameUsage::Load => {
                        if self.current_symbol_table().typ == CompilerScope::Class
                            && self.current_code_info().in_inlined_comp
                        {
                            self.emit_load_global(namei, false);
                        } else {
                            emit!(self, Instruction::LoadName { namei });
                        }
                    }
                    NameUsage::Store => emit!(self, Instruction::StoreName { namei }),
                    NameUsage::Delete => emit!(self, Instruction::DeleteName { namei }),
                };
            }
            NameOp::DictOrGlobals => {
                // PEP 649: First check classdict (from __classdict__ freevar), then globals
                let idx = self.get_global_name_index(&name);
                debug_assert!(usage == NameUsage::Load);
                let classdict_idx = self.get_free_var_index("__classdict__");
                emit!(self, Instruction::LoadDeref { i: classdict_idx });
                emit!(self, Instruction::LoadFromDictOrGlobals { i: idx });
            }
        }

        Ok(())
    }

    fn compile_statement(&mut self, statement: &ast::Stmt) -> CompileResult<()> {
        trace!("Compiling {statement:?}");
        let prev_source_range = self.current_source_range;
        self.set_source_range(statement.range());

        match &statement {
            // we do this here because `from __future__` still executes that `from` statement at runtime,
            // we still need to compile the ImportFrom down below
            ast::Stmt::ImportFrom(ast::StmtImportFrom {
                module,
                names,
                level,
                ..
            }) if *level == 0 && module.as_ref().map(|id| id.as_str()) == Some("__future__") => {
                self.compile_future_features(names)?
            }
            // ignore module-level doc comments
            ast::Stmt::Expr(ast::StmtExpr { value, .. })
                if is_docstring_expr(value)
                    && matches!(self.done_with_future_stmts, DoneWithFuture::No) =>
            {
                self.done_with_future_stmts = DoneWithFuture::DoneWithDoc
            }
            // if we find any other statement, stop accepting future statements
            _ => self.done_with_future_stmts = DoneWithFuture::Yes,
        }

        match &statement {
            ast::Stmt::Import(ast::StmtImport { names, .. }) => {
                // import a, b, c as d
                for name in names {
                    let name = &name;
                    self.emit_load_const(ConstantData::Integer {
                        value: num_traits::Zero::zero(),
                    });
                    self.emit_load_const(ConstantData::None);
                    let namei = self.name(&name.name);
                    emit!(self, Instruction::ImportName { namei });
                    if let Some(alias) = &name.asname {
                        let parts: Vec<&str> = name.name.split('.').skip(1).collect();
                        for (i, part) in parts.iter().enumerate() {
                            let namei = self.name(part);
                            emit!(self, Instruction::ImportFrom { namei });
                            if i < parts.len() - 1 {
                                emit!(self, Instruction::Swap { i: 2 });
                                emit!(self, Instruction::PopTop);
                            }
                        }
                        self.store_name(alias.as_str())?;
                        if !parts.is_empty() {
                            emit!(self, Instruction::PopTop);
                        }
                    } else {
                        self.store_name(name.name.split('.').next().unwrap())?
                    }
                }
            }
            ast::Stmt::ImportFrom(ast::StmtImportFrom {
                level,
                module,
                names,
                ..
            }) => {
                let import_star = names.first().is_some_and(|n| &n.name == "*");

                let from_list = names
                    .iter()
                    .map(|n| ConstantData::Str {
                        value: n.name.as_str().into(),
                    })
                    .collect();

                // from .... import (*fromlist)
                self.emit_load_const(ConstantData::Integer {
                    value: (*level).into(),
                });
                self.emit_load_const(ConstantData::Tuple {
                    elements: from_list,
                });

                let module_name = module.as_ref().map_or("", |s| s.as_str());
                let module_idx = self.name(module_name);
                emit!(self, Instruction::ImportName { namei: module_idx });

                if import_star {
                    // from .... import *
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::ImportStar
                        }
                    );
                    emit!(self, Instruction::PopTop);
                    self.set_no_location();
                } else {
                    // from mod import a, b as c

                    for name in names {
                        let name = &name;
                        let idx = self.name(name.name.as_str());
                        // import symbol from module:
                        emit!(self, Instruction::ImportFrom { namei: idx });

                        // Store module under proper name:
                        if let Some(alias) = &name.asname {
                            self.store_name(alias.as_str())?
                        } else {
                            self.store_name(name.name.as_str())?
                        }
                    }

                    // Pop module from stack:
                    emit!(self, Instruction::PopTop);
                }
            }
            ast::Stmt::Expr(ast::StmtExpr { value, .. }) => {
                // Optimize away constant expressions with no side effects.
                // In interactive mode, always compile (to print the result).
                let dominated_by_interactive =
                    self.interactive && !self.ctx.in_func() && !self.ctx.in_class;
                if !dominated_by_interactive && value.is_constant() {
                    emit!(self, Instruction::Nop);
                } else {
                    self.compile_expression(value)?;

                    if dominated_by_interactive {
                        emit!(
                            self,
                            Instruction::CallIntrinsic1 {
                                func: bytecode::IntrinsicFunction1::Print
                            }
                        );
                    }

                    emit!(self, Instruction::PopTop);
                    self.set_no_location();
                }
            }
            ast::Stmt::Global(_) | ast::Stmt::Nonlocal(_) => {
                // Handled during symbol table construction.
            }
            ast::Stmt::If(ast::StmtIf {
                test,
                body,
                elif_else_clauses,
                ..
            }) => {
                self.enter_conditional_block();
                self.compile_if(test, body, elif_else_clauses, statement.range())?;
                self.leave_conditional_block();
                self.set_source_range(statement.range());
            }
            ast::Stmt::While(ast::StmtWhile {
                test,
                body,
                orelse,
                range,
                ..
            }) => self.compile_while(test, body, orelse, *range)?,
            ast::Stmt::With(ast::StmtWith {
                items,
                body,
                is_async,
                ..
            }) => self.compile_with(items, body, *is_async)?,
            ast::Stmt::For(ast::StmtFor {
                target,
                iter,
                body,
                orelse,
                is_async,
                range,
                ..
            }) => self.compile_for(target, iter, body, orelse, *is_async, *range)?,
            ast::Stmt::Match(ast::StmtMatch { subject, cases, .. }) => {
                self.compile_match(subject, cases)?
            }
            ast::Stmt::Raise(ast::StmtRaise {
                exc, cause, range, ..
            }) => {
                let kind = match exc {
                    Some(value) => {
                        self.compile_expression(value)?;
                        match cause {
                            Some(cause) => {
                                self.compile_expression(cause)?;
                                bytecode::RaiseKind::RaiseCause
                            }
                            None => bytecode::RaiseKind::Raise,
                        }
                    }
                    None => bytecode::RaiseKind::BareRaise,
                };
                self.set_source_range(*range);
                emit!(self, Instruction::RaiseVarargs { argc: kind });
            }
            ast::Stmt::Try(ast::StmtTry {
                body,
                handlers,
                orelse,
                finalbody,
                is_star,
                ..
            }) => {
                self.enter_conditional_block();
                if *is_star {
                    self.compile_try_star_statement(body, handlers, orelse, finalbody)?
                } else {
                    self.compile_try_statement(body, handlers, orelse, finalbody)?
                }
                self.leave_conditional_block();
            }
            ast::Stmt::FunctionDef(ast::StmtFunctionDef {
                name,
                parameters,
                body,
                decorator_list,
                returns,
                type_params,
                is_async,
                ..
            }) => {
                validate_duplicate_params(parameters).map_err(|e| self.error(e))?;

                self.compile_function_def(
                    name.as_str(),
                    parameters,
                    body,
                    decorator_list,
                    returns.as_deref(),
                    *is_async,
                    type_params.as_deref(),
                    false,
                )?
            }
            ast::Stmt::ClassDef(ast::StmtClassDef {
                name,
                body,
                decorator_list,
                type_params,
                arguments,
                ..
            }) => self.compile_class_def(
                name.as_str(),
                body,
                decorator_list,
                type_params.as_deref(),
                arguments.as_deref(),
                false,
            )?,
            ast::Stmt::Assert(assert_stmt) => {
                let ast::StmtAssert {
                    test, msg, range, ..
                } = assert_stmt;
                self.check_assert(assert_stmt)?;
                // if some flag, ignore all assert statements!
                if self.opts.optimize == 0 {
                    let after_block = self.new_block();
                    self.compile_jump_if_inner(test, true, after_block, Some(*range))?;
                    self.set_source_range(*range);
                    emit!(
                        self,
                        Instruction::LoadCommonConstant {
                            idx: bytecode::CommonConstant::AssertionError
                        }
                    );
                    if let Some(e) = msg {
                        self.compile_expression(e)?;
                        self.set_source_range(*range);
                        emit!(self, Instruction::Call { argc: 0 });
                    }
                    self.set_source_range(test.range());
                    emit!(
                        self,
                        Instruction::RaiseVarargs {
                            argc: bytecode::RaiseKind::Raise,
                        }
                    );
                    self.use_cpython_label_block(after_block);
                } else {
                    // Optimized-out asserts still need to consume any nested
                    // scope symbol tables they contain so later nested scopes
                    // stay aligned with AST traversal order.
                    self.consume_skipped_nested_scopes_in_expr(test)?;
                    if let Some(expr) = msg {
                        self.consume_skipped_nested_scopes_in_expr(expr)?;
                    }
                }
            }
            ast::Stmt::Break(_) => {
                // Unwind fblock stack until we find a loop, emitting cleanup for each fblock
                self.compile_break_continue(statement.range(), true)?;
            }
            ast::Stmt::Continue(_) => {
                // Unwind fblock stack until we find a loop, emitting cleanup for each fblock
                self.compile_break_continue(statement.range(), false)?;
            }
            ast::Stmt::Return(ast::StmtReturn { value, .. }) => {
                if !self.ctx.in_func() {
                    return Err(
                        self.error_ranged(CodegenErrorType::InvalidReturn, statement.range())
                    );
                }

                let prev_source_range = self.current_source_range;
                let stmt_range = statement.range();
                match value {
                    Some(v) => {
                        if self.ctx.func == FunctionContext::AsyncFunction
                            && self.current_symbol_table().is_generator
                        {
                            return Err(self.error_ranged(
                                CodegenErrorType::AsyncReturnValue,
                                statement.range(),
                            ));
                        }
                        let debug_constant = matches!(
                            &**v,
                            ast::Expr::Name(ast::ExprName { id, ctx, .. })
                                if matches!(ctx, ast::ExprContext::Load)
                                    && id.as_str() == "__debug__"
                        );
                        let folded_constant = if self.is_constant_expr(v) || debug_constant {
                            self.try_fold_constant_expr(v)?
                        } else {
                            None
                        };
                        let preserve_tos = folded_constant.is_none();
                        let mut return_range = stmt_range;
                        if preserve_tos {
                            self.compile_expression(v)?;
                        } else {
                            return_range = v.range();
                            self.set_source_range(v.range());
                            emit!(self, Instruction::Nop);
                        }

                        let source = self.source_file.to_source_code();
                        if source.line_index(v.range().start())
                            != source.line_index(stmt_range.start())
                        {
                            return_range = stmt_range;
                            self.set_source_range(stmt_range);
                            emit!(self, Instruction::Nop);
                        }
                        self.set_source_range(return_range);
                        let unwind_loc = self.unwind_fblock_stack(preserve_tos, false)?;
                        if let Some(loc) = unwind_loc {
                            self.set_source_range(loc);
                            match folded_constant {
                                Some(constant) => self.emit_return_const(constant),
                                None => {
                                    self.emit_return_value();
                                }
                            }
                        } else {
                            match folded_constant {
                                Some(constant) => self.emit_return_const_no_location(constant),
                                None => {
                                    self.emit_return_value();
                                    self.set_no_location();
                                }
                            }
                        }
                    }
                    None => {
                        self.set_source_range(stmt_range);
                        emit!(self, Instruction::Nop);
                        // Unwind fblock stack with preserve_tos=false (no value to preserve)
                        let unwind_loc = self.unwind_fblock_stack(false, false)?;
                        if let Some(loc) = unwind_loc {
                            self.set_source_range(loc);
                            self.emit_return_const(ConstantData::None);
                        } else {
                            self.emit_return_const_no_location(ConstantData::None);
                        }
                    }
                }
                self.set_source_range(prev_source_range);
            }
            ast::Stmt::Assign(ast::StmtAssign {
                targets,
                value,
                range,
                ..
            }) => {
                self.compile_expression(value)?;

                for (i, target) in targets.iter().enumerate() {
                    if i + 1 != targets.len() {
                        self.set_source_range(*range);
                        emit!(self, Instruction::Copy { i: 1 });
                    }
                    self.compile_store(target)?;
                }
            }
            ast::Stmt::AugAssign(ast::StmtAugAssign {
                target, op, value, ..
            }) => self.compile_augassign(target, *op, value)?,
            ast::Stmt::AnnAssign(ast::StmtAnnAssign {
                target,
                annotation,
                value,
                simple,
                range,
                ..
            }) => {
                self.compile_annotated_assign(
                    target,
                    annotation,
                    value.as_deref(),
                    *simple,
                    *range,
                )?;
                // Bare annotations in function scope emit no code; restore
                // source range so subsequent instructions keep the correct line.
                if value.is_none() && self.ctx.in_func() {
                    self.set_source_range(prev_source_range);
                }
            }
            ast::Stmt::Delete(ast::StmtDelete { targets, .. }) => {
                for target in targets {
                    self.compile_delete(target)?;
                }
            }
            ast::Stmt::Pass(_) => {
                emit!(self, Instruction::Nop); // NOP for line tracing
            }
            ast::Stmt::TypeAlias(ast::StmtTypeAlias {
                name,
                type_params,
                value,
                range,
                ..
            }) => {
                let Some(name) = name.as_name_expr() else {
                    return Err(self.error(CodegenErrorType::SyntaxError(
                        "type alias expect name".to_owned(),
                    )));
                };
                let name_string = name.id.to_string();

                if let Some(type_params) = type_params {
                    self.set_source_range(*range);
                    self.push_symbol_table()?;
                    let key = self.symbol_table_stack.len() - 1;
                    let lineno = self.get_source_line_number().get().to_u32();
                    let scope_name = format!("<generic parameters of {name_string}>");
                    self.enter_scope(&scope_name, CompilerScope::TypeParams, key, lineno)?;

                    // TypeParams scope is function-like
                    let prev_ctx = self.ctx;
                    self.ctx = CompileContext {
                        in_class: prev_ctx.in_class,
                        func: FunctionContext::Function,
                        in_async_scope: false,
                    };

                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::Str {
                        value: name_string.clone().into(),
                    });
                    self.compile_type_params(type_params)?;
                    self.compile_typealias_value_closure(&name_string, value, *range)?;
                    self.set_source_range(*range);
                    emit!(self, Instruction::BuildTuple { count: 3 });
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::TypeAlias
                        }
                    );
                    emit!(self, Instruction::ReturnValue);

                    let code = self.exit_scope();
                    self.ctx = prev_ctx;
                    self.set_source_range(*range);
                    self.make_closure(code, bytecode::MakeFunctionFlags::new())?;
                    self.set_source_range(*range);
                    emit!(self, Instruction::PushNull);
                    emit!(self, Instruction::Call { argc: 0 });
                } else {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::Str {
                        value: name_string.clone().into(),
                    });
                    self.emit_load_const(ConstantData::None);
                    self.compile_typealias_value_closure(&name_string, value, *range)?;
                    self.set_source_range(*range);
                    emit!(self, Instruction::BuildTuple { count: 3 });
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::TypeAlias
                        }
                    );
                }

                self.set_source_range(*range);
                self.store_name(&name_string)?;
            }
            ast::Stmt::IpyEscapeCommand(stmt) => {
                return Err(self.error_ranged(
                    CodegenErrorType::SyntaxError("invalid syntax".to_owned()),
                    stmt.range,
                ));
            }
        }
        Ok(())
    }

    fn compile_delete(&mut self, expression: &ast::Expr) -> CompileResult<()> {
        let prev_source_range = self.current_source_range;
        self.set_source_range(expression.range());
        let result = (|| -> CompileResult<()> {
            match &expression {
                ast::Expr::Name(ast::ExprName { id, .. }) => {
                    self.compile_name(id.as_str(), NameUsage::Delete)?
                }
                ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
                    self.compile_expression(value)?;
                    let namei = self.name(attr.as_str());
                    self.set_source_range(self.update_start_location_to_match_attr(
                        expression.range(),
                        expression.range(),
                        attr.as_str(),
                    ));
                    emit!(self, Instruction::DeleteAttr { namei });
                }
                ast::Expr::Subscript(ast::ExprSubscript {
                    value, slice, ctx, ..
                }) => {
                    self.compile_subscript(value, slice, *ctx)?;
                }
                ast::Expr::Tuple(ast::ExprTuple { elts, .. })
                | ast::Expr::List(ast::ExprList { elts, .. }) => {
                    for element in elts {
                        self.compile_delete(element)?;
                    }
                }
                ast::Expr::BinOp(_) | ast::Expr::UnaryOp(_) => {
                    return Err(self.error(CodegenErrorType::Delete("expression")));
                }
                _ => return Err(self.error(CodegenErrorType::Delete(expression.python_name()))),
            }
            Ok(())
        })();
        self.set_source_range(prev_source_range);
        result
    }

    fn enter_function(&mut self, name: &str, parameters: &ast::Parameters) -> CompileResult<()> {
        self.push_output(
            bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED,
            parameters.posonlyargs.len().to_u32(),
            parameters.args.len().to_u32(),
            parameters.kwonlyargs.len().to_u32(),
            name,
        )?;

        let args_iter = core::iter::empty()
            .chain(&parameters.posonlyargs)
            .chain(&parameters.args)
            .map(|arg| &arg.parameter)
            .chain(parameters.kwonlyargs.iter().map(|arg| &arg.parameter));
        for name in args_iter {
            self.varname(name.name.as_str());
        }

        if let Some(name) = parameters.vararg.as_deref() {
            self.current_code_info().flags |= bytecode::CodeFlags::VARARGS;
            self.varname(name.name.as_str());
        }
        if let Some(name) = parameters.kwarg.as_deref() {
            self.current_code_info().flags |= bytecode::CodeFlags::VARKEYWORDS;
            self.varname(name.name.as_str());
        }

        Ok(())
    }

    /// Push decorators onto the stack in source order.
    /// For @dec1 @dec2 def foo(): stack becomes [dec1, dec2]
    fn prepare_decorators(&mut self, decorator_list: &[ast::Decorator]) -> CompileResult<()> {
        for decorator in decorator_list {
            self.compile_expression(&decorator.expression)?;
        }
        Ok(())
    }

    /// Apply decorators: each decorator calls the function below it.
    /// Stack: [dec1, dec2, func] → CALL 0 → [dec1, dec2(func)] → CALL 0 → [dec1(dec2(func))]
    fn apply_decorators(&mut self, decorator_list: &[ast::Decorator]) {
        for decorator in decorator_list.iter().rev() {
            self.set_source_range(decorator.expression.range());
            emit!(self, Instruction::Call { argc: 0 });
        }
    }

    /// Compile type parameter bound or default in a separate scope and return closure
    fn compile_type_param_bound_or_default(
        &mut self,
        expr: &ast::Expr,
        name: &str,
        allow_starred: bool,
    ) -> CompileResult<()> {
        let expr_range = expr.range();
        self.set_source_range(expr_range);
        self.emit_load_const(ConstantData::Tuple {
            elements: vec![ConstantData::Integer { value: 1.into() }],
        });

        // Push the next symbol table onto the stack
        self.push_symbol_table()?;

        // Get the current symbol table
        let key = self.symbol_table_stack.len() - 1;
        let lineno = self.get_source_line_number().get().to_u32();

        // Enter scope with the type parameter name
        self.enter_scope(name, CompilerScope::TypeVariable, key, lineno)?;

        self.current_code_info()
            .metadata
            .varnames
            .insert(".format".to_owned());

        self.emit_format_validation();

        // TypeParams scope is function-like
        let prev_ctx = self.ctx;
        self.ctx = CompileContext {
            in_class: prev_ctx.in_class,
            func: FunctionContext::Function,
            in_async_scope: false,
        };

        // Compile the expression
        if allow_starred && matches!(expr, ast::Expr::Starred(_)) {
            if let ast::Expr::Starred(starred) = expr {
                self.compile_expression(&starred.value)?;
                self.set_source_range(expr_range);
                emit!(self, Instruction::UnpackSequence { count: 1 });
            }
        } else {
            self.compile_expression(expr)?;
        }

        // Return value
        self.set_source_range(expr_range);
        emit!(self, Instruction::ReturnValue);
        self.emit_return_const_no_location(ConstantData::None);

        // Exit scope and create closure
        let code = self.exit_scope();
        self.ctx = prev_ctx;

        self.set_source_range(expr_range);
        self.make_closure(
            code,
            bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]),
        )?;

        Ok(())
    }

    fn compile_typealias_value_closure(
        &mut self,
        alias_name: &str,
        value: &ast::Expr,
        alias_range: TextRange,
    ) -> CompileResult<()> {
        self.set_source_range(alias_range);
        self.emit_load_const(ConstantData::Tuple {
            elements: vec![ConstantData::Integer { value: 1.into() }],
        });

        self.push_symbol_table()?;
        let key = self.symbol_table_stack.len() - 1;
        let lineno = self.get_source_line_number().get().to_u32();
        self.enter_scope(alias_name, CompilerScope::TypeAlias, key, lineno)?;
        self.current_code_info()
            .metadata
            .varnames
            .insert(".format".to_owned());
        self.emit_format_validation();

        let prev_ctx = self.ctx;
        self.ctx = CompileContext {
            in_class: prev_ctx.in_class,
            func: FunctionContext::Function,
            in_async_scope: false,
        };

        self.compile_expression(value)?;
        self.set_source_range(alias_range);
        emit!(self, Instruction::ReturnValue);

        let code = self.exit_scope();
        self.ctx = prev_ctx;
        self.set_source_range(alias_range);
        self.make_closure(
            code,
            bytecode::MakeFunctionFlags::from([bytecode::MakeFunctionFlag::Defaults]),
        )?;

        Ok(())
    }

    /// Store each type parameter so it is accessible to the current scope, and leave a tuple of
    /// all the type parameters on the stack. Handles default values per PEP 695.
    fn compile_type_params(&mut self, type_params: &ast::TypeParams) -> CompileResult<()> {
        let mut seen_default = false;
        // First, compile each type parameter and store it
        for type_param in &type_params.type_params {
            match type_param {
                ast::TypeParam::TypeVar(ast::TypeParamTypeVar {
                    name,
                    bound,
                    default,
                    range,
                    ..
                }) => {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::Str {
                        value: name.as_str().into(),
                    });

                    if let Some(expr) = &bound {
                        self.compile_type_param_bound_or_default(expr, name.as_str(), false)?;

                        self.set_source_range(*range);
                        let intrinsic = if expr.is_tuple_expr() {
                            bytecode::IntrinsicFunction2::TypeVarWithConstraint
                        } else {
                            bytecode::IntrinsicFunction2::TypeVarWithBound
                        };
                        emit!(self, Instruction::CallIntrinsic2 { func: intrinsic });
                    } else {
                        emit!(
                            self,
                            Instruction::CallIntrinsic1 {
                                func: bytecode::IntrinsicFunction1::TypeVar
                            }
                        );
                    }

                    if let Some(default_expr) = default {
                        seen_default = true;
                        self.compile_type_param_bound_or_default(
                            default_expr,
                            name.as_str(),
                            false,
                        )?;
                        self.set_source_range(*range);
                        emit!(
                            self,
                            Instruction::CallIntrinsic2 {
                                func: bytecode::IntrinsicFunction2::SetTypeparamDefault
                            }
                        );
                    } else if seen_default {
                        return Err(self.error_ranged(
                            CodegenErrorType::SyntaxError(format!(
                                "non-default type parameter '{name}' follows default type parameter"
                            )),
                            *range,
                        ));
                    }

                    self.set_source_range(*range);
                    emit!(self, Instruction::Copy { i: 1 });
                    self.store_name(name.as_ref())?;
                }
                ast::TypeParam::ParamSpec(ast::TypeParamParamSpec {
                    name,
                    default,
                    range,
                    ..
                }) => {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::Str {
                        value: name.as_str().into(),
                    });
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::ParamSpec
                        }
                    );

                    if let Some(default_expr) = default {
                        seen_default = true;
                        self.compile_type_param_bound_or_default(
                            default_expr,
                            name.as_str(),
                            false,
                        )?;
                        self.set_source_range(*range);
                        emit!(
                            self,
                            Instruction::CallIntrinsic2 {
                                func: bytecode::IntrinsicFunction2::SetTypeparamDefault
                            }
                        );
                    } else if seen_default {
                        return Err(self.error_ranged(
                            CodegenErrorType::SyntaxError(format!(
                                "non-default type parameter '{name}' follows default type parameter"
                            )),
                            *range,
                        ));
                    }

                    self.set_source_range(*range);
                    emit!(self, Instruction::Copy { i: 1 });
                    self.store_name(name.as_ref())?;
                }
                ast::TypeParam::TypeVarTuple(ast::TypeParamTypeVarTuple {
                    name,
                    default,
                    range,
                    ..
                }) => {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::Str {
                        value: name.as_str().into(),
                    });
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::TypeVarTuple
                        }
                    );

                    if let Some(default_expr) = default {
                        // TypeVarTuple allows starred expressions
                        self.compile_type_param_bound_or_default(
                            default_expr,
                            name.as_str(),
                            true,
                        )?;
                        self.set_source_range(*range);
                        emit!(
                            self,
                            Instruction::CallIntrinsic2 {
                                func: bytecode::IntrinsicFunction2::SetTypeparamDefault
                            }
                        );
                        seen_default = true;
                    } else if seen_default {
                        return Err(self.error_ranged(
                            CodegenErrorType::SyntaxError(format!(
                                "non-default type parameter '{name}' follows default type parameter"
                            )),
                            *range,
                        ));
                    }

                    self.set_source_range(*range);
                    emit!(self, Instruction::Copy { i: 1 });
                    self.store_name(name.as_ref())?;
                }
            };
        }
        if let Some(first) = type_params.type_params.first() {
            self.set_source_range(first.range());
        }
        emit!(
            self,
            Instruction::BuildTuple {
                count: u32::try_from(type_params.len()).unwrap(),
            }
        );
        Ok(())
    }

    fn compile_try_statement(
        &mut self,
        body: &[ast::Stmt],
        handlers: &[ast::ExceptHandler],
        orelse: &[ast::Stmt],
        finalbody: &[ast::Stmt],
    ) -> CompileResult<()> {
        if finalbody.is_empty() {
            return self.compile_try_except_no_finally(body, handlers, orelse);
        }

        let body_block = self.new_block();
        let finally_except_block = self.new_block();
        let exit_block = self.new_block();
        let finally_cleanup_block = self.new_block();

        emit!(
            self,
            PseudoInstruction::SetupFinally {
                delta: finally_except_block
            }
        );
        self.use_cpython_label_block(body_block);
        let body_label = self.instr_sequence_label_for_block(body_block);
        let finally_except_label = self.instr_sequence_label_for_block(finally_except_block);
        self.push_fblock_labels(
            FBlockType::FinallyTry,
            body_label,
            finally_except_label,
            FBlockDatum::FinallyBody(finalbody.to_vec()),
        )?;

        if handlers.is_empty() {
            self.compile_statements(body)?;
        } else {
            self.compile_try_except_no_finally(body, handlers, orelse)?;
        }

        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        self.pop_fblock_label(FBlockType::FinallyTry, body_label);

        let symbol_table_cursors = self.current_symbol_table_cursors();

        self.compile_statements(finalbody)?;
        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: exit_block }
        );
        self.set_no_location();

        self.set_symbol_table_cursors(symbol_table_cursors);

        self.use_cpython_label_block(finally_except_block);
        emit!(
            self,
            PseudoInstruction::SetupCleanup {
                delta: finally_cleanup_block
            }
        );
        self.set_no_location();
        emit!(self, Instruction::PushExcInfo);
        self.set_no_location();
        self.push_fblock_labels(
            FBlockType::FinallyEnd,
            finally_except_label,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;
        self.compile_statements(finalbody)?;
        self.pop_fblock_label(FBlockType::FinallyEnd, finally_except_label);
        emit!(self, Instruction::Reraise { depth: 0 });
        self.set_no_location();

        self.use_cpython_label_block(finally_cleanup_block);
        emit!(self, Instruction::Copy { i: 3 });
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 1 });
        self.set_no_location();

        self.use_cpython_label_block(exit_block);

        Ok(())
    }

    fn compile_try_except_no_finally(
        &mut self,
        body: &[ast::Stmt],
        handlers: &[ast::ExceptHandler],
        orelse: &[ast::Stmt],
    ) -> CompileResult<()> {
        let body_block = self.new_block();
        let handler_block = self.new_block();
        let end_block = self.new_block();
        let cleanup_block = self.new_block();
        emit!(
            self,
            PseudoInstruction::SetupFinally {
                delta: handler_block
            }
        );
        self.use_cpython_label_block(body_block);
        let body_label = self.instr_sequence_label_for_block(body_block);
        self.push_fblock_labels(
            FBlockType::TryExcept,
            body_label,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;
        self.compile_statements(body)?;
        self.pop_fblock_label(FBlockType::TryExcept, body_label);
        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();

        // The symtable stores child scopes in AST visit order
        // (body, handlers, orelse), while codegen_try_except() emits orelse
        // before the exception handlers. Keep the symbol table in symtable order
        // and only move the codegen cursor while compiling orelse.
        let handler_symbol_table_cursors = self.current_symbol_table_cursors();
        self.consume_skipped_nested_scopes_in_except_handlers(handlers)?;
        self.compile_statements(orelse)?;
        let after_orelse_symbol_table_cursors = self.current_symbol_table_cursors();
        self.set_symbol_table_cursors(handler_symbol_table_cursors);
        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: end_block }
        );
        self.set_no_location();

        self.use_cpython_label_block(handler_block);
        emit!(
            self,
            PseudoInstruction::SetupCleanup {
                delta: cleanup_block
            }
        );
        self.set_no_location();
        emit!(self, Instruction::PushExcInfo);
        self.set_no_location();
        self.push_fblock_labels(
            FBlockType::ExceptionHandler,
            ir::InstructionSequenceLabel::NO_LABEL,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;

        for (i, handler) in handlers.iter().enumerate() {
            let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
                type_,
                name,
                body,
                range: handler_range,
                ..
            }) = handler;
            self.set_source_range(*handler_range);
            if type_.is_none() && i < handlers.len() - 1 {
                return Err(self.error(CodegenErrorType::SyntaxError(
                    "default 'except:' must be last".to_owned(),
                )));
            }
            let next_handler = self.new_block();

            if let Some(exc_type) = type_ {
                self.compile_expression(exc_type)?;
                self.set_source_range(*handler_range);
                emit!(self, Instruction::CheckExcMatch);
                emit!(
                    self,
                    Instruction::PopJumpIfFalse {
                        delta: next_handler
                    }
                );
            }

            if let Some(alias) = name {
                let cleanup_end = self.new_block();
                let cleanup_body = self.new_block();

                self.store_name(alias.as_str())?;

                emit!(self, PseudoInstruction::SetupCleanup { delta: cleanup_end });
                self.use_cpython_label_block(cleanup_body);
                let cleanup_body_label = self.instr_sequence_label_for_block(cleanup_body);
                self.push_fblock_labels(
                    FBlockType::HandlerCleanup,
                    cleanup_body_label,
                    ir::InstructionSequenceLabel::NO_LABEL,
                    FBlockDatum::ExceptionName(alias.as_str().to_owned()),
                )?;

                self.compile_statements(body)?;

                self.pop_fblock_label(FBlockType::HandlerCleanup, cleanup_body_label);
                emit!(self, PseudoInstruction::PopBlock);
                self.set_no_location();
                emit!(self, PseudoInstruction::PopBlock);
                self.set_no_location();
                emit!(self, Instruction::PopExcept);
                self.set_no_location();

                self.emit_no_location_exception_name_cleanup(alias.as_str())?;

                emit!(
                    self,
                    PseudoInstruction::JumpNoInterrupt { delta: end_block }
                );
                self.set_no_location();

                self.use_cpython_label_block(cleanup_end);
                self.emit_no_location_exception_name_cleanup(alias.as_str())?;
                emit!(self, Instruction::Reraise { depth: 1 });
                self.set_no_location();
            } else {
                let cleanup_body = self.new_block();

                emit!(self, Instruction::PopTop);
                self.use_cpython_label_block(cleanup_body);
                let cleanup_body_label = self.instr_sequence_label_for_block(cleanup_body);
                self.push_fblock_labels(
                    FBlockType::HandlerCleanup,
                    cleanup_body_label,
                    ir::InstructionSequenceLabel::NO_LABEL,
                    FBlockDatum::None,
                )?;

                self.compile_statements(body)?;

                self.pop_fblock_label(FBlockType::HandlerCleanup, cleanup_body_label);
                emit!(self, PseudoInstruction::PopBlock);
                self.set_no_location();
                emit!(self, Instruction::PopExcept);
                self.set_no_location();
                emit!(
                    self,
                    PseudoInstruction::JumpNoInterrupt { delta: end_block }
                );
                self.set_no_location();
            }

            self.use_cpython_label_block(next_handler);
        }
        self.set_symbol_table_cursors(after_orelse_symbol_table_cursors);

        self.pop_fblock_label(
            FBlockType::ExceptionHandler,
            ir::InstructionSequenceLabel::NO_LABEL,
        );
        emit!(self, Instruction::Reraise { depth: 0 });
        self.set_no_location();

        self.use_cpython_label_block(cleanup_block);
        emit!(self, Instruction::Copy { i: 3 });
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 1 });
        self.set_no_location();

        self.use_cpython_label_block(end_block);
        Ok(())
    }

    fn compile_try_star_statement(
        &mut self,
        body: &[ast::Stmt],
        handlers: &[ast::ExceptHandler],
        orelse: &[ast::Stmt],
        finalbody: &[ast::Stmt],
    ) -> CompileResult<()> {
        if finalbody.is_empty() {
            return self.compile_try_star_except(body, handlers, orelse);
        }

        let body_block = self.new_block();
        let finally_except_block = self.new_block();
        let exit_block = self.new_block();
        let finally_cleanup_block = self.new_block();

        emit!(
            self,
            PseudoInstruction::SetupFinally {
                delta: finally_except_block
            }
        );
        self.use_cpython_label_block(body_block);
        let body_label = self.instr_sequence_label_for_block(body_block);
        let finally_except_label = self.instr_sequence_label_for_block(finally_except_block);
        self.push_fblock_labels(
            FBlockType::FinallyTry,
            body_label,
            finally_except_label,
            FBlockDatum::FinallyBody(finalbody.to_vec()),
        )?;

        if handlers.is_empty() {
            self.compile_statements(body)?;
        } else {
            self.compile_try_star_except(body, handlers, orelse)?;
        }

        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        self.pop_fblock_label(FBlockType::FinallyTry, body_label);

        let symbol_table_cursors = self.current_symbol_table_cursors();
        self.compile_statements(finalbody)?;

        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: exit_block }
        );
        self.set_no_location();

        self.set_symbol_table_cursors(symbol_table_cursors);

        self.use_cpython_label_block(finally_except_block);
        emit!(
            self,
            PseudoInstruction::SetupCleanup {
                delta: finally_cleanup_block
            }
        );
        self.set_no_location();
        emit!(self, Instruction::PushExcInfo);
        self.set_no_location();
        self.push_fblock_labels(
            FBlockType::FinallyEnd,
            finally_except_label,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;
        self.compile_statements(finalbody)?;
        self.pop_fblock_label(FBlockType::FinallyEnd, finally_except_label);
        emit!(self, Instruction::Reraise { depth: 0 });
        self.set_no_location();

        self.use_cpython_label_block(finally_cleanup_block);
        emit!(self, Instruction::Copy { i: 3 });
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 1 });
        self.set_no_location();

        self.use_cpython_label_block(exit_block);

        Ok(())
    }

    fn compile_try_star_except(
        &mut self,
        body: &[ast::Stmt],
        handlers: &[ast::ExceptHandler],
        orelse: &[ast::Stmt],
    ) -> CompileResult<()> {
        // compiler_try_star_except
        // Stack layout during handler processing: [prev_exc, orig, list, rest]
        let body_block = self.new_block();
        let handler_block = self.new_block();
        let else_block = self.new_block();
        let end_block = self.new_block();
        let cleanup_block = self.new_block();
        let reraise_star_block = self.new_block();

        // SETUP_FINALLY for try body
        emit!(
            self,
            PseudoInstruction::SetupFinally {
                delta: handler_block
            }
        );
        self.use_cpython_label_block(body_block);
        let body_label = self.instr_sequence_label_for_block(body_block);
        self.push_fblock_labels(
            FBlockType::TryExcept,
            body_label,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;
        self.compile_statements(body)?;
        self.pop_fblock_label(FBlockType::TryExcept, body_label);
        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: else_block }
        );
        self.set_no_location();

        // Exception handler entry
        self.use_cpython_label_block(handler_block);
        // Stack: [exc] (from exception table)

        emit!(
            self,
            PseudoInstruction::SetupCleanup {
                delta: cleanup_block
            }
        );
        self.set_no_location();

        // PUSH_EXC_INFO
        emit!(self, Instruction::PushExcInfo);
        self.set_no_location();
        // Stack: [prev_exc, exc]

        // Push EXCEPTION_GROUP_HANDLER fblock
        self.push_fblock_labels(
            FBlockType::ExceptionGroupHandler,
            ir::InstructionSequenceLabel::NO_LABEL,
            ir::InstructionSequenceLabel::NO_LABEL,
            FBlockDatum::None,
        )?;

        let n = handlers.len();
        for (i, handler) in handlers.iter().enumerate() {
            let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
                type_,
                name,
                body,
                range: handler_range,
                ..
            }) = handler;
            let is_last_handler = i == n - 1;
            self.set_source_range(*handler_range);

            let next_handler_block = self.new_block();
            let except_with_error_block = self.new_block();
            let no_match_block = self.new_block();

            if i == 0 {
                // CPython initializes the except* work stack inside the first
                // handler iteration in codegen_try_star_except().
                emit!(self, Instruction::BuildList { count: 0 });
                emit!(self, Instruction::Copy { i: 2 });
            }

            // Compile exception type. The public-AST validator allows a
            // NULL type here, so codegen only emits CHECK_EG_MATCH when present.
            if let Some(exc_type) = type_ {
                self.compile_expression(exc_type)?;
                self.set_source_range(*handler_range);
            }

            if type_.is_some() {
                // Stack: [prev_exc, orig, list, rest, type]
                // ADDOP(c, loc, CHECK_EG_MATCH);
                emit!(self, Instruction::CheckEgMatch);
                // Stack: [prev_exc, orig, list, new_rest, match]

                // ADDOP_I(c, loc, COPY, 1);
                // ADDOP_JUMP(c, loc, POP_JUMP_IF_NONE, no_match);
                emit!(self, Instruction::Copy { i: 1 });
                emit!(
                    self,
                    Instruction::PopJumpIfNone {
                        delta: no_match_block
                    }
                );
            }

            // Handler matched
            // Stack: [prev_exc, orig, list, new_rest, match]
            // Note: CheckEgMatch already sets the matched exception as current exception
            let cleanup_end_block = self.new_block();
            let cleanup_body_block = self.new_block();

            // Store match to name or pop
            if let Some(alias) = name {
                self.store_name(alias.as_str())?;
            } else {
                emit!(self, Instruction::PopTop); // pop match
            }
            // Stack: [prev_exc, orig, list, new_rest]

            // HANDLER_CLEANUP fblock for handler body
            emit!(
                self,
                PseudoInstruction::SetupCleanup {
                    delta: cleanup_end_block
                }
            );
            self.use_cpython_label_block(cleanup_body_block);
            let cleanup_body_label = self.instr_sequence_label_for_block(cleanup_body_block);
            self.push_fblock_labels(
                FBlockType::HandlerCleanup,
                cleanup_body_label,
                ir::InstructionSequenceLabel::NO_LABEL,
                if let Some(alias) = name {
                    FBlockDatum::ExceptionName(alias.as_str().to_owned())
                } else {
                    FBlockDatum::None
                },
            )?;

            // Execute handler body
            self.compile_statements(body)?;

            // Handler body completed normally
            self.pop_fblock_label(FBlockType::HandlerCleanup, cleanup_body_label);
            emit!(self, PseudoInstruction::PopBlock);
            self.set_no_location();

            // Cleanup name binding
            if let Some(alias) = name {
                self.emit_no_location_exception_name_cleanup(alias.as_str())?;
            }

            emit!(
                self,
                PseudoInstruction::JumpNoInterrupt {
                    delta: next_handler_block
                }
            );
            self.set_no_location();

            // Handler raised an exception (cleanup_end label)
            self.use_cpython_label_block(cleanup_end_block);
            // Stack: [prev_exc, orig, list, new_rest, lasti, raised_exc]
            // (lasti is pushed because push_lasti=true in HANDLER_CLEANUP fblock)

            // Cleanup name binding
            if let Some(alias) = name {
                self.emit_no_location_exception_name_cleanup(alias.as_str())?;
            }

            // LIST_APPEND(3) - append raised_exc to list
            // Stack: [prev_exc, orig, list, new_rest, lasti, raised_exc]
            // After pop: [prev_exc, orig, list, new_rest, lasti] (len=5)
            // nth_value(i) = stack[len - i - 1], we need stack[2] = list
            // stack[5 - i - 1] = 2 -> i = 2
            emit!(self, Instruction::ListAppend { i: 3 });
            self.set_no_location();
            // Stack: [prev_exc, orig, list, new_rest, lasti]

            // POP_TOP - pop lasti
            emit!(self, Instruction::PopTop);
            self.set_no_location();
            // Stack: [prev_exc, orig, list, new_rest]

            emit!(
                self,
                PseudoInstruction::JumpNoInterrupt {
                    delta: except_with_error_block
                }
            );
            self.set_no_location();

            self.use_cpython_label_block(next_handler_block);
            emit!(self, Instruction::Nop);
            self.set_no_location();
            emit!(
                self,
                PseudoInstruction::JumpNoInterrupt {
                    delta: except_with_error_block
                }
            );
            self.set_no_location();

            self.use_cpython_label_block(no_match_block);
            self.set_source_range(*handler_range);
            emit!(self, Instruction::PopTop); // pop match (None)
            // Stack: [prev_exc, orig, list, new_rest]

            self.use_cpython_label_block(except_with_error_block);

            if is_last_handler {
                emit!(self, Instruction::ListAppend { i: 1 });
                self.set_no_location();
                emit!(
                    self,
                    PseudoInstruction::JumpNoInterrupt {
                        delta: reraise_star_block
                    }
                );
                self.set_no_location();
            }
        }

        // Pop EXCEPTION_GROUP_HANDLER fblock
        self.pop_fblock_label(
            FBlockType::ExceptionGroupHandler,
            ir::InstructionSequenceLabel::NO_LABEL,
        );
        let reraise_block = self.new_block();

        // Reraise star block
        self.use_cpython_label_block(reraise_star_block);
        // Stack: [prev_exc, orig, list]

        // CALL_INTRINSIC_2 PREP_RERAISE_STAR
        // Takes 2 args (orig, list) and produces result
        emit!(
            self,
            Instruction::CallIntrinsic2 {
                func: bytecode::IntrinsicFunction2::PrepReraiseStar
            }
        );
        self.set_no_location();
        // Stack: [prev_exc, result]

        // COPY 1
        emit!(self, Instruction::Copy { i: 1 });
        self.set_no_location();
        // Stack: [prev_exc, result, result]

        // POP_JUMP_IF_NOT_NONE reraise
        emit!(
            self,
            Instruction::PopJumpIfNotNone {
                delta: reraise_block
            }
        );
        self.set_no_location();
        // Stack: [prev_exc, result]

        // Nothing to reraise
        // POP_TOP - pop result (None)
        emit!(self, Instruction::PopTop);
        self.set_no_location();
        // Stack: [prev_exc]

        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        // POP_EXCEPT - restore previous exception context
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        // Stack: []

        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: end_block }
        );
        self.set_no_location();

        // Reraise the result
        self.use_cpython_label_block(reraise_block);

        // Stack: [prev_exc, result]
        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();
        emit!(self, Instruction::Swap { i: 2 });
        self.set_no_location();
        // Stack: [result, prev_exc]

        // POP_EXCEPT
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        // Stack: [result]

        // RERAISE 0
        emit!(self, Instruction::Reraise { depth: 0 });
        self.set_no_location();

        self.use_cpython_label_block(cleanup_block);
        emit!(self, Instruction::Copy { i: 3 });
        self.set_no_location();
        emit!(self, Instruction::PopExcept);
        self.set_no_location();
        emit!(self, Instruction::Reraise { depth: 1 });
        self.set_no_location();

        self.use_cpython_label_block(else_block);
        self.compile_statements(orelse)?;

        self.use_cpython_label_block(end_block);

        Ok(())
    }

    /// Compile default arguments
    // = compiler_default_arguments
    fn compile_default_arguments(
        &mut self,
        parameters: &ast::Parameters,
        loc: TextRange,
    ) -> CompileResult<bytecode::MakeFunctionFlags> {
        let mut funcflags = bytecode::MakeFunctionFlags::new();

        // Handle positional defaults
        let defaults: Vec<_> = core::iter::empty()
            .chain(&parameters.posonlyargs)
            .chain(&parameters.args)
            .filter_map(|x| x.default.as_deref())
            .collect();

        if !defaults.is_empty() {
            // Compile defaults and build tuple
            for default in &defaults {
                self.compile_expression(default)?;
            }
            self.set_source_range(loc);
            emit!(
                self,
                Instruction::BuildTuple {
                    count: defaults.len().to_u32()
                }
            );
            funcflags.insert(bytecode::MakeFunctionFlag::Defaults);
        }

        // Handle keyword-only defaults
        let mut kw_with_defaults = vec![];
        for kwonlyarg in &parameters.kwonlyargs {
            if let Some(default) = &kwonlyarg.default {
                kw_with_defaults.push((&kwonlyarg.parameter, default));
            }
        }

        if !kw_with_defaults.is_empty() {
            // Compile kwdefaults and build dict
            for (arg, default) in &kw_with_defaults {
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Str {
                    value: self.mangle(arg.name.as_str()).into_owned().into(),
                });
                self.compile_expression(default)?;
            }
            self.set_source_range(loc);
            emit!(
                self,
                Instruction::BuildMap {
                    count: kw_with_defaults.len().to_u32(),
                }
            );
            funcflags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
        }

        Ok(funcflags)
    }

    /// Compile function body and create function object
    // = compiler_function_body
    fn compile_function_body(
        &mut self,
        name: &str,
        parameters: &ast::Parameters,
        body: &[ast::Stmt],
        is_async: bool,
        funcflags: bytecode::MakeFunctionFlags,
        closure_range: TextRange,
    ) -> CompileResult<()> {
        // Always enter function scope
        self.enter_function(name, parameters)?;
        self.current_code_info()
            .flags
            .set(bytecode::CodeFlags::COROUTINE, is_async);

        // Set up context
        let prev_ctx = self.ctx;
        self.ctx = CompileContext {
            in_class: prev_ctx.in_class,
            func: if is_async {
                FunctionContext::AsyncFunction
            } else {
                FunctionContext::Function
            },
            // A function starts a new async scope only if it's async
            in_async_scope: is_async,
        };

        // Set qualname
        self.set_qualname();

        // Handle docstring - store in co_consts[0] if present
        let (doc_info, body) = split_doc_with_range(body, &self.opts);
        let doc_str = doc_info.as_ref().map(|(doc, _)| doc);
        if let Some(doc) = &doc_str {
            // Docstring present: store in co_consts[0] and set HAS_DOCSTRING flag
            self.current_code_info()
                .metadata
                .consts
                .insert_full(ConstantData::Str {
                    value: (*doc).to_string().into(),
                });
            self.current_code_info().flags |= bytecode::CodeFlags::HAS_DOCSTRING;
        }

        let start_label = self.use_cpython_function_start_label();

        // PEP 479: Wrap generator/coroutine body with StopIteration handler
        let is_gen = is_async || self.current_symbol_table().is_generator;
        let stop_iteration_block = if is_gen {
            let handler_block = self.new_block();
            self.insert_cpython_stopiteration_setup_cleanup(handler_block);
            self.push_fblock_labels(
                FBlockType::StopIteration,
                start_label,
                ir::InstructionSequenceLabel::NO_LABEL,
                FBlockDatum::None,
            )?;
            Some(handler_block)
        } else {
            None
        };
        // Compile body statements
        self.compile_statements(body)?;

        if stop_iteration_block.is_some() {
            self.emit_return_const_no_location(ConstantData::None);
        }

        // Close StopIteration handler and emit handler code
        if let Some(handler_block) = stop_iteration_block {
            self.pop_fblock_label(FBlockType::StopIteration, start_label);
            self.use_cpython_label_block(handler_block);
            emit!(
                self,
                Instruction::CallIntrinsic1 {
                    func: oparg::IntrinsicFunction1::StopIterationError
                }
            );
            self.set_no_location();
            emit!(self, Instruction::Reraise { depth: 1u32 });
            self.set_no_location();
        }
        self.emit_return_const_no_location(ConstantData::None);

        // Exit scope and create function object
        let code = self.exit_scope();
        self.ctx = prev_ctx;

        self.set_source_range(closure_range);

        // Create function object with closure
        self.make_closure(code, funcflags)?;

        // Note: docstring is now retrieved from co_consts[0] by the VM
        // when HAS_DOCSTRING flag is set, so no runtime __doc__ assignment needed

        Ok(())
    }

    /// Compile function annotations as a closure (PEP 649)
    /// Returns true if an __annotate__ closure was created
    /// Uses the matching annotation symbol table for proper scoping.
    fn compile_annotations_closure(
        &mut self,
        func_name: &str,
        parameters: &ast::Parameters,
        returns: Option<&ast::Expr>,
        func_range: TextRange,
    ) -> CompileResult<bool> {
        if !self.next_function_annotation_symbol_table_uses_annotations() {
            return Ok(false);
        }

        // Try to enter annotation scope - returns None if no matching symbol table exists.
        let Some(saved_ctx) = self.enter_annotation_scope(func_name, func_range)? else {
            return Ok(false);
        };

        // Count annotations
        let parameters_iter = parameters
            .args
            .iter()
            .map(|x| &x.parameter)
            .chain(parameters.posonlyargs.iter().map(|x| &x.parameter))
            .chain(parameters.vararg.as_deref())
            .chain(parameters.kwonlyargs.iter().map(|x| &x.parameter))
            .chain(parameters.kwarg.as_deref());

        let num_annotations =
            u32::try_from(parameters_iter.filter(|p| p.annotation.is_some()).count())
                .expect("too many annotations")
                + u32::from(returns.is_some());

        // Compile annotations inside the annotation scope
        let parameters_iter = parameters
            .args
            .iter()
            .map(|x| &x.parameter)
            .chain(parameters.posonlyargs.iter().map(|x| &x.parameter))
            .chain(parameters.vararg.as_deref())
            .chain(parameters.kwonlyargs.iter().map(|x| &x.parameter))
            .chain(parameters.kwarg.as_deref());

        for param in parameters_iter {
            if let Some(annotation) = &param.annotation {
                self.set_source_range(func_range);
                self.emit_load_const(ConstantData::Str {
                    value: self.mangle(param.name.as_str()).into_owned().into(),
                });
                self.compile_annotation(annotation)?;
            }
        }

        // Handle return annotation
        if let Some(annotation) = returns {
            self.set_source_range(func_range);
            self.emit_load_const(ConstantData::Str {
                value: "return".into(),
            });
            self.compile_annotation(annotation)?;
        }

        // Build the map and return it
        self.set_source_range(func_range);
        emit!(
            self,
            Instruction::BuildMap {
                count: num_annotations,
            }
        );
        emit!(self, Instruction::ReturnValue);
        self.emit_return_const_no_location(ConstantData::None);

        // Exit the annotation scope and get the code object
        let annotate_code = self.exit_annotation_scope(saved_ctx);

        // Make a closure from the code object
        self.set_source_range(func_range);
        self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;

        Ok(true)
    }

    /// Collect annotated assignments from module/class body in AST order
    /// (including nested conditional blocks). This preserves the same walk
    /// order as symbol-table construction so the annotation scope's
    /// `sub_tables` cursor stays aligned.
    fn collect_annotations(
        body: &[ast::Stmt],
        parent_scope_type: CompilerScope,
    ) -> Vec<(&ast::StmtAnnAssign, bool)> {
        fn walk<'a>(
            stmts: &'a [ast::Stmt],
            out: &mut Vec<(&'a ast::StmtAnnAssign, bool)>,
            in_conditional_block: bool,
            module_scope: bool,
        ) {
            for stmt in stmts {
                match stmt {
                    ast::Stmt::AnnAssign(stmt) => {
                        out.push((stmt, module_scope || in_conditional_block));
                    }
                    ast::Stmt::If(ast::StmtIf {
                        body,
                        elif_else_clauses,
                        ..
                    }) => {
                        walk(body, out, true, module_scope);
                        for clause in elif_else_clauses {
                            walk(&clause.body, out, true, module_scope);
                        }
                    }
                    ast::Stmt::For(ast::StmtFor { body, orelse, .. })
                    | ast::Stmt::While(ast::StmtWhile { body, orelse, .. }) => {
                        walk(body, out, true, module_scope);
                        walk(orelse, out, true, module_scope);
                    }
                    ast::Stmt::With(ast::StmtWith { body, .. }) => {
                        walk(body, out, true, module_scope);
                    }
                    ast::Stmt::Try(ast::StmtTry {
                        body,
                        handlers,
                        orelse,
                        finalbody,
                        ..
                    }) => {
                        walk(body, out, true, module_scope);
                        for handler in handlers {
                            let ast::ExceptHandler::ExceptHandler(
                                ast::ExceptHandlerExceptHandler { body, .. },
                            ) = handler;
                            walk(body, out, true, module_scope);
                        }
                        walk(orelse, out, true, module_scope);
                        walk(finalbody, out, true, module_scope);
                    }
                    ast::Stmt::Match(ast::StmtMatch { cases, .. }) => {
                        for case in cases {
                            walk(&case.body, out, true, module_scope);
                        }
                    }
                    _ => {}
                }
            }
        }
        let mut annotations = Vec::new();
        walk(
            body,
            &mut annotations,
            false,
            parent_scope_type == CompilerScope::Module,
        );
        annotations
    }

    fn compile_annotation_for_symbol_cursor_only(
        &mut self,
        annotation: &ast::Expr,
    ) -> CompileResult<()> {
        self.consume_skipped_nested_scopes_in_expr(annotation)
    }

    /// Compile module-level __annotate__ function (PEP 649)
    /// Returns true if __annotate__ was created and stored
    fn compile_module_annotate(
        &mut self,
        body: &[ast::Stmt],
        loc: Option<TextRange>,
    ) -> CompileResult<bool> {
        let loc = loc.unwrap_or(self.current_source_range);
        // Get parent scope type BEFORE pushing annotation symbol table.
        let parent_scope_type = self.current_symbol_table().typ;
        let annotations = Self::collect_annotations(body, parent_scope_type);
        let simple_annotation_count = annotations
            .iter()
            .filter(|(stmt, _)| stmt.simple && matches!(stmt.target.as_ref(), ast::Expr::Name(_)))
            .count();

        if simple_annotation_count == 0 {
            return Ok(false);
        }

        // Check if we have conditional annotations
        let has_conditional = self.current_symbol_table().has_conditional_annotations;

        // Try to push annotation symbol table from current scope
        if !self.push_current_annotation_symbol_table() {
            return Ok(false);
        }

        // Annotation scopes are never async (even inside async functions)
        let saved_ctx = self.ctx;
        self.ctx = CompileContext {
            in_class: saved_ctx.in_class,
            func: FunctionContext::Function,
            in_async_scope: false,
        };

        // Enter annotation scope for code generation
        self.set_source_range(loc);
        let key = self.symbol_table_stack.len() - 1;
        let lineno = self.get_source_line_number().get();
        self.enter_scope(
            "__annotate__",
            CompilerScope::Annotation,
            key,
            lineno.to_u32(),
        )?;

        // Keep the internal ".format" name; the final code object
        // exposes this parameter as "format".
        self.current_code_info()
            .metadata
            .varnames
            .insert(".format".to_owned());

        // Emit format validation: if format > VALUE_WITH_FAKE_GLOBALS: raise NotImplementedError
        self.emit_format_validation();

        self.set_source_range(loc);
        emit!(self, Instruction::BuildMap { count: 0 });

        let mut conditional_idx = 0usize;
        for (stmt, is_conditional) in annotations {
            let ast::StmtAnnAssign {
                target,
                annotation,
                simple,
                range,
                ..
            } = stmt;
            let simple_name = if *simple {
                match target.as_ref() {
                    ast::Expr::Name(ast::ExprName { id, .. }) => Some(id.as_str()),
                    _ => None,
                }
            } else {
                None
            };

            if simple_name.is_none() {
                if !self.future_annotations {
                    self.compile_annotation_for_symbol_cursor_only(annotation)?;
                }
                continue;
            }

            let not_set_block = (has_conditional && is_conditional).then(|| self.new_block());
            let not_set_label = (!has_conditional || !is_conditional)
                .then(|| self.current_code_info().new_instr_sequence_label());
            let name = simple_name.expect("missing simple annotation name");

            if let Some(not_set_block) = not_set_block {
                self.set_source_range(*range);
                self.emit_load_const(ConstantData::Integer {
                    value: conditional_idx.into(),
                });
                conditional_idx += 1;
                if parent_scope_type == CompilerScope::Class {
                    let idx = self.get_free_var_index("__conditional_annotations__");
                    emit!(self, Instruction::LoadDeref { i: idx });
                } else {
                    let cond_annotations_name = self.name("__conditional_annotations__");
                    self.emit_load_global(cond_annotations_name, false);
                }
                emit!(
                    self,
                    Instruction::ContainsOp {
                        invert: bytecode::Invert::No
                    }
                );
                emit!(
                    self,
                    Instruction::PopJumpIfFalse {
                        delta: not_set_block
                    }
                );
            }

            self.compile_annotation(annotation)?;
            self.set_source_range(*range);
            emit!(self, Instruction::Copy { i: 2 });
            self.emit_load_const(ConstantData::Str {
                value: self.mangle(name).into_owned().into(),
            });
            self.set_source_range(loc);
            emit!(self, Instruction::StoreSubscr);

            if let Some(not_set_block) = not_set_block {
                self.use_cpython_label_block(not_set_block);
            } else if let Some(not_set_label) = not_set_label {
                let result = self
                    .current_code_info()
                    .use_raw_instr_sequence_label(not_set_label);
                unwrap_internal(self, result);
            }
        }

        self.set_source_range(loc);
        emit!(self, Instruction::ReturnValue);
        self.emit_return_const_no_location(ConstantData::None);

        // Exit annotation scope - pop symbol table, restore to parent's annotation_block, and get code
        let annotation_table = self.pop_symbol_table();
        // Restore annotation_block to module's symbol table
        self.symbol_table_stack
            .last_mut()
            .expect("no module symbol table")
            .annotation_block = Some(Box::new(annotation_table));
        // Restore context
        self.ctx = saved_ctx;
        // Exit code scope
        let pop = self.code_stack.pop();
        let mut annotate_code = unwrap_internal(
            self,
            compiler_unwrap_option(self, pop).finalize_code(&self.opts),
        );
        Self::expose_annotation_format_parameter(&mut annotate_code);

        // Make a closure from the code object
        self.set_source_range(loc);
        self.make_closure(annotate_code, bytecode::MakeFunctionFlags::new())?;

        // Store as __annotate_func__ for classes, __annotate__ for modules
        let name = if parent_scope_type == CompilerScope::Class {
            "__annotate_func__"
        } else {
            "__annotate__"
        };
        self.set_source_range(loc);
        self.store_name(name)?;

        Ok(true)
    }

    // = compiler_function
    #[expect(clippy::too_many_arguments, reason = "ignore warning for now")]
    fn compile_function_def(
        &mut self,
        name: &str,
        parameters: &ast::Parameters,
        body: &[ast::Stmt],
        decorator_list: &[ast::Decorator],
        returns: Option<&ast::Expr>, // TODO: use type hint somehow..
        is_async: bool,
        type_params: Option<&ast::TypeParams>,
        preserve_value_before_store: bool,
    ) -> CompileResult<()> {
        // CPython's FunctionDef/AsyncFunctionDef LOC(s) starts at the
        // definition line even when decorators are present.
        let stmt_source_range = self.current_source_range;
        let def_source_range = self.decorated_definition_range(
            stmt_source_range,
            decorator_list,
            if is_async { "async def " } else { "def " },
        );

        // The symtable visits defaults before decorators, but
        // codegen_function() emits decorators first. Keep the symbol table in
        // symtable order and only move the codegen cursor while compiling
        // decorators.
        let defaults_symbol_table_cursors = self.current_symbol_table_cursors();
        self.consume_skipped_nested_scopes_in_parameter_defaults(parameters)?;
        self.prepare_decorators(decorator_list)?;
        let after_decorators_symbol_table_cursors = self.current_symbol_table_cursors();
        self.set_symbol_table_cursors(defaults_symbol_table_cursors);

        // The first decorator line is used for code objects created by
        // this definition, but LOC(s) for the surrounding instructions.
        let firstlineno_range = decorator_list
            .first()
            .map_or(stmt_source_range, |decorator| decorator.expression.range());

        // compile defaults and return funcflags
        let funcflags = self.compile_default_arguments(parameters, def_source_range)?;
        self.set_symbol_table_cursors(after_decorators_symbol_table_cursors);

        let is_generic = type_params.is_some();
        let mut num_typeparam_args = 0u32;

        // Save context before entering TypeParams scope
        let saved_ctx = self.ctx;

        if is_generic {
            // Count args to pass to type params scope
            if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
                num_typeparam_args += 1;
            }
            if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
                num_typeparam_args += 1;
            }
            if num_typeparam_args == 2 {
                self.set_source_range(def_source_range);
                emit!(self, Instruction::Swap { i: 2 });
            }

            // Enter type params scope
            let type_params_name = format!("<generic parameters of {name}>");
            self.set_source_range(firstlineno_range);
            self.push_output(
                bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS,
                0,
                num_typeparam_args,
                0,
                &type_params_name,
            )?;

            // TypeParams scope is function-like
            self.ctx = CompileContext {
                in_class: saved_ctx.in_class,
                func: FunctionContext::Function,
                in_async_scope: false,
            };

            // Add parameter names to varnames for the type params scope
            // These will be passed as arguments when the closure is called
            let current_info = self.current_code_info();
            if funcflags.contains(&bytecode::MakeFunctionFlag::Defaults) {
                current_info
                    .metadata
                    .varnames
                    .insert(".defaults".to_owned());
            }
            if funcflags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
                current_info
                    .metadata
                    .varnames
                    .insert(".kwdefaults".to_owned());
            }

            // Compile type parameters
            self.compile_type_params(type_params.unwrap())?;

            // Load defaults/kwdefaults with LOAD_FAST
            self.set_source_range(def_source_range);
            for i in 0..num_typeparam_args {
                let var_num = oparg::VarNum::from(i);
                emit!(self, Instruction::LoadFast { var_num });
            }
        }

        // Compile annotations as closure (PEP 649)
        let mut annotations_flag = bytecode::MakeFunctionFlags::new();
        if self.compile_annotations_closure(name, parameters, returns, def_source_range)? {
            annotations_flag.insert(bytecode::MakeFunctionFlag::Annotate);
        }

        // Compile function body. codegen_function() uses the first
        // decorator line for co_firstlineno, but LOC(s) for MAKE_FUNCTION.
        self.set_source_range(firstlineno_range);
        let final_funcflags = funcflags | annotations_flag;
        self.compile_function_body(
            name,
            parameters,
            body,
            is_async,
            final_funcflags,
            def_source_range,
        )?;

        // Handle type params if present
        if is_generic {
            // SWAP to get function on top
            // Stack: [type_params_tuple, function] -> [function, type_params_tuple]
            self.set_source_range(def_source_range);
            emit!(self, Instruction::Swap { i: 2 });

            // Call INTRINSIC_SET_FUNCTION_TYPE_PARAMS
            self.set_source_range(def_source_range);
            emit!(
                self,
                Instruction::CallIntrinsic2 {
                    func: bytecode::IntrinsicFunction2::SetFunctionTypeParams,
                }
            );

            // Return the function object from type params scope
            emit!(self, Instruction::ReturnValue);
            self.set_no_location();

            // Set argcount for type params scope
            self.current_code_info().metadata.argcount = num_typeparam_args;
            self.current_code_info().nparams = num_typeparam_args as usize;

            // Exit type params scope and create closure
            let type_params_code = self.exit_scope();
            self.ctx = saved_ctx;

            // Make closure for type params code
            self.set_source_range(def_source_range);
            self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;

            if num_typeparam_args > 0 {
                self.set_source_range(def_source_range);
                emit!(
                    self,
                    Instruction::Swap {
                        i: num_typeparam_args + 1
                    }
                );
                self.set_source_range(def_source_range);
                emit!(
                    self,
                    Instruction::Call {
                        argc: num_typeparam_args - 1
                    }
                );
            } else {
                // Stack: [closure]
                self.set_source_range(def_source_range);
                emit!(self, Instruction::PushNull);
                // Stack: [closure, NULL]
                self.set_source_range(def_source_range);
                emit!(self, Instruction::Call { argc: 0 });
            }
        }

        // Apply decorators
        self.apply_decorators(decorator_list);

        // Store the function
        self.set_source_range(def_source_range);
        if preserve_value_before_store {
            emit!(self, Instruction::Copy { i: 1 });
        }
        self.store_name(name)?;

        Ok(())
    }

    /// Determines if a variable should be CELL or FREE type
    // = get_ref_type
    fn get_ref_type(&self, name: &str) -> Result<SymbolScope, CodegenErrorType> {
        let table = self.symbol_table_stack.last().unwrap();

        // Special handling for __class__, __classdict__, and __conditional_annotations__ in class scope
        // This should only apply when we're actually IN a class body,
        // not when we're in a method nested inside a class.
        if table.typ == CompilerScope::Class
            && (name == "__class__"
                || name == "__classdict__"
                || name == "__conditional_annotations__")
        {
            return Ok(SymbolScope::Cell);
        }
        match table.lookup(name) {
            Some(symbol) => match symbol.scope {
                SymbolScope::Cell => Ok(SymbolScope::Cell),
                SymbolScope::Free => Ok(SymbolScope::Free),
                _ if symbol.flags.contains(SymbolFlags::DEF_FREE_CLASS) => Ok(SymbolScope::Free),
                _ => Err(CodegenErrorType::SyntaxError(format!(
                    "get_ref_type: invalid scope for '{name}'"
                ))),
            },
            None => Err(CodegenErrorType::SyntaxError(format!(
                "get_ref_type: cannot find symbol '{name}'"
            ))),
        }
    }

    /// Loads closure variables if needed and creates a function object
    // = compiler_make_closure
    fn make_closure(
        &mut self,
        code: CodeObject,
        flags: bytecode::MakeFunctionFlags,
    ) -> CompileResult<()> {
        // Handle free variables (closure)
        let has_freevars = !code.freevars.is_empty();
        if has_freevars {
            // Build closure tuple by loading free variables

            for var in &code.freevars {
                // Special case: If a class contains a method with a
                // free variable that has the same name as a method,
                // the name will be considered free *and* local in the
                // class. It should be handled by the closure, as
                // well as by the normal name lookup logic.

                // Get reference type using our get_ref_type function
                let ref_type = self.get_ref_type(var).map_err(|e| self.error(e))?;

                // Get parent code info
                let parent_code = self.code_stack.last().unwrap();
                let cellvars_len = parent_code.metadata.cellvars.len();

                // Look up the variable index based on reference type
                let idx = match ref_type {
                    SymbolScope::Cell => parent_code
                        .metadata
                        .cellvars
                        .get_index_of(var)
                        .or_else(|| {
                            parent_code
                                .metadata
                                .freevars
                                .get_index_of(var)
                                .map(|i| i + cellvars_len)
                        })
                        .ok_or_else(|| {
                            self.error(CodegenErrorType::SyntaxError(format!(
                                "compiler_make_closure: cannot find '{var}' in parent vars",
                            )))
                        })?,
                    SymbolScope::Free => parent_code
                        .metadata
                        .freevars
                        .get_index_of(var)
                        .map(|i| i + cellvars_len)
                        .or_else(|| parent_code.metadata.cellvars.get_index_of(var))
                        .ok_or_else(|| {
                            self.error(CodegenErrorType::SyntaxError(format!(
                                "compiler_make_closure: cannot find '{var}' in parent vars",
                            )))
                        })?,
                    _ => {
                        return Err(self.error(CodegenErrorType::SyntaxError(format!(
                            "compiler_make_closure: unexpected ref_type {ref_type:?} for '{var}'",
                        ))));
                    }
                };

                emit!(self, PseudoInstruction::LoadClosure { i: idx.to_u32() });
            }

            // Build tuple of closure variables
            emit!(
                self,
                Instruction::BuildTuple {
                    count: code.freevars.len().to_u32(),
                }
            );
        }

        // load code object and create function
        self.emit_load_const(ConstantData::Code {
            code: Box::new(code),
        });

        // Create function with no flags
        emit!(self, Instruction::MakeFunction);

        // Now set attributes one by one using SET_FUNCTION_ATTRIBUTE
        // Note: The order matters! Values must be on stack before calling SET_FUNCTION_ATTRIBUTE

        // Set closure if needed
        if has_freevars {
            emit!(
                self,
                Instruction::SetFunctionAttribute {
                    flag: bytecode::MakeFunctionFlag::Closure
                }
            );
        }

        // Set annotations if present
        if flags.contains(&bytecode::MakeFunctionFlag::Annotations) {
            emit!(
                self,
                Instruction::SetFunctionAttribute {
                    flag: bytecode::MakeFunctionFlag::Annotations
                }
            );
        }

        // Set __annotate__ closure if present (PEP 649)
        if flags.contains(&bytecode::MakeFunctionFlag::Annotate) {
            emit!(
                self,
                Instruction::SetFunctionAttribute {
                    flag: bytecode::MakeFunctionFlag::Annotate
                }
            );
        }

        // Set kwdefaults if present
        if flags.contains(&bytecode::MakeFunctionFlag::KwOnlyDefaults) {
            emit!(
                self,
                Instruction::SetFunctionAttribute {
                    flag: bytecode::MakeFunctionFlag::KwOnlyDefaults
                }
            );
        }

        // Set defaults if present
        if flags.contains(&bytecode::MakeFunctionFlag::Defaults) {
            emit!(
                self,
                Instruction::SetFunctionAttribute {
                    flag: bytecode::MakeFunctionFlag::Defaults
                }
            );
        }

        Ok(())
    }

    // Python/compile.c _PyCompile_MaybeAddStaticAttributeToClass
    fn maybe_add_static_attribute_to_class(&mut self, value: &ast::Expr, attr: &str) {
        if !matches!(value, ast::Expr::Name(n) if n.id.as_str() == "self") {
            return;
        }
        if let Some(class_unit) = self
            .code_stack
            .iter_mut()
            .rev()
            .find(|unit| unit.static_attributes.is_some())
        {
            class_unit
                .static_attributes
                .as_mut()
                .unwrap()
                .insert(attr.to_owned());
        }
    }

    /// Compile the class body into a code object
    // = compiler_class_body
    fn compile_class_body(
        &mut self,
        name: &str,
        body: &[ast::Stmt],
        type_params: Option<&ast::TypeParams>,
        firstlineno: u32,
    ) -> CompileResult<CodeObject> {
        // 1. Enter class scope
        let key = self.symbol_table_stack.len();
        self.push_symbol_table_matching(CompilerScope::Class, name)?;
        self.enter_scope(name, CompilerScope::Class, key, firstlineno)?;

        // Set qualname using the new method
        let qualname = self.set_qualname();

        // For class scopes, set u_private to the class name for name mangling
        self.code_stack.last_mut().unwrap().private = Some(name.to_owned());

        // 2. Set up class namespace
        let (doc_str, body) = split_doc_with_range(body, &self.opts);
        let class_body_prefix_range = self.source_line_start_range(firstlineno);
        self.set_source_range(class_body_prefix_range);

        // Load __name__ and store as __module__
        self.load_name("__name__")?;
        self.store_name("__module__")?;

        // Store __qualname__
        self.emit_load_const(ConstantData::Str {
            value: qualname.into(),
        });
        self.store_name("__qualname__")?;

        // Store __firstlineno__ before __doc__
        self.emit_load_const(ConstantData::Integer {
            value: BigInt::from(firstlineno),
        });
        self.store_name("__firstlineno__")?;

        // Set __type_params__ from the enclosing type-params closure when
        // compiling a generic class body.
        if type_params.is_some() {
            self.load_name(".type_params")?;
            self.store_name("__type_params__")?;
        }

        // PEP 649: Initialize __classdict__ after synthetic generic-class
        // setup so nested generic classes match CPython's prologue order.
        if self.current_symbol_table().needs_classdict {
            emit!(self, Instruction::LoadLocals);
            let classdict_idx = self.get_cell_var_index("__classdict__");
            emit!(self, Instruction::StoreDeref { i: classdict_idx });
        }

        // Handle class annotation bookkeeping in CPython order.
        let annotations_used = self.current_symbol_table().annotations_used;
        if Self::scope_needs_conditional_annotations_cell(self.current_symbol_table()) {
            emit!(self, Instruction::BuildSet { count: 0 });
            self.store_name("__conditional_annotations__")?;
        }

        if self.future_annotations && annotations_used {
            emit!(self, Instruction::SetupAnnotations);
        }

        // Store __doc__ only if there's an explicit docstring.
        if let Some((doc, range)) = doc_str {
            let saved_range = self.current_source_range;
            self.set_source_range(range);
            self.emit_load_const(ConstantData::Str { value: doc.into() });
            self.store_name("__doc__")?;
            self.set_no_location();
            self.set_source_range(saved_range);
        }

        // 3. Compile the class body
        self.compile_statements(body)?;

        if annotations_used && !self.future_annotations {
            self.compile_module_annotate(body, Some(class_body_prefix_range))?;
        }

        // 4. Handle __classcell__ if needed
        let classcell_idx = self
            .code_stack
            .last_mut()
            .unwrap()
            .metadata
            .cellvars
            .iter()
            .position(|var| *var == "__class__");

        // Emit __static_attributes__ tuple
        {
            let mut attrs: Vec<String> = self
                .code_stack
                .last()
                .unwrap()
                .static_attributes
                .as_ref()
                .map(|s| s.iter().cloned().collect())
                .unwrap_or_default();
            attrs.sort();
            self.emit_load_const(ConstantData::Tuple {
                elements: attrs
                    .into_iter()
                    .map(|s| ConstantData::Str { value: s.into() })
                    .collect(),
            });
            self.set_no_location();
            self.store_name("__static_attributes__")?;
            self.set_no_location();
        }

        // Store __classdictcell__ if __classdict__ is a cell variable
        if self.current_symbol_table().needs_classdict {
            let classdict_idx = u32::from(self.get_cell_var_index("__classdict__"));
            emit!(self, PseudoInstruction::LoadClosure { i: classdict_idx });
            self.set_no_location();
            self.store_name("__classdictcell__")?;
            self.set_no_location();
        }

        if let Some(classcell_idx) = classcell_idx {
            emit!(
                self,
                PseudoInstruction::LoadClosure {
                    i: classcell_idx.to_u32()
                }
            );
            self.set_no_location();
            emit!(self, Instruction::Copy { i: 1 });
            self.set_no_location();
            self.store_name("__classcell__")?;
            self.set_no_location();
        } else {
            self.emit_load_const(ConstantData::None);
            self.set_no_location();
        }

        // Return the class namespace
        self.emit_return_value();
        self.set_no_location();
        self.emit_return_const_no_location(ConstantData::None);

        // Exit scope and return the code object
        Ok(self.exit_scope())
    }

    fn compile_class_def(
        &mut self,
        name: &str,
        body: &[ast::Stmt],
        decorator_list: &[ast::Decorator],
        type_params: Option<&ast::TypeParams>,
        arguments: Option<&ast::Arguments>,
        preserve_value_before_store: bool,
    ) -> CompileResult<()> {
        // CPython's ClassDef LOC(s) starts at the class line even when
        // decorators are present.
        let stmt_source_range = self.current_source_range;
        let class_source_range =
            self.decorated_definition_range(stmt_source_range, decorator_list, "class ");
        self.prepare_decorators(decorator_list)?;

        let is_generic = type_params.is_some();
        let firstlineno_range = decorator_list
            .first()
            .map_or(stmt_source_range, |decorator| decorator.expression.range());
        #[expect(clippy::map_unwrap_or, reason = "Changing this will not compile")]
        let firstlineno = decorator_list
            .first()
            .map(|decorator| {
                self.source_file
                    .to_source_code()
                    .line_index(decorator.expression.range().start())
                    .get()
                    .to_u32()
            })
            .unwrap_or_else(|| self.get_source_line_number().get().to_u32());

        // Save context before entering any scopes
        let saved_ctx = self.ctx;

        // Step 1: If generic, enter type params scope and compile type params
        if is_generic {
            let type_params_name = format!("<generic parameters of {name}>");
            self.set_source_range(firstlineno_range);
            self.push_output(
                bytecode::CodeFlags::OPTIMIZED | bytecode::CodeFlags::NEWLOCALS,
                0,
                0,
                0,
                &type_params_name,
            )?;

            // Set private name for name mangling
            self.code_stack.last_mut().unwrap().private = Some(name.to_owned());

            // TypeParams scope is function-like
            self.ctx = CompileContext {
                in_class: saved_ctx.in_class,
                func: FunctionContext::Function,
                in_async_scope: false,
            };

            // Compile type parameters and store them in the synthetic cell that
            // generic class bodies close over.
            self.compile_type_params(type_params.unwrap())?;
            self.set_source_range(class_source_range);
            self.store_name(".type_params")?;
        }

        // Step 2: Compile class body (always done, whether generic or not)
        let prev_ctx = self.ctx;
        self.ctx = CompileContext {
            func: FunctionContext::NoFunction,
            in_class: true,
            in_async_scope: false,
        };
        let pre_class_body_symbol_table_cursors = self.current_symbol_table_cursors();
        let class_code = self.compile_class_body(name, body, type_params, firstlineno)?;
        let post_class_body_symbol_table_cursors = self.current_symbol_table_cursors();
        self.set_symbol_table_cursors(pre_class_body_symbol_table_cursors);
        self.ctx = prev_ctx;
        self.set_source_range(class_source_range);

        // Step 3: Generate the rest of the code for the call
        if is_generic {
            // Generate class creation code
            emit!(self, Instruction::LoadBuildClass);
            emit!(self, Instruction::PushNull);

            // Create the class body function with the .type_params closure
            // captured through the class code object's freevars.
            self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?;
            self.emit_load_const(ConstantData::Str { value: name.into() });

            // Create .generic_base after the class function and name are on the
            // stack so the remaining call shape matches CPython's ordering.
            self.set_source_range(class_source_range);
            self.load_name(".type_params")?;
            emit!(
                self,
                Instruction::CallIntrinsic1 {
                    func: bytecode::IntrinsicFunction1::SubscriptGeneric
                }
            );
            self.set_source_range(class_source_range);
            self.store_name(".generic_base")?;

            let (bases, keywords) = arguments.map_or((&[][..], &[][..]), |args| {
                (&args.args[..], &args.keywords[..])
            });
            self.codegen_call_helper_impl(
                2,
                bases,
                keywords,
                class_source_range,
                None,
                Some(".generic_base"),
            )?;

            // Return the created class
            self.emit_return_value();
            self.set_no_location();

            // Exit type params scope and wrap in function
            let type_params_code = self.exit_scope();
            self.ctx = saved_ctx;

            // Execute the type params function
            self.set_source_range(class_source_range);
            self.make_closure(type_params_code, bytecode::MakeFunctionFlags::new())?;
            self.set_source_range(class_source_range);
            emit!(self, Instruction::PushNull);
            self.set_source_range(class_source_range);
            emit!(self, Instruction::Call { argc: 0 });
        } else {
            // Non-generic class: standard path
            emit!(self, Instruction::LoadBuildClass);
            emit!(self, Instruction::PushNull);

            // Create class function with closure
            self.make_closure(class_code, bytecode::MakeFunctionFlags::new())?;
            self.emit_load_const(ConstantData::Str { value: name.into() });

            if let Some(arguments) = arguments {
                self.codegen_call_helper(2, arguments, class_source_range, None)?;
            } else {
                self.set_source_range(class_source_range);
                emit!(self, Instruction::Call { argc: 2 });
            }
            self.set_symbol_table_cursors(post_class_body_symbol_table_cursors);
        }

        // Step 4: Apply decorators and store (common to both paths)
        self.apply_decorators(decorator_list);
        self.set_source_range(class_source_range);
        if preserve_value_before_store {
            emit!(self, Instruction::Copy { i: 1 });
        }
        self.store_name(name)
    }

    /// Compile an if statement with constant condition elimination.
    /// = compiler_if in CPython codegen.c
    fn compile_if(
        &mut self,
        test: &ast::Expr,
        body: &[ast::Stmt],
        elif_else_clauses: &[ast::ElifElseClause],
        stmt_range: TextRange,
    ) -> CompileResult<()> {
        let end_block = self.new_block();
        let next_block = if elif_else_clauses.is_empty() {
            end_block
        } else {
            self.new_block()
        };

        self.compile_jump_if_inner(test, false, next_block, Some(stmt_range))?;
        self.compile_statements(body)?;

        let Some((clause, rest)) = elif_else_clauses.split_first() else {
            self.use_cpython_label_block(end_block);
            return Ok(());
        };

        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: end_block }
        );
        self.set_no_location();
        self.use_cpython_label_block(next_block);

        if let Some(test) = &clause.test {
            self.compile_if(test, &clause.body, rest, clause.range)?;
        } else {
            debug_assert!(rest.is_empty());
            self.compile_statements(&clause.body)?;
        }
        self.use_cpython_label_block(end_block);
        Ok(())
    }

    fn compile_while(
        &mut self,
        test: &ast::Expr,
        body: &[ast::Stmt],
        orelse: &[ast::Stmt],
        while_range: TextRange,
    ) -> CompileResult<()> {
        self.enter_conditional_block();

        let loop_block = self.new_block();
        let end_block = self.new_block();
        let anchor_block = self.new_block();
        let loop_label = self.instr_sequence_label_for_block(loop_block);
        let end_label = self.instr_sequence_label_for_block(end_block);
        self.use_cpython_label_block(loop_block);
        self.push_fblock_labels(
            FBlockType::WhileLoop,
            loop_label,
            end_label,
            FBlockDatum::None,
        )?;
        self.compile_jump_if_inner(test, false, anchor_block, Some(while_range))?;

        self.compile_loop_body_statements(body)?;
        emit!(self, PseudoInstruction::Jump { delta: loop_block });
        self.set_no_location();

        self.pop_fblock_label(FBlockType::WhileLoop, loop_label);
        self.use_cpython_label_block(anchor_block);
        self.compile_statements(orelse)?;
        self.use_cpython_label_block(end_block);

        self.leave_conditional_block();
        Ok(())
    }

    fn compile_with(
        &mut self,
        items: &[ast::WithItem],
        body: &[ast::Stmt],
        is_async: bool,
    ) -> CompileResult<()> {
        self.enter_conditional_block();
        let result = self.compile_with_inner(items, body, is_async);
        self.leave_conditional_block();
        result
    }

    fn compile_with_inner(
        &mut self,
        items: &[ast::WithItem],
        body: &[ast::Stmt],
        is_async: bool,
    ) -> CompileResult<()> {
        // Python 3.12+ style with statement:
        //
        // BEFORE_WITH          # TOS: ctx_mgr -> [__exit__, __enter__ result]
        // L1: STORE_NAME f     # exception table: L1 to L2 -> L3 [1] lasti
        // L2: ... body ...
        //     LOAD_CONST None  # normal exit
        //     LOAD_CONST None
        //     LOAD_CONST None
        //     CALL 2           # __exit__(None, None, None)
        //     POP_TOP
        //     JUMP after
        // L3: PUSH_EXC_INFO    # exception handler
        //     WITH_EXCEPT_START # call __exit__(type, value, tb), push result
        //     TO_BOOL
        //     POP_JUMP_IF_TRUE suppress
        //     RERAISE 2
        // suppress:
        //     POP_TOP          # pop exit result
        // L5: POP_EXCEPT
        //     POP_TOP          # pop __exit__
        //     POP_TOP          # pop prev_exc (or lasti depending on layout)
        //     JUMP after
        // L6: COPY 3           # cleanup handler for reraise
        //     POP_EXCEPT
        //     RERAISE 1
        // after: ...

        let Some((item, items)) = items.split_first() else {
            return Err(self.error(CodegenErrorType::EmptyWithItems));
        };
        let with_range = item.context_expr.range();

        let body_block = self.new_block();
        let exc_handler_block = self.new_block();
        let after_block = self.new_block();
        let cleanup_block = self.new_block();

        // Compile context expression and load __enter__/__exit__ methods
        self.compile_expression(&item.context_expr)?;
        self.set_source_range(with_range);

        // Stack: [cm]
        emit!(self, Instruction::Copy { i: 1 }); // [cm, cm]

        if is_async {
            if self.ctx.func != FunctionContext::AsyncFunction
                && !self.allows_top_level_await_in_current_context()
            {
                return Err(self.error(CodegenErrorType::InvalidAsyncWith));
            }
            // Load __aexit__ and __aenter__, then call __aenter__
            emit!(
                self,
                Instruction::LoadSpecial {
                    method: SpecialMethod::AExit
                }
            ); // [cm, aexit_func, self_ae]
            emit!(self, Instruction::Swap { i: 2 }); // [cm, self_ae, aexit_func]
            emit!(self, Instruction::Swap { i: 3 }); // [aexit_func, self_ae, cm]
            emit!(
                self,
                Instruction::LoadSpecial {
                    method: SpecialMethod::AEnter
                }
            ); // [aexit_func, self_ae, aenter_func, self_an]
            emit!(self, Instruction::Call { argc: 0 }); // [aexit_func, self_ae, awaitable]
            emit!(self, Instruction::GetAwaitable { r#where: 1 });
            self.emit_load_const(ConstantData::None);
            let _ = self.compile_yield_from_sequence(true);
        } else {
            // Load __exit__ and __enter__, then call __enter__
            emit!(
                self,
                Instruction::LoadSpecial {
                    method: SpecialMethod::Exit
                }
            ); // [cm, exit_func, self_exit]
            emit!(self, Instruction::Swap { i: 2 }); // [cm, self_exit, exit_func]
            emit!(self, Instruction::Swap { i: 3 }); // [exit_func, self_exit, cm]
            emit!(
                self,
                Instruction::LoadSpecial {
                    method: SpecialMethod::Enter
                }
            ); // [exit_func, self_exit, enter_func, self_enter]
            emit!(self, Instruction::Call { argc: 0 }); // [exit_func, self_exit, result]
        }

        // Stack: [..., __exit__, enter_result]
        // Push fblock for exception table - handler goes to exc_handler_block
        // preserve_lasti=true for with statements
        emit!(
            self,
            PseudoInstruction::SetupWith {
                delta: exc_handler_block
            }
        );
        self.use_cpython_label_block(body_block);
        let fblock_type = if is_async {
            FBlockType::AsyncWith
        } else {
            FBlockType::With
        };
        let body_label = self.instr_sequence_label_for_block(body_block);
        let exc_handler_label = self.instr_sequence_label_for_block(exc_handler_block);
        self.push_fblock_labels(
            fblock_type,
            body_label,
            exc_handler_label,
            FBlockDatum::None,
        )?;

        // Store or pop the enter result
        match &item.optional_vars {
            Some(var) => {
                self.set_source_range(var.range());
                self.compile_store(var)?;
            }
            None => {
                emit!(self, Instruction::PopTop);
            }
        }
        // Stack: [..., __exit__]

        // Compile body or nested with
        if items.is_empty() {
            if body.is_empty() {
                return Err(self.error(CodegenErrorType::EmptyWithBody));
            }
            self.compile_with_body_statements(body)?;
        } else {
            self.set_source_range(items[0].context_expr.range());
            self.compile_with_inner(items, body, is_async)?;
        }

        // CPython pops the async-with fblock before emitting POP_BLOCK, but
        // sync with emits the artificial POP_BLOCK before popping the fblock.
        if is_async {
            self.pop_fblock_label(fblock_type, body_label);
            self.set_source_range(with_range);
            emit!(self, PseudoInstruction::PopBlock);
        } else {
            emit!(self, PseudoInstruction::PopBlock);
            self.set_no_location();
            self.set_source_range(with_range);
            self.pop_fblock_label(fblock_type, body_label);
        }

        self.compile_call_exit_with_nones();
        if is_async {
            emit!(self, Instruction::GetAwaitable { r#where: 2 });
            self.emit_load_const(ConstantData::None);
            let _ = self.compile_yield_from_sequence(true);
        }
        emit!(self, Instruction::PopTop); // Pop __exit__ result
        emit!(self, PseudoInstruction::Jump { delta: after_block });

        // ===== Exception handler path =====
        // Stack at entry: [..., exit_func, self_exit, lasti, exc]
        // PUSH_EXC_INFO -> [..., exit_func, self_exit, lasti, prev_exc, exc]
        self.use_cpython_label_block(exc_handler_block);

        emit!(
            self,
            PseudoInstruction::SetupCleanup {
                delta: cleanup_block
            }
        );

        emit!(self, Instruction::PushExcInfo);

        // WITH_EXCEPT_START: call exit_func(self_exit, type, value, tb)
        // Stack: [..., exit_func, self_exit, lasti, prev_exc, exc]
        emit!(self, Instruction::WithExceptStart);

        if is_async {
            emit!(self, Instruction::GetAwaitable { r#where: 2 });
            self.emit_load_const(ConstantData::None);
            let _ = self.compile_yield_from_sequence(true);
        }

        self.compile_with_except_finish(cleanup_block);

        self.use_cpython_label_block(after_block);

        Ok(())
    }

    fn compile_for(
        &mut self,
        target: &ast::Expr,
        iter: &ast::Expr,
        body: &[ast::Stmt],
        orelse: &[ast::Stmt],
        is_async: bool,
        for_range: TextRange,
    ) -> CompileResult<()> {
        self.enter_conditional_block();

        // Start loop
        let for_block = self.new_block();
        let (body_label, send_block) = if is_async {
            (None, self.new_block())
        } else {
            let body_label = self.current_code_info().new_instr_sequence_label();
            (Some(body_label), BlockIdx::NULL)
        };
        let else_block = self.new_block();
        let after_block = self.new_block();
        let for_label = self.instr_sequence_label_for_block(for_block);
        let after_label = self.instr_sequence_label_for_block(after_block);
        let mut end_async_for_target = BlockIdx::NULL;

        if !is_async {
            // CPython codegen_for() pushes the loop fblock before compiling
            // the iterable expression.
            self.push_fblock_labels(
                FBlockType::ForLoop,
                for_label,
                after_label,
                FBlockDatum::None,
            )?;
        }

        // The thing iterated:
        self.compile_expression(iter)?;

        if is_async {
            if self.ctx.func != FunctionContext::AsyncFunction
                && !self.allows_top_level_await_in_current_context()
            {
                return Err(self.error(CodegenErrorType::InvalidAsyncFor));
            }
            self.set_source_range(iter.range());
            emit!(self, Instruction::GetAiter);

            self.use_cpython_label_block(for_block);
            self.set_source_range(for_range);

            // codegen_async_for: push fblock BEFORE SETUP_FINALLY
            self.push_fblock_labels(
                FBlockType::ForLoop,
                for_label,
                after_label,
                FBlockDatum::None,
            )?;

            // SETUP_FINALLY to guard the __anext__ call
            emit!(self, PseudoInstruction::SetupFinally { delta: else_block });
            emit!(self, Instruction::GetAnext);
            self.emit_load_const(ConstantData::None);
            self.use_cpython_label_block(send_block);
            let _ = self.compile_yield_from_sequence(true);
            end_async_for_target = send_block;
            // POP_BLOCK for SETUP_FINALLY - only GetANext/yield_from are protected
            emit!(self, PseudoInstruction::PopBlock);
            emit!(self, Instruction::NotTaken);

            // Success block for __anext__
            self.compile_store(target)?;
        } else {
            // Retrieve Iterator
            self.set_source_range(iter.range());
            emit!(self, Instruction::GetIter);

            self.use_cpython_label_block(for_block);

            emit!(self, Instruction::ForIter { delta: else_block });

            let saved_range = self.current_source_range;
            self.set_source_range(target.range());
            emit!(self, Instruction::Nop);
            let result = self
                .current_code_info()
                .use_raw_instr_sequence_label(body_label.expect("sync for must have body label"));
            unwrap_internal(self, result);
            self.compile_store(target)?;
            self.set_source_range(saved_range);
        };

        self.compile_loop_body_statements(body)?;
        emit!(self, PseudoInstruction::Jump { delta: for_block });
        self.set_no_location();

        if is_async {
            // codegen_async_for() pops the loop fblock before the
            // END_ASYNC_FOR exception block. Sync codegen_for() keeps the
            // fblock through END_FOR/POP_ITER and pops below.
            self.pop_fblock_label(FBlockType::ForLoop, for_label);
        }

        self.use_cpython_label_block(else_block);

        // Except block for __anext__ / end of sync for
        if is_async {
            // codegen_async_for emits END_ASYNC_FOR at the iterator location,
            // after the for-loop fblock has already been popped.
            let saved_range = self.current_source_range;
            self.set_source_range(iter.range());
            self.emit_end_async_for(end_async_for_target);
            self.set_source_range(saved_range);
        } else {
            // codegen_for emits END_FOR/POP_ITER with NO_LOCATION. Line numbers
            // are propagated later by flowgraph.c::resolve_line_numbers().
            emit!(self, Instruction::EndFor);
            self.set_no_location();
            emit!(self, Instruction::PopIter);
            self.set_no_location();
            self.pop_fblock_label(FBlockType::ForLoop, for_label);
        }
        self.compile_statements(orelse)?;

        self.use_cpython_label_block(after_block);

        // Implicit return after for-loop should be attributed to the `for` line
        self.set_source_range(iter.range());

        self.leave_conditional_block();
        Ok(())
    }

    fn compile_comprehension_iter(&mut self, generator: &ast::Comprehension) -> CompileResult<()> {
        let saved_range = self.current_source_range;
        self.compile_expression(&generator.iter)?;
        self.set_source_range(generator.iter.range());
        if generator.is_async {
            emit!(self, Instruction::GetAiter);
        } else {
            emit!(self, Instruction::GetIter);
        }
        self.set_source_range(saved_range);
        Ok(())
    }

    fn singleton_comprehension_assignment_iter(iter: &ast::Expr) -> Option<&ast::Expr> {
        let elts = match iter {
            ast::Expr::List(ast::ExprList { elts, .. }) => elts,
            ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => elts,
            _ => return None,
        };
        match elts.as_slice() {
            [elt] if !matches!(elt, ast::Expr::Starred(_)) => Some(elt),
            _ => None,
        }
    }

    /// Ensures that `pc.fail_pop` has at least `n + 1` entries.
    /// If not, new labels are generated and pushed until the required size is reached.
    fn ensure_fail_pop(&mut self, pc: &mut PatternContext, n: usize) {
        let required_size = n + 1;
        if required_size <= pc.fail_pop.len() {
            return;
        }
        while pc.fail_pop.len() < required_size {
            let new_block = self.new_block();
            pc.fail_pop.push(new_block);
        }
    }

    fn jump_to_fail_pop(&mut self, pc: &mut PatternContext, op: JumpOp) {
        // Compute the total number of items to pop:
        // items on top plus the captured objects.
        let pops = pc.on_top + pc.stores.len();
        // Ensure that the fail_pop vector has at least `pops + 1` elements.
        self.ensure_fail_pop(pc, pops);
        // Emit a jump using the jump target stored at index `pops`.
        match op {
            JumpOp::Jump => {
                emit!(
                    self,
                    PseudoInstruction::Jump {
                        delta: pc.fail_pop[pops]
                    }
                )
            }
            JumpOp::PopJumpIfFalse => {
                emit!(
                    self,
                    Instruction::PopJumpIfFalse {
                        delta: pc.fail_pop[pops]
                    }
                )
            }
        };
    }

    /// Emits the necessary POP instructions for all failure targets in the pattern context,
    /// then resets the fail_pop vector.
    fn emit_and_reset_fail_pop(&mut self, pc: &mut PatternContext, loc: TextRange) {
        // If the fail_pop vector is empty, nothing needs to be done.
        if pc.fail_pop.is_empty() {
            debug_assert!(pc.fail_pop.is_empty());
            return;
        }
        // Iterate over the fail_pop vector in reverse order, skipping the first label.
        for &label in pc.fail_pop.iter().skip(1).rev() {
            // CPython emit_and_reset_fail_pop() uses USE_LABEL here.
            self.use_cpython_label_block(label);
            // Emit the POP instruction.
            self.set_source_range(loc);
            emit!(self, Instruction::PopTop);
        }
        // Finally, use the first label.
        // CPython emit_and_reset_fail_pop() uses USE_LABEL here too.
        self.use_cpython_label_block(pc.fail_pop[0]);
        pc.fail_pop.clear();
        // Free the memory used by the vector.
        pc.fail_pop.shrink_to_fit();
    }

    /// Duplicate the effect of Python 3.10's ROT_* instructions using SWAPs.
    fn pattern_helper_rotate(&mut self, loc: TextRange, mut count: usize) {
        // Rotate TOS (top of stack) to position `count` down
        // This is done by a series of swaps
        // For count=1, no rotation needed (already at top)
        // For count=2, swap TOS with item 1 position down
        // For count=3, swap TOS with item 2 positions down, then with item 1 position down
        while count > 1 {
            // Emit a SWAP instruction with the current count.
            self.set_source_range(loc);
            emit!(
                self,
                Instruction::Swap {
                    i: u32::try_from(count).unwrap()
                }
            );
            count -= 1;
        }
    }

    /// Helper to store a captured name for a star pattern.
    ///
    /// If `n` is `None`, it emits a POP_TOP instruction. Otherwise, it first
    /// checks that the name is allowed and not already stored. Then it rotates
    /// the object on the stack beneath any preserved items and appends the name
    /// to the list of captured names.
    fn pattern_helper_store_name(
        &mut self,
        loc: TextRange,
        n: Option<&ast::Identifier>,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        match n {
            // If no name is provided, simply pop the top of the stack.
            None => {
                self.set_source_range(loc);
                emit!(self, Instruction::PopTop);
                Ok(())
            }
            Some(name) => {
                // Ensure we don't store the same name twice.
                // TODO: maybe pc.stores should be a set?
                if pc.stores.contains(&name.to_string()) {
                    return Err(self.error_ranged(
                        CodegenErrorType::DuplicateStore(name.as_str().to_string()),
                        loc,
                    ));
                }

                // Calculate how many items to rotate:
                let rotations = pc.on_top + pc.stores.len() + 1;
                self.pattern_helper_rotate(loc, rotations);

                // Append the name to the captured stores.
                pc.stores.push(name.to_string());
                Ok(())
            }
        }
    }

    fn pattern_wildcard_check(pattern: &ast::Pattern) -> bool {
        matches!(
            pattern,
            ast::Pattern::MatchAs(ast::PatternMatchAs { name: None, .. })
        )
    }

    fn pattern_wildcard_star_check(pattern: &ast::Pattern) -> bool {
        matches!(
            pattern,
            ast::Pattern::MatchStar(ast::PatternMatchStar { name: None, .. })
        )
    }

    fn pattern_unpack_helper(
        &mut self,
        loc: TextRange,
        elts: &[ast::Pattern],
    ) -> CompileResult<()> {
        let n = elts.len();
        let mut seen_star = false;
        for (i, elt) in elts.iter().enumerate() {
            if elt.is_match_star() && !seen_star {
                if i >= (1 << 8) || (n - i - 1) >= ((i32::MAX as usize) >> 8) {
                    return Err(self.error_ranged(
                        CodegenErrorType::TooManyExpressionsInStarUnpackingSequencePattern,
                        loc,
                    ));
                }
                let counts = UnpackExArgs {
                    before: u8::try_from(i).unwrap(),
                    after: u32::try_from(n - i - 1).unwrap(),
                };
                self.set_source_range(loc);
                emit!(self, Instruction::UnpackEx { counts });
                seen_star = true;
            } else if elt.is_match_star() {
                return Err(self.error_ranged(
                    CodegenErrorType::MultipleStarredExpressionsInSequencePattern,
                    loc,
                ));
            }
        }
        if !seen_star {
            self.set_source_range(loc);
            emit!(
                self,
                Instruction::UnpackSequence {
                    count: u32::try_from(n).unwrap()
                }
            );
        }
        Ok(())
    }

    fn pattern_helper_sequence_unpack(
        &mut self,
        loc: TextRange,
        patterns: &[ast::Pattern],
        _star: Option<usize>,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Unpack the sequence into individual subjects.
        self.pattern_unpack_helper(loc, patterns)?;
        let size = patterns.len();
        // Increase the on_top counter for the newly unpacked subjects.
        pc.on_top += size;
        // For each unpacked subject, compile its subpattern.
        for pattern in patterns {
            // Decrement on_top for each subject as it is consumed.
            pc.on_top -= 1;
            self.compile_pattern_subpattern(pattern, pc)?;
        }
        Ok(())
    }

    fn pattern_helper_sequence_subscr(
        &mut self,
        loc: TextRange,
        patterns: &[ast::Pattern],
        star: usize,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Keep the subject around for extracting elements.
        pc.on_top += 1;
        for (i, pattern) in patterns.iter().enumerate() {
            if Self::pattern_wildcard_check(pattern) {
                continue;
            }
            if i == star {
                // This must be a starred wildcard.
                debug_assert!(Self::pattern_wildcard_star_check(pattern));
                continue;
            }
            // Duplicate the subject.
            self.set_source_range(loc);
            emit!(self, Instruction::Copy { i: 1 });
            if i < star {
                // For indices before the star, use a nonnegative index equal to i.
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Integer { value: i.into() });
            } else {
                // For indices after the star, compute a nonnegative index:
                // index = len(subject) - (size - i)
                self.set_source_range(loc);
                emit!(self, Instruction::GetLen);
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Integer {
                    value: (patterns.len() - i).into(),
                });
                // Subtract to compute the correct index.
                self.set_source_range(loc);
                emit!(
                    self,
                    Instruction::BinaryOp {
                        op: BinaryOperator::Subtract
                    }
                );
            }
            // Use BINARY_OP/NB_SUBSCR to extract the element.
            self.set_source_range(loc);
            emit!(
                self,
                Instruction::BinaryOp {
                    op: BinaryOperator::Subscr
                }
            );
            // Compile the subpattern in irrefutable mode.
            self.compile_pattern_subpattern(pattern, pc)?;
        }
        // Pop the subject off the stack.
        pc.on_top -= 1;
        self.set_source_range(loc);
        emit!(self, Instruction::PopTop);
        Ok(())
    }

    fn compile_pattern_subpattern(
        &mut self,
        p: &ast::Pattern,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Save the current allow_irrefutable state.
        let old_allow_irrefutable = pc.allow_irrefutable;
        // Temporarily allow irrefutable patterns.
        pc.allow_irrefutable = true;
        // Compile the pattern.
        self.compile_pattern(p, pc)?;
        // Restore the original state.
        pc.allow_irrefutable = old_allow_irrefutable;
        Ok(())
    }

    fn compile_pattern_as(
        &mut self,
        p: &ast::PatternMatchAs,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // If there is no sub-pattern, then it's an irrefutable match.
        if p.pattern.is_none() {
            if !pc.allow_irrefutable {
                if let Some(name) = p.name.as_ref() {
                    return Err(self.error_ranged(
                        CodegenErrorType::UnreachableNameCapturePattern(name.to_string()),
                        p.range,
                    ));
                }
                // A wildcard makes remaining patterns unreachable.
                return Err(
                    self.error_ranged(CodegenErrorType::UnreachableWildcardPattern, p.range)
                );
            }
            // If irrefutable matches are allowed, store the name (if any).
            return self.pattern_helper_store_name(p.range, p.name.as_ref(), pc);
        }

        // Otherwise, there is a sub-pattern. Duplicate the object on top of the stack.
        pc.on_top += 1;
        self.set_source_range(p.range);
        emit!(self, Instruction::Copy { i: 1 });
        // Compile the sub-pattern.
        self.compile_pattern(p.pattern.as_ref().unwrap(), pc)?;
        // After success, decrement the on_top counter.
        pc.on_top -= 1;
        // Store the captured name (if any).
        self.pattern_helper_store_name(p.range, p.name.as_ref(), pc)?;
        Ok(())
    }

    fn compile_pattern_star(
        &mut self,
        p: &ast::PatternMatchStar,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        self.pattern_helper_store_name(p.range, p.name.as_ref(), pc)?;
        Ok(())
    }

    /// Validates that keyword attributes in a class pattern are allowed
    /// and not duplicated.
    fn validate_kwd_attrs(
        &mut self,
        attrs: &[ast::Identifier],
        patterns: &[ast::Pattern],
    ) -> CompileResult<()> {
        let n_attrs = attrs.len();
        for i in 0..n_attrs {
            let attr = attrs[i].as_str();
            // Check for duplicates: compare with every subsequent attribute.
            for (j, ident) in attrs.iter().enumerate().take(n_attrs).skip(i + 1) {
                let other = ident.as_str();
                if attr == other {
                    return Err(self.error_ranged(
                        CodegenErrorType::RepeatedAttributePattern(attr.to_owned()),
                        patterns[j].range(),
                    ));
                }
            }
        }
        Ok(())
    }

    fn compile_pattern_class(
        &mut self,
        p: &ast::PatternMatchClass,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Extract components from the MatchClass pattern.
        let match_class = p;
        let patterns = &match_class.arguments.patterns;

        // Extract keyword attributes and patterns.
        // Capacity is pre-allocated based on the number of keyword arguments.
        let mut kwd_attrs = Vec::with_capacity(match_class.arguments.keywords.len());
        let mut kwd_patterns = Vec::with_capacity(match_class.arguments.keywords.len());
        for kwd in &match_class.arguments.keywords {
            kwd_attrs.push(kwd.attr.clone());
            kwd_patterns.push(kwd.pattern.clone());
        }

        let nargs = patterns.len();
        let n_attrs = kwd_attrs.len();
        let n_kwd_patterns = kwd_patterns.len();
        if n_attrs != n_kwd_patterns {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError(format!(
                    "kwd_attrs ({n_attrs}) / kwd_patterns ({n_kwd_patterns}) length mismatch in class pattern"
                )),
                p.range,
            ));
        }

        // Check for too many sub-patterns.
        if nargs > i32::MAX as usize
            || nargs.saturating_add(n_attrs).saturating_sub(1) > i32::MAX as usize
        {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError(format!(
                    "too many sub-patterns in class pattern {}",
                    UnparseExpr::new(&match_class.cls, &self.source_file)
                )),
                p.range,
            ));
        }

        // Validate keyword attributes if any.
        if n_attrs != 0 {
            self.validate_kwd_attrs(&kwd_attrs, &kwd_patterns)?;
        }

        // Compile the class expression.
        self.compile_expression(&match_class.cls)?;
        self.set_source_range(p.range);

        // Create a new tuple of attribute names.
        let mut attr_names = vec![];
        for name in &kwd_attrs {
            // Py_NewRef(name) is emulated by cloning the name into a PyObject.
            attr_names.push(ConstantData::Str {
                value: name.as_str().to_string().into(),
            });
        }

        // Emit instructions:
        // 1. Load the new tuple of attribute names.
        self.emit_load_const(ConstantData::Tuple {
            elements: attr_names,
        });
        // 2. Emit MATCH_CLASS with nargs.
        emit!(
            self,
            Instruction::MatchClass {
                count: u32::try_from(nargs).unwrap()
            }
        );
        // 3. Duplicate the top of the stack.
        emit!(self, Instruction::Copy { i: 1 });
        // 4. Load None.
        self.emit_load_const(ConstantData::None);
        // 5. Compare with IS_OP 1.
        emit!(
            self,
            Instruction::IsOp {
                invert: Invert::Yes
            }
        );

        // At this point the TOS is a tuple of (nargs + n_attrs) attributes (or None).
        pc.on_top += 1;
        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);

        // Unpack the tuple into (nargs + n_attrs) items.
        let total = nargs + n_attrs;
        emit!(
            self,
            Instruction::UnpackSequence {
                count: u32::try_from(total).unwrap()
            }
        );
        if total == 0 {
            pc.on_top -= 1;
        } else {
            pc.on_top += total - 1;
        }

        // Process each sub-pattern.
        for subpattern in patterns.iter().chain(kwd_patterns.iter()) {
            // Decrement the on_top counter for each sub-pattern
            pc.on_top -= 1;

            if Self::pattern_wildcard_check(subpattern) {
                self.set_source_range(p.range);
                emit!(self, Instruction::PopTop);
                continue; // Don't compile wildcard patterns
            }

            // Compile the subpattern without irrefutability checks.
            self.compile_pattern_subpattern(subpattern, pc)?;
        }
        Ok(())
    }

    fn compile_pattern_mapping(
        &mut self,
        p: &ast::PatternMatchMapping,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        let mapping = p;
        let keys = &mapping.keys;
        let patterns = &mapping.patterns;
        let size = keys.len();
        let star_target = &mapping.rest;

        // Validate pattern count matches key count
        if keys.len() != patterns.len() {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError(format!(
                    "keys ({}) / patterns ({}) length mismatch in mapping pattern",
                    keys.len(),
                    patterns.len()
                )),
                p.range,
            ));
        }

        // `case {**_}:` is rejected before codegen. RustPython's parser
        // currently lets it through, so keep the compiler boundary equivalent.
        if let Some(rest) = star_target
            && rest.as_str() == "_"
        {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError("invalid syntax".to_string()),
                rest.range,
            ));
        }

        // Step 1: Check if subject is a mapping
        // Stack: [subject]
        pc.on_top += 1;

        self.set_source_range(p.range);
        emit!(self, Instruction::MatchMapping);
        // Stack: [subject, is_mapping]

        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
        // Stack: [subject]

        // Special case: empty pattern {} with no rest
        if size == 0 && star_target.is_none() {
            // If the pattern is just "{}", we're done! Pop the subject
            pc.on_top -= 1;
            emit!(self, Instruction::PopTop);
            return Ok(());
        }

        // Length check for patterns with keys
        if size > 0 {
            // Check if the mapping has at least 'size' keys
            self.set_source_range(p.range);
            emit!(self, Instruction::GetLen);
            self.set_source_range(p.range);
            self.emit_load_const(ConstantData::Integer { value: size.into() });
            // Stack: [subject, len, size]
            self.set_source_range(p.range);
            emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::GreaterOrEqual
                }
            );
            self.set_source_range(p.range);
            self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
            // Stack: [subject]
        }

        // Check for overflow (INT_MAX < size - 1)
        if size.saturating_sub(1) > i32::MAX as usize {
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError(
                    "too many sub-patterns in mapping pattern".to_string(),
                ),
                p.range,
            ));
        }
        let size = size.to_u32();

        // Step 2: Validate and compile all keys.
        let mut seen = Vec::new();
        for key in keys {
            self.compile_pattern_mapping_key(&mut seen, p.range, key)?;
        }
        self.set_source_range(p.range);
        // Stack: [subject, key1, key2, ..., key_n]

        // Build tuple of keys (empty tuple if size==0)
        emit!(self, Instruction::BuildTuple { count: size });
        // Stack: [subject, keys_tuple]

        // Match keys
        emit!(self, Instruction::MatchKeys);
        // Stack: [subject, keys_tuple, values_or_none]
        pc.on_top += 2; // subject and keys_tuple are underneath

        // Check if match succeeded
        self.set_source_range(p.range);
        emit!(self, Instruction::Copy { i: 1 });
        // Stack: [subject, keys_tuple, values_tuple, values_tuple_copy]

        // Check if copy is None (consumes the copy like POP_JUMP_IF_NONE)
        self.set_source_range(p.range);
        self.emit_load_const(ConstantData::None);
        self.set_source_range(p.range);
        emit!(
            self,
            Instruction::IsOp {
                invert: Invert::Yes
            }
        );

        // Stack: [subject, keys_tuple, values_tuple, bool]
        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
        // Stack: [subject, keys_tuple, values_tuple]

        // Unpack values (the original values_tuple)
        emit!(self, Instruction::UnpackSequence { count: size });
        // Stack after unpack: [subject, keys_tuple, ...unpacked values...]
        if size == 0 {
            pc.on_top -= 1;
        } else {
            pc.on_top += size as usize - 1;
        }

        // Step 3: Process matched values
        for i in 0..size {
            pc.on_top -= 1;
            self.compile_pattern_subpattern(&patterns[i as usize], pc)?;
        }

        // After processing subpatterns, adjust on_top
        // "Whatever happens next should consume the tuple of keys and the subject"
        // Stack currently: [subject, keys_tuple, ...any captured values...]
        pc.on_top -= 2;

        // Step 4: Handle rest pattern or cleanup
        if let Some(rest_name) = star_target {
            // Build rest dict for **rest pattern
            // Stack: [subject, keys_tuple]

            // Build rest dict exactly
            self.set_source_range(p.range);
            emit!(self, Instruction::BuildMap { count: 0 });
            // Stack: [subject, keys_tuple, {}]
            self.set_source_range(p.range);
            emit!(self, Instruction::Swap { i: 3 });
            // Stack: [{}, keys_tuple, subject]
            self.set_source_range(p.range);
            emit!(self, Instruction::DictUpdate { i: 2 });
            // Stack after DICT_UPDATE: [rest_dict, keys_tuple]
            // DICT_UPDATE consumes source (subject) and leaves dict in place

            // Unpack keys and delete from rest_dict
            self.set_source_range(p.range);
            emit!(self, Instruction::UnpackSequence { count: size });
            // Stack: [rest_dict, k1, k2, ..., kn] (if size==0, nothing pushed)

            // Delete each key from rest_dict (skipped when size==0)
            // while (size) { COPY(1 + size--); SWAP(2); DELETE_SUBSCR }
            let mut remaining = size;
            while remaining > 0 {
                // Copy rest_dict which is at position (1 + remaining) from TOS
                self.set_source_range(p.range);
                emit!(self, Instruction::Copy { i: 1 + remaining });
                // Stack: [rest_dict, k1, ..., kn, rest_dict]
                self.set_source_range(p.range);
                emit!(self, Instruction::Swap { i: 2 });
                // Stack: [rest_dict, k1, ..., kn-1, rest_dict, kn]
                self.set_source_range(p.range);
                emit!(self, Instruction::DeleteSubscr);
                // Stack: [rest_dict, k1, ..., kn-1] (removed kn from rest_dict)
                remaining -= 1;
            }
            // Stack: [rest_dict] (plus any previously stored values)
            // pattern_helper_store_name will handle the rotation correctly

            // Store the rest dict
            self.pattern_helper_store_name(p.range, Some(rest_name), pc)?;
        } else {
            // Non-rest pattern: just clean up the stack

            // Pop them as we're not using them
            self.set_source_range(p.range);
            emit!(self, Instruction::PopTop); // Pop keys_tuple
            self.set_source_range(p.range);
            emit!(self, Instruction::PopTop); // Pop subject
        }

        Ok(())
    }

    fn compile_pattern_mapping_key(
        &mut self,
        seen: &mut Vec<ConstantData>,
        pattern_range: TextRange,
        key: &ast::Expr,
    ) -> CompileResult<()> {
        let is_attribute = matches!(key, ast::Expr::Attribute(_));
        let constant = match self.try_compile_match_mapping_key_constant(key)? {
            Some(constant) => Some(constant),
            None if is_attribute => None,
            None => {
                if Self::is_unexpected_match_literal_constant(key) {
                    return Err(self.error_ranged(
                        CodegenErrorType::SyntaxError(
                            "unexpected constant inside of a literal pattern".to_string(),
                        ),
                        pattern_range,
                    ));
                }
                return Err(self.error_ranged(
                    CodegenErrorType::SyntaxError(
                        "mapping pattern keys may only match literals and attribute lookups"
                            .to_string(),
                    ),
                    pattern_range,
                ));
            }
        };

        if let Some(constant) = constant {
            if seen
                .iter()
                .any(|seen| Self::match_mapping_keys_equal(seen, &constant))
            {
                let key_repr = Self::match_mapping_key_repr(&constant);
                return Err(self.error_ranged(
                    CodegenErrorType::SyntaxError(format!(
                        "mapping pattern checks duplicate key ({key_repr})"
                    )),
                    pattern_range,
                ));
            }
            seen.push(constant);
        }

        self.compile_match_pattern_expr(key)
    }

    fn try_compile_match_mapping_key_constant(
        &mut self,
        key: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.try_fold_match_pattern_const_expr(key)? {
            return Ok(Some(constant));
        }
        self.try_compile_match_mapping_key_direct_constant(key)
    }

    fn try_compile_match_value_constant(
        &mut self,
        value: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.try_fold_match_pattern_const_expr(value)? {
            return Ok(Some(constant));
        }
        self.try_compile_match_pattern_direct_literal(value)
    }

    fn match_mapping_keys_equal(left: &ConstantData, right: &ConstantData) -> bool {
        use ConstantData::{Bytes, Ellipsis, None, Str};

        if Self::match_mapping_numeric_keys_equal(left, right).unwrap_or(false) {
            return true;
        }

        match (left, right) {
            (Str { value: left }, Str { value: right }) => left == right,
            (Bytes { value: left }, Bytes { value: right }) => left == right,
            (None, None) | (Ellipsis, Ellipsis) => true,
            _ => false,
        }
    }

    fn match_mapping_key_repr(key: &ConstantData) -> String {
        match key {
            ConstantData::Integer { value } => value.to_string(),
            ConstantData::Float { value } => literal_float::to_string(*value),
            ConstantData::Complex { value } => literal_complex::to_string(value.re, value.im),
            ConstantData::Boolean { value } => {
                if *value {
                    "True".to_owned()
                } else {
                    "False".to_owned()
                }
            }
            ConstantData::Str { value } => UnicodeEscape::new_repr(value.as_ref())
                .str_repr()
                .to_string()
                .unwrap_or_else(|| value.to_string()),
            ConstantData::Bytes { value } => AsciiEscape::new_repr(value)
                .bytes_repr()
                .to_string()
                .unwrap_or_else(|| format!(r#"b"{}""#, value.escape_ascii())),
            ConstantData::None => "None".to_owned(),
            ConstantData::Ellipsis => "...".to_owned(),
            other => other.to_string(),
        }
    }

    fn match_mapping_numeric_keys_equal(left: &ConstantData, right: &ConstantData) -> Option<bool> {
        use ConstantData::{Boolean, Complex, Float, Integer};

        match (left, right) {
            (Integer { value: left }, Integer { value: right }) => Some(left == right),
            (Boolean { value: left }, Boolean { value: right }) => Some(left == right),
            (Boolean { value }, Integer { value: int })
            | (Integer { value: int }, Boolean { value }) => {
                Some(BigInt::from(u8::from(*value)) == *int)
            }
            (Float { value: left }, Float { value: right }) => Some(left == right),
            (Integer { value: int }, Float { value: float })
            | (Float { value: float }, Integer { value: int }) => {
                Some(Self::match_mapping_float_integer_equal(*float, int))
            }
            (Boolean { value }, Float { value: float })
            | (Float { value: float }, Boolean { value }) => Some(
                Self::match_mapping_float_integer_equal(*float, &BigInt::from(u8::from(*value))),
            ),
            (Complex { value: left }, Complex { value: right }) => {
                Some(left.re == right.re && left.im == right.im)
            }
            (Complex { value: complex }, other) | (other, Complex { value: complex }) => Some(
                complex.im == 0.0
                    && Self::match_mapping_float_real_constant_equal(complex.re, other)
                        .unwrap_or(false),
            ),
            _ => Option::None,
        }
    }

    fn match_mapping_float_real_constant_equal(float: f64, other: &ConstantData) -> Option<bool> {
        match other {
            ConstantData::Integer { value } => {
                Some(Self::match_mapping_float_integer_equal(float, value))
            }
            ConstantData::Boolean { value } => Some(Self::match_mapping_float_integer_equal(
                float,
                &BigInt::from(u8::from(*value)),
            )),
            ConstantData::Float { value } => Some(float == *value),
            _ => None,
        }
    }

    fn match_mapping_float_integer_equal(float: f64, int: &BigInt) -> bool {
        Self::match_mapping_float_to_integer(float).is_some_and(|float_int| &float_int == int)
    }

    fn match_mapping_float_to_integer(value: f64) -> Option<BigInt> {
        if !value.is_finite() {
            return None;
        }
        if value == 0.0 {
            return Some(BigInt::from(0));
        }

        let bits = value.to_bits();
        let negative = (bits >> 63) != 0;
        let exponent_bits = i32::try_from((bits >> 52) & 0x7ff).ok()?;
        let fraction = bits & ((1_u64 << 52) - 1);
        let (mantissa, exponent) = if exponent_bits == 0 {
            (fraction, -1074)
        } else {
            ((1_u64 << 52) | fraction, exponent_bits - 1023 - 52)
        };

        let mut integer = if exponent >= 0 {
            BigInt::from(mantissa) << u32::try_from(exponent).ok()?
        } else {
            let shift = u32::try_from(-exponent).ok()?;
            if shift >= u64::BITS {
                return None;
            }
            let mask = (1_u64 << shift) - 1;
            if mantissa & mask != 0 {
                return None;
            }
            BigInt::from(mantissa >> shift)
        };

        if negative {
            integer = -integer;
        }
        Some(integer)
    }

    fn compile_pattern_or(
        &mut self,
        p: &ast::PatternMatchOr,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Ensure the pattern is a MatchOr.
        let end = self.new_block(); // Create a new jump target label.
        let size = p.patterns.len();
        if size <= 1 {
            return Err(self.error(CodegenErrorType::SyntaxError(
                "MatchOr requires at least 2 patterns".to_owned(),
            )));
        }

        // Save the current pattern context.
        let old_pc = pc.clone();
        // Simulate Py_INCREF on pc.stores by cloning it.
        pc.stores = pc.stores.clone();
        let mut control: Option<Vec<String>> = None; // Will hold the capture list of the first alternative.

        // Process each alternative.
        for (i, alt) in p.patterns.iter().enumerate() {
            // Create a fresh empty store for this alternative.
            pc.stores = Vec::new();
            // An irrefutable subpattern must be last (if allowed).
            pc.allow_irrefutable = (i == size - 1) && old_pc.allow_irrefutable;
            // Reset failure targets and the on_top counter.
            pc.fail_pop.clear();
            pc.on_top = 0;
            // Emit a COPY(1) instruction before compiling the alternative.
            self.set_source_range(alt.range());
            emit!(self, Instruction::Copy { i: 1 });
            self.compile_pattern(alt, pc)?;

            let n_stores = pc.stores.len();
            if i == 0 {
                // Save the captured names from the first alternative.
                control = Some(pc.stores.clone());
            } else {
                let control_vec = control.as_ref().unwrap();
                if n_stores != control_vec.len() {
                    return Err(
                        self.error_ranged(CodegenErrorType::ConflictingNameBindPattern, p.range())
                    );
                } else if n_stores > 0 {
                    // Check that the names occur in the same order.
                    for i_control in (0..n_stores).rev() {
                        let name = &control_vec[i_control];
                        // Find the index of `name` in the current stores.
                        let i_stores =
                            pc.stores.iter().position(|n| n == name).ok_or_else(|| {
                                self.error_ranged(
                                    CodegenErrorType::ConflictingNameBindPattern,
                                    p.range(),
                                )
                            })?;
                        if i_control != i_stores {
                            // The orders differ; we must reorder.
                            assert!(i_stores < i_control, "expected i_stores < i_control");
                            let rotations = i_stores + 1;
                            // Rotate pc.stores: take a slice of the first `rotations` items...
                            let rotated = pc.stores[0..rotations].to_vec();
                            // Remove those elements.
                            for _ in 0..rotations {
                                pc.stores.remove(0);
                            }
                            // Insert the rotated slice at the appropriate index.
                            let insert_pos = i_control - i_stores;
                            for (j, elem) in rotated.into_iter().enumerate() {
                                pc.stores.insert(insert_pos + j, elem);
                            }
                            // Also perform the same rotation on the evaluation stack.
                            self.set_source_range(alt.range());
                            for _ in 0..=i_stores {
                                self.pattern_helper_rotate(alt.range(), i_control + 1);
                            }
                        }
                    }
                }
            }
            // Emit a jump to the common end label and reset any failure jump targets.
            self.set_source_range(alt.range());
            emit!(self, PseudoInstruction::Jump { delta: end });
            self.set_source_range(alt.range());
            self.emit_and_reset_fail_pop(pc, alt.range());
        }

        // Restore the original pattern context.
        *pc = old_pc;
        // Simulate Py_INCREF on pc.stores.
        pc.stores = pc.stores.clone();
        // In C, old_pc.fail_pop is set to NULL to avoid freeing it later.
        // In Rust, old_pc is a local clone, so we need not worry about that.

        // No alternative matched: pop the subject and fail.
        self.set_source_range(p.range());
        emit!(self, Instruction::PopTop);
        self.jump_to_fail_pop(pc, JumpOp::Jump);

        // Use the label "end".
        // CPython codegen_pattern_or() emits USE_LABEL(c, end).
        self.use_cpython_label_block(end);

        // Adjust the final captures.
        let n_stores = control.as_ref().unwrap().len();
        let n_rots = n_stores + 1 + pc.on_top + pc.stores.len();
        for i in 0..n_stores {
            // Rotate the capture to its proper place.
            self.set_source_range(p.range());
            self.pattern_helper_rotate(p.range(), n_rots);
            let name = &control.as_ref().unwrap()[i];
            // Check for duplicate binding.
            if pc.stores.contains(name) {
                return Err(self.error_ranged(
                    CodegenErrorType::DuplicateStore(name.to_string()),
                    p.range(),
                ));
            }
            pc.stores.push(name.clone());
        }

        // Old context and control will be dropped automatically.
        // Finally, pop the copy of the subject.
        self.set_source_range(p.range());
        emit!(self, Instruction::PopTop);
        Ok(())
    }

    fn compile_pattern_sequence(
        &mut self,
        p: &ast::PatternMatchSequence,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Ensure the pattern is a MatchSequence.
        let patterns = &p.patterns; // a slice of ast::Pattern
        let size = patterns.len();
        let mut star: Option<usize> = None;
        let mut only_wildcard = true;
        let mut star_wildcard = false;

        // Find a starred pattern, if it exists. There may be at most one.
        for (i, pattern) in patterns.iter().enumerate() {
            if pattern.is_match_star() {
                if star.is_some() {
                    return Err(self.error_ranged(
                        CodegenErrorType::MultipleStarredNamesInSequencePattern,
                        p.range,
                    ));
                }
                // star wildcard check
                star_wildcard = Self::pattern_wildcard_star_check(pattern);
                only_wildcard &= star_wildcard;
                star = Some(i);
                continue;
            }
            // wildcard check
            only_wildcard &= Self::pattern_wildcard_check(pattern);
        }

        // Keep the subject on top during the sequence and length checks.
        pc.on_top += 1;
        self.set_source_range(p.range);
        emit!(self, Instruction::MatchSequence);
        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);

        if star.is_none() {
            // No star: len(subject) == size
            self.set_source_range(p.range);
            emit!(self, Instruction::GetLen);
            self.set_source_range(p.range);
            self.emit_load_const(ConstantData::Integer { value: size.into() });
            self.set_source_range(p.range);
            emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::Equal
                }
            );
            self.set_source_range(p.range);
            self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
        } else if size > 1 {
            // Star exists: len(subject) >= size - 1
            self.set_source_range(p.range);
            emit!(self, Instruction::GetLen);
            self.set_source_range(p.range);
            self.emit_load_const(ConstantData::Integer {
                value: (size - 1).into(),
            });
            self.set_source_range(p.range);
            emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::GreaterOrEqual
                }
            );
            self.set_source_range(p.range);
            self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
        }

        // Whatever comes next should consume the subject.
        pc.on_top -= 1;
        if only_wildcard {
            // ast::Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc.
            self.set_source_range(p.range);
            emit!(self, Instruction::PopTop);
        } else if star_wildcard {
            self.pattern_helper_sequence_subscr(p.range, patterns, star.unwrap(), pc)?;
        } else {
            self.pattern_helper_sequence_unpack(p.range, patterns, star, pc)?;
        }
        Ok(())
    }

    fn compile_pattern_value(
        &mut self,
        p: &ast::PatternMatchValue,
        pc: &mut PatternContext,
    ) -> CompileResult<()> {
        // Match CPython codegen_pattern_value(): compare, then normalize to bool
        // before the fail jump. Late IR folding will collapse COMPARE_OP+TO_BOOL
        // into COMPARE_OP bool(...) when applicable.
        if let Some(constant) = self.try_compile_match_value_constant(&p.value)? {
            self.set_source_range(p.value.range());
            self.emit_load_const(constant);
        } else if matches!(*p.value, ast::Expr::Attribute(_)) {
            self.compile_expression(&p.value)?;
        } else {
            if Self::is_unexpected_match_literal_constant(&p.value) {
                return Err(self.error_ranged(
                    CodegenErrorType::SyntaxError(
                        "unexpected constant inside of a literal pattern".to_string(),
                    ),
                    p.range,
                ));
            }
            return Err(self.error_ranged(
                CodegenErrorType::SyntaxError(
                    "patterns may only match literals and attribute lookups".to_string(),
                ),
                p.range,
            ));
        }
        self.set_source_range(p.range);
        emit!(
            self,
            Instruction::CompareOp {
                opname: bytecode::ComparisonOperator::Equal
            }
        );
        self.set_source_range(p.range);
        emit!(self, Instruction::ToBool);
        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
        Ok(())
    }

    fn compile_pattern_singleton(
        &mut self,
        p: &ast::PatternMatchSingleton,
        pc: &mut PatternContext,
    ) {
        // Load the singleton constant value.
        self.set_source_range(p.range);
        self.emit_load_const(match p.value {
            ast::Singleton::None => ConstantData::None,
            ast::Singleton::False => ConstantData::Boolean { value: false },
            ast::Singleton::True => ConstantData::Boolean { value: true },
        });
        // Compare using the "Is" operator.
        self.set_source_range(p.range);
        emit!(self, Instruction::IsOp { invert: Invert::No });
        // Jump to the failure label if the comparison is false.
        self.set_source_range(p.range);
        self.jump_to_fail_pop(pc, JumpOp::PopJumpIfFalse);
    }

    fn compile_pattern(
        &mut self,
        pattern_type: &ast::Pattern,
        pattern_context: &mut PatternContext,
    ) -> CompileResult<()> {
        let prev_source_range = self.current_source_range;
        self.set_source_range(pattern_type.range());
        let result = match &pattern_type {
            ast::Pattern::MatchValue(pattern_type) => {
                self.compile_pattern_value(pattern_type, pattern_context)
            }
            ast::Pattern::MatchSingleton(pattern_type) => {
                self.compile_pattern_singleton(pattern_type, pattern_context);
                Ok(())
            }
            ast::Pattern::MatchSequence(pattern_type) => {
                self.compile_pattern_sequence(pattern_type, pattern_context)
            }
            ast::Pattern::MatchMapping(pattern_type) => {
                self.compile_pattern_mapping(pattern_type, pattern_context)
            }
            ast::Pattern::MatchClass(pattern_type) => {
                self.compile_pattern_class(pattern_type, pattern_context)
            }
            ast::Pattern::MatchStar(pattern_type) => {
                self.compile_pattern_star(pattern_type, pattern_context)
            }
            ast::Pattern::MatchAs(pattern_type) => {
                self.compile_pattern_as(pattern_type, pattern_context)
            }
            ast::Pattern::MatchOr(pattern_type) => {
                self.compile_pattern_or(pattern_type, pattern_context)
            }
        };
        self.set_source_range(prev_source_range);
        result
    }

    fn compile_match_inner(
        &mut self,
        subject: &ast::Expr,
        cases: &[ast::MatchCase],
        pattern_context: &mut PatternContext,
    ) -> CompileResult<()> {
        self.compile_expression(subject)?;
        let end = self.new_block();

        let num_cases = cases.len();
        assert!(num_cases > 0);
        let has_default =
            num_cases > 1 && Self::pattern_wildcard_check(&cases.last().unwrap().pattern);

        let case_count = num_cases - usize::from(has_default);
        for (i, m) in cases.iter().enumerate().take(case_count) {
            // Only copy the subject if not on the last case
            if i != case_count - 1 {
                self.set_source_range(m.pattern.range());
                emit!(self, Instruction::Copy { i: 1 });
            }

            pattern_context.stores = Vec::with_capacity(1);
            pattern_context.allow_irrefutable = m.guard.is_some() || i == num_cases - 1;
            pattern_context.fail_pop.clear();
            pattern_context.on_top = 0;

            self.compile_pattern(&m.pattern, pattern_context)?;
            assert_eq!(pattern_context.on_top, 0);

            for name in &pattern_context.stores {
                self.set_source_range(m.pattern.range());
                self.compile_name(name, NameUsage::Store)?;
            }

            if let Some(ref guard) = m.guard {
                self.ensure_fail_pop(pattern_context, 0);
                self.compile_jump_if_inner(
                    guard,
                    false,
                    pattern_context.fail_pop[0],
                    Some(m.pattern.range()),
                )?;
            }

            if i != case_count - 1 {
                if let Some(first_stmt) = m.body.first() {
                    self.set_source_range(first_stmt.range());
                }
                emit!(self, Instruction::PopTop);
                // CPython emits NEXT_LOCATION here; resolve it after redundant
                // NOP removal so a following pass NOP survives.
                self.set_last_emitted_lineno_override(ir::NEXT_LOCATION_OVERRIDE);
            }

            self.compile_statements(&m.body)?;
            emit!(self, PseudoInstruction::Jump { delta: end });
            self.set_no_location();
            self.set_source_range(m.pattern.range());
            self.emit_and_reset_fail_pop(pattern_context, m.pattern.range());
        }

        if has_default {
            let m = &cases[num_cases - 1];
            self.set_source_range(m.pattern.range());
            if num_cases == 1 {
                emit!(self, Instruction::PopTop);
            } else {
                emit!(self, Instruction::Nop);
            }
            if let Some(ref guard) = m.guard {
                self.compile_jump_if_inner(guard, false, end, Some(m.pattern.range()))?;
            }
            self.compile_statements(&m.body)?;
        }
        // CPython codegen_match_inner() emits USE_LABEL(c, end).
        self.use_cpython_label_block(end);
        Ok(())
    }

    fn compile_match(
        &mut self,
        subject: &ast::Expr,
        cases: &[ast::MatchCase],
    ) -> CompileResult<()> {
        self.enter_conditional_block();
        let mut pattern_context = PatternContext::new();
        self.compile_match_inner(subject, cases, &mut pattern_context)?;
        self.leave_conditional_block();
        Ok(())
    }

    /// [CPython `compiler_addcompare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L2880-L2924)
    fn compile_addcompare(&mut self, op: ast::CmpOp) {
        match op {
            ast::CmpOp::Eq => emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::Equal
                }
            ),
            ast::CmpOp::NotEq => emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::NotEqual
                }
            ),
            ast::CmpOp::Lt => emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::Less
                }
            ),
            ast::CmpOp::LtE => emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::LessOrEqual
                }
            ),
            ast::CmpOp::Gt => emit!(
                self,
                Instruction::CompareOp {
                    opname: ComparisonOperator::Greater
                }
            ),
            ast::CmpOp::GtE => {
                emit!(
                    self,
                    Instruction::CompareOp {
                        opname: ComparisonOperator::GreaterOrEqual
                    }
                )
            }
            ast::CmpOp::In => emit!(self, Instruction::ContainsOp { invert: Invert::No }),
            ast::CmpOp::NotIn => emit!(
                self,
                Instruction::ContainsOp {
                    invert: Invert::Yes
                }
            ),
            ast::CmpOp::Is => emit!(self, Instruction::IsOp { invert: Invert::No }),
            ast::CmpOp::IsNot => emit!(
                self,
                Instruction::IsOp {
                    invert: Invert::Yes
                }
            ),
        }
    }

    /// Compile a chained comparison.
    ///
    /// ```py
    /// a == b == c == d
    /// ```
    ///
    /// Will compile into (pseudo code):
    ///
    /// ```py
    /// result = a == b
    /// if result:
    ///   result = b == c
    ///   if result:
    ///     result = c == d
    /// ```
    ///
    /// # See Also
    /// - [CPython `compiler_compare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L4678-L4717)
    fn compile_compare(
        &mut self,
        left: &ast::Expr,
        ops: &[ast::CmpOp],
        comparators: &[ast::Expr],
    ) -> CompileResult<()> {
        // Save the full Compare expression range for COMPARE_OP positions
        let compare_range = self.current_source_range;
        self.check_compare(compare_range, left, ops, comparators)?;
        let (last_op, mid_ops) = ops.split_last().unwrap();
        let (last_comparator, mid_comparators) = comparators.split_last().unwrap();

        // initialize lhs outside of loop
        self.compile_expression(left)?;

        if mid_comparators.is_empty() {
            self.compile_expression(last_comparator)?;
            self.set_source_range(compare_range);
            self.compile_addcompare(*last_op);

            return Ok(());
        }

        let cleanup = self.new_block();

        // for all comparisons except the last (as the last one doesn't need a conditional jump)
        for (op, comparator) in mid_ops.iter().zip(mid_comparators) {
            self.compile_expression(comparator)?;

            // store rhs for the next comparison in chain
            self.set_source_range(compare_range);
            emit!(self, Instruction::Swap { i: 2 });
            emit!(self, Instruction::Copy { i: 2 });

            self.compile_addcompare(*op);

            // if comparison result is false, we break with this value; if true, try the next one.
            emit!(self, Instruction::Copy { i: 1 });
            emit!(self, Instruction::ToBool);
            emit!(self, Instruction::PopJumpIfFalse { delta: cleanup });
            emit!(self, Instruction::PopTop);
        }

        self.compile_expression(last_comparator)?;
        self.set_source_range(compare_range);
        self.compile_addcompare(*last_op);

        let end = self.new_block();
        emit!(self, PseudoInstruction::JumpNoInterrupt { delta: end });
        self.set_no_location();

        // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs.
        self.use_cpython_label_block(cleanup);
        emit!(self, Instruction::Swap { i: 2 });
        emit!(self, Instruction::PopTop);

        self.use_cpython_label_block(end);
        Ok(())
    }

    fn compile_jump_if_compare(
        &mut self,
        left: &ast::Expr,
        ops: &[ast::CmpOp],
        comparators: &[ast::Expr],
        condition: bool,
        target_block: BlockIdx,
    ) -> CompileResult<()> {
        let compare_range = self.current_source_range;
        self.check_compare(compare_range, left, ops, comparators)?;
        let (last_op, mid_ops) = ops.split_last().unwrap();
        let (last_comparator, mid_comparators) = comparators.split_last().unwrap();

        if mid_comparators.is_empty() {
            self.compile_expression(left)?;
            self.compile_expression(last_comparator)?;
            self.set_source_range(compare_range);
            self.compile_addcompare(*last_op);
            self.emit_pop_jump_by_condition(condition, target_block);
            return Ok(());
        }

        let cleanup = self.new_block();
        self.compile_expression(left)?;

        for (op, comparator) in mid_ops.iter().zip(mid_comparators) {
            self.compile_expression(comparator)?;
            self.set_source_range(compare_range);
            emit!(self, Instruction::Swap { i: 2 });
            emit!(self, Instruction::Copy { i: 2 });
            self.compile_addcompare(*op);
            emit!(self, Instruction::ToBool);
            emit!(self, Instruction::PopJumpIfFalse { delta: cleanup });
        }

        self.compile_expression(last_comparator)?;
        self.set_source_range(compare_range);
        self.compile_addcompare(*last_op);
        emit!(self, Instruction::ToBool);
        self.emit_pop_jump_by_condition(condition, target_block);
        let end = self.new_block();
        emit!(self, PseudoInstruction::JumpNoInterrupt { delta: end });
        self.set_no_location();

        self.use_cpython_label_block(cleanup);
        emit!(self, Instruction::PopTop);
        if !condition {
            emit!(
                self,
                PseudoInstruction::JumpNoInterrupt {
                    delta: target_block
                }
            );
            self.set_no_location();
        }

        self.use_cpython_label_block(end);
        Ok(())
    }

    fn emit_pop_jump_by_condition(&mut self, condition: bool, target_block: BlockIdx) {
        if condition {
            emit!(
                self,
                Instruction::PopJumpIfTrue {
                    delta: target_block
                }
            );
        } else {
            emit!(
                self,
                Instruction::PopJumpIfFalse {
                    delta: target_block,
                }
            );
        }
    }

    fn compile_annotation(&mut self, annotation: &ast::Expr) -> CompileResult<()> {
        if self.future_annotations {
            self.set_source_range(annotation.range());
            self.emit_load_const(ConstantData::Str {
                value: UnparseExpr::new(annotation, &self.source_file)
                    .to_string()
                    .into(),
            });
        } else {
            let was_in_annotation = self.in_annotation;
            self.in_annotation = true;

            // Special handling for starred annotations (*Ts -> Unpack[Ts])
            let result = match annotation {
                ast::Expr::Starred(ast::ExprStarred { value, .. }) => {
                    // *args: *Ts (where Ts is a TypeVarTuple).
                    // Do [annotation_value] = [*Ts].
                    let saved_range = self.current_source_range;
                    self.compile_expression(value)?;
                    self.set_source_range(saved_range);
                    emit!(self, Instruction::UnpackSequence { count: 1 });
                    Ok(())
                }
                _ => self.compile_expression(annotation),
            };

            self.in_annotation = was_in_annotation;
            result?;
        }
        Ok(())
    }

    fn compile_check_annotation_expression(&mut self, expression: &ast::Expr) -> CompileResult<()> {
        self.compile_expression(expression)?;
        self.set_source_range(expression.range());
        emit!(self, Instruction::PopTop);
        Ok(())
    }

    fn compile_check_annotation_subscript(&mut self, expression: &ast::Expr) -> CompileResult<()> {
        match expression {
            ast::Expr::Slice(ast::ExprSlice {
                lower, upper, step, ..
            }) => {
                if let Some(lower) = lower {
                    self.compile_check_annotation_expression(lower)?;
                }
                if let Some(upper) = upper {
                    self.compile_check_annotation_expression(upper)?;
                }
                if let Some(step) = step {
                    self.compile_check_annotation_expression(step)?;
                }
            }
            ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
                for element in elts {
                    self.compile_check_annotation_subscript(element)?;
                }
            }
            _ => self.compile_check_annotation_expression(expression)?,
        }
        Ok(())
    }

    fn compile_annotated_assign(
        &mut self,
        target: &ast::Expr,
        annotation: &ast::Expr,
        value: Option<&ast::Expr>,
        simple: bool,
        loc: TextRange,
    ) -> CompileResult<()> {
        // Perform the actual assignment first
        if let Some(value) = value {
            self.compile_expression(value)?;
            self.compile_store(target)?;
        }

        // If we have a simple name in module or class scope, store annotation
        if simple
            && !self.ctx.in_func()
            && let ast::Expr::Name(ast::ExprName { id, .. }) = target
        {
            if self.future_annotations {
                // PEP 563: Store stringified annotation directly to __annotations__
                // Compile annotation as string
                self.compile_annotation(annotation)?;
                self.set_source_range(loc);
                // Load __annotations__
                let annotations_name = self.name("__annotations__");
                emit!(
                    self,
                    Instruction::LoadName {
                        namei: annotations_name
                    }
                );
                // Load the variable name
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Str {
                    value: self.mangle(id.as_str()).into_owned().into(),
                });
                // Store: __annotations__[name] = annotation
                self.set_source_range(loc);
                emit!(self, Instruction::StoreSubscr);
            } else {
                // PEP 649: Handle conditional annotations
                if self.current_symbol_table().has_conditional_annotations {
                    let scope_type = self.current_symbol_table().typ;
                    let in_conditional_block = self.current_code_info().in_conditional_block > 0;
                    let is_conditional =
                        matches!(scope_type, CompilerScope::Module) || in_conditional_block;

                    if is_conditional {
                        let code_info = self.current_code_info();
                        let annotation_index = code_info.next_conditional_annotation_index;
                        code_info.next_conditional_annotation_index += 1;

                        self.set_source_range(loc);
                        if matches!(scope_type, CompilerScope::Class) {
                            let i = self.get_cell_var_index("__conditional_annotations__");
                            emit!(self, Instruction::LoadDeref { i });
                        } else {
                            let namei = self.name("__conditional_annotations__");
                            emit!(self, Instruction::LoadName { namei });
                        }
                        self.emit_load_const(ConstantData::Integer {
                            value: annotation_index.into(),
                        });
                        emit!(self, Instruction::SetAdd { i: 1 });
                        emit!(self, Instruction::PopTop);
                    }
                }
            }
        }

        if value.is_none() {
            match target {
                ast::Expr::Attribute(ast::ExprAttribute { value, .. }) => {
                    self.compile_check_annotation_expression(value)?;
                }
                ast::Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => {
                    self.compile_check_annotation_expression(value)?;
                    self.compile_check_annotation_subscript(slice)?;
                }
                _ => {}
            }
        }

        Ok(())
    }

    fn compile_store(&mut self, target: &ast::Expr) -> CompileResult<()> {
        let prev_source_range = self.current_source_range;
        self.set_source_range(target.range());
        let result = (|| -> CompileResult<()> {
            match &target {
                ast::Expr::Name(ast::ExprName { id, .. }) => self.store_name(id.as_str())?,
                ast::Expr::Subscript(ast::ExprSubscript {
                    value, slice, ctx, ..
                }) => {
                    self.compile_subscript(value, slice, *ctx)?;
                }
                ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
                    self.maybe_add_static_attribute_to_class(value, attr.as_str());
                    self.compile_expression(value)?;
                    self.set_source_range(self.update_start_location_to_match_attr(
                        target.range(),
                        target.range(),
                        attr.as_str(),
                    ));
                    let namei = self.name(attr.as_str());
                    emit!(self, Instruction::StoreAttr { namei });
                }
                ast::Expr::List(ast::ExprList { elts, .. })
                | ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
                    let mut seen_star = false;

                    // Scan for star args:
                    for (i, element) in elts.iter().enumerate() {
                        if matches!(element, ast::Expr::Starred(_)) && !seen_star {
                            let before = i;
                            let after = elts.len() - i - 1;
                            if before >= (1 << 8) || after >= ((i32::MAX as usize) >> 8) {
                                return Err(self.error_ranged(
                                    CodegenErrorType::TooManyStarUnpack,
                                    target.range(),
                                ));
                            }
                            let before = before.to_u8().ok_or_else(|| {
                                self.error_ranged(
                                    CodegenErrorType::TooManyStarUnpack,
                                    target.range(),
                                )
                            })?;
                            let after = after.to_u32();
                            let counts = bytecode::UnpackExArgs { before, after };
                            emit!(self, Instruction::UnpackEx { counts });
                            seen_star = true;
                        } else if matches!(element, ast::Expr::Starred(_)) {
                            return Err(self.error(CodegenErrorType::MultipleStarArgs));
                        }
                    }

                    if !seen_star {
                        emit!(
                            self,
                            Instruction::UnpackSequence {
                                count: elts.len().to_u32(),
                            }
                        );
                    }

                    for element in elts {
                        if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = &element {
                            self.compile_store(value)?;
                        } else {
                            self.compile_store(element)?;
                        }
                    }
                }
                _ => {
                    return Err(self.error(match target {
                        ast::Expr::Starred(_) => CodegenErrorType::SyntaxError(
                            "starred assignment target must be in a list or tuple".to_owned(),
                        ),
                        _ => CodegenErrorType::Assign(target.python_name()),
                    }));
                }
            }
            Ok(())
        })();

        self.set_source_range(prev_source_range);
        result
    }

    fn compile_augassign(
        &mut self,
        target: &ast::Expr,
        op: ast::Operator,
        value: &ast::Expr,
    ) -> CompileResult<()> {
        let stmt_range = self.current_source_range;
        let target_range = target.range();
        enum AugAssignKind<'a> {
            Name {
                id: &'a str,
            },
            Subscript {
                use_slice_opt: bool,
            },
            Attr {
                idx: bytecode::NameIdx,
                attr_range: TextRange,
            },
        }

        let kind = match &target {
            ast::Expr::Name(ast::ExprName { id, .. }) => {
                let id = id.as_str();
                self.set_source_range(target_range);
                self.compile_name(id, NameUsage::Load)?;
                AugAssignKind::Name { id }
            }
            ast::Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => {
                let use_slice_opt = self.should_apply_two_element_slice_optimization(slice);
                self.compile_expression(value)?;
                self.set_source_range(target_range);
                if use_slice_opt {
                    let ast::Expr::Slice(slice_expr) = slice.as_ref() else {
                        unreachable!(
                            "should_use_slice_optimization should only return true for ast::Expr::Slice"
                        );
                    };
                    self.compile_slice_two_parts(slice_expr)?;
                    self.set_source_range(target_range);
                    emit!(self, Instruction::Copy { i: 3 });
                    emit!(self, Instruction::Copy { i: 3 });
                    emit!(self, Instruction::Copy { i: 3 });
                    emit!(self, Instruction::BinarySlice);
                } else {
                    self.compile_expression(slice)?;
                    self.set_source_range(target_range);
                    emit!(self, Instruction::Copy { i: 2 });
                    emit!(self, Instruction::Copy { i: 2 });
                    emit!(
                        self,
                        Instruction::BinaryOp {
                            op: BinaryOperator::Subscr
                        }
                    );
                }
                AugAssignKind::Subscript { use_slice_opt }
            }
            ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
                let attr = attr.as_str();
                self.compile_expression(value)?;
                let attr_range =
                    self.update_start_location_to_match_attr(target_range, target_range, attr);
                self.set_source_range(target_range);
                emit!(self, Instruction::Copy { i: 1 });
                let idx = self.name(attr);
                self.set_source_range(attr_range);
                self.emit_load_attr(idx);
                AugAssignKind::Attr { idx, attr_range }
            }
            _ => {
                return Err(self.error(CodegenErrorType::Assign(target.python_name())));
            }
        };

        self.compile_expression(value)?;
        self.set_source_range(stmt_range);
        self.compile_op(op, true);

        match kind {
            AugAssignKind::Name { id } => {
                // stack: RESULT
                self.set_source_range(target_range);
                self.compile_name(id, NameUsage::Store)?;
            }
            AugAssignKind::Subscript { use_slice_opt } => {
                self.set_source_range(target_range);
                if use_slice_opt {
                    // stack: CONTAINER START STOP RESULT
                    emit!(self, Instruction::Swap { i: 4 });
                    emit!(self, Instruction::Swap { i: 3 });
                    emit!(self, Instruction::Swap { i: 2 });
                    emit!(self, Instruction::StoreSlice);
                } else {
                    // stack: CONTAINER SLICE RESULT
                    emit!(self, Instruction::Swap { i: 3 });
                    emit!(self, Instruction::Swap { i: 2 });
                    emit!(self, Instruction::StoreSubscr);
                }
            }
            AugAssignKind::Attr { idx, attr_range } => {
                // stack: CONTAINER RESULT
                self.set_source_range(attr_range);
                emit!(self, Instruction::Swap { i: 2 });
                emit!(self, Instruction::StoreAttr { namei: idx });
            }
        }

        Ok(())
    }

    fn compile_op(&mut self, op: ast::Operator, inplace: bool) {
        let bin_op = match op {
            ast::Operator::Add => BinaryOperator::Add,
            ast::Operator::Sub => BinaryOperator::Subtract,
            ast::Operator::Mult => BinaryOperator::Multiply,
            ast::Operator::MatMult => BinaryOperator::MatrixMultiply,
            ast::Operator::Div => BinaryOperator::TrueDivide,
            ast::Operator::FloorDiv => BinaryOperator::FloorDivide,
            ast::Operator::Mod => BinaryOperator::Remainder,
            ast::Operator::Pow => BinaryOperator::Power,
            ast::Operator::LShift => BinaryOperator::Lshift,
            ast::Operator::RShift => BinaryOperator::Rshift,
            ast::Operator::BitOr => BinaryOperator::Or,
            ast::Operator::BitXor => BinaryOperator::Xor,
            ast::Operator::BitAnd => BinaryOperator::And,
        };

        let op = if inplace { bin_op.as_inplace() } else { bin_op };
        emit!(self, Instruction::BinaryOp { op })
    }

    /// Implement boolean short circuit evaluation logic.
    /// https://en.wikipedia.org/wiki/Short-circuit_evaluation
    ///
    /// This means, in a boolean statement 'x and y' the variable y will
    /// not be evaluated when x is false.
    ///
    /// The idea is to jump to a label if the expression is either true or false
    /// (indicated by the condition parameter).
    fn compile_jump_if_inner(
        &mut self,
        expression: &ast::Expr,
        condition: bool,
        target_block: BlockIdx,
        source_range: Option<TextRange>,
    ) -> CompileResult<()> {
        let prev_source_range = self.current_source_range;
        self.set_source_range(source_range.unwrap_or_else(|| expression.range()));

        // Compile expression for test, and jump to label if false
        let result = match &expression {
            ast::Expr::BoolOp(ast::ExprBoolOp { op, values, .. }) => {
                let (last_value, prefix_values) = values.split_last().unwrap();
                let cond2 = matches!(op, ast::BoolOp::Or);
                let next2 = if cond2 != condition {
                    self.new_block()
                } else {
                    target_block
                };

                for value in prefix_values {
                    self.compile_jump_if_inner(value, cond2, next2, source_range)?;
                }
                self.compile_jump_if_inner(last_value, condition, target_block, source_range)?;

                if next2 != target_block {
                    self.use_cpython_label_block(next2);
                }
                Ok(())
            }
            ast::Expr::UnaryOp(ast::ExprUnaryOp {
                op: ast::UnaryOp::Not,
                operand,
                ..
            }) => self.compile_jump_if_inner(operand, !condition, target_block, source_range),
            ast::Expr::If(ast::ExprIf {
                test, body, orelse, ..
            }) => {
                let end = self.new_block();
                let next2 = self.new_block();
                self.compile_jump_if_inner(test, false, next2, source_range)?;
                self.compile_jump_if_inner(body, condition, target_block, source_range)?;
                emit!(self, PseudoInstruction::JumpNoInterrupt { delta: end });
                self.set_no_location();

                self.use_cpython_label_block(next2);
                self.compile_jump_if_inner(orelse, condition, target_block, source_range)?;

                self.use_cpython_label_block(end);
                Ok(())
            }
            ast::Expr::Compare(ast::ExprCompare {
                left,
                ops,
                comparators,
                ..
            }) if ops.len() > 1 => {
                self.set_source_range(expression.range());
                self.compile_jump_if_compare(left, ops, comparators, condition, target_block)
            }
            _ => {
                // Fall back case which always will work!
                self.compile_expression(expression)?;
                self.set_source_range(expression.range());
                emit!(self, Instruction::ToBool);
                if condition {
                    emit!(
                        self,
                        Instruction::PopJumpIfTrue {
                            delta: target_block,
                        }
                    );
                } else {
                    emit!(
                        self,
                        Instruction::PopJumpIfFalse {
                            delta: target_block,
                        }
                    );
                }
                Ok(())
            }
        };

        self.set_source_range(prev_source_range);
        result
    }

    fn compile_jump_if(
        &mut self,
        expression: &ast::Expr,
        condition: bool,
        target_block: BlockIdx,
    ) -> CompileResult<()> {
        self.compile_jump_if_inner(expression, condition, target_block, None)
    }

    /// Compile a boolean operation as an expression.
    /// This means, that the last value remains on the stack.
    fn compile_bool_op(&mut self, op: ast::BoolOp, values: &[ast::Expr]) -> CompileResult<()> {
        let boolop_range = self.current_source_range;
        let after_block = self.new_block();
        let (last_value, prefix_values) = values.split_last().unwrap();

        for value in prefix_values {
            self.compile_expression(value)?;
            self.set_source_range(boolop_range);
            self.emit_short_circuit_test(op, after_block);
            self.set_source_range(boolop_range);
            emit!(self, Instruction::PopTop);
        }

        self.compile_expression(last_value)?;
        self.use_cpython_label_block(after_block);
        Ok(())
    }

    /// Emit CPython-style pseudo conditional jump for short-circuit evaluation.
    /// flowgraph.c lowers it to `COPY 1; TO_BOOL; POP_JUMP_IF_*`.
    fn emit_short_circuit_test(&mut self, op: ast::BoolOp, target: BlockIdx) {
        match op {
            ast::BoolOp::And => {
                emit!(self, PseudoInstruction::JumpIfFalse { delta: target });
            }
            ast::BoolOp::Or => {
                emit!(self, PseudoInstruction::JumpIfTrue { delta: target });
            }
        }
    }

    fn compile_subdict(
        &mut self,
        items: &[ast::DictItem],
        begin: usize,
        end: usize,
        range: TextRange,
    ) -> CompileResult<()> {
        let n = end - begin;
        let big = n * 2 > STACK_USE_GUIDELINE as usize;
        if big {
            self.set_source_range(range);
            emit!(self, Instruction::BuildMap { count: 0 });
        }
        for item in &items[begin..end] {
            self.compile_expression(item.key.as_ref().unwrap())?;
            self.compile_expression(&item.value)?;
            if big {
                self.set_source_range(range);
                emit!(self, Instruction::MapAdd { i: 1 });
            }
        }
        if !big {
            self.set_source_range(range);
            emit!(self, Instruction::BuildMap { count: n.to_u32() });
        }
        Ok(())
    }

    fn compile_dict(&mut self, items: &[ast::DictItem], range: TextRange) -> CompileResult<()> {
        let n = items.len();
        let mut have_dict = false;
        let mut elements = 0usize;

        for (i, item) in items.iter().enumerate() {
            if item.key.is_none() {
                if elements != 0 {
                    self.compile_subdict(items, i - elements, i, range)?;
                    if have_dict {
                        self.set_source_range(range);
                        emit!(self, Instruction::DictUpdate { i: 1 });
                    }
                    have_dict = true;
                    elements = 0;
                }
                if !have_dict {
                    self.set_source_range(range);
                    emit!(self, Instruction::BuildMap { count: 0 });
                    have_dict = true;
                }
                self.compile_expression(&item.value)?;
                self.set_source_range(range);
                emit!(self, Instruction::DictUpdate { i: 1 });
            } else if elements * 2 > STACK_USE_GUIDELINE as usize {
                self.compile_subdict(items, i - elements, i + 1, range)?;
                if have_dict {
                    self.set_source_range(range);
                    emit!(self, Instruction::DictUpdate { i: 1 });
                }
                have_dict = true;
                elements = 0;
            } else {
                elements += 1;
            }
        }

        if elements != 0 {
            self.compile_subdict(items, n - elements, n, range)?;
            if have_dict {
                self.set_source_range(range);
                emit!(self, Instruction::DictUpdate { i: 1 });
            }
            have_dict = true;
        }
        if !have_dict {
            self.set_source_range(range);
            emit!(self, Instruction::BuildMap { count: 0 });
        }

        Ok(())
    }

    /// Compile the yield-from/await sequence using SEND/END_SEND/CLEANUP_THROW.
    /// compiler_add_yield_from
    /// This generates:
    ///   send:
    ///     SEND exit
    ///     SETUP_FINALLY fail (via exception table)
    ///     YIELD_VALUE 1
    ///     POP_BLOCK (NO_LOCATION)
    ///     RESUME
    ///     JUMP send
    ///   fail:
    ///     CLEANUP_THROW
    ///     JUMP exit
    ///   exit:
    ///     END_SEND
    fn compile_yield_from_sequence(&mut self, is_await: bool) -> BlockIdx {
        let send_block = self.new_block();
        let fail_block = self.new_block();
        let exit_block = self.new_block();

        // send:
        self.use_cpython_label_block(send_block);
        emit!(self, Instruction::Send { delta: exit_block });

        // SETUP_FINALLY fail - set up exception handler for YIELD_VALUE
        emit!(self, PseudoInstruction::SetupFinally { delta: fail_block });

        // YIELD_VALUE with arg=1 (yield-from/await mode - not wrapped for async gen)
        emit!(self, Instruction::YieldValue { arg: 1 });

        // POP_BLOCK before RESUME
        emit!(self, PseudoInstruction::PopBlock);
        self.set_no_location();

        // RESUME
        emit!(
            self,
            Instruction::Resume {
                context: if is_await {
                    oparg::ResumeContext::from(oparg::ResumeLocation::AfterAwait)
                } else {
                    oparg::ResumeContext::from(oparg::ResumeLocation::AfterYieldFrom)
                }
            }
        );

        // JUMP_BACKWARD_NO_INTERRUPT send
        emit!(
            self,
            PseudoInstruction::JumpNoInterrupt { delta: send_block }
        );

        // fail: CLEANUP_THROW
        // Stack when exception: [receiver, yielded_value, exc]
        // CLEANUP_THROW: [sub_iter, last_sent_val, exc] -> [None, value]
        // CPython lets this block fall through to END_SEND during codegen;
        // push_cold_blocks_to_end later inserts the no-interrupt jump after
        // moving the cold fail block behind the warm exit path.
        self.use_cpython_label_block(fail_block);
        emit!(self, Instruction::CleanupThrow);

        // exit: END_SEND
        // Stack: [receiver, value] (from SEND) or [None, value] (from CLEANUP_THROW)
        // END_SEND: [receiver/None, value] -> [value]
        self.use_cpython_label_block(exit_block);
        emit!(self, Instruction::EndSend);

        send_block
    }

    fn ast_constant_value(&self, expr: &ast::Expr) -> Option<ConstantData> {
        expr.as_constant_expr()
            .map(|expr| ast_constant_value_to_constant_data(expr.value.clone()))
    }

    fn single_runtime_interpolation(
        expr_tstring: &ast::ExprTString,
    ) -> Option<(&ast::ConstantValue, Option<&ast::Expr>)> {
        let tstring = expr_tstring.as_single_part_tstring()?;
        let interpolation = tstring.elements.first()?.as_interpolation()?;
        Some((
            interpolation.runtime_str.as_ref()?,
            interpolation.runtime_interpolation_format_spec.as_deref(),
        ))
    }

    fn compile_expression(&mut self, expression: &ast::Expr) -> CompileResult<()> {
        trace!("Compiling {expression:?}");
        let range = expression.range();
        self.set_source_range(range);

        if let Some(constant) = self.ast_constant_value(expression) {
            self.emit_load_const(constant);
            return Ok(());
        }

        match &expression {
            ast::Expr::Call(ast::ExprCall {
                func, arguments, ..
            }) => self.compile_call(func, arguments)?,
            ast::Expr::BoolOp(ast::ExprBoolOp { op, values, .. }) => {
                self.compile_bool_op(*op, values)?
            }
            ast::Expr::BinOp(ast::ExprBinOp {
                left, op, right, ..
            }) => {
                self.compile_expression(left)?;
                self.compile_expression(right)?;

                // Restore full expression range before emitting the operation
                self.set_source_range(range);
                self.compile_op(*op, false);
            }
            ast::Expr::Subscript(ast::ExprSubscript {
                value, slice, ctx, ..
            }) => {
                self.compile_subscript(value, slice, *ctx)?;
            }
            ast::Expr::UnaryOp(ast::ExprUnaryOp { op, operand, .. }) => {
                self.compile_expression(operand)?;

                // Restore full expression range before emitting the operation
                self.set_source_range(range);
                match op {
                    ast::UnaryOp::UAdd => emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::UnaryPositive
                        }
                    ),
                    ast::UnaryOp::USub => emit!(self, Instruction::UnaryNegative),
                    ast::UnaryOp::Not => {
                        emit!(self, Instruction::ToBool);
                        emit!(self, Instruction::UnaryNot);
                    }
                    ast::UnaryOp::Invert => emit!(self, Instruction::UnaryInvert),
                };
            }
            ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) => {
                // Check for super() attribute access optimization
                if let Some(super_type) = self.can_optimize_super_call(value, attr.as_str()) {
                    // super().attr or super(cls, self).attr optimization
                    // Stack: [global_super, class, self] → LOAD_SUPER_ATTR → [attr]
                    let ast::Expr::Call(ast::ExprCall {
                        func: super_func, ..
                    }) = value.as_ref()
                    else {
                        unreachable!("can_optimize_super_call only accepts calls");
                    };
                    self.load_args_for_super(&super_type, super_func.range(), value.range())?;
                    let attr_access_range =
                        self.update_start_location_to_match_attr(range, range, attr.as_str());
                    self.set_source_range(range);
                    let idx = self.name(attr.as_str());
                    match super_type {
                        SuperCallType::TwoArg { .. } => {
                            self.emit_load_super_attr(idx);
                        }
                        SuperCallType::ZeroArg => {
                            self.emit_load_zero_super_attr(idx);
                        }
                    }
                    self.set_source_range(attr_access_range);
                    emit!(self, Instruction::Nop);
                } else {
                    // Normal attribute access
                    self.compile_expression(value)?;
                    self.set_source_range(self.update_start_location_to_match_attr(
                        range,
                        range,
                        attr.as_str(),
                    ));
                    let idx = self.name(attr.as_str());
                    self.emit_load_attr(idx);
                }
            }
            ast::Expr::Compare(ast::ExprCompare {
                left,
                ops,
                comparators,
                ..
            }) => {
                self.compile_compare(left, ops, comparators)?;
            }
            ast::Expr::Constant(ast::ExprConstant { value, .. }) => {
                self.emit_load_const(ast_constant_value_to_constant_data(value.clone()));
            }
            ast::Expr::List(ast::ExprList { elts, range, .. }) => {
                self.set_source_range(*range);
                self.starunpack_helper(elts, 0, CollectionType::List)?;
            }
            ast::Expr::Tuple(ast::ExprTuple { elts, range, .. }) => {
                self.set_source_range(*range);
                self.starunpack_helper(elts, 0, CollectionType::Tuple)?;
            }
            ast::Expr::Set(ast::ExprSet { elts, range, .. }) => {
                self.set_source_range(*range);
                self.starunpack_helper(elts, 0, CollectionType::Set)?;
            }
            ast::Expr::Dict(ast::ExprDict { items, range, .. }) => {
                self.compile_dict(items, *range)?;
            }
            ast::Expr::Slice(ast::ExprSlice {
                lower,
                upper,
                step,
                range,
                ..
            }) => {
                if let Some(folded_const) = self.try_fold_constant_slice(
                    lower.as_deref(),
                    upper.as_deref(),
                    step.as_deref(),
                )? {
                    self.set_source_range(*range);
                    self.emit_load_const(folded_const);
                    return Ok(());
                }
                if let Some(lower) = lower {
                    self.compile_expression(lower)?;
                } else {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::None);
                }
                if let Some(upper) = upper {
                    self.compile_expression(upper)?;
                } else {
                    self.set_source_range(*range);
                    self.emit_load_const(ConstantData::None);
                }
                if let Some(step) = step {
                    self.compile_expression(step)?;
                }
                let argc = match step {
                    Some(_) => BuildSliceArgCount::Three,
                    None => BuildSliceArgCount::Two,
                };
                self.set_source_range(*range);
                emit!(self, Instruction::BuildSlice { argc });
            }
            ast::Expr::Yield(ast::ExprYield { value, .. }) => {
                if !self.ctx.in_func() {
                    return Err(self.error(CodegenErrorType::InvalidYield));
                }
                self.mark_generator();
                match value {
                    Some(expression) => self.compile_expression(expression)?,
                    Option::None => self.emit_load_const(ConstantData::None),
                };
                self.set_source_range(range);
                if self.ctx.func == FunctionContext::AsyncFunction {
                    emit!(
                        self,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::AsyncGenWrap
                        }
                    );
                }
                // arg=0: direct yield (wrapped for async generators)
                emit!(self, Instruction::YieldValue { arg: 0 });
                emit!(
                    self,
                    Instruction::Resume {
                        context: oparg::ResumeContext::from(oparg::ResumeLocation::AfterYield)
                    }
                );
            }
            ast::Expr::Await(ast::ExprAwait { value, .. }) => {
                if self.ctx.func != FunctionContext::AsyncFunction
                    && !self.allows_top_level_await_in_current_context()
                {
                    return Err(self.error(CodegenErrorType::InvalidAwait));
                }
                self.compile_expression(value)?;
                self.set_source_range(range);
                emit!(self, Instruction::GetAwaitable { r#where: 0 });
                self.emit_load_const(ConstantData::None);
                let _ = self.compile_yield_from_sequence(true);
            }
            ast::Expr::YieldFrom(ast::ExprYieldFrom { value, .. }) => {
                match self.ctx.func {
                    FunctionContext::NoFunction => {
                        return Err(self.error(CodegenErrorType::InvalidYieldFrom));
                    }
                    FunctionContext::AsyncFunction => {
                        return Err(self.error(CodegenErrorType::AsyncYieldFrom));
                    }
                    FunctionContext::Function => {}
                }
                self.mark_generator();
                self.compile_expression(value)?;
                self.set_source_range(range);
                emit!(self, Instruction::GetYieldFromIter);
                self.emit_load_const(ConstantData::None);
                let _ = self.compile_yield_from_sequence(false);
            }
            ast::Expr::Name(ast::ExprName { id, .. }) => self.load_name(id.as_str())?,
            ast::Expr::Lambda(ast::ExprLambda {
                parameters,
                body,
                range,
                ..
            }) => {
                let default_params = ast::Parameters::default();
                let params = parameters.as_deref().unwrap_or(&default_params);
                validate_duplicate_params(params).map_err(|e| self.error(e))?;

                let prev_ctx = self.ctx;
                let name = "<lambda>".to_owned();

                // Prepare defaults before entering function
                let defaults: Vec<_> = core::iter::empty()
                    .chain(&params.posonlyargs)
                    .chain(&params.args)
                    .filter_map(|x| x.default.as_deref())
                    .collect();
                let have_defaults = !defaults.is_empty();

                if have_defaults {
                    let size = defaults.len().to_u32();
                    for element in &defaults {
                        self.compile_expression(element)?;
                    }
                    self.set_source_range(*range);
                    emit!(self, Instruction::BuildTuple { count: size });
                }

                // Prepare keyword-only defaults
                let mut kw_with_defaults = vec![];
                for kwonlyarg in &params.kwonlyargs {
                    if let Some(default) = &kwonlyarg.default {
                        kw_with_defaults.push((&kwonlyarg.parameter, default));
                    }
                }

                let have_kwdefaults = !kw_with_defaults.is_empty();
                if have_kwdefaults {
                    let default_kw_count = kw_with_defaults.len();
                    for (arg, default) in &kw_with_defaults {
                        self.set_source_range(*range);
                        self.emit_load_const(ConstantData::Str {
                            value: self.mangle(arg.name.as_str()).into_owned().into(),
                        });
                        self.compile_expression(default)?;
                    }
                    self.set_source_range(*range);
                    emit!(
                        self,
                        Instruction::BuildMap {
                            count: default_kw_count.to_u32(),
                        }
                    );
                }

                self.enter_function(&name, params)?;
                let mut func_flags = bytecode::MakeFunctionFlags::new();
                if have_defaults {
                    func_flags.insert(bytecode::MakeFunctionFlag::Defaults);
                }
                if have_kwdefaults {
                    func_flags.insert(bytecode::MakeFunctionFlag::KwOnlyDefaults);
                }

                // Set qualname for lambda
                self.set_qualname();

                self.ctx = CompileContext {
                    in_class: prev_ctx.in_class,
                    func: FunctionContext::Function,
                    // Lambda is never async, so new scope is not async
                    in_async_scope: false,
                };

                self.compile_expression(body)?;
                let is_generator = self
                    .current_code_info()
                    .flags
                    .contains(bytecode::CodeFlags::GENERATOR);
                if is_generator {
                    // codegen_lambda() calls OptimizeAndAssemble with
                    // addNone=0, so AddReturnAtEnd appends RETURN_VALUE without
                    // adding None to co_consts.
                    emit!(self, Instruction::ReturnValue);
                    self.set_no_location();
                } else {
                    self.set_source_range(body.range());
                    self.emit_return_value();
                    self.emit_return_const_no_location(ConstantData::None);
                }
                let code = self.exit_scope();

                // Create lambda function with closure
                self.set_source_range(*range);
                self.make_closure(code, func_flags)?;

                self.ctx = prev_ctx;
            }
            ast::Expr::ListComp(ast::ExprListComp {
                elt,
                generators,
                range,
                ..
            }) => {
                self.compile_comprehension(
                    "<listcomp>",
                    Some(
                        Instruction::BuildList {
                            count: OpArgMarker::marker(),
                        }
                        .into(),
                    ),
                    generators,
                    &|compiler, collection_add_i| {
                        compiler.compile_comprehension_element(elt)?;
                        compiler.set_source_range(elt.range());
                        emit!(
                            compiler,
                            Instruction::ListAppend {
                                i: collection_add_i.to_u32(),
                            }
                        );
                        Ok(())
                    },
                    ComprehensionType::List,
                    Self::contains_await(elt) || Self::generators_contain_await(generators),
                    *range,
                    elt.range(),
                    elt.range(),
                )?;
            }
            ast::Expr::SetComp(ast::ExprSetComp {
                elt,
                generators,
                range,
                ..
            }) => {
                self.compile_comprehension(
                    "<setcomp>",
                    Some(
                        Instruction::BuildSet {
                            count: OpArgMarker::marker(),
                        }
                        .into(),
                    ),
                    generators,
                    &|compiler, collection_add_i| {
                        compiler.compile_comprehension_element(elt)?;
                        compiler.set_source_range(elt.range());
                        emit!(
                            compiler,
                            Instruction::SetAdd {
                                i: collection_add_i.to_u32(),
                            }
                        );
                        Ok(())
                    },
                    ComprehensionType::Set,
                    Self::contains_await(elt) || Self::generators_contain_await(generators),
                    *range,
                    elt.range(),
                    elt.range(),
                )?;
            }
            ast::Expr::DictComp(ast::ExprDictComp {
                key,
                value,
                generators,
                range,
                ..
            }) => {
                let key = key.as_ref();
                self.compile_comprehension(
                    "<dictcomp>",
                    Some(
                        Instruction::BuildMap {
                            count: OpArgMarker::marker(),
                        }
                        .into(),
                    ),
                    generators,
                    &|compiler, collection_add_i| {
                        // changed evaluation order for Py38 named expression PEP 572
                        compiler.compile_expression(key)?;
                        compiler.compile_expression(value)?;

                        compiler.set_source_range(TextRange::new(
                            key.range().start(),
                            value.range().end(),
                        ));
                        emit!(
                            compiler,
                            Instruction::MapAdd {
                                i: collection_add_i.to_u32(),
                            }
                        );

                        Ok(())
                    },
                    ComprehensionType::Dict,
                    Self::contains_await(key)
                        || Self::contains_await(value)
                        || Self::generators_contain_await(generators),
                    *range,
                    TextRange::new(key.range().start(), value.range().end()),
                    key.range(),
                )?;
            }
            ast::Expr::Generator(ast::ExprGenerator {
                elt,
                generators,
                range,
                ..
            }) => {
                self.compile_generator_expression(elt, generators, *range)?;
            }
            ast::Expr::Starred(ast::ExprStarred { value, .. }) => {
                if self.in_annotation {
                    // In annotation context, starred expressions are allowed (PEP 646)
                    // For now, just compile the inner value without wrapping with Unpack
                    // This is a temporary solution until we figure out how to properly import typing
                    self.compile_expression(value)?;
                } else {
                    return Err(self.error(CodegenErrorType::InvalidStarExpr));
                }
            }
            ast::Expr::If(ast::ExprIf {
                test, body, orelse, ..
            }) => {
                let after_block = self.new_block();
                let else_block = self.new_block();
                self.compile_jump_if(test, false, else_block)?;

                // True case
                self.compile_expression(body)?;
                emit!(
                    self,
                    PseudoInstruction::JumpNoInterrupt { delta: after_block }
                );
                self.set_no_location();

                // False case
                self.use_cpython_label_block(else_block);
                self.compile_expression(orelse)?;

                // End
                self.use_cpython_label_block(after_block);
            }

            ast::Expr::Named(ast::ExprNamed {
                target,
                value,
                node_index: _,
                range,
            }) => {
                // Walrus targets in inlined comps should NOT be hidden from locals()
                if self.current_code_info().in_inlined_comp
                    && let ast::Expr::Name(ast::ExprName { id, .. }) = target.as_ref()
                {
                    let name = self.mangle(id.as_str());
                    let info = self.code_stack.last_mut().unwrap();
                    info.metadata.fast_hidden.insert(name.to_string(), false);
                    info.metadata.fast_hidden_final.swap_remove(name.as_ref());
                }
                self.compile_expression(value)?;
                self.set_source_range(*range);
                emit!(self, Instruction::Copy { i: 1 });
                self.compile_store(target)?;
                self.set_source_range(target.range());
            }
            ast::Expr::FString(fstring) => {
                if let Some(joined_str) = fstring.runtime_joined_str.as_ref() {
                    return self.compile_runtime_joined_str(fstring, joined_str);
                }
                self.compile_expr_fstring(fstring)?;
            }
            ast::Expr::TString(tstring) => {
                if let Some(template_str) = tstring.runtime_template_str.as_ref() {
                    return self.compile_runtime_template_str(tstring, template_str);
                }
                if let Some(interpolation) = Self::single_runtime_interpolation(tstring)
                    && self.compile_runtime_interpolation(tstring, interpolation)?
                {
                    return Ok(());
                }
                self.compile_expr_tstring(tstring)?;
            }
            ast::Expr::StringLiteral(string) => {
                let value = self.compile_string_value(string);
                self.emit_load_const(ConstantData::Str { value });
            }
            ast::Expr::BytesLiteral(bytes) => {
                let iter = bytes.value.iter().flat_map(|x| x.iter().copied());
                let v: Vec<u8> = iter.collect();
                self.emit_load_const(ConstantData::Bytes { value: v });
            }
            ast::Expr::NumberLiteral(number) => match &number.value {
                ast::Number::Int(int) => {
                    let value = ruff_int_to_bigint(int).map_err(|e| self.error(e))?;
                    self.emit_load_const(ConstantData::Integer { value });
                }
                ast::Number::Float(float) => {
                    self.emit_load_const(ConstantData::Float { value: *float });
                }
                ast::Number::Complex { real, imag } => {
                    self.emit_load_const(ConstantData::Complex {
                        value: Complex::new(*real, *imag),
                    });
                }
            },
            ast::Expr::BooleanLiteral(b) => {
                self.emit_load_const(ConstantData::Boolean { value: b.value });
            }
            ast::Expr::NoneLiteral(_) => {
                self.emit_load_const(ConstantData::None);
            }
            ast::Expr::EllipsisLiteral(_) => {
                self.emit_load_const(ConstantData::Ellipsis);
            }
            ast::Expr::IpyEscapeCommand(expr) => {
                return Err(self.error_ranged(
                    CodegenErrorType::SyntaxError("invalid syntax".to_owned()),
                    expr.range,
                ));
            }
        }
        Ok(())
    }

    fn cpython_sync_genexpr_call_name<'a>(
        &self,
        func: &'a ast::Expr,
        args: &ast::Arguments,
    ) -> Option<&'a str> {
        let ast::Expr::Name(ast::ExprName { id, .. }) = func else {
            return None;
        };
        let [ast::Expr::Generator(ast::ExprGenerator { .. })] = &args.args[..] else {
            return None;
        };
        if !args.keywords.is_empty() || {
            let table = self.current_symbol_table();
            table
                .sub_tables
                .get(table.next_sub_table)
                .is_none_or(|generator_entry| generator_entry.is_coroutine)
        } {
            return None;
        }
        Some(id.as_str())
    }

    fn detect_builtin_generator_call(
        &self,
        func: &ast::Expr,
        args: &ast::Arguments,
    ) -> Option<BuiltinGeneratorCallKind> {
        match self.cpython_sync_genexpr_call_name(func, args)? {
            "tuple" => Some(BuiltinGeneratorCallKind::Tuple),
            "all" => Some(BuiltinGeneratorCallKind::All),
            "any" => Some(BuiltinGeneratorCallKind::Any),
            _ => None,
        }
    }

    /// Emit the optimized inline loop for builtin(genexpr) calls.
    ///
    /// Stack on entry: `[func]` where `func` is the builtin candidate.
    /// On return the compiler is positioned at the skip-optimization block so the
    /// normal call path can compile the original generator argument again.
    fn optimize_builtin_generator_call(
        &mut self,
        kind: BuiltinGeneratorCallKind,
        generator_expr: &ast::Expr,
        loc: TextRange,
        end: BlockIdx,
    ) -> CompileResult<()> {
        let common_constant = match kind {
            BuiltinGeneratorCallKind::Tuple => bytecode::CommonConstant::BuiltinTuple,
            BuiltinGeneratorCallKind::All => bytecode::CommonConstant::BuiltinAll,
            BuiltinGeneratorCallKind::Any => bytecode::CommonConstant::BuiltinAny,
        };

        let skip_optimization = self.new_block();

        // Stack: [func] - copy function for identity check
        self.set_source_range(loc);
        emit!(self, Instruction::Copy { i: 1 });
        emit!(
            self,
            Instruction::LoadCommonConstant {
                idx: common_constant
            }
        );
        emit!(self, Instruction::IsOp { invert: Invert::No });
        emit!(
            self,
            Instruction::PopJumpIfFalse {
                delta: skip_optimization
            }
        );
        emit!(self, Instruction::PopTop);

        if matches!(kind, BuiltinGeneratorCallKind::Tuple) {
            self.set_source_range(loc);
            emit!(self, Instruction::BuildList { count: 0 });
        }

        let symbol_table_cursors = self.current_symbol_table_cursors();
        if let Some(range) = self.cpython_implicit_call_generator_range(generator_expr) {
            self.compile_expression_with_generator_range(generator_expr, range)?;
        } else {
            self.compile_expression(generator_expr)?;
        }
        self.set_symbol_table_cursors(symbol_table_cursors);

        let loop_block = self.new_block();
        let cleanup = self.new_block();
        self.use_cpython_label_block(loop_block);
        self.set_source_range(loc);
        emit!(self, Instruction::ForIter { delta: cleanup });

        match kind {
            BuiltinGeneratorCallKind::Tuple => {
                self.set_source_range(loc);
                emit!(self, Instruction::ListAppend { i: 2 });
                self.set_source_range(loc);
                emit!(self, PseudoInstruction::Jump { delta: loop_block });
            }
            BuiltinGeneratorCallKind::All => {
                self.set_source_range(loc);
                emit!(self, Instruction::ToBool);
                emit!(self, Instruction::PopJumpIfTrue { delta: loop_block });
                emit!(self, Instruction::PopIter);
                self.set_no_location();
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Boolean { value: false });
                self.set_source_range(loc);
                emit!(self, PseudoInstruction::Jump { delta: end });
            }
            BuiltinGeneratorCallKind::Any => {
                self.set_source_range(loc);
                emit!(self, Instruction::ToBool);
                emit!(self, Instruction::PopJumpIfFalse { delta: loop_block });
                emit!(self, Instruction::PopIter);
                self.set_no_location();
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Boolean { value: true });
                self.set_source_range(loc);
                emit!(self, PseudoInstruction::Jump { delta: end });
            }
        }

        self.use_cpython_label_block(cleanup);
        emit!(self, Instruction::EndFor);
        self.set_no_location();
        emit!(self, Instruction::PopIter);
        self.set_no_location();
        match kind {
            BuiltinGeneratorCallKind::Tuple => {
                self.set_source_range(loc);
                emit!(
                    self,
                    Instruction::CallIntrinsic1 {
                        func: IntrinsicFunction1::ListToTuple
                    }
                );
            }
            BuiltinGeneratorCallKind::All => {
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Boolean { value: true });
            }
            BuiltinGeneratorCallKind::Any => {
                self.set_source_range(loc);
                self.emit_load_const(ConstantData::Boolean { value: false });
            }
        }
        self.set_source_range(loc);
        emit!(self, PseudoInstruction::Jump { delta: end });

        self.use_cpython_label_block(skip_optimization);
        Ok(())
    }

    fn can_use_cpython_method_call(&self, value: &ast::Expr, args: &ast::Arguments) -> bool {
        let is_import = matches!(value, ast::Expr::Name(ast::ExprName { id, .. })
            if self.is_name_imported(id.as_str()));
        if is_import {
            return false;
        }

        if args.args.len() + args.keywords.len() + usize::from(!args.keywords.is_empty())
            >= STACK_USE_GUIDELINE as usize
        {
            return false;
        }

        !args
            .args
            .iter()
            .any(|arg| matches!(arg, ast::Expr::Starred(_)))
            && args.keywords.iter().all(|kw| kw.arg.is_some())
    }

    fn compile_method_call_arguments(
        &mut self,
        args: &ast::Arguments,
        call_range: TextRange,
        kw_names_range: TextRange,
    ) -> CompileResult<()> {
        let implicit_generator_range = if args.args.len() == 1 && args.keywords.is_empty() {
            self.cpython_implicit_call_generator_range(&args.args[0])
        } else {
            None
        };
        for arg in &args.args {
            if let Some(range) = implicit_generator_range {
                self.compile_expression_with_generator_range(arg, range)?;
            } else {
                self.compile_expression(arg)?;
            }
        }

        if args.keywords.is_empty() {
            self.set_source_range(call_range);
            emit!(
                self,
                Instruction::Call {
                    argc: args.args.len().to_u32()
                }
            );
            return Ok(());
        }

        let mut kwarg_names = Vec::with_capacity(args.keywords.len());
        for keyword in &args.keywords {
            kwarg_names.push(ConstantData::Str {
                value: keyword.arg.as_ref().unwrap().as_str().into(),
            });
            self.compile_expression(&keyword.value)?;
        }
        self.set_source_range(kw_names_range);
        self.emit_load_const(ConstantData::Tuple {
            elements: kwarg_names,
        });
        self.set_source_range(call_range);
        emit!(
            self,
            Instruction::CallKw {
                argc: (args.args.len() + args.keywords.len()).to_u32()
            }
        );
        Ok(())
    }

    fn compile_call(&mut self, func: &ast::Expr, args: &ast::Arguments) -> CompileResult<()> {
        // Save the call expression's source range so CALL instructions use the
        // call start line, not the last argument's line.
        let call_range = self.current_source_range;
        self.validate_keywords(&args.keywords)?;
        let uses_ex_call = self.call_uses_ex_call(args);

        // Method call: obj → LOAD_ATTR_METHOD → [method, self_or_null] → args → CALL
        // Regular call: func → PUSH_NULL → args → CALL
        if let ast::Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = &func {
            if !self.can_use_cpython_method_call(value, args) {
                self.check_caller(func)?;
                self.compile_expression(func)?;
                self.set_source_range(func.range());
                emit!(self, Instruction::PushNull);
                self.codegen_call_helper(0, args, call_range, None)?;
                return Ok(());
            }

            // Check for super() method call optimization
            if let Some(super_type) = self.can_optimize_super_call(value, attr.as_str()) {
                // super().method() or super(cls, self).method() optimization
                // CALL path: [global_super, class, self] → LOAD_SUPER_METHOD → [method, self]
                let ast::Expr::Call(ast::ExprCall {
                    func: super_func, ..
                }) = value.as_ref()
                else {
                    unreachable!("can_optimize_super_call only accepts calls");
                };
                self.load_args_for_super(&super_type, super_func.range(), value.range())?;
                let attr_access_range = self.update_start_location_to_match_attr(
                    func.range(),
                    func.range(),
                    attr.as_str(),
                );
                let method_call_range = self.update_start_location_to_match_attr(
                    call_range,
                    func.range(),
                    attr.as_str(),
                );
                self.set_source_range(func.range());
                let idx = self.name(attr.as_str());
                match super_type {
                    SuperCallType::TwoArg { .. } => {
                        self.emit_load_super_method(idx);
                    }
                    SuperCallType::ZeroArg => {
                        self.emit_load_zero_super_method(idx);
                    }
                }
                // NOP for line tracking at .method( line
                self.set_source_range(attr_access_range);
                emit!(self, Instruction::Nop);
                // CALL at .method( line (not the full expression line)
                self.compile_method_call_arguments(args, method_call_range, attr_access_range)?;
            } else {
                self.compile_expression(value)?;
                let idx = self.name(attr.as_str());
                let attr_access_range = self.update_start_location_to_match_attr(
                    func.range(),
                    func.range(),
                    attr.as_str(),
                );
                let method_call_range = self.update_start_location_to_match_attr(
                    call_range,
                    func.range(),
                    attr.as_str(),
                );
                self.set_source_range(attr_access_range);
                self.emit_load_attr_method(idx);
                self.compile_method_call_arguments(args, method_call_range, attr_access_range)?;
            }
        } else if let Some(kind) = (!uses_ex_call)
            .then(|| self.detect_builtin_generator_call(func, args))
            .flatten()
        {
            let skip_normal_call = self.new_block();
            self.check_caller(func)?;
            self.compile_expression(func)?;
            self.optimize_builtin_generator_call(
                kind,
                &args.args[0],
                func.range(),
                skip_normal_call,
            )?;
            self.set_source_range(func.range());
            emit!(self, Instruction::PushNull);
            self.codegen_call_helper(0, args, call_range, None)?;
            self.use_cpython_label_block(skip_normal_call);
        } else {
            // Regular call: push func, then NULL for self_or_null slot
            // Stack layout: [func, NULL, args...] - same as method call [func, self, args...]
            // CPython `codegen_call()` always creates and uses
            // `skip_normal_call`, even when `maybe_optimize_function_call()`
            // leaves it untargeted.
            let skip_normal_call = self.current_code_info().new_instr_sequence_label();
            let sync_genexpr_call_name = (!uses_ex_call)
                .then(|| self.cpython_sync_genexpr_call_name(func, args))
                .flatten()
                .is_some();
            self.check_caller(func)?;
            self.compile_expression(func)?;
            if sync_genexpr_call_name {
                // CPython `maybe_optimize_function_call()` creates and uses
                // `skip_optimization` for every sync name(genexpr) shape after
                // loading the function, even when the name is not all/any/tuple.
                let skip_optimization = self.current_code_info().new_instr_sequence_label();
                let result = self
                    .current_code_info()
                    .use_raw_instr_sequence_label(skip_optimization);
                unwrap_internal(self, result);
            }
            self.set_source_range(func.range());
            emit!(self, Instruction::PushNull);
            self.codegen_call_helper(0, args, call_range, None)?;
            let result = self
                .current_code_info()
                .use_raw_instr_sequence_label(skip_normal_call);
            unwrap_internal(self, result);
        }
        Ok(())
    }

    fn call_uses_ex_call(&self, arguments: &ast::Arguments) -> bool {
        let has_starred = arguments
            .args
            .iter()
            .any(|arg| matches!(arg, ast::Expr::Starred(_)));
        let has_double_star = arguments.keywords.iter().any(|k| k.arg.is_none());
        let too_big =
            arguments.args.len() + arguments.keywords.len() * 2 > STACK_USE_GUIDELINE as usize;
        has_starred || has_double_star || too_big
    }

    /// Reject duplicate keyword-argument names in a call.
    fn validate_keywords(&mut self, keywords: &[ast::Keyword]) -> CompileResult<()> {
        for (i, keyword) in keywords.iter().enumerate() {
            let Some(arg) = &keyword.arg else {
                continue;
            };
            for other in &keywords[i + 1..] {
                if other.arg.as_ref() == Some(arg) {
                    return Err(self.error_ranged(
                        CodegenErrorType::SyntaxError(format!("keyword argument repeated: {arg}")),
                        other.range,
                    ));
                }
            }
        }
        Ok(())
    }

    /// Compile subkwargs: emit key-value pairs for BUILD_MAP
    fn codegen_subkwargs(
        &mut self,
        keywords: &[ast::Keyword],
        begin: usize,
        end: usize,
        call_range: TextRange,
    ) -> CompileResult<()> {
        let n = end - begin;
        assert!(n > 0);

        // For large kwargs, use BUILD_MAP(0) + MAP_ADD to avoid stack overflow.
        let big = n * 2 > STACK_USE_GUIDELINE as usize;

        if big {
            emit!(self, Instruction::BuildMap { count: 0 });
            self.set_no_location();
        }

        for kw in &keywords[begin..end] {
            // Key first, then value - this is critical!
            self.set_source_range(call_range);
            self.emit_load_const(ConstantData::Str {
                value: kw.arg.as_ref().unwrap().as_str().into(),
            });
            self.compile_expression(&kw.value)?;

            if big {
                emit!(self, Instruction::MapAdd { i: 1 });
                self.set_no_location();
            }
        }

        if !big {
            self.set_source_range(call_range);
            emit!(self, Instruction::BuildMap { count: n.to_u32() });
        }

        Ok(())
    }

    /// Compile call arguments and emit the appropriate CALL instruction.
    /// `call_range` is the source range of the call expression, used to set
    /// the correct line number on the CALL instruction.
    fn codegen_call_helper(
        &mut self,
        additional_positional: u32,
        arguments: &ast::Arguments,
        call_range: TextRange,
        kw_names_range: Option<TextRange>,
    ) -> CompileResult<()> {
        self.codegen_call_helper_impl(
            additional_positional,
            &arguments.args,
            &arguments.keywords,
            call_range,
            kw_names_range,
            None,
        )
    }

    fn codegen_call_helper_impl(
        &mut self,
        additional_positional: u32,
        args: &[ast::Expr],
        keywords: &[ast::Keyword],
        call_range: TextRange,
        kw_names_range: Option<TextRange>,
        injected_arg: Option<&str>,
    ) -> CompileResult<()> {
        self.validate_keywords(keywords)?;

        let nelts = args.len();
        let nkwelts = keywords.len();

        // Check if we have starred args or **kwargs
        let has_starred = args.iter().any(|arg| matches!(arg, ast::Expr::Starred(_)));
        let has_double_star = keywords.iter().any(|k| k.arg.is_none());

        // Check if exceeds CPython's stack-use guideline.
        // With CALL_KW, kwargs values go on stack but keys go in a const tuple,
        // so stack usage is: func + null + positional_args + kwarg_values + kwnames_tuple
        let too_big = nelts + nkwelts * 2 > STACK_USE_GUIDELINE as usize;

        if !has_starred && !has_double_star && !too_big {
            // Simple call path: no * or ** args
            let implicit_generator_range =
                if additional_positional == 0 && nelts == 1 && nkwelts == 0 {
                    self.cpython_implicit_call_generator_range(&args[0])
                } else {
                    None
                };
            for arg in args {
                if let Some(range) = implicit_generator_range {
                    self.compile_expression_with_generator_range(arg, range)?;
                } else {
                    self.compile_expression(arg)?;
                }
            }
            let injected_count = if let Some(injected_arg) = injected_arg {
                self.set_source_range(call_range);
                self.load_name(injected_arg)?;
                1
            } else {
                0
            };

            if nkwelts > 0 {
                // Compile keyword values and build kwnames tuple
                let mut kwarg_names = Vec::with_capacity(nkwelts);
                for keyword in keywords {
                    kwarg_names.push(ConstantData::Str {
                        value: keyword.arg.as_ref().unwrap().as_str().into(),
                    });
                    self.compile_expression(&keyword.value)?;
                }

                // Restore call expression range for kwnames and CALL_KW
                self.set_source_range(kw_names_range.unwrap_or(call_range));
                self.emit_load_const(ConstantData::Tuple {
                    elements: kwarg_names,
                });

                self.set_source_range(call_range);
                let argc =
                    additional_positional + nelts.to_u32() + injected_count + nkwelts.to_u32();
                emit!(self, Instruction::CallKw { argc });
            } else {
                self.set_source_range(call_range);
                let argc = additional_positional + nelts.to_u32() + injected_count;
                emit!(self, Instruction::Call { argc });
            }
        } else {
            // ex_call path: has * or ** args

            // Compile positional arguments
            if additional_positional == 0 && nelts == 1 && matches!(args[0], ast::Expr::Starred(_))
            {
                // Single starred arg: pass value directly to CallFunctionEx.
                // Runtime will convert to tuple and validate with function name.
                if let ast::Expr::Starred(ast::ExprStarred { value, .. }) = &args[0] {
                    self.compile_expression(value)?;
                }
            } else {
                // CPython `codegen_call_helper_impl()` sends every other
                // CALL_FUNCTION_EX positional shape through
                // `starunpack_helper_impl(..., BUILD_LIST, LIST_APPEND,
                // LIST_EXTEND, tuple=1)`, even when the only reason for the
                // ex-call path is too many non-starred positional arguments.
                self.set_source_range(call_range);
                self.starunpack_helper_impl(
                    args,
                    injected_arg,
                    additional_positional,
                    CollectionType::Tuple,
                )?;
            }

            self.compile_call_function_ex_keywords(keywords, call_range)?;

            self.set_source_range(call_range);
            emit!(self, Instruction::CallFunctionEx);
        }

        Ok(())
    }

    fn compile_call_function_ex_keywords(
        &mut self,
        keywords: &[ast::Keyword],
        call_range: TextRange,
    ) -> CompileResult<()> {
        if keywords.is_empty() {
            self.set_source_range(call_range);
            emit!(self, Instruction::PushNull);
            return Ok(());
        }

        let mut have_dict = false;
        let mut nseen = 0usize;

        for (i, keyword) in keywords.iter().enumerate() {
            if keyword.arg.is_none() {
                if nseen > 0 {
                    self.codegen_subkwargs(keywords, i - nseen, i, call_range)?;
                    if have_dict {
                        self.set_source_range(call_range);
                        emit!(self, Instruction::DictMerge { i: 1 });
                    }
                    have_dict = true;
                    nseen = 0;
                }

                if !have_dict {
                    self.set_source_range(call_range);
                    emit!(self, Instruction::BuildMap { count: 0 });
                    have_dict = true;
                }

                self.compile_expression(&keyword.value)?;
                self.set_source_range(call_range);
                emit!(self, Instruction::DictMerge { i: 1 });
            } else {
                nseen += 1;
            }
        }

        if nseen > 0 {
            self.codegen_subkwargs(keywords, keywords.len() - nseen, keywords.len(), call_range)?;
            if have_dict {
                self.set_source_range(call_range);
                emit!(self, Instruction::DictMerge { i: 1 });
            }
            have_dict = true;
        }

        debug_assert!(have_dict);
        Ok(())
    }

    fn compile_comprehension_element(&mut self, element: &ast::Expr) -> CompileResult<()> {
        self.compile_expression(element).map_err(|e| {
            if let CodegenErrorType::InvalidStarExpr = e.error {
                self.error(CodegenErrorType::SyntaxError(
                    "iterable unpacking cannot be used in comprehension".to_owned(),
                ))
            } else {
                e
            }
        })
    }

    fn compile_expression_with_generator_range(
        &mut self,
        expression: &ast::Expr,
        range: TextRange,
    ) -> CompileResult<()> {
        if let ast::Expr::Generator(ast::ExprGenerator {
            elt, generators, ..
        }) = expression
        {
            self.set_source_range(range);
            self.compile_generator_expression(elt, generators, range)
        } else {
            self.compile_expression(expression)
        }
    }

    fn cpython_implicit_call_generator_range(&self, expression: &ast::Expr) -> Option<TextRange> {
        if !matches!(expression, ast::Expr::Generator(_)) {
            return None;
        }
        let range = expression.range();
        let source = self.source_file.source_text().as_bytes();
        let start = range.start().to_usize();
        let end = range.end().to_usize();
        if source.get(start) == Some(&b'(')
            && !Self::starts_with_parenthesized_generator_element(source, start, end)
        {
            return None;
        }

        let mut open = start;
        while open > 0 && source[open - 1].is_ascii_whitespace() {
            open -= 1;
        }
        if open == 0 || source[open - 1] != b'(' {
            return None;
        }

        let mut close = end;
        while close < source.len() && source[close].is_ascii_whitespace() {
            close += 1;
        }
        if source.get(close) != Some(&b')') {
            return None;
        }

        let adjusted_start = u32::try_from(open - 1).ok()?;
        let adjusted_end = u32::try_from(close + 1).ok()?;
        Some(TextRange::new(
            TextSize::from(adjusted_start),
            TextSize::from(adjusted_end),
        ))
    }

    fn starts_with_parenthesized_generator_element(
        source: &[u8],
        start: usize,
        end: usize,
    ) -> bool {
        let mut depth = 0usize;
        let mut i = start;
        while i < end {
            match source[i] {
                b'(' | b'[' | b'{' => depth += 1,
                b')' | b']' | b'}' => {
                    if depth == 0 {
                        return false;
                    }
                    depth -= 1;
                    if depth == 0 {
                        return Self::next_token_is_for(source, i + 1, end);
                    }
                }
                b'\'' | b'"' => i = Self::skip_python_string_literal(source, i),
                _ => {}
            }
            i += 1;
        }
        false
    }

    fn skip_python_string_literal(source: &[u8], quote: usize) -> usize {
        let quote_byte = source[quote];
        let triple = source.get(quote + 1) == Some(&quote_byte)
            && source.get(quote + 2) == Some(&quote_byte);
        let mut i = quote + if triple { 3 } else { 1 };
        while i < source.len() {
            if source[i] == b'\\' {
                i += 2;
                continue;
            }
            if triple {
                if source[i] == quote_byte
                    && source.get(i + 1) == Some(&quote_byte)
                    && source.get(i + 2) == Some(&quote_byte)
                {
                    return i + 2;
                }
            } else if source[i] == quote_byte {
                return i;
            }
            i += 1;
        }
        source.len().saturating_sub(1)
    }

    fn next_token_is_for(source: &[u8], mut i: usize, end: usize) -> bool {
        while i < end && source[i].is_ascii_whitespace() {
            i += 1;
        }
        source.get(i..i + 3) == Some(b"for")
            && source
                .get(i + 3)
                .is_none_or(|byte| !byte.is_ascii_alphanumeric() && *byte != b'_')
    }

    fn compile_generator_expression(
        &mut self,
        elt: &ast::Expr,
        generators: &[ast::Comprehension],
        range: TextRange,
    ) -> CompileResult<()> {
        // Check if element or generators contain async content
        // This makes the generator expression into an async generator
        let element_contains_await =
            Self::contains_await(elt) || Self::generators_contain_await(generators);
        self.compile_comprehension(
            "<genexpr>",
            None,
            generators,
            &|compiler, _collection_add_i| {
                // Compile the element expression
                // Note: if element is an async comprehension, compile_expression
                // already handles awaiting it, so we don't need to await again here
                compiler.compile_comprehension_element(elt)?;

                compiler.mark_generator();
                if compiler.ctx.func == FunctionContext::AsyncFunction {
                    compiler.set_source_range(elt.range());
                    emit!(
                        compiler,
                        Instruction::CallIntrinsic1 {
                            func: bytecode::IntrinsicFunction1::AsyncGenWrap
                        }
                    );
                }
                // arg=0: direct yield (wrapped for async generators)
                compiler.set_source_range(elt.range());
                emit!(compiler, Instruction::YieldValue { arg: 0 });
                emit!(
                    compiler,
                    Instruction::Resume {
                        context: oparg::ResumeContext::from(oparg::ResumeLocation::AfterYield)
                    }
                );
                emit!(compiler, Instruction::PopTop);

                Ok(())
            },
            ComprehensionType::Generator,
            element_contains_await,
            range,
            elt.range(),
            elt.range(),
        )
    }

    fn consume_next_sub_table(&mut self) -> CompileResult<()> {
        {
            let _ = self.push_symbol_table()?;
        }
        self.pop_symbol_table();
        Ok(())
    }

    fn consume_function_annotation_symbol_table_if_used(&mut self) -> CompileResult<()> {
        if !self.next_function_annotation_symbol_table_uses_annotations() {
            return Ok(());
        }
        if !self.push_annotation_symbol_table() {
            let current_table = self.current_symbol_table();
            return Err(self.error(CodegenErrorType::SyntaxError(format!(
                "no annotation symbol table available in {} (type: {:?})",
                current_table.name, current_table.typ
            ))));
        }
        self.pop_annotation_symbol_table();
        Ok(())
    }

    fn consume_skipped_nested_scopes_in_expr(
        &mut self,
        expression: &ast::Expr,
    ) -> CompileResult<()> {
        use ast::visitor::Visitor;

        struct SkippedScopeVisitor<'a, 'warnings> {
            compiler: &'a mut Compiler<'warnings>,
            error: Option<CodegenError>,
        }

        impl SkippedScopeVisitor<'_, '_> {
            fn consume_scope(&mut self) {
                if self.error.is_none() {
                    self.error = self.compiler.consume_next_sub_table().err();
                }
            }

            fn consume_inlined_comprehension_scope(&mut self) -> bool {
                if self.error.is_some() {
                    return false;
                }
                let Some(current_table) = self.compiler.symbol_table_stack.last_mut() else {
                    return false;
                };
                if current_table.next_inlined_comprehension_block
                    < current_table.inlined_comprehension_blocks.len()
                {
                    current_table.next_inlined_comprehension_block += 1;
                    true
                } else {
                    false
                }
            }

            fn visit_comprehension_tail(
                &mut self,
                elt1: &ast::Expr,
                elt2: Option<&ast::Expr>,
                generators: &[ast::Comprehension],
            ) {
                if let Some(outermost) = generators.first() {
                    self.visit_expr(&outermost.target);
                    for if_expr in &outermost.ifs {
                        self.visit_expr(if_expr);
                    }
                }
                for generator in generators.iter().skip(1) {
                    self.visit_expr(&generator.target);
                    self.visit_expr(&generator.iter);
                    for if_expr in &generator.ifs {
                        self.visit_expr(if_expr);
                    }
                }
                if let Some(elt2) = elt2 {
                    self.visit_expr(elt2);
                }
                self.visit_expr(elt1);
            }
        }

        impl ast::visitor::Visitor<'_> for SkippedScopeVisitor<'_, '_> {
            fn visit_expr(&mut self, expr: &ast::Expr) {
                if self.error.is_some() {
                    return;
                }

                match expr {
                    ast::Expr::Lambda(ast::ExprLambda { parameters, .. }) => {
                        // Defaults are scanned before enter_scope in the
                        // symbol table builder, so their nested scopes
                        // precede the lambda scope in sub_tables.
                        if let Some(params) = parameters.as_deref() {
                            for default in params
                                .posonlyargs
                                .iter()
                                .chain(&params.args)
                                .chain(&params.kwonlyargs)
                                .filter_map(|p| p.default.as_deref())
                            {
                                self.visit_expr(default);
                            }
                        }
                        self.consume_scope();
                    }
                    ast::Expr::Generator(ast::ExprGenerator { generators, .. }) => {
                        if let Some(first) = generators.first() {
                            self.visit_expr(&first.iter);
                        }
                        self.consume_scope();
                    }
                    ast::Expr::ListComp(ast::ExprListComp {
                        elt, generators, ..
                    })
                    | ast::Expr::SetComp(ast::ExprSetComp {
                        elt, generators, ..
                    }) => {
                        if let Some(first) = generators.first() {
                            self.visit_expr(&first.iter);
                        }
                        if self.consume_inlined_comprehension_scope() {
                            self.visit_comprehension_tail(elt, None, generators);
                        } else {
                            self.consume_scope();
                        }
                    }
                    ast::Expr::DictComp(ast::ExprDictComp {
                        key,
                        value,
                        generators,
                        ..
                    }) => {
                        if let Some(first) = generators.first() {
                            self.visit_expr(&first.iter);
                        }
                        if self.consume_inlined_comprehension_scope() {
                            self.visit_comprehension_tail(key, Some(value), generators);
                        } else {
                            self.consume_scope();
                        }
                    }
                    _ => ast::visitor::walk_expr(self, expr),
                }
            }
        }

        let mut visitor = SkippedScopeVisitor {
            compiler: self,
            error: None,
        };
        visitor.visit_expr(expression);
        if let Some(err) = visitor.error {
            Err(err)
        } else {
            Ok(())
        }
    }

    fn consume_skipped_nested_scopes_in_parameter_defaults(
        &mut self,
        parameters: &ast::Parameters,
    ) -> CompileResult<()> {
        for default in parameters
            .posonlyargs
            .iter()
            .chain(&parameters.args)
            .chain(&parameters.kwonlyargs)
            .filter_map(|arg| arg.default.as_deref())
        {
            self.consume_skipped_nested_scopes_in_expr(default)?;
        }
        Ok(())
    }

    fn consume_skipped_nested_scopes_in_statements(
        &mut self,
        statements: &[ast::Stmt],
    ) -> CompileResult<()> {
        use ast::visitor::Visitor;

        struct SkippedStatementScopeVisitor<'a, 'warnings> {
            compiler: &'a mut Compiler<'warnings>,
            error: Option<CodegenError>,
        }

        impl SkippedStatementScopeVisitor<'_, '_> {
            fn consume_scope(&mut self) {
                if self.error.is_none() {
                    self.error = self.compiler.consume_next_sub_table().err();
                }
            }

            fn consume_function_annotation_scope_if_used(&mut self) {
                if self.error.is_none() {
                    self.error = self
                        .compiler
                        .consume_function_annotation_symbol_table_if_used()
                        .err();
                }
            }

            fn visit_parameter_defaults(&mut self, parameters: &ast::Parameters) {
                for default in parameters
                    .posonlyargs
                    .iter()
                    .chain(&parameters.args)
                    .chain(&parameters.kwonlyargs)
                    .filter_map(|arg| arg.default.as_deref())
                {
                    self.visit_expr(default);
                }
            }

            fn visit_decorators(&mut self, decorators: &[ast::Decorator]) {
                for decorator in decorators {
                    self.visit_expr(&decorator.expression);
                }
            }

            fn visit_arguments(&mut self, arguments: &ast::Arguments) {
                for arg in &arguments.args {
                    self.visit_expr(arg);
                }
                for keyword in &arguments.keywords {
                    self.visit_expr(&keyword.value);
                }
            }
        }

        impl ast::visitor::Visitor<'_> for SkippedStatementScopeVisitor<'_, '_> {
            fn visit_stmt(&mut self, stmt: &ast::Stmt) {
                if self.error.is_some() {
                    return;
                }

                match stmt {
                    ast::Stmt::FunctionDef(ast::StmtFunctionDef {
                        parameters,
                        decorator_list,
                        type_params,
                        ..
                    }) => {
                        self.visit_parameter_defaults(parameters);
                        self.visit_decorators(decorator_list);
                        if type_params.is_some() {
                            self.consume_scope();
                        } else {
                            self.consume_function_annotation_scope_if_used();
                            self.consume_scope();
                        }
                    }
                    ast::Stmt::ClassDef(ast::StmtClassDef {
                        arguments,
                        decorator_list,
                        type_params,
                        ..
                    }) => {
                        self.visit_decorators(decorator_list);
                        if type_params.is_some() {
                            self.consume_scope();
                        }
                        if let Some(arguments) = arguments {
                            self.visit_arguments(arguments);
                        }
                        self.consume_scope();
                    }
                    ast::Stmt::TypeAlias(ast::StmtTypeAlias { type_params, .. }) => {
                        if type_params.is_some() {
                            self.consume_scope();
                        }
                        self.consume_scope();
                    }
                    ast::Stmt::AnnAssign(ast::StmtAnnAssign { target, value, .. }) => {
                        self.visit_expr(target);
                        if let Some(value) = value {
                            self.visit_expr(value);
                        }
                    }
                    ast::Stmt::If(ast::StmtIf {
                        test,
                        body,
                        elif_else_clauses,
                        ..
                    }) => {
                        self.visit_expr(test);
                        for stmt in body {
                            self.visit_stmt(stmt);
                        }
                        for clause in elif_else_clauses {
                            if let Some(test) = &clause.test {
                                self.visit_expr(test);
                            }
                            for stmt in &clause.body {
                                self.visit_stmt(stmt);
                            }
                        }
                    }
                    ast::Stmt::Try(ast::StmtTry {
                        body,
                        handlers,
                        orelse,
                        finalbody,
                        ..
                    }) => {
                        for stmt in body {
                            self.visit_stmt(stmt);
                        }
                        for handler in handlers {
                            self.visit_except_handler(handler);
                        }
                        for stmt in orelse {
                            self.visit_stmt(stmt);
                        }
                        for stmt in finalbody {
                            self.visit_stmt(stmt);
                        }
                    }
                    _ => ast::visitor::walk_stmt(self, stmt),
                }
            }

            fn visit_expr(&mut self, expr: &ast::Expr) {
                if self.error.is_some() {
                    return;
                }
                self.error = self
                    .compiler
                    .consume_skipped_nested_scopes_in_expr(expr)
                    .err();
            }

            fn visit_except_handler(&mut self, handler: &ast::ExceptHandler) {
                if self.error.is_some() {
                    return;
                }
                let ast::ExceptHandler::ExceptHandler(ast::ExceptHandlerExceptHandler {
                    type_,
                    body,
                    ..
                }) = handler;
                if let Some(type_) = type_ {
                    self.visit_expr(type_);
                }
                for stmt in body {
                    self.visit_stmt(stmt);
                }
            }
        }

        let mut visitor = SkippedStatementScopeVisitor {
            compiler: self,
            error: None,
        };
        for statement in statements {
            visitor.visit_stmt(statement);
        }
        if let Some(err) = visitor.error {
            Err(err)
        } else {
            Ok(())
        }
    }

    fn consume_skipped_nested_scopes_in_except_handlers(
        &mut self,
        handlers: &[ast::ExceptHandler],
    ) -> CompileResult<()> {
        use ast::visitor::Visitor;

        struct SkippedHandlerScopeVisitor<'a, 'warnings> {
            compiler: &'a mut Compiler<'warnings>,
            error: Option<CodegenError>,
        }

        impl ast::visitor::Visitor<'_> for SkippedHandlerScopeVisitor<'_, '_> {
            fn visit_expr(&mut self, expr: &ast::Expr) {
                if self.error.is_some() {
                    return;
                }
                self.error = self
                    .compiler
                    .consume_skipped_nested_scopes_in_expr(expr)
                    .err();
            }

            fn visit_stmt(&mut self, stmt: &ast::Stmt) {
                if self.error.is_some() {
                    return;
                }
                self.error = self
                    .compiler
                    .consume_skipped_nested_scopes_in_statements(slice::from_ref(stmt))
                    .err();
            }
        }

        let mut visitor = SkippedHandlerScopeVisitor {
            compiler: self,
            error: None,
        };
        for handler in handlers {
            visitor.visit_except_handler(handler);
            if visitor.error.is_some() {
                break;
            }
        }
        if let Some(err) = visitor.error {
            Err(err)
        } else {
            Ok(())
        }
    }

    fn current_symbol_table_cursors(&self) -> SymbolTableCursors {
        let table = self
            .symbol_table_stack
            .last()
            .expect("no current symbol table");
        SymbolTableCursors {
            sub_table: table.next_sub_table,
            hidden_annotation_block: table.next_hidden_annotation_block,
            inlined_comprehension_block: table.next_inlined_comprehension_block,
        }
    }

    fn set_symbol_table_cursors(&mut self, cursors: SymbolTableCursors) {
        let table = self
            .symbol_table_stack
            .last_mut()
            .expect("no current symbol table");
        table.next_sub_table = cursors.sub_table;
        table.next_hidden_annotation_block = cursors.hidden_annotation_block;
        table.next_inlined_comprehension_block = cursors.inlined_comprehension_block;
    }

    fn lookup_comprehension_symbol_table_after_skipped_nested_scopes_in_expr(
        &mut self,
        expression: &ast::Expr,
        comprehension_type: ComprehensionType,
    ) -> CompileResult<(SymbolTable, ComprehensionSymbolSource)> {
        let saved_cursor = self
            .symbol_table_stack
            .last()
            .expect("no current symbol table")
            .next_sub_table;
        let saved_inlined_cursor = self
            .symbol_table_stack
            .last()
            .expect("no current symbol table")
            .next_inlined_comprehension_block;
        let result = (|| {
            self.consume_skipped_nested_scopes_in_expr(expression)?;
            let current_table = self
                .symbol_table_stack
                .last()
                .expect("no current symbol table");
            if comprehension_type != ComprehensionType::Generator
                && let Some(table) = current_table
                    .inlined_comprehension_blocks
                    .get(current_table.next_inlined_comprehension_block)
            {
                return Ok((table.clone(), ComprehensionSymbolSource::Inlined));
            }
            if let Some(table) = current_table.sub_tables.get(current_table.next_sub_table) {
                Ok((table.clone(), ComprehensionSymbolSource::Child))
            } else {
                let name = current_table.name.clone();
                let typ = current_table.typ;
                Err(self.error(CodegenErrorType::SyntaxError(format!(
                    "no symbol table available in {name} (type: {typ:?})"
                ))))
            }
        })();
        self.symbol_table_stack
            .last_mut()
            .expect("no current symbol table")
            .next_sub_table = saved_cursor;
        self.symbol_table_stack
            .last_mut()
            .expect("no current symbol table")
            .next_inlined_comprehension_block = saved_inlined_cursor;
        result
    }

    fn push_output_with_symbol_table(
        &mut self,
        table: SymbolTable,
        flags: bytecode::CodeFlags,
        posonlyarg_count: u32,
        arg_count: u32,
        kwonlyarg_count: u32,
        obj_name: &str,
    ) -> CompileResult<()> {
        let scope_type = table.typ;
        self.symbol_table_stack.push(table);

        let key = self.symbol_table_stack.len() - 1;
        let lineno = self.get_source_line_number().get();
        self.enter_scope(obj_name, scope_type, key, lineno.to_u32())?;

        if let Some(info) = self.code_stack.last_mut() {
            info.flags = flags
                | (info.flags
                    & (bytecode::CodeFlags::NESTED
                        | bytecode::CodeFlags::METHOD
                        | bytecode::CodeFlags::FUTURE_DIVISION
                        | bytecode::CodeFlags::FUTURE_ABSOLUTE_IMPORT
                        | bytecode::CodeFlags::FUTURE_WITH_STATEMENT
                        | bytecode::CodeFlags::FUTURE_PRINT_FUNCTION
                        | bytecode::CodeFlags::FUTURE_UNICODE_LITERALS
                        | bytecode::CodeFlags::FUTURE_GENERATOR_STOP
                        | bytecode::CodeFlags::FUTURE_ANNOTATIONS));
            info.metadata.argcount = arg_count;
            info.metadata.posonlyargcount = posonlyarg_count;
            info.metadata.kwonlyargcount = kwonlyarg_count;
        }
        Ok(())
    }

    #[expect(clippy::too_many_arguments, reason = "ignore warning for now")]
    fn compile_comprehension(
        &mut self,
        name: &str,
        init_collection: Option<AnyInstruction>,
        generators: &[ast::Comprehension],
        compile_element: &dyn Fn(&mut Self, usize) -> CompileResult<()>,
        comprehension_type: ComprehensionType,
        element_contains_await: bool,
        comprehension_range: TextRange,
        element_range: TextRange,
        outer_backedge_range: TextRange,
    ) -> CompileResult<()> {
        let prev_ctx = self.ctx;
        let has_an_async_gen = generators.iter().any(|g| g.is_async);
        let is_top_level_await_context = self.opts.allow_top_level_await
            && prev_ctx.func == FunctionContext::NoFunction
            && !prev_ctx.in_class;

        // Check for async comprehension outside async function (list/set/dict only, not generator expressions)
        // Use in_async_scope to allow nested async comprehensions inside an async function
        if comprehension_type != ComprehensionType::Generator
            && (has_an_async_gen || element_contains_await)
            && !prev_ctx.in_async_scope
            && !is_top_level_await_context
        {
            return Err(self.error(CodegenErrorType::InvalidAsyncComprehension));
        }

        // async comprehensions are allowed in various contexts:
        // - list/set/dict comprehensions in async functions (or nested within)
        // - always for generator expressions
        let is_async_list_set_dict_comprehension = comprehension_type
            != ComprehensionType::Generator
            && (has_an_async_gen || element_contains_await)
            && (prev_ctx.in_async_scope || is_top_level_await_context);

        let is_async_generator_comprehension = comprehension_type == ComprehensionType::Generator
            && (has_an_async_gen || element_contains_await);

        debug_assert!(!(is_async_list_set_dict_comprehension && is_async_generator_comprehension));

        let is_async = is_async_list_set_dict_comprehension || is_async_generator_comprehension;

        // We must have at least one generator:
        assert!(!generators.is_empty());
        let outermost = &generators[0];
        let (comp_table, comp_source) = self
            .lookup_comprehension_symbol_table_after_skipped_nested_scopes_in_expr(
                &outermost.iter,
                comprehension_type,
            )?;

        let is_inlined = self.is_inlined_comprehension_context(comprehension_type, &comp_table);

        if is_inlined {
            // CPython inlines every non-generator comprehension that the
            // symtable marked as comp_inlined, including async variants.
            // codegen_comprehension() only branches on ste_comp_inlined here
            // and relies on the inlined path itself to handle GET_AITER /
            // async-comprehension cleanup.
            return self.compile_inlined_comprehension(
                &comp_table,
                init_collection,
                generators,
                compile_element,
                (comprehension_range, element_range, outer_backedge_range),
                comp_source,
            );
        }

        // Non-inlined path: create a new code object (generator expressions, etc.)
        self.ctx = CompileContext {
            in_class: prev_ctx.in_class,
            func: if is_async {
                FunctionContext::AsyncFunction
            } else {
                FunctionContext::Function
            },
            // Inherit in_async_scope from parent - nested async comprehensions are allowed
            // if we're anywhere inside an async function
            in_async_scope: prev_ctx.in_async_scope || is_async,
        };

        let flags = bytecode::CodeFlags::NEWLOCALS | bytecode::CodeFlags::OPTIMIZED;
        let flags = if is_async {
            flags | bytecode::CodeFlags::COROUTINE
        } else {
            flags
        };

        // The symbol table follows CPython's symtable walk: nested scopes
        // in the outermost iterator are recorded before the comprehension
        // scope itself. Peek past those nested scopes so we can enter the
        // correct comprehension table here, then let the real outermost
        // iterator compile consume its nested scopes later in parent scope.
        self.push_output_with_symbol_table(comp_table, flags, 0, 1, 0, name)?;

        // Set qualname for comprehension
        self.set_qualname();
        self.set_source_range(comprehension_range);

        let arg0 = self.varname(".0");

        let return_none = init_collection.is_none();

        // CPython codegen_comprehension() wraps only generator expressions
        // with codegen_wrap_in_stopiteration_handler(); unlike function bodies,
        // it does not push a COMPILE_FBLOCK_STOP_ITERATION fblock.
        let stop_iteration_block = if comprehension_type == ComprehensionType::Generator {
            let handler_block = self.new_block();
            self.insert_cpython_stopiteration_setup_cleanup(handler_block);
            Some(handler_block)
        } else {
            None
        };

        // Create empty object of proper type:
        if let Some(init_collection) = init_collection {
            self._emit(init_collection, OpArg::new(0), BlockIdx::NULL)
        }

        let mut loop_labels = vec![];
        let mut real_loop_depth = 0;
        for (gen_index, generator) in generators.iter().enumerate() {
            if gen_index > 0
                && !generator.is_async
                && let Some(singleton_iter) =
                    Self::singleton_comprehension_assignment_iter(&generator.iter)
            {
                // CPython allocates start/if_cleanup/anchor labels before the
                // singleton sub-iterator fast path sets start = NO_LABEL.
                let _start_label = self.current_code_info().new_instr_sequence_label();
                let if_cleanup_block = self.new_block();
                let _anchor_label = self.current_code_info().new_instr_sequence_label();
                self.compile_expression(singleton_iter)?;
                self.compile_store(&generator.target)?;

                if !generator.ifs.is_empty() {
                    for if_condition in &generator.ifs {
                        self.compile_jump_if(if_condition, false, if_cleanup_block)?;
                    }
                }
                loop_labels.push(ComprehensionLoopControl::IfCleanupOnly { if_cleanup_block });
                continue;
            }

            let loop_block = self.new_block();
            let (send_block, after_block, if_cleanup_block) = if generator.is_async {
                let send_block = self.new_block();
                let after_block = self.new_block();
                let if_cleanup_block = self.new_block();
                (send_block, after_block, if_cleanup_block)
            } else {
                let if_cleanup_block = self.new_block();
                let after_block = self.new_block();
                (BlockIdx::NULL, after_block, if_cleanup_block)
            };

            if gen_index == 0 {
                // Load iterator onto stack (passed as first argument):
                emit!(self, Instruction::LoadFast { var_num: arg0 });
            } else {
                // Evaluate iterated item:
                self.compile_comprehension_iter(generator)?;
            }

            self.use_cpython_label_block(loop_block);
            let mut end_async_for_target = BlockIdx::NULL;
            if generator.is_async {
                let loop_label = self.instr_sequence_label_for_block(loop_block);
                self.push_fblock_labels(
                    FBlockType::AsyncComprehensionGenerator,
                    loop_label,
                    ir::InstructionSequenceLabel::NO_LABEL,
                    FBlockDatum::None,
                )?;
                emit!(self, PseudoInstruction::SetupFinally { delta: after_block });
                emit!(self, Instruction::GetAnext);
                self.emit_load_const(ConstantData::None);
                self.use_cpython_label_block(send_block);
                let _ = self.compile_yield_from_sequence(true);
                end_async_for_target = send_block;
                // POP_BLOCK before store: only __anext__/yield_from are
                // protected by SetupFinally targeting END_ASYNC_FOR.
                emit!(self, PseudoInstruction::PopBlock);
                self.compile_store(&generator.target)?;
            } else {
                let saved_range = self.current_source_range;
                self.set_source_range(generator.iter.range());
                emit!(self, Instruction::ForIter { delta: after_block });
                self.set_source_range(saved_range);
                self.compile_store(&generator.target)?;
            }
            real_loop_depth += 1;
            let backedge_range = if gen_index + 1 == generators.len() {
                element_range
            } else {
                outer_backedge_range
            };
            loop_labels.push(ComprehensionLoopControl::Iteration {
                loop_block,
                if_cleanup_block,
                after_block,
                backedge_range,
                is_async: generator.is_async,
                end_async_for_target,
            });

            // CPython always lowers comprehension guards through codegen_jump_if
            // and leaves constant-folding to later CFG optimization passes.
            for if_condition in &generator.ifs {
                self.compile_jump_if(if_condition, false, if_cleanup_block)?;
            }
        }

        compile_element(self, real_loop_depth + 1)?;

        for loop_control in loop_labels.iter().rev().copied() {
            match loop_control {
                ComprehensionLoopControl::Iteration {
                    loop_block,
                    if_cleanup_block,
                    after_block,
                    backedge_range,
                    is_async,
                    end_async_for_target,
                } => {
                    self.use_cpython_label_block(if_cleanup_block);
                    self.set_source_range(backedge_range);
                    emit!(self, PseudoInstruction::Jump { delta: loop_block });

                    if is_async {
                        let loop_label = self.instr_sequence_label_for_block(loop_block);
                        self.pop_fblock_label(FBlockType::AsyncComprehensionGenerator, loop_label);
                    }

                    self.use_cpython_label_block(after_block);
                    if is_async {
                        self.set_source_range(comprehension_range);
                        // EndAsyncFor pops both the exception and the aiter
                        // (handler depth is before GetANext, so aiter is at handler depth)
                        self.emit_end_async_for(end_async_for_target);
                    } else {
                        self.emit_sync_comprehension_end_for();
                    }
                }
                ComprehensionLoopControl::IfCleanupOnly { if_cleanup_block } => {
                    self.use_cpython_label_block(if_cleanup_block);
                }
            }
        }

        if return_none {
            self.emit_return_const_no_location(ConstantData::None);
        } else {
            self.set_source_range(comprehension_range);
            self.emit_return_value();
        }

        // Close StopIteration handler and emit handler code
        if let Some(handler_block) = stop_iteration_block {
            self.use_cpython_label_block(handler_block);
            emit!(
                self,
                Instruction::CallIntrinsic1 {
                    func: oparg::IntrinsicFunction1::StopIterationError
                }
            );
            self.set_no_location();
            emit!(self, Instruction::Reraise { depth: 1u32 });
            self.set_no_location();
        }
        self.emit_return_const_no_location(ConstantData::None);

        let code = self.exit_scope();

        self.ctx = prev_ctx;

        // Create comprehension function with closure
        self.set_source_range(comprehension_range);
        self.make_closure(code, bytecode::MakeFunctionFlags::new())?;

        // Evaluate iterated item and get its iterator.
        self.compile_comprehension_iter(outermost)?;
        self.symbol_table_stack
            .last_mut()
            .expect("no current symbol table")
            .next_sub_table += 1;

        // Call just created <listcomp> function:
        self.set_source_range(comprehension_range);
        emit!(self, Instruction::Call { argc: 0 });
        if is_async_list_set_dict_comprehension {
            emit!(self, Instruction::GetAwaitable { r#where: 0 });
            self.emit_load_const(ConstantData::None);
            let _ = self.compile_yield_from_sequence(true);
        }

        Ok(())
    }

    /// Compile an inlined comprehension (PEP 709)
    /// This generates bytecode inline without creating a new code object
    fn compile_inlined_comprehension(
        &mut self,
        comp_table: &SymbolTable,
        init_collection: Option<AnyInstruction>,
        generators: &[ast::Comprehension],
        compile_element: &dyn Fn(&mut Self, usize) -> CompileResult<()>,
        ranges: (TextRange, TextRange, TextRange),
        comp_source: ComprehensionSymbolSource,
    ) -> CompileResult<()> {
        let (comprehension_range, element_range, outer_backedge_range) = ranges;
        // Compile the outermost iterator first. Its expression may reference
        // nested scopes (e.g. lambdas) whose sub_tables sit at the current
        // position in the parent's list. Those must be consumed before we
        // splice in the comprehension's own children.
        self.compile_comprehension_iter(&generators[0])?;
        match comp_source {
            ComprehensionSymbolSource::Child => {
                self.symbol_table_stack
                    .last_mut()
                    .expect("no current symbol table")
                    .next_sub_table += 1;
            }
            ComprehensionSymbolSource::Inlined => {
                self.symbol_table_stack
                    .last_mut()
                    .expect("no current symbol table")
                    .next_inlined_comprehension_block += 1;
            }
        }

        let was_in_inlined_comp = self.current_code_info().in_inlined_comp;
        let saved_source_range = self.current_source_range;
        let tweak_in_class_block = {
            let ct = self.current_symbol_table();
            ct.typ == CompilerScope::Class && !was_in_inlined_comp
        };
        self.current_code_info().in_inlined_comp = true;

        let mut temp_symbols: IndexMap<String, Symbol> = IndexMap::default();
        let mut changed_fast_hidden = Vec::new();

        let result = (|| {
            // If the symbol table still carries the inlined comprehension as
            // a child, splice its children here. The symtable normally
            // performs this splice before codegen, and the Inlined source path
            // has already done so.
            if matches!(comp_source, ComprehensionSymbolSource::Child)
                && !comp_table.sub_tables.is_empty()
            {
                let current_table = self
                    .symbol_table_stack
                    .last_mut()
                    .expect("no current symbol table");
                let insert_pos = current_table.next_sub_table;
                for (i, st) in comp_table.sub_tables.iter().enumerate() {
                    current_table.sub_tables.insert(insert_pos + i, st.clone());
                }
            }
            let mut pushed_locals: Vec<String> = Vec::new();
            let mut fast_hidden_locals: Vec<String> = Vec::new();
            for (name, sym) in &comp_table.symbols {
                if sym.flags.contains(SymbolFlags::DEF_PARAM) {
                    continue; // skip .0
                }
                let is_local = sym
                    .flags
                    .intersects(SymbolFlags::DEF_LOCAL | SymbolFlags::ITER)
                    && !sym.flags.contains(SymbolFlags::DEF_NONLOCAL);
                if is_local {
                    pushed_locals.push(name.clone());
                }
                if is_local || tweak_in_class_block {
                    fast_hidden_locals.push(name.clone());
                }
            }

            // TweakInlinedComprehensionScopes: temporarily override parent
            // symbols with comprehension scopes where they differ. For
            // module/class scopes, also enable temporary fast locals for
            // comprehension-bound names only.
            for (name, comp_sym) in &comp_table.symbols {
                if comp_sym.flags.contains(SymbolFlags::DEF_PARAM) {
                    continue; // skip .0
                }
                let comp_scope = comp_sym.scope;

                let current_table = self.symbol_table_stack.last().expect("no symbol table");
                if let Some(outer_sym) = current_table.symbols.get(name) {
                    let outer_scope = outer_sym.scope;
                    if (comp_scope != outer_scope
                        && comp_scope != SymbolScope::Free
                        && !(comp_scope == SymbolScope::Cell && outer_scope == SymbolScope::Free))
                        || tweak_in_class_block
                    {
                        temp_symbols.insert(name.clone(), outer_sym.clone());
                        let current_table =
                            self.symbol_table_stack.last_mut().expect("no symbol table");
                        current_table.symbols.insert(name.clone(), comp_sym.clone());
                    }
                }
            }
            if !self.ctx.in_func() {
                for name in &fast_hidden_locals {
                    if self
                        .current_code_info()
                        .metadata
                        .fast_hidden
                        .get(name.as_str())
                        .is_none_or(|&hidden| !hidden)
                    {
                        self.current_code_info()
                            .metadata
                            .fast_hidden
                            .insert(name.clone(), true);
                        self.current_code_info()
                            .metadata
                            .fast_hidden_final
                            .insert(name.clone());
                        changed_fast_hidden.push(name.clone());
                    }
                }
            }

            // Step 2: Save local variables that will be shadowed by the comprehension.
            // For each variable, we push the fast local value via LoadFastAndClear.
            // For merged CELL variables, LoadFastAndClear saves the cell object from
            // the merged slot, and MAKE_CELL creates a new empty cell in-place.
            // MAKE_CELL has no stack effect (operates only on fastlocals).
            self.set_source_range(comprehension_range);
            let mut total_stack_items: usize = 0;
            for name in &pushed_locals {
                let var_num = self.varname(name);
                emit!(self, Instruction::LoadFastAndClear { var_num });
                total_stack_items += 1;
                // If the comp symbol is CELL, emit MAKE_CELL to create fresh cell
                if let Some(comp_sym) = comp_table.symbols.get(name)
                    && comp_sym.scope == SymbolScope::Cell
                {
                    let i = if self
                        .current_symbol_table()
                        .symbols
                        .get(name)
                        .is_some_and(|s| s.scope == SymbolScope::Free)
                    {
                        self.get_free_var_index(name)
                    } else {
                        self.get_cell_var_index(name)
                    };
                    emit!(self, Instruction::MakeCell { i });
                }
            }

            // Step 3: SWAP iterator to TOS (above saved locals + cell values)
            if total_stack_items > 0 {
                emit!(
                    self,
                    Instruction::Swap {
                        i: u32::try_from(total_stack_items + 1).unwrap()
                    }
                );
            }

            // CPython's codegen_push_inlined_comprehension_locals()
            // installs the virtual cleanup before codegen_comprehension()
            // emits BUILD_LIST/BUILD_SET/BUILD_MAP for the result object.
            let cleanup_block = if !pushed_locals.is_empty() {
                let cleanup_block = self.new_block();
                emit!(
                    self,
                    PseudoInstruction::SetupFinally {
                        delta: cleanup_block
                    }
                );
                Some(cleanup_block)
            } else {
                None
            };

            // Step 4: Create the collection (list/set/dict)
            if let Some(init_collection) = init_collection {
                self._emit(init_collection, OpArg::new(0), BlockIdx::NULL);
                // SWAP to get iterator on top
                emit!(self, Instruction::Swap { i: 2 });
            }

            // Step 5: Compile the comprehension loop(s)
            let mut loop_labels: Vec<ComprehensionLoopControl> = vec![];
            let mut real_loop_depth = 0;
            for (i, generator) in generators.iter().enumerate() {
                if i > 0
                    && !generator.is_async
                    && let Some(singleton_iter) =
                        Self::singleton_comprehension_assignment_iter(&generator.iter)
                {
                    // CPython allocates start/if_cleanup/anchor labels before
                    // the singleton sub-iterator fast path sets start = NO_LABEL.
                    let _start_label = self.current_code_info().new_instr_sequence_label();
                    let if_cleanup_block = self.new_block();
                    let _anchor_label = self.current_code_info().new_instr_sequence_label();
                    self.compile_expression(singleton_iter)?;
                    self.compile_store(&generator.target)?;

                    if !generator.ifs.is_empty() {
                        for if_condition in &generator.ifs {
                            self.compile_jump_if(if_condition, false, if_cleanup_block)?;
                        }
                    }
                    loop_labels.push(ComprehensionLoopControl::IfCleanupOnly { if_cleanup_block });
                    continue;
                }

                let loop_block = self.new_block();
                let (send_block, after_block, if_cleanup_block) = if generator.is_async {
                    let send_block = self.new_block();
                    let after_block = self.new_block();
                    let if_cleanup_block = self.new_block();
                    (send_block, after_block, if_cleanup_block)
                } else {
                    let if_cleanup_block = self.new_block();
                    let after_block = self.new_block();
                    (BlockIdx::NULL, after_block, if_cleanup_block)
                };

                if i > 0 {
                    self.compile_comprehension_iter(generator)?;
                }

                self.use_cpython_label_block(loop_block);

                let mut end_async_for_target = BlockIdx::NULL;
                if generator.is_async {
                    let loop_label = self.instr_sequence_label_for_block(loop_block);
                    self.push_fblock_labels(
                        FBlockType::AsyncComprehensionGenerator,
                        loop_label,
                        ir::InstructionSequenceLabel::NO_LABEL,
                        FBlockDatum::None,
                    )?;
                    emit!(self, PseudoInstruction::SetupFinally { delta: after_block });
                    emit!(self, Instruction::GetAnext);
                    self.emit_load_const(ConstantData::None);
                    self.use_cpython_label_block(send_block);
                    let _ = self.compile_yield_from_sequence(true);
                    end_async_for_target = send_block;
                    emit!(self, PseudoInstruction::PopBlock);
                    self.compile_store(&generator.target)?;
                } else {
                    let saved_range = self.current_source_range;
                    self.set_source_range(generator.iter.range());
                    emit!(self, Instruction::ForIter { delta: after_block });
                    self.set_source_range(saved_range);
                    self.compile_store(&generator.target)?;
                }

                real_loop_depth += 1;
                let backedge_range = if i + 1 == generators.len() {
                    element_range
                } else {
                    outer_backedge_range
                };
                loop_labels.push(ComprehensionLoopControl::Iteration {
                    loop_block,
                    if_cleanup_block,
                    after_block,
                    backedge_range,
                    is_async: generator.is_async,
                    end_async_for_target,
                });

                // CPython always lowers comprehension guards through codegen_jump_if
                // and leaves constant-folding to later CFG optimization passes.
                for if_condition in &generator.ifs {
                    self.compile_jump_if(if_condition, false, if_cleanup_block)?;
                }
            }

            // Step 6: Compile the element expression and append to collection
            compile_element(self, real_loop_depth + 1)?;

            // Step 7: Close all loops
            for loop_control in loop_labels.iter().rev().copied() {
                match loop_control {
                    ComprehensionLoopControl::Iteration {
                        loop_block,
                        if_cleanup_block,
                        after_block,
                        backedge_range,
                        is_async,
                        end_async_for_target,
                    } => {
                        self.use_cpython_label_block(if_cleanup_block);
                        self.set_source_range(backedge_range);
                        emit!(self, PseudoInstruction::Jump { delta: loop_block });

                        if is_async {
                            let loop_label = self.instr_sequence_label_for_block(loop_block);
                            self.pop_fblock_label(
                                FBlockType::AsyncComprehensionGenerator,
                                loop_label,
                            );
                        }

                        self.use_cpython_label_block(after_block);
                        if is_async {
                            self.set_source_range(comprehension_range);
                            self.emit_end_async_for(end_async_for_target);
                        } else {
                            self.emit_sync_comprehension_end_for();
                        }
                    }
                    ComprehensionLoopControl::IfCleanupOnly { if_cleanup_block } => {
                        self.use_cpython_label_block(if_cleanup_block);
                    }
                }
            }

            // Step 8: Clean up - restore saved locals (and cell values)
            self.set_source_range(comprehension_range);
            if let Some(cleanup_block) = cleanup_block {
                emit!(self, PseudoInstruction::PopBlock);
                self.set_no_location();

                // Match CPython codegen_pop_inlined_comprehension_locals():
                // the synthetic jump that skips the exception cleanup uses
                // JUMP_NO_INTERRUPT, which becomes JUMP_BACKWARD_NO_INTERRUPT
                // when the cleanup tail sits above the final restore block.
                let end_block = self.new_block();
                emit!(
                    self,
                    PseudoInstruction::JumpNoInterrupt { delta: end_block }
                );
                self.set_no_location();

                // Exception cleanup path
                self.use_cpython_label_block(cleanup_block);
                // Stack: [saved_values..., collection, exception]
                emit!(self, Instruction::Swap { i: 2 });
                self.set_no_location();
                emit!(self, Instruction::PopTop); // Pop incomplete collection
                self.set_no_location();

                // Restore locals and cell values
                self.set_source_range(comprehension_range);
                emit!(
                    self,
                    Instruction::Swap {
                        i: u32::try_from(total_stack_items + 1).unwrap()
                    }
                );
                for name in pushed_locals.iter().rev() {
                    let var_num = self.varname(name).as_u32();
                    emit!(self, PseudoInstruction::StoreFastMaybeNull { var_num });
                }
                // Re-raise the exception
                emit!(self, Instruction::Reraise { depth: 0 });
                self.set_no_location();

                // Normal end path
                self.use_cpython_label_block(end_block);
                self.set_source_range(comprehension_range);
            }

            // SWAP result to TOS (above saved values)
            if total_stack_items > 0 {
                emit!(
                    self,
                    Instruction::Swap {
                        i: u32::try_from(total_stack_items + 1).unwrap()
                    }
                );
            }

            // Restore saved locals (StoreFast restores the saved cell object for merged cells)
            for name in pushed_locals.iter().rev() {
                let var_num = self.varname(name).as_u32();
                emit!(self, PseudoInstruction::StoreFastMaybeNull { var_num });
            }
            self.set_source_range(saved_source_range);

            Ok(())
        })();

        let current_table = self.symbol_table_stack.last_mut().expect("no symbol table");
        for (name, original_sym) in temp_symbols {
            current_table.symbols.insert(name, original_sym);
        }
        for name in changed_fast_hidden {
            self.current_code_info()
                .metadata
                .fast_hidden
                .insert(name, false);
        }
        self.current_code_info().in_inlined_comp = was_in_inlined_comp;

        result
    }

    fn compile_future_features(&mut self, features: &[ast::Alias]) -> Result<(), CodegenError> {
        if let DoneWithFuture::Yes = self.done_with_future_stmts {
            return Err(self.error(CodegenErrorType::InvalidFuturePlacement));
        }

        self.done_with_future_stmts = DoneWithFuture::DoneWithDoc;

        for feature in features {
            let future_feature = feature.name.as_str().try_into().map_err(|name| {
                self.error_ranged(CodegenErrorType::InvalidFutureFeature(name), feature.range)
            })?;

            match future_feature {
                FutureFeature::Braces => {
                    return Err(
                        self.error_ranged(CodegenErrorType::InvalidFutureBraces, feature.range)
                    );
                }
                FutureFeature::Annotations => {
                    self.future_annotations = true;
                    self.future_features
                        .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
                    self.current_code_info()
                        .flags
                        .insert(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
                }
                FutureFeature::BarryAsFLUFL => {
                    // We do not support Barry-as-BDFL parser mode yet. This is a nop for now.
                }
                FutureFeature::AbsoluteImport
                | FutureFeature::Division
                | FutureFeature::GeneratorStop
                | FutureFeature::Generators
                | FutureFeature::NestedScopes
                | FutureFeature::PrintFunction
                | FutureFeature::UnicodeLiterals
                | FutureFeature::WithStatement => {
                    // Python 3 features. They are already implemented by default.
                }
            }
        }
        Ok(())
    }

    // Low level helper functions:
    /// CPython `_PyCfgBuilder_Addop()`: start a new basic block if the current
    /// one is terminated, then append the instruction to the current block.
    fn cpython_cfg_builder_addop(&mut self, info: ir::InstructionInfo) {
        self.maybe_start_cpython_cfg_addop_block();
        self.push_emitted_instruction(info);
    }

    fn push_emitted_instruction(&mut self, info: ir::InstructionInfo) {
        self.current_code_info()
            .addop_to_instr_sequence(info)
            .expect("malformed instruction sequence emission");
        self.current_code_info()
            .addop_to_current_block(info)
            .expect("malformed CFG emission");
    }

    fn push_emitted_instruction_with_target_label(
        &mut self,
        info: ir::InstructionInfo,
        target_label: ir::InstructionSequenceLabel,
    ) {
        self.current_code_info()
            .addop_to_instr_sequence_with_target_label(info, target_label)
            .expect("malformed instruction sequence emission");
        self.current_code_info()
            .addop_to_current_block(info)
            .expect("malformed CFG emission");
    }

    fn last_emitted_instruction_mut(&mut self) -> Option<&mut ir::InstructionInfo> {
        self.current_code_info().last_current_block_instr_mut()
    }

    fn set_last_emitted_lineno_override(&mut self, lineno_override: i32) {
        self.current_code_info()
            .set_last_instr_sequence_lineno_override(lineno_override);
        if let Some(last) = self.last_emitted_instruction_mut() {
            last.lineno_override = Some(lineno_override);
        }
    }

    fn _emit<I: Into<AnyInstruction>>(&mut self, instr: I, arg: OpArg, target: BlockIdx) {
        if self.do_not_emit_bytecode > 0 {
            return;
        }
        let instr = instr.into();
        let opcode = AnyOpcode::from(instr);
        debug_assert!(
            !instr.is_assembler(),
            "CPython codegen_addop_* must not emit assembler-only opcodes"
        );
        debug_assert!(
            opcode.has_arg() || instr.has_target() || u32::from(arg) == 0,
            "CPython _PyInstructionSequence_Addop requires either OPCODE_HAS_ARG, HAS_TARGET, or oparg == 0"
        );
        debug_assert!(
            target == BlockIdx::NULL || instr.has_target(),
            "CPython codegen_addop_j only accepts HAS_TARGET opcodes"
        );
        let range = self.current_source_range;
        let source = self.source_file.to_source_code();
        let location = source.source_location(range.start(), PositionEncoding::Utf8);
        let end_location = source.source_location(range.end(), PositionEncoding::Utf8);
        let except_handler = None;
        self.cpython_cfg_builder_addop(ir::InstructionInfo {
            instr,
            arg,
            target,
            location,
            end_location,
            except_handler,
            lineno_override: None,
        });
    }

    /// CPython `codegen_addop_j()`: emit a HAS_TARGET instruction with a
    /// jump_target_label oparg.
    fn emit_jump_label<I: Into<AnyInstruction>>(
        &mut self,
        instr: I,
        target_label: ir::InstructionSequenceLabel,
    ) {
        if self.do_not_emit_bytecode > 0 {
            return;
        }
        let instr = instr.into();
        debug_assert!(
            instr.has_target(),
            "CPython codegen_addop_j only accepts HAS_TARGET opcodes"
        );
        debug_assert!(
            !instr.is_assembler(),
            "CPython codegen_addop_j must not emit assembler-only opcodes"
        );
        let range = self.current_source_range;
        let source = self.source_file.to_source_code();
        let location = source.source_location(range.start(), PositionEncoding::Utf8);
        let end_location = source.source_location(range.end(), PositionEncoding::Utf8);
        let target = self
            .current_code_info()
            .block_for_instr_sequence_label(target_label);
        self.maybe_start_cpython_cfg_addop_block();
        self.push_emitted_instruction_with_target_label(
            ir::InstructionInfo {
                instr,
                arg: OpArg::NULL,
                target,
                location,
                end_location,
                except_handler: None,
                lineno_override: None,
            },
            target_label,
        );
    }

    /// Mark the last emitted instruction as having no source location.
    /// Prevents it from triggering LINE events in sys.monitoring.
    fn set_no_location(&mut self) {
        self.set_last_emitted_lineno_override(-1);
    }

    /// CPython `codegen_sync_comprehension_generator()` emits END_FOR/POP_ITER
    /// with NO_LOCATION and lets `flowgraph.c::propagate_line_numbers()` copy
    /// the FOR_ITER location onto the cleanup block.
    fn emit_sync_comprehension_end_for(&mut self) {
        emit!(self, Instruction::EndFor);
        self.set_no_location();
        emit!(self, Instruction::PopIter);
        self.set_no_location();
    }

    /// CPython `codegen_wrap_in_stopiteration_handler()` inserts
    /// `SETUP_CLEANUP` into the instruction sequence at index 0 with
    /// `_PyInstructionSequence_InsertInstruction()`. Generator and cell/free
    /// prefixes are inserted later by `flowgraph.c::insert_prefix_instructions()`.
    fn insert_cpython_stopiteration_setup_cleanup(&mut self, handler_block: BlockIdx) {
        let code = self.current_code_info();
        let entry = code
            .blocks
            .first_mut()
            .expect("code unit must have an entry block");
        debug_assert!(
            entry
                .used_instructions()
                .first()
                .is_some_and(|info| match info.instr.real() {
                    Some(Instruction::Resume { context }) => matches!(
                        context.get(info.arg).location(),
                        oparg::ResumeLocation::AtFuncStart
                    ),
                    _ => false,
                }),
            "scope entry must start with a function-start RESUME"
        );
        debug_assert!(
            !entry.used_instructions().iter().any(|info| matches!(
                info.instr.real(),
                Some(
                    Instruction::ReturnGenerator
                        | Instruction::MakeCell { .. }
                        | Instruction::CopyFreeVars { .. }
                )
            )),
            "CPython inserts StopIteration cleanup before CFG prefix instructions"
        );

        let result = code.insert_start_setup_cleanup(handler_block);
        unwrap_internal(self, result);
    }

    fn emit_no_arg<I: Into<AnyInstruction>>(&mut self, ins: I) {
        self._emit(ins, OpArg::NULL, BlockIdx::NULL)
    }

    fn emit_arg<A: OpArgType, T: EmitArg<A>, I: Into<AnyInstruction>>(
        &mut self,
        arg: T,
        f: impl FnOnce(OpArgMarker<A>) -> I,
    ) {
        let (op, arg, target) = arg.emit(f);
        self._emit(op, arg, target)
    }

    // fn block_done()

    /// Convert a string literal AST node to Wtf8Buf, handling surrogate literals correctly.
    fn compile_string_value(&self, string: &ast::ExprStringLiteral) -> Wtf8Buf {
        let value = string.value.to_str();
        if value.contains(char::REPLACEMENT_CHARACTER) {
            // Might have a surrogate literal; reparse from source to preserve them.
            string
                .value
                .iter()
                .map(|lit| {
                    let source = self.source_file.slice(lit.range);
                    crate::string_parser::parse_string_literal(source, lit.flags.into())
                })
                .collect()
        } else {
            value.into()
        }
    }

    fn compile_fstring_literal_value(
        &self,
        string: &ast::InterpolatedStringLiteralElement,
        flags: ast::FStringFlags,
    ) -> Wtf8Buf {
        if string.value.contains(char::REPLACEMENT_CHARACTER) {
            let source = self.source_file.slice(string.range);
            crate::string_parser::parse_fstring_literal_element(source.into(), flags.into()).into()
        } else {
            string.value.to_string().into()
        }
    }

    fn compile_tstring_literal_value(
        &self,
        string: &ast::InterpolatedStringLiteralElement,
        flags: ast::TStringFlags,
    ) -> Wtf8Buf {
        if string.value.contains(char::REPLACEMENT_CHARACTER) {
            let source = self.source_file.slice(string.range);
            crate::string_parser::parse_fstring_literal_element(source.into(), flags.into()).into()
        } else {
            string.value.to_string().into()
        }
    }

    fn compile_fstring_part_literal_value(&self, string: &ast::StringLiteral) -> Wtf8Buf {
        if string.value.contains(char::REPLACEMENT_CHARACTER) {
            let source = self.source_file.slice(string.range);
            crate::string_parser::parse_string_literal(source, string.flags.into()).into()
        } else {
            string.value.to_string().into()
        }
    }

    fn arg_constant(&mut self, constant: ConstantData) -> oparg::ConstIdx {
        let info = self.current_code_info();
        if let ConstantData::Code { code } = &constant
            && let Some(idx) = info.metadata.consts.iter().position(|existing| {
                matches!(
                    existing,
                    ConstantData::Code {
                        code: existing_code
                    } if Self::code_objects_equivalent(existing_code, code)
                )
            })
        {
            return u32::try_from(idx)
                .expect("constant table index overflow")
                .into();
        }
        info.metadata.consts.insert_full(constant).0.to_u32().into()
    }

    fn constants_equivalent(lhs: &ConstantData, rhs: &ConstantData) -> bool {
        match (lhs, rhs) {
            (ConstantData::Code { code: lhs }, ConstantData::Code { code: rhs }) => {
                Self::code_objects_equivalent(lhs, rhs)
            }
            (ConstantData::Tuple { elements: lhs }, ConstantData::Tuple { elements: rhs })
            | (
                ConstantData::Frozenset { elements: lhs },
                ConstantData::Frozenset { elements: rhs },
            ) => {
                lhs.len() == rhs.len()
                    && lhs
                        .iter()
                        .zip(rhs.iter())
                        .all(|(lhs, rhs)| Self::constants_equivalent(lhs, rhs))
            }
            (ConstantData::Slice { elements: lhs }, ConstantData::Slice { elements: rhs }) => lhs
                .iter()
                .zip(rhs.iter())
                .all(|(lhs, rhs)| Self::constants_equivalent(lhs, rhs)),
            _ => lhs == rhs,
        }
    }

    fn code_objects_equivalent(lhs: &bytecode::CodeObject, rhs: &bytecode::CodeObject) -> bool {
        lhs.instructions.len() == rhs.instructions.len()
            && lhs
                .instructions
                .iter()
                .zip(rhs.instructions.iter())
                .all(|(lhs, rhs)| u8::from(lhs.op) == u8::from(rhs.op) && lhs.arg == rhs.arg)
            && lhs.locations == rhs.locations
            && lhs.flags.bits() == rhs.flags.bits()
            && lhs.posonlyarg_count == rhs.posonlyarg_count
            && lhs.arg_count == rhs.arg_count
            && lhs.kwonlyarg_count == rhs.kwonlyarg_count
            && lhs.source_path == rhs.source_path
            && lhs.first_line_number == rhs.first_line_number
            && lhs.max_stackdepth == rhs.max_stackdepth
            && lhs.obj_name == rhs.obj_name
            && lhs.qualname == rhs.qualname
            && lhs.constants.len() == rhs.constants.len()
            && lhs
                .constants
                .iter()
                .zip(rhs.constants.iter())
                .all(|(lhs, rhs)| Self::constants_equivalent(lhs, rhs))
            && lhs.names == rhs.names
            && lhs.varnames == rhs.varnames
            && lhs.cellvars == rhs.cellvars
            && lhs.freevars == rhs.freevars
            && lhs.localspluskinds == rhs.localspluskinds
            && lhs.linetable == rhs.linetable
            && lhs.exceptiontable == rhs.exceptiontable
    }

    fn constant_as_fold_int(constant: &ConstantData) -> Option<(BigInt, bool)> {
        match constant {
            ConstantData::Boolean { value } => Some((BigInt::from(u8::from(*value)), true)),
            ConstantData::Integer { value } => Some((value.clone(), false)),
            _ => None,
        }
    }

    fn try_fold_constant_binop(
        op: ast::Operator,
        left: &ConstantData,
        right: &ConstantData,
    ) -> Option<ConstantData> {
        let (left_int, left_is_bool) = Self::constant_as_fold_int(left)?;
        let (right_int, right_is_bool) = Self::constant_as_fold_int(right)?;

        if !(left_is_bool && right_is_bool) {
            return None;
        }

        match op {
            ast::Operator::BitAnd => Some(ConstantData::Boolean {
                value: !left_int.is_zero() & !right_int.is_zero(),
            }),
            ast::Operator::BitOr => Some(ConstantData::Boolean {
                value: !left_int.is_zero() | !right_int.is_zero(),
            }),
            ast::Operator::BitXor => Some(ConstantData::Boolean {
                value: !left_int.is_zero() ^ !right_int.is_zero(),
            }),
            _ => None,
        }
    }

    fn try_fold_constant_expr(&mut self, expr: &ast::Expr) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Ok(Some(constant));
        }
        Ok(Some(match expr {
            ast::Expr::NumberLiteral(num) => match &num.value {
                ast::Number::Int(int) => ConstantData::Integer {
                    value: ruff_int_to_bigint(int).map_err(|e| self.error(e))?,
                },
                ast::Number::Float(f) => ConstantData::Float { value: *f },
                ast::Number::Complex { real, imag } => ConstantData::Complex {
                    value: Complex::new(*real, *imag),
                },
            },
            ast::Expr::StringLiteral(s) => ConstantData::Str {
                value: self.compile_string_value(s),
            },
            ast::Expr::BytesLiteral(b) => ConstantData::Bytes {
                value: b.value.bytes().collect(),
            },
            ast::Expr::BooleanLiteral(b) => ConstantData::Boolean { value: b.value },
            ast::Expr::NoneLiteral(_) => ConstantData::None,
            ast::Expr::EllipsisLiteral(_) => ConstantData::Ellipsis,
            ast::Expr::Name(ast::ExprName { id, ctx, .. })
                if matches!(ctx, ast::ExprContext::Load) && id.as_str() == "__debug__" =>
            {
                ConstantData::Boolean {
                    value: self.opts.optimize == 0,
                }
            }
            ast::Expr::Tuple(ast::ExprTuple { elts, .. }) => {
                let mut elements = Vec::with_capacity(elts.len());
                for elt in elts {
                    let Some(constant) = self.try_fold_constant_expr(elt)? else {
                        return Ok(None);
                    };
                    elements.push(constant);
                }
                ConstantData::Tuple { elements }
            }
            ast::Expr::Subscript(ast::ExprSubscript { value, slice, .. }) => {
                let Some(container) = self.try_fold_constant_expr(value)? else {
                    return Ok(None);
                };
                let Some(index) = self.try_fold_constant_expr(slice)? else {
                    return Ok(None);
                };
                let ConstantData::Integer { value: index } = index else {
                    return Ok(None);
                };
                let Some(index): Option<i64> = index.try_into().ok() else {
                    return Ok(None);
                };

                match container {
                    ConstantData::Str { value } => {
                        let string = value.to_string();
                        if string.contains(char::REPLACEMENT_CHARACTER) {
                            return Ok(None);
                        }
                        let chars: Vec<_> = string.chars().collect();
                        let Some(len) = i64::try_from(chars.len()).ok() else {
                            return Ok(None);
                        };
                        let idx: i64 = if index < 0 { len + index } else { index };
                        let Some(idx) = usize::try_from(idx).ok() else {
                            return Ok(None);
                        };
                        let Some(ch) = chars.get(idx) else {
                            return Ok(None);
                        };
                        ConstantData::Str {
                            value: ch.to_string().into(),
                        }
                    }
                    ConstantData::Bytes { value } => {
                        let Some(len) = i64::try_from(value.len()).ok() else {
                            return Ok(None);
                        };
                        let idx: i64 = if index < 0 { len + index } else { index };
                        let Some(idx) = usize::try_from(idx).ok() else {
                            return Ok(None);
                        };
                        let Some(byte) = value.get(idx) else {
                            return Ok(None);
                        };
                        ConstantData::Integer {
                            value: BigInt::from(*byte),
                        }
                    }
                    ConstantData::Tuple { elements } => {
                        let Some(len) = i64::try_from(elements.len()).ok() else {
                            return Ok(None);
                        };
                        let idx: i64 = if index < 0 { len + index } else { index };
                        let Some(idx) = usize::try_from(idx).ok() else {
                            return Ok(None);
                        };
                        let Some(element) = elements.get(idx) else {
                            return Ok(None);
                        };
                        element.clone()
                    }
                    _ => return Ok(None),
                }
            }
            ast::Expr::BinOp(ast::ExprBinOp {
                left, op, right, ..
            }) => {
                let Some(left) = self.try_fold_constant_expr(left)? else {
                    return Ok(None);
                };
                let Some(right) = self.try_fold_constant_expr(right)? else {
                    return Ok(None);
                };
                let Some(constant) = Self::try_fold_constant_binop(*op, &left, &right) else {
                    return Ok(None);
                };
                constant
            }
            ast::Expr::UnaryOp(ast::ExprUnaryOp { op, operand, .. }) => {
                let Some(constant) = self.try_fold_constant_expr(operand)? else {
                    return Ok(None);
                };
                match (op, constant) {
                    (ast::UnaryOp::UAdd, value) => value,
                    (ast::UnaryOp::USub, ConstantData::Integer { value }) => {
                        ConstantData::Integer { value: -value }
                    }
                    (ast::UnaryOp::USub, ConstantData::Float { value }) => {
                        ConstantData::Float { value: -value }
                    }
                    (ast::UnaryOp::USub, ConstantData::Complex { value }) => {
                        ConstantData::Complex { value: -value }
                    }
                    (ast::UnaryOp::Invert, ConstantData::Integer { value }) => {
                        ConstantData::Integer { value: !value }
                    }
                    (ast::UnaryOp::Not, ConstantData::Tuple { .. }) => return Ok(None),
                    (ast::UnaryOp::Not, value) => ConstantData::Boolean {
                        value: !Self::constant_truthiness(&value),
                    },
                    _ => return Ok(None),
                }
            }
            ast::Expr::BoolOp(ast::ExprBoolOp { op, values, .. }) => {
                let mut constants = Vec::with_capacity(values.len());
                for value in values {
                    let Some(constant) = self.try_fold_constant_expr(value)? else {
                        return Ok(None);
                    };
                    constants.push(constant);
                }
                let mut iter = constants.into_iter();
                let Some(first) = iter.next() else {
                    return Ok(None);
                };
                let mut selected = first;
                match op {
                    ast::BoolOp::Or => {
                        if !Self::constant_truthiness(&selected) {
                            for constant in iter {
                                let is_truthy = Self::constant_truthiness(&constant);
                                selected = constant;
                                if is_truthy {
                                    break;
                                }
                            }
                        }
                    }
                    ast::BoolOp::And => {
                        if Self::constant_truthiness(&selected) {
                            for constant in iter {
                                let is_truthy = Self::constant_truthiness(&constant);
                                selected = constant;
                                if !is_truthy {
                                    break;
                                }
                            }
                        }
                    }
                }
                selected
            }
            _ => return Ok(None),
        }))
    }

    fn try_compile_ast_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Ok(Some(constant));
        }
        Ok(Some(match expr {
            ast::Expr::NumberLiteral(num) => match &num.value {
                ast::Number::Int(int) => ConstantData::Integer {
                    value: ruff_int_to_bigint(int).map_err(|e| self.error(e))?,
                },
                ast::Number::Float(value) => ConstantData::Float { value: *value },
                ast::Number::Complex { real, imag } => ConstantData::Complex {
                    value: Complex::new(*real, *imag),
                },
            },
            ast::Expr::StringLiteral(s) => ConstantData::Str {
                value: self.compile_string_value(s),
            },
            ast::Expr::BytesLiteral(b) => ConstantData::Bytes {
                value: b.value.bytes().collect(),
            },
            ast::Expr::BooleanLiteral(b) => ConstantData::Boolean { value: b.value },
            ast::Expr::NoneLiteral(_) => ConstantData::None,
            ast::Expr::EllipsisLiteral(_) => ConstantData::Ellipsis,
            _ => return Ok(None),
        }))
    }

    fn try_compile_match_mapping_key_direct_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Ok(match constant {
                ConstantData::Integer { .. }
                | ConstantData::Float { .. }
                | ConstantData::Bytes { .. }
                | ConstantData::Complex { .. }
                | ConstantData::Str { .. }
                | ConstantData::Boolean { .. }
                | ConstantData::None => Some(constant),
                _ => None,
            });
        }
        if matches!(
            expr,
            ast::Expr::BooleanLiteral(_) | ast::Expr::NoneLiteral(_)
        ) {
            return self.try_compile_ast_constant(expr);
        }
        self.try_compile_match_pattern_direct_literal(expr)
    }

    fn is_unexpected_match_literal_constant(expr: &ast::Expr) -> bool {
        if let Some(constant) = expr
            .as_constant_expr()
            .map(|expr| ast_constant_value_to_constant_data(expr.value.clone()))
        {
            return matches!(
                constant,
                ConstantData::Boolean { .. } | ConstantData::None | ConstantData::Ellipsis
            );
        }
        matches!(
            expr,
            ast::Expr::BooleanLiteral(_)
                | ast::Expr::NoneLiteral(_)
                | ast::Expr::EllipsisLiteral(_)
        )
    }

    fn try_compile_match_pattern_direct_literal(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Ok(match constant {
                ConstantData::Integer { .. }
                | ConstantData::Float { .. }
                | ConstantData::Bytes { .. }
                | ConstantData::Complex { .. }
                | ConstantData::Str { .. } => Some(constant),
                _ => None,
            });
        }
        match expr {
            ast::Expr::NumberLiteral(_)
            | ast::Expr::StringLiteral(_)
            | ast::Expr::BytesLiteral(_) => self.try_compile_ast_constant(expr),
            _ => Ok(None),
        }
    }

    fn try_negate_match_pattern_constant(constant: ConstantData) -> Option<ConstantData> {
        match constant {
            ConstantData::Integer { value } => Some(ConstantData::Integer { value: -value }),
            ConstantData::Float { value } => Some(ConstantData::Float { value: -value }),
            ConstantData::Complex { value } => Some(ConstantData::Complex { value: -value }),
            _ => None,
        }
    }

    fn try_fold_match_pattern_binop(
        op: ast::Operator,
        left: &ConstantData,
        right: &ConstantData,
    ) -> Option<ConstantData> {
        let left = match left {
            ConstantData::Integer { value } => value.to_f64()?,
            ConstantData::Float { value } => *value,
            _ => return None,
        };
        let ConstantData::Complex { value: right } = right else {
            return None;
        };
        let value = match op {
            ast::Operator::Add => Complex::new(left + right.re, right.im),
            ast::Operator::Sub => Complex::new(left - right.re, -right.im),
            _ => return None,
        };
        Some(ConstantData::Complex { value })
    }

    fn try_fold_match_pattern_const_expr(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        // CPython 3.14 ast_preprocess.c::fold_const_match_patterns()
        // folds only the constant forms needed by match patterns before
        // codegen_pattern_value()/codegen_pattern_mapping_key() visit them.
        Ok(match expr {
            ast::Expr::UnaryOp(ast::ExprUnaryOp {
                op: ast::UnaryOp::USub,
                operand,
                ..
            }) => {
                let Some(constant) = self.try_compile_match_pattern_number_constant(operand)?
                else {
                    return Ok(None);
                };
                Self::try_negate_match_pattern_constant(constant)
            }
            ast::Expr::BinOp(ast::ExprBinOp {
                left, op, right, ..
            }) if matches!(op, ast::Operator::Add | ast::Operator::Sub) => {
                let Some(left) = self.try_compile_match_pattern_signed_real_constant(left)? else {
                    return Ok(None);
                };
                let Some(right) = self.try_compile_match_pattern_imaginary_constant(right)? else {
                    return Ok(None);
                };
                Self::try_fold_match_pattern_binop(*op, &left, &right)
            }
            _ => None,
        })
    }

    fn try_compile_match_pattern_signed_real_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.try_compile_match_pattern_real_constant(expr)? {
            return Ok(Some(constant));
        }
        let ast::Expr::UnaryOp(ast::ExprUnaryOp {
            op: ast::UnaryOp::USub,
            operand,
            ..
        }) = expr
        else {
            return Ok(None);
        };
        let Some(constant) = self.try_compile_match_pattern_real_constant(operand)? else {
            return Ok(None);
        };
        Ok(Self::try_negate_match_pattern_constant(constant))
    }

    fn try_compile_match_pattern_real_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        let Some(constant) = self.try_compile_match_pattern_number_constant(expr)? else {
            return Ok(None);
        };
        Ok(match constant {
            ConstantData::Integer { .. } | ConstantData::Float { .. } => Some(constant),
            _ => None,
        })
    }

    fn try_compile_match_pattern_imaginary_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        let Some(constant) = self.try_compile_match_pattern_number_constant(expr)? else {
            return Ok(None);
        };
        Ok(match constant {
            ConstantData::Complex { .. } => Some(constant),
            _ => None,
        })
    }

    fn try_compile_match_pattern_number_constant(
        &mut self,
        expr: &ast::Expr,
    ) -> CompileResult<Option<ConstantData>> {
        if let Some(constant) = self.ast_constant_value(expr) {
            return Ok(match constant {
                ConstantData::Integer { .. }
                | ConstantData::Float { .. }
                | ConstantData::Complex { .. } => Some(constant),
                _ => None,
            });
        }
        match expr {
            ast::Expr::NumberLiteral(_) => self.try_compile_ast_constant(expr),
            _ => Ok(None),
        }
    }

    fn compile_match_pattern_expr(&mut self, expr: &ast::Expr) -> CompileResult<()> {
        if let Some(constant) = self.try_fold_match_pattern_const_expr(expr)? {
            self.set_source_range(expr.range());
            self.emit_load_const(constant);
        } else {
            self.compile_expression(expr)?;
        }
        Ok(())
    }

    fn emit_load_const(&mut self, constant: ConstantData) {
        let idx = self.arg_constant(constant);
        self.emit_arg(idx, |consti| Instruction::LoadConst { consti })
    }

    fn try_fold_constant_slice(
        &mut self,
        lower: Option<&ast::Expr>,
        upper: Option<&ast::Expr>,
        step: Option<&ast::Expr>,
    ) -> CompileResult<Option<ConstantData>> {
        if [lower, upper, step]
            .into_iter()
            .flatten()
            .any(|expr| !self.is_constant_expr(expr))
        {
            return Ok(None);
        }

        let start = match lower {
            Some(expr) => {
                let Some(constant) = self.try_fold_constant_expr(expr)? else {
                    return Ok(None);
                };
                constant
            }
            None => ConstantData::None,
        };
        let stop = match upper {
            Some(expr) => {
                let Some(constant) = self.try_fold_constant_expr(expr)? else {
                    return Ok(None);
                };
                constant
            }
            None => ConstantData::None,
        };
        let step = match step {
            Some(expr) => {
                let Some(constant) = self.try_fold_constant_expr(expr)? else {
                    return Ok(None);
                };
                constant
            }
            None => ConstantData::None,
        };

        Ok(Some(ConstantData::Slice {
            elements: Box::new([start, stop, step]),
        }))
    }

    fn emit_return_const(&mut self, constant: ConstantData) {
        self.emit_load_const(constant);
        emit!(self, Instruction::ReturnValue)
    }

    fn emit_return_const_no_location(&mut self, constant: ConstantData) {
        self.emit_load_const(constant);
        self.set_no_location();
        emit!(self, Instruction::ReturnValue);
        self.set_no_location();
    }

    fn emit_end_async_for(&mut self, send_target: BlockIdx) {
        self._emit(Instruction::EndAsyncFor, OpArg::NULL, send_target);
    }

    /// Emit LOAD_ATTR for attribute access (method=false).
    /// Encodes: (name_idx << 1) | 0
    fn emit_load_attr(&mut self, name_idx: u32) {
        let encoded = LoadAttr::new(name_idx, false);
        self.emit_arg(encoded, |namei| Instruction::LoadAttr { namei })
    }

    /// Emit LOAD_ATTR with method flag set (for method calls).
    /// Encodes: (name_idx << 1) | 1
    fn emit_load_attr_method(&mut self, name_idx: u32) {
        let encoded = LoadAttr::new(name_idx, true);
        self.emit_arg(encoded, |namei| Instruction::LoadAttr { namei })
    }

    /// Emit LOAD_GLOBAL.
    /// Encodes: (name_idx << 1) | push_null_bit
    fn emit_load_global(&mut self, name_idx: u32, push_null: bool) {
        let encoded = (name_idx << 1) | u32::from(push_null);
        self.emit_arg(encoded, |namei| Instruction::LoadGlobal { namei });
    }

    /// Emit LOAD_SUPER_ATTR for 2-arg super().attr access.
    /// Encodes: (name_idx << 2) | 0b10 (method=0, class=1)
    fn emit_load_super_attr(&mut self, name_idx: u32) {
        let encoded = LoadSuperAttr::new(name_idx, false, true);
        self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
    }

    /// Emit LOAD_SUPER_ATTR for 2-arg super().method() call.
    /// Encodes: (name_idx << 2) | 0b11 (method=1, class=1)
    fn emit_load_super_method(&mut self, name_idx: u32) {
        let encoded = LoadSuperAttr::new(name_idx, true, true);
        self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
    }

    /// Emit LOAD_SUPER_ATTR for 0-arg super().attr access.
    /// Encodes: (name_idx << 2) | 0b00 (method=0, class=0)
    fn emit_load_zero_super_attr(&mut self, name_idx: u32) {
        let encoded = LoadSuperAttr::new(name_idx, false, false);
        self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
    }

    /// Emit LOAD_SUPER_ATTR for 0-arg super().method() call.
    /// Encodes: (name_idx << 2) | 0b01 (method=1, class=0)
    fn emit_load_zero_super_method(&mut self, name_idx: u32) {
        let encoded = LoadSuperAttr::new(name_idx, true, false);
        self.emit_arg(encoded, |namei| Instruction::LoadSuperAttr { namei })
    }

    fn emit_return_value(&mut self) {
        emit!(self, Instruction::ReturnValue)
    }

    fn allows_top_level_await_in_current_context(&self) -> bool {
        self.opts.allow_top_level_await
            && self.ctx.func == FunctionContext::NoFunction
            && !self.ctx.in_class
    }

    fn current_code_info(&mut self) -> &mut ir::CodeInfo {
        self.code_stack.last_mut().expect("no code on stack")
    }

    /// Enter a conditional block (if/for/while/match/try/with)
    /// PEP 649: Track conditional annotation context
    fn enter_conditional_block(&mut self) {
        self.current_code_info().in_conditional_block += 1;
    }

    /// Leave a conditional block
    fn leave_conditional_block(&mut self) {
        let code_info = self.current_code_info();
        debug_assert!(code_info.in_conditional_block > 0);
        code_info.in_conditional_block -= 1;
    }

    /// Compile break or continue statement with proper fblock cleanup.
    /// compiler_break, compiler_continue
    /// This handles unwinding through With blocks and exception handlers.
    fn compile_break_continue(
        &mut self,
        range: ruff_text_size::TextRange,
        is_break: bool,
    ) -> CompileResult<()> {
        if self.do_not_emit_bytecode > 0 {
            // Still validate that we're inside a loop even in dead code
            let code = self.current_code_info();
            let mut found_loop = false;
            for i in (0..code.fblock.len()).rev() {
                match code.fblock[i].fb_type {
                    FBlockType::WhileLoop | FBlockType::ForLoop => {
                        found_loop = true;
                        break;
                    }
                    FBlockType::ExceptionGroupHandler => {
                        return Err(self.error_ranged(
                            CodegenErrorType::BreakContinueReturnInExceptStar,
                            range,
                        ));
                    }
                    _ => {}
                }
            }
            if !found_loop {
                if is_break {
                    return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
                }
                return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
            }
            return Ok(());
        }

        let prev_source_range = self.current_source_range;
        self.set_source_range(range);
        emit!(self, Instruction::Nop);

        let (mut unwind_loc, loop_fblock) = self.unwind_fblock_stack_with_loop(false, true)?;
        let Some(loop_fblock) = loop_fblock else {
            self.set_source_range(prev_source_range);
            if is_break {
                return Err(self.error_ranged(CodegenErrorType::InvalidBreak, range));
            }
            return Err(self.error_ranged(CodegenErrorType::InvalidContinue, range));
        };

        // CPython `codegen_break()` unwinds the loop fblock itself after
        // `codegen_unwind_fblock_stack()` returns it. `codegen_continue()`
        // jumps directly to the loop body label.
        if is_break {
            self.unwind_fblock(&loop_fblock, false, &mut unwind_loc)?;
        }

        // Jump to target
        let target_label = if is_break {
            debug_assert!(loop_fblock.fb_exit.is_jump_target_label());
            loop_fblock.fb_exit
        } else {
            debug_assert!(loop_fblock.fb_block.is_jump_target_label());
            loop_fblock.fb_block
        };
        let jump_is_artificial = if let Some(loc) = unwind_loc {
            self.set_source_range(loc);
            false
        } else {
            true
        };
        self.emit_jump_label(
            PseudoInstruction::Jump {
                delta: OpArgMarker::marker(),
            },
            target_label,
        );
        if jump_is_artificial {
            self.set_no_location();
        }
        self.set_source_range(prev_source_range);

        Ok(())
    }

    /// CPython `_PyCfgBuilder_Addop()` calls
    /// `cfg_builder_maybe_start_new_block()` before appending each instruction.
    /// That keeps any `IS_TERMINATOR_OPCODE` as the final instruction in its
    /// basicblock before `flowgraph.c::check_cfg()`.
    fn maybe_start_cpython_cfg_addop_block(&mut self) {
        let code = self.current_code_info();
        let cur = code.current_block;
        if !code.blocks[cur.idx()]
            .used_instructions()
            .last()
            .is_some_and(|instr| instr.instr.is_terminator())
        {
            return;
        }

        debug_assert_eq!(code.blocks[cur.idx()].next, BlockIdx::NULL);
        let block = self.cpython_cfg_builder_new_block();
        self.cpython_cfg_builder_use_next_block(block);
    }

    /// CPython `codegen_funcbody()` emits `NEW_JUMP_TARGET_LABEL(start)` and
    /// `USE_LABEL(start)` after scope entry. That label is part of the
    /// instruction-sequence label map, but it does not become a CFG
    /// `basicblock.b_label` unless some emitted instruction targets it.
    fn use_cpython_function_start_label(&mut self) -> ir::InstructionSequenceLabel {
        let (label, result) = {
            let code = self.current_code_info();
            let label = code.new_instr_sequence_label();
            let result = code.use_raw_instr_sequence_label(label);
            (label, result)
        };
        unwrap_internal(self, result);
        label
    }

    fn instr_sequence_label_for_block(&mut self, block: BlockIdx) -> ir::InstructionSequenceLabel {
        let result = self
            .current_code_info()
            .instr_sequence_label_for_block(block);
        unwrap_internal(self, result)
    }

    /// Switch to a block as CPython instruction-sequence labels would resolve.
    ///
    /// Consecutive `USE_LABEL()` calls can map multiple labels to the same
    /// instruction offset before `_PyCfg_FromInstructionSequence()` builds a
    /// CFG. Reuse an empty current block even if it already carries a label so
    /// codegen CFG path preserves that aliasing.
    fn use_cpython_label_block(&mut self, block: BlockIdx) {
        let result = self.current_code_info().use_instr_sequence_label(block);
        unwrap_internal(self, result);
        let code = self.current_code_info();
        let block = code.resolve_instr_sequence_label(block);
        let cur = code.current_block;
        let can_reuse_current = cur != block
            && code.blocks[cur.idx()].is_empty()
            && code.blocks[cur.idx()].next == BlockIdx::NULL
            && code.blocks[block.idx()].is_empty()
            && code.blocks[block.idx()].next == BlockIdx::NULL;

        if !can_reuse_current {
            let result = code.mark_cpython_cfg_label(block);
            unwrap_internal(self, result);
            self.switch_to_block(block);
            return;
        }

        {
            let target = &code.blocks[block.idx()];
            debug_assert!(!target.except_handler);
            debug_assert!(!target.preserve_lasti);
            debug_assert_eq!(target.start_depth, ir::START_DEPTH_UNSET);
            debug_assert!(!target.cold);
        }
        let result = code.mark_cpython_cfg_label(cur);
        unwrap_internal(self, result);

        let result = self
            .current_code_info()
            .use_instr_sequence_label_at_block(block, cur);
        unwrap_internal(self, result);
    }

    fn new_block(&mut self) -> BlockIdx {
        let result = self
            .current_code_info()
            .blocks
            .try_reserve(1)
            .map_err(|_| InternalError::MalformedControlFlowGraph);
        unwrap_internal(self, result);
        let code = self.current_code_info();
        let idx = BlockIdx::new(code.blocks.len().to_u32());
        code.blocks.push(Block::default());
        let result = code.push_unmapped_instr_sequence_label();
        unwrap_internal(self, result);
        idx
    }

    fn new_unlabeled_block(&mut self) -> BlockIdx {
        let result = self
            .current_code_info()
            .blocks
            .try_reserve(1)
            .map_err(|_| InternalError::MalformedControlFlowGraph);
        unwrap_internal(self, result);
        let code = self.current_code_info();
        let idx = BlockIdx::new(code.blocks.len().to_u32());
        code.blocks.push(Block::default());
        let result = code.push_unlabeled_instr_sequence_block();
        unwrap_internal(self, result);
        idx
    }

    /// flowgraph.c cfg_builder_new_block
    fn cpython_cfg_builder_new_block(&mut self) -> BlockIdx {
        self.new_unlabeled_block()
    }

    /// flowgraph.c cfg_builder_use_next_block
    fn cpython_cfg_builder_use_next_block(&mut self, block: BlockIdx) {
        let code = self.current_code_info();
        let cur = code.current_block;
        code.blocks[cur.idx()].next = block;
        code.current_block = block;
    }

    fn switch_to_block(&mut self, block: BlockIdx) {
        let result = self.current_code_info().use_instr_sequence_label(block);
        unwrap_internal(self, result);
        let code = self.current_code_info();
        let block = code.resolve_instr_sequence_label(block);
        let prev = code.current_block;
        assert_ne!(prev, block, "recursive switching {prev:?} -> {block:?}");
        assert_eq!(
            code.blocks[block].next,
            BlockIdx::NULL,
            "switching {prev:?} -> {block:?} to completed block"
        );
        let prev_block = &mut code.blocks[prev.idx()];
        assert_eq!(
            u32::from(prev_block.next),
            u32::MAX,
            "switching {prev:?} -> {block:?} from block that's already got a next"
        );
        prev_block.next = block;
        code.current_block = block;
    }

    const fn set_source_range(&mut self, range: TextRange) {
        self.current_source_range = range;
    }

    fn decorated_definition_range(
        &self,
        statement_range: TextRange,
        decorator_list: &[ast::Decorator],
        keyword: &str,
    ) -> TextRange {
        let Some(last_decorator) = decorator_list.last() else {
            return statement_range;
        };
        let search_start = last_decorator.expression.range().end();
        if search_start >= statement_range.end() {
            return statement_range;
        }
        let search_range = TextRange::new(search_start, statement_range.end());
        let source = self.source_file.slice(search_range);
        let Some(keyword_offset) = source.find(keyword) else {
            return statement_range;
        };
        let Ok(keyword_offset) = u32::try_from(keyword_offset) else {
            return statement_range;
        };
        TextRange::new(
            search_start + TextSize::new(keyword_offset),
            statement_range.end(),
        )
    }

    fn update_start_location_to_match_attr(
        &self,
        loc_range: TextRange,
        attr_range: TextRange,
        attr: &str,
    ) -> TextRange {
        let source = self.source_file.to_source_code();
        if source.line_index(loc_range.start()) == source.line_index(attr_range.end()) {
            return loc_range;
        }
        let Ok(attr_len) = u32::try_from(attr.chars().count()) else {
            return TextRange::new(loc_range.start(), loc_range.end());
        };
        let attr_len = TextSize::new(attr_len);
        if attr_len > attr_range.len() {
            return TextRange::new(loc_range.start(), loc_range.end());
        }
        TextRange::new(attr_range.end() - attr_len, loc_range.end())
    }

    fn source_line_start_range(&self, lineno: u32) -> TextRange {
        let source = self.source_file.to_source_code();
        let line = OneIndexed::new(lineno as usize).unwrap_or(OneIndexed::MIN);
        let start = source.line_start(line);
        TextRange::new(start, start)
    }

    fn module_start_location(&self, body: &[ast::Stmt]) -> TextRange {
        body.first()
            .map_or_else(|| self.source_line_start_range(1), Ranged::range)
    }

    fn get_source_line_number(&mut self) -> OneIndexed {
        self.source_file
            .to_source_code()
            .line_index(self.current_source_range.start())
    }

    fn mark_generator(&mut self) {
        let is_async = self.ctx.func == FunctionContext::AsyncFunction;
        let flags = &mut self.current_code_info().flags;
        if is_async {
            flags.remove(bytecode::CodeFlags::COROUTINE);
            flags.insert(bytecode::CodeFlags::ASYNC_GENERATOR);
        } else {
            flags.insert(bytecode::CodeFlags::GENERATOR);
        }
    }

    /// Whether the expression contains an await expression and
    /// thus requires the function to be async.
    ///
    /// Both:
    /// ```py
    /// async with: ...
    /// async for: ...
    /// ```
    /// are statements, so we won't check for them here
    fn contains_await(expression: &ast::Expr) -> bool {
        use ast::visitor::Visitor;

        #[derive(Default)]
        struct AwaitVisitor {
            found: bool,
        }

        impl ast::visitor::Visitor<'_> for AwaitVisitor {
            fn visit_expr(&mut self, expr: &ast::Expr) {
                if self.found {
                    return;
                }

                match expr {
                    ast::Expr::Await(_) => self.found = true,
                    ast::Expr::ListComp(ast::ExprListComp { generators, .. })
                    | ast::Expr::SetComp(ast::ExprSetComp { generators, .. })
                    | ast::Expr::DictComp(ast::ExprDictComp { generators, .. })
                        if generators.iter().any(|generator| generator.is_async) =>
                    {
                        self.found = true
                    }
                    _ => ast::visitor::walk_expr(self, expr),
                }
            }
        }

        let mut visitor = AwaitVisitor::default();
        visitor.visit_expr(expression);
        visitor.found
    }

    /// Check if any of the generators (except the first one's iter) contains an await expression.
    /// The first generator's iter is evaluated outside the comprehension scope.
    fn generators_contain_await(generators: &[ast::Comprehension]) -> bool {
        for (i, generator) in generators.iter().enumerate() {
            // First generator's iter is evaluated outside the comprehension
            if i > 0 && Self::contains_await(&generator.iter) {
                return true;
            }
            // Check ifs in all generators
            for if_expr in &generator.ifs {
                if Self::contains_await(if_expr) {
                    return true;
                }
            }
        }
        false
    }

    fn compile_expr_fstring(&mut self, fstring: &ast::ExprFString) -> CompileResult<()> {
        let fstring_range = fstring.range;
        let fstring = fstring.value.as_slice();
        if self.count_fstring_parts(fstring) > STACK_USE_GUIDELINE {
            return self.compile_fstring_parts_joined(fstring, fstring_range);
        }

        let mut element_count = 0;
        let mut pending_literal = None;
        let mut pending_literal_range = None;
        let mut pending_literal_no_location = false;
        for part in fstring {
            self.compile_fstring_part_into(
                part,
                &mut pending_literal,
                &mut pending_literal_range,
                &mut pending_literal_no_location,
                &mut element_count,
                None,
            )?;
        }
        self.finish_fstring(
            pending_literal,
            pending_literal_range,
            pending_literal_no_location,
            element_count,
            Some(fstring_range),
        );
        Ok(())
    }

    fn compile_runtime_joined_str(
        &mut self,
        fstring: &ast::ExprFString,
        values: &[ast::Expr],
    ) -> CompileResult<()> {
        let range = fstring.range;
        let value_count: u32 = values
            .len()
            .try_into()
            .expect("JoinedStr value count overflowed");
        if value_count > STACK_USE_GUIDELINE {
            self.set_source_range(range);
            self.emit_load_const(ConstantData::Str {
                value: Wtf8Buf::new(),
            });
            let join_idx = self.get_global_name_index("join");
            self.emit_load_attr_method(join_idx);
            emit!(self, Instruction::BuildList { count: 0 });
            for value in values {
                self.compile_expression(value)?;
                self.set_source_range(range);
                emit!(self, Instruction::ListAppend { i: 1 });
            }
            self.set_source_range(range);
            emit!(self, Instruction::Call { argc: 1 });
        } else {
            for value in values {
                self.compile_expression(value)?;
            }
            if value_count > 1 {
                self.set_source_range(range);
                emit!(self, Instruction::BuildString { count: value_count });
            } else if value_count == 0 {
                self.set_source_range(range);
                self.emit_load_const(ConstantData::Str {
                    value: Wtf8Buf::new(),
                });
            }
        }
        Ok(())
    }

    fn compile_fstring_parts_joined(
        &mut self,
        fstring: &[ast::FStringPart],
        fstring_range: TextRange,
    ) -> CompileResult<()> {
        self.set_source_range(fstring_range);
        self.emit_load_const(ConstantData::Str {
            value: Wtf8Buf::new(),
        });
        let join_idx = self.get_global_name_index("join");
        self.emit_load_attr_method(join_idx);
        emit!(self, Instruction::BuildList { count: 0 });

        let mut element_count = 0;
        let mut pending_literal = None;
        let mut pending_literal_range = None;
        let mut pending_literal_no_location = false;
        for part in fstring {
            self.compile_fstring_part_into(
                part,
                &mut pending_literal,
                &mut pending_literal_range,
                &mut pending_literal_no_location,
                &mut element_count,
                Some(fstring_range),
            )?;
        }
        self.finish_fstring_join(
            pending_literal,
            pending_literal_range,
            pending_literal_no_location,
            element_count,
            fstring_range,
        );
        Ok(())
    }

    fn compile_fstring_part_into(
        &mut self,
        part: &ast::FStringPart,
        pending_literal: &mut Option<Wtf8Buf>,
        pending_literal_range: &mut Option<TextRange>,
        pending_literal_no_location: &mut bool,
        element_count: &mut u32,
        join_append_range: Option<TextRange>,
    ) -> CompileResult<()> {
        match part {
            ast::FStringPart::Literal(string) => {
                let value = self.compile_fstring_part_literal_value(string);
                if pending_literal.is_none() {
                    *pending_literal_range = Some(string.range);
                    *pending_literal_no_location = string.range == TextRange::default();
                    *pending_literal = Some(value);
                } else if let Some(pending) = pending_literal.as_mut() {
                    Self::extend_pending_literal_range(pending_literal_range, string.range);
                    *pending_literal_no_location &= string.range == TextRange::default();
                    pending.push_wtf8(value.as_ref());
                }
                Ok(())
            }
            ast::FStringPart::FString(fstring) => self.compile_fstring_elements_into(
                fstring.flags,
                &fstring.elements,
                pending_literal,
                (pending_literal_range, pending_literal_no_location),
                element_count,
                join_append_range,
            ),
        }
    }

    fn finish_fstring(
        &mut self,
        mut pending_literal: Option<Wtf8Buf>,
        mut pending_literal_range: Option<TextRange>,
        mut pending_literal_no_location: bool,
        mut element_count: u32,
        fstring_range: Option<TextRange>,
    ) {
        let keep_empty = element_count == 0;
        self.emit_pending_fstring_literal(
            &mut pending_literal,
            &mut pending_literal_range,
            &mut pending_literal_no_location,
            &mut element_count,
            keep_empty,
            None,
        );

        if element_count == 0 {
            if let Some(fstring_range) = fstring_range {
                self.set_source_range(fstring_range);
            }
            self.emit_load_const(ConstantData::Str {
                value: Wtf8Buf::new(),
            });
        } else if element_count > 1 {
            if let Some(fstring_range) = fstring_range {
                self.set_source_range(fstring_range);
            }
            emit!(
                self,
                Instruction::BuildString {
                    count: element_count
                }
            );
        }
    }

    fn finish_fstring_join(
        &mut self,
        mut pending_literal: Option<Wtf8Buf>,
        mut pending_literal_range: Option<TextRange>,
        mut pending_literal_no_location: bool,
        mut element_count: u32,
        fstring_range: TextRange,
    ) {
        let keep_empty = element_count == 0;
        self.emit_pending_fstring_literal(
            &mut pending_literal,
            &mut pending_literal_range,
            &mut pending_literal_no_location,
            &mut element_count,
            keep_empty,
            Some(fstring_range),
        );
        self.set_source_range(fstring_range);
        emit!(self, Instruction::Call { argc: 1 });
    }

    fn emit_pending_fstring_literal(
        &mut self,
        pending_literal: &mut Option<Wtf8Buf>,
        pending_literal_range: &mut Option<TextRange>,
        pending_literal_no_location: &mut bool,
        element_count: &mut u32,
        keep_empty: bool,
        join_append_range: Option<TextRange>,
    ) {
        let Some(value) = pending_literal.take() else {
            return;
        };
        let range = pending_literal_range.take();
        let no_location = *pending_literal_no_location;
        *pending_literal_no_location = false;

        // CPython drops empty literal fragments when they are adjacent to
        // formatted values, but still emits an empty string for a fully-empty
        // f-string.
        if value.is_empty() && (!keep_empty || *element_count > 0) {
            return;
        }

        if let Some(range) = range {
            self.set_source_range(range);
        }
        self.emit_load_const(ConstantData::Str { value });
        if no_location {
            self.set_no_location();
        }
        *element_count += 1;
        if let Some(join_append_range) = join_append_range {
            self.set_source_range(join_append_range);
            emit!(self, Instruction::ListAppend { i: 1 });
        }
    }

    fn extend_pending_literal_range(pending: &mut Option<TextRange>, range: TextRange) {
        let Some(existing) = pending else {
            *pending = Some(range);
            return;
        };
        if *existing == TextRange::default() {
            *existing = range;
        } else if range != TextRange::default() {
            *existing = TextRange::new(existing.start(), range.end());
        }
    }

    fn count_fstring_parts(&self, fstring: &[ast::FStringPart]) -> u32 {
        let mut element_count = 0;
        let mut pending_literal = None;
        for part in fstring {
            self.count_fstring_part_into(part, &mut pending_literal, &mut element_count);
        }
        let keep_empty = element_count == 0;
        Self::count_pending_fstring_literal(&mut pending_literal, &mut element_count, keep_empty);
        element_count
    }

    fn count_fstring_part_into(
        &self,
        part: &ast::FStringPart,
        pending_literal: &mut Option<Wtf8Buf>,
        element_count: &mut u32,
    ) {
        match part {
            ast::FStringPart::Literal(string) => {
                let value = self.compile_fstring_part_literal_value(string);
                if let Some(pending) = pending_literal.as_mut() {
                    pending.push_wtf8(value.as_ref());
                } else {
                    *pending_literal = Some(value);
                }
            }
            ast::FStringPart::FString(fstring) => self.count_fstring_elements_into(
                fstring.flags,
                &fstring.elements,
                pending_literal,
                element_count,
            ),
        }
    }

    fn count_pending_fstring_literal(
        pending_literal: &mut Option<Wtf8Buf>,
        element_count: &mut u32,
        keep_empty: bool,
    ) {
        let Some(value) = pending_literal.take() else {
            return;
        };

        if value.is_empty() && (!keep_empty || *element_count > 0) {
            return;
        }

        *element_count += 1;
    }

    fn compile_fstring_elements(
        &mut self,
        flags: ast::FStringFlags,
        fstring_elements: &ast::InterpolatedStringElements,
        fstring_range: Option<TextRange>,
    ) -> CompileResult<()> {
        if self.count_fstring_elements(flags, fstring_elements) > STACK_USE_GUIDELINE {
            let fstring_range = fstring_range.unwrap_or(self.current_source_range);
            return self.compile_fstring_elements_joined(flags, fstring_elements, fstring_range);
        }

        let mut element_count = 0;
        let mut pending_literal: Option<Wtf8Buf> = None;
        let mut pending_literal_range: Option<TextRange> = None;
        let mut pending_literal_no_location = false;
        self.compile_fstring_elements_into(
            flags,
            fstring_elements,
            &mut pending_literal,
            (&mut pending_literal_range, &mut pending_literal_no_location),
            &mut element_count,
            None,
        )?;
        self.finish_fstring(
            pending_literal,
            pending_literal_range,
            pending_literal_no_location,
            element_count,
            fstring_range,
        );
        Ok(())
    }

    fn compile_fstring_elements_joined(
        &mut self,
        flags: ast::FStringFlags,
        fstring_elements: &ast::InterpolatedStringElements,
        fstring_range: TextRange,
    ) -> CompileResult<()> {
        self.set_source_range(fstring_range);
        self.emit_load_const(ConstantData::Str {
            value: Wtf8Buf::new(),
        });
        let join_idx = self.get_global_name_index("join");
        self.emit_load_attr_method(join_idx);
        emit!(self, Instruction::BuildList { count: 0 });

        let mut element_count = 0;
        let mut pending_literal: Option<Wtf8Buf> = None;
        let mut pending_literal_range: Option<TextRange> = None;
        let mut pending_literal_no_location = false;
        self.compile_fstring_elements_into(
            flags,
            fstring_elements,
            &mut pending_literal,
            (&mut pending_literal_range, &mut pending_literal_no_location),
            &mut element_count,
            Some(fstring_range),
        )?;
        self.finish_fstring_join(
            pending_literal,
            pending_literal_range,
            pending_literal_no_location,
            element_count,
            fstring_range,
        );
        Ok(())
    }

    fn cpython_format_spec_range(&self, range: TextRange) -> TextRange {
        let start = range.start().to_usize();
        if start == 0 {
            return range;
        }
        let source = self.source_file.source_text().as_bytes();
        if source.get(start - 1) == Some(&b':') {
            TextRange::new(range.start() - TextSize::new(1), range.end())
        } else {
            range
        }
    }

    fn compile_fstring_elements_into(
        &mut self,
        flags: ast::FStringFlags,
        fstring_elements: &ast::InterpolatedStringElements,
        pending_literal: &mut Option<Wtf8Buf>,
        pending_literal_meta: (&mut Option<TextRange>, &mut bool),
        element_count: &mut u32,
        join_append_range: Option<TextRange>,
    ) -> CompileResult<()> {
        let (pending_literal_range, pending_literal_no_location) = pending_literal_meta;
        for element in fstring_elements {
            match element {
                ast::InterpolatedStringElement::Literal(string) => {
                    let value = self.compile_fstring_literal_value(string, flags);
                    if pending_literal.is_none() {
                        *pending_literal_range = Some(string.range);
                        *pending_literal_no_location = string.range == TextRange::default();
                        *pending_literal = Some(value);
                    } else if let Some(pending) = pending_literal.as_mut() {
                        Self::extend_pending_literal_range(pending_literal_range, string.range);
                        *pending_literal_no_location &= string.range == TextRange::default();
                        pending.push_wtf8(value.as_ref());
                    }
                }
                ast::InterpolatedStringElement::Interpolation(fstring_expr) => {
                    let mut conversion = match fstring_expr.conversion {
                        ast::ConversionFlag::None => ConvertValueOparg::None,
                        ast::ConversionFlag::Str => ConvertValueOparg::Str,
                        ast::ConversionFlag::Repr => ConvertValueOparg::Repr,
                        ast::ConversionFlag::Ascii => ConvertValueOparg::Ascii,
                    };

                    if let Some(debug_text) = &fstring_expr.debug_text {
                        let leading = debug_text.leading.as_str();
                        let trailing = debug_text.trailing.as_str();
                        self.emit_pending_fstring_literal(
                            pending_literal,
                            pending_literal_range,
                            pending_literal_no_location,
                            element_count,
                            false,
                            join_append_range,
                        );

                        let range = fstring_expr.expression.range();
                        let leading = strip_fstring_debug_comments(leading);
                        let trailing = strip_fstring_debug_comments(trailing);
                        let source = self.source_file.slice(range);
                        let text = [leading.as_str(), source, trailing.as_str()].concat();
                        let debug_text_range = TextRange::new(
                            range.start()
                                - TextSize::new(
                                    u32::try_from(leading.len())
                                        .expect("debug f-string leading text too long"),
                                ),
                            range.end()
                                + TextSize::new(
                                    u32::try_from(trailing.len())
                                        .expect("debug f-string trailing text too long"),
                                ),
                        );

                        let text: Wtf8Buf = text.into();
                        *pending_literal_range = Some(debug_text_range);
                        *pending_literal_no_location = false;
                        *pending_literal = Some(Wtf8Buf::new());
                        pending_literal.as_mut().unwrap().push_wtf8(text.as_ref());

                        // If debug text is present, apply repr conversion when no `format_spec` specified.
                        // See action_helpers.c: fstring_find_expr_replacement
                        if matches!(
                            (conversion, &fstring_expr.format_spec),
                            (ConvertValueOparg::None, None)
                        ) {
                            conversion = ConvertValueOparg::Repr;
                        }
                    }

                    self.emit_pending_fstring_literal(
                        pending_literal,
                        pending_literal_range,
                        pending_literal_no_location,
                        element_count,
                        false,
                        join_append_range,
                    );

                    self.compile_expression(&fstring_expr.expression)?;

                    let formatted_value_range = fstring_expr.range;
                    match conversion {
                        ConvertValueOparg::None => {}
                        ConvertValueOparg::Str
                        | ConvertValueOparg::Repr
                        | ConvertValueOparg::Ascii => {
                            self.set_source_range(formatted_value_range);
                            emit!(self, Instruction::ConvertValue { oparg: conversion })
                        }
                    }

                    if let Some(format_spec) =
                        fstring_expr.runtime_formatted_value_format_spec.as_deref()
                    {
                        self.compile_expression(format_spec)?;

                        self.set_source_range(formatted_value_range);
                        emit!(self, Instruction::FormatWithSpec);
                    } else {
                        match &fstring_expr.format_spec {
                            Some(format_spec) => {
                                let format_spec_range =
                                    self.cpython_format_spec_range(format_spec.range);
                                self.compile_fstring_elements(
                                    flags,
                                    &format_spec.elements,
                                    Some(format_spec_range),
                                )?;

                                self.set_source_range(formatted_value_range);
                                emit!(self, Instruction::FormatWithSpec);
                            }
                            None => {
                                self.set_source_range(formatted_value_range);
                                emit!(self, Instruction::FormatSimple);
                            }
                        }
                    }

                    *element_count += 1;
                    if let Some(join_append_range) = join_append_range {
                        self.set_source_range(join_append_range);
                        emit!(self, Instruction::ListAppend { i: 1 });
                    }
                }
            }
        }

        Ok(())
    }

    fn count_fstring_elements(
        &self,
        flags: ast::FStringFlags,
        fstring_elements: &ast::InterpolatedStringElements,
    ) -> u32 {
        let mut element_count = 0;
        let mut pending_literal = None;
        self.count_fstring_elements_into(
            flags,
            fstring_elements,
            &mut pending_literal,
            &mut element_count,
        );
        let keep_empty = element_count == 0;
        Self::count_pending_fstring_literal(&mut pending_literal, &mut element_count, keep_empty);
        element_count
    }

    fn count_fstring_elements_into(
        &self,
        flags: ast::FStringFlags,
        fstring_elements: &ast::InterpolatedStringElements,
        pending_literal: &mut Option<Wtf8Buf>,
        element_count: &mut u32,
    ) {
        for element in fstring_elements {
            match element {
                ast::InterpolatedStringElement::Literal(string) => {
                    let value = self.compile_fstring_literal_value(string, flags);
                    if let Some(pending) = pending_literal.as_mut() {
                        pending.push_wtf8(value.as_ref());
                    } else {
                        *pending_literal = Some(value);
                    }
                }
                ast::InterpolatedStringElement::Interpolation(fstring_expr) => {
                    if let Some(debug_text) = &fstring_expr.debug_text {
                        let leading = debug_text.leading.as_str();
                        let trailing = debug_text.trailing.as_str();
                        Self::count_pending_fstring_literal(pending_literal, element_count, false);
                        let range = fstring_expr.expression.range();
                        let source = self.source_file.slice(range);
                        let text = [
                            strip_fstring_debug_comments(leading).as_str(),
                            source,
                            strip_fstring_debug_comments(trailing).as_str(),
                        ]
                        .concat();

                        let text: Wtf8Buf = text.into();
                        let mut debug_text = Wtf8Buf::new();
                        debug_text.push_wtf8(text.as_ref());
                        *pending_literal = Some(debug_text);
                    }

                    Self::count_pending_fstring_literal(pending_literal, element_count, false);
                    *element_count += 1;
                }
            }
        }
    }

    fn compile_expr_tstring(&mut self, expr_tstring: &ast::ExprTString) -> CompileResult<()> {
        // ast::TStringValue can contain multiple ast::TString parts (implicit
        // concatenation). Match CPython's stack order by materializing the
        // strings tuple first, then evaluating interpolations left-to-right.
        let tstring_value = &expr_tstring.value;

        let mut all_strings: Vec<(Wtf8Buf, TextRange)> = Vec::new();
        let mut current_string = Wtf8Buf::new();
        let mut current_string_range = None;
        let mut interp_count: u32 = 0;

        for tstring in tstring_value {
            self.collect_tstring_strings(
                tstring,
                &mut all_strings,
                &mut current_string,
                &mut current_string_range,
                &mut interp_count,
                expr_tstring.range,
            );
        }

        all_strings.push((
            core::mem::take(&mut current_string),
            current_string_range.unwrap_or(expr_tstring.range),
        ));

        let string_count: u32 = all_strings
            .len()
            .try_into()
            .expect("t-string string count overflowed");
        for (s, range) in &all_strings {
            self.set_source_range(*range);
            self.emit_load_const(ConstantData::Str { value: s.clone() });
        }
        self.set_source_range(expr_tstring.range);
        emit!(
            self,
            Instruction::BuildTuple {
                count: string_count
            }
        );

        for tstring in tstring_value {
            self.compile_tstring_interpolations(tstring)?;
        }

        self.set_source_range(expr_tstring.range);
        emit!(
            self,
            Instruction::BuildTuple {
                count: interp_count
            }
        );
        self.set_source_range(expr_tstring.range);
        emit!(self, Instruction::BuildTemplate);

        Ok(())
    }

    fn compile_runtime_template_str(
        &mut self,
        expr_tstring: &ast::ExprTString,
        values: &[ast::Expr],
    ) -> CompileResult<()> {
        let mut last_was_interpolation = true;
        let mut strings_len = 0;
        for value in values {
            if self.runtime_template_value_interpolation(value).is_some() {
                if last_was_interpolation {
                    self.set_source_range(expr_tstring.range);
                    self.emit_load_const(ConstantData::Str {
                        value: Wtf8Buf::new(),
                    });
                    strings_len += 1;
                }
                last_was_interpolation = true;
            } else {
                self.compile_expression(value)?;
                strings_len += 1;
                last_was_interpolation = false;
            }
        }
        if last_was_interpolation {
            self.set_source_range(expr_tstring.range);
            self.emit_load_const(ConstantData::Str {
                value: Wtf8Buf::new(),
            });
            strings_len += 1;
        }
        self.set_source_range(expr_tstring.range);
        emit!(self, Instruction::BuildTuple { count: strings_len });

        let mut interpolations_len = 0;
        for value in values {
            if let Some((tstring, interpolation)) = self.runtime_template_value_interpolation(value)
            {
                self.compile_runtime_interpolation(tstring, interpolation)?;
                interpolations_len += 1;
            }
        }
        self.set_source_range(expr_tstring.range);
        emit!(
            self,
            Instruction::BuildTuple {
                count: interpolations_len
            }
        );
        self.set_source_range(expr_tstring.range);
        emit!(self, Instruction::BuildTemplate);
        Ok(())
    }

    fn runtime_template_value_interpolation<'a>(
        &self,
        value: &'a ast::Expr,
    ) -> Option<(
        &'a ast::ExprTString,
        (&'a ast::ConstantValue, Option<&'a ast::Expr>),
    )> {
        let ast::Expr::TString(tstring) = value else {
            return None;
        };
        let interpolation = Self::single_runtime_interpolation(tstring)?;
        Self::single_tstring_interpolation(tstring)?;
        Some((tstring, interpolation))
    }

    fn compile_runtime_interpolation(
        &mut self,
        expr_tstring: &ast::ExprTString,
        interpolation: (&ast::ConstantValue, Option<&ast::Expr>),
    ) -> CompileResult<bool> {
        let Some(interp) = Self::single_tstring_interpolation(expr_tstring) else {
            return Ok(false);
        };

        self.compile_interpolation(interp, interpolation)?;
        Ok(true)
    }

    fn compile_interpolation(
        &mut self,
        interp: &ast::InterpolatedElement,
        interpolation: (&ast::ConstantValue, Option<&ast::Expr>),
    ) -> CompileResult<()> {
        let (str, format_spec) = interpolation;
        self.compile_expression(&interp.expression)?;
        self.set_source_range(interp.range);
        self.emit_load_const(ast_constant_value_to_constant_data(str.clone()));

        let conversion = match interp.conversion {
            ast::ConversionFlag::None => 0,
            ast::ConversionFlag::Str => 1,
            ast::ConversionFlag::Repr => 2,
            ast::ConversionFlag::Ascii => 3,
        };

        let has_format_spec = format_spec.is_some();
        if let Some(format_spec) = format_spec {
            self.compile_expression(format_spec)?;
        }

        let format = 2 | (conversion << 2) | u32::from(has_format_spec);
        self.set_source_range(interp.range);
        emit!(self, Instruction::BuildInterpolation { format });
        Ok(())
    }

    fn single_tstring_interpolation(
        expr_tstring: &ast::ExprTString,
    ) -> Option<&ast::InterpolatedElement> {
        let [tstring] = expr_tstring.value.as_slice() else {
            return None;
        };
        let mut elements = tstring.elements.iter();
        let ast::InterpolatedStringElement::Interpolation(interp) = elements.next()? else {
            return None;
        };
        if elements.next().is_some() {
            return None;
        }
        Some(interp)
    }

    fn collect_tstring_strings(
        &self,
        tstring: &ast::TString,
        strings: &mut Vec<(Wtf8Buf, TextRange)>,
        current_string: &mut Wtf8Buf,
        current_string_range: &mut Option<TextRange>,
        interp_count: &mut u32,
        template_range: TextRange,
    ) {
        for element in &tstring.elements {
            match element {
                ast::InterpolatedStringElement::Literal(lit) => {
                    if current_string_range.is_none() {
                        *current_string_range = Some(lit.range);
                    } else {
                        Self::extend_pending_literal_range(current_string_range, lit.range);
                    }
                    current_string
                        .push_wtf8(&self.compile_tstring_literal_value(lit, tstring.flags));
                }
                ast::InterpolatedStringElement::Interpolation(interp) => {
                    if let Some(debug_text) = &interp.debug_text {
                        let leading = debug_text.leading.as_str();
                        let trailing = debug_text.trailing.as_str();
                        let range = interp.expression.range();
                        let source = self.source_file.slice(range);
                        let text = [
                            strip_fstring_debug_comments(leading).as_str(),
                            source,
                            strip_fstring_debug_comments(trailing).as_str(),
                        ]
                        .concat();
                        let debug_text_range = TextRange::new(
                            range.start()
                                - TextSize::new(
                                    u32::try_from(leading.len())
                                        .expect("debug t-string leading text too long"),
                                ),
                            range.end()
                                + TextSize::new(
                                    u32::try_from(trailing.len())
                                        .expect("debug t-string trailing text too long"),
                                ),
                        );
                        if current_string_range.is_none() {
                            *current_string_range = Some(debug_text_range);
                        } else {
                            Self::extend_pending_literal_range(
                                current_string_range,
                                debug_text_range,
                            );
                        }
                        current_string.push_str(&text);
                        strings.push((
                            core::mem::take(current_string),
                            current_string_range.take().unwrap_or(template_range),
                        ));
                    } else {
                        strings.push((
                            core::mem::take(current_string),
                            current_string_range.take().unwrap_or(template_range),
                        ));
                    }
                    *interp_count += 1;
                }
            }
        }
    }

    fn compile_tstring_interpolations(&mut self, tstring: &ast::TString) -> CompileResult<()> {
        for element in &tstring.elements {
            let ast::InterpolatedStringElement::Interpolation(interp) = element else {
                continue;
            };

            if let Some(runtime_str) = interp.runtime_str.as_ref() {
                let interpolation = (
                    runtime_str,
                    interp.runtime_interpolation_format_spec.as_deref(),
                );
                self.compile_interpolation(interp, interpolation)?;
                continue;
            }

            self.compile_expression(&interp.expression)?;

            let expr_range = interp.expression.range();
            let expr_source = if interp.range.start() < expr_range.start()
                && interp.range.end() >= expr_range.end()
            {
                let after_brace = interp.range.start() + TextSize::new(1);
                self.source_file
                    .slice(TextRange::new(after_brace, expr_range.end()))
            } else {
                self.source_file.slice(expr_range)
            }
            .to_string();
            self.set_source_range(interp.range);
            self.emit_load_const(ConstantData::Str {
                value: expr_source.into(),
            });

            let mut conversion: u32 = match interp.conversion {
                ast::ConversionFlag::None => 0,
                ast::ConversionFlag::Str => 1,
                ast::ConversionFlag::Repr => 2,
                ast::ConversionFlag::Ascii => 3,
            };

            if interp.debug_text.is_some() && conversion == 0 && interp.format_spec.is_none() {
                conversion = 2;
            }

            let has_format_spec = interp.format_spec.is_some();
            if let Some(format_spec) = &interp.format_spec {
                let format_spec_range = self.cpython_format_spec_range(format_spec.range);
                self.compile_fstring_elements(
                    ast::FStringFlags::empty(),
                    &format_spec.elements,
                    Some(format_spec_range),
                )?;
            }

            // CPython keeps bit 1 set in BUILD_INTERPOLATION's oparg and uses
            // bit 0 for the optional format spec.
            let format = 2 | (conversion << 2) | u32::from(has_format_spec);
            self.set_source_range(interp.range);
            emit!(self, Instruction::BuildInterpolation { format });
        }

        Ok(())
    }
}

trait EmitArg<Arg: OpArgType> {
    fn emit<I: Into<AnyInstruction>>(
        self,
        f: impl FnOnce(OpArgMarker<Arg>) -> I,
    ) -> (AnyInstruction, OpArg, BlockIdx);
}

impl<T: OpArgType> EmitArg<T> for T {
    fn emit<I: Into<AnyInstruction>>(
        self,
        f: impl FnOnce(OpArgMarker<T>) -> I,
    ) -> (AnyInstruction, OpArg, BlockIdx) {
        let (marker, arg) = OpArgMarker::new(self);
        (f(marker).into(), arg, BlockIdx::NULL)
    }
}

impl EmitArg<bytecode::Label> for BlockIdx {
    fn emit<I: Into<AnyInstruction>>(
        self,
        f: impl FnOnce(OpArgMarker<bytecode::Label>) -> I,
    ) -> (AnyInstruction, OpArg, BlockIdx) {
        (f(OpArgMarker::marker()).into(), OpArg::NULL, self)
    }
}

/// Strips leading whitespace from a docstring.
///
/// `inspect.cleandoc` is a good reference, but has a few incompatibilities.
// = _PyCompile_CleanDoc
fn clean_doc(doc: &str) -> String {
    let doc = expandtabs(doc, 8);
    // First pass: find minimum indentation of non-blank lines AFTER the first line.
    // A "blank line" is one containing only spaces (or empty).
    let margin = doc
        .split('\n')
        .skip(1) // skip first line
        .filter(|line| line.chars().any(|c| c != ' ')) // non-blank lines only
        .map(|line| line.chars().take_while(|c| *c == ' ').count())
        .min()
        .unwrap_or(0);

    let mut cleaned = String::with_capacity(doc.len());
    // Strip all leading spaces from the first line
    if let Some(first_line) = doc.split('\n').next() {
        let trimmed = first_line.trim_start();
        // Early exit: no leading spaces on first line AND margin == 0
        if trimmed.len() == first_line.len() && margin == 0 {
            return doc.to_owned();
        }
        cleaned.push_str(trimmed);
    }
    // Subsequent lines: skip up to `margin` leading spaces
    for line in doc.split('\n').skip(1) {
        cleaned.push('\n');
        let skip = line.chars().take(margin).take_while(|c| *c == ' ').count();
        cleaned.push_str(&line[skip..]);
    }

    cleaned
}

// copied from rustpython_common::str, so we don't have to depend on it just for this function
fn expandtabs(input: &str, tab_size: usize) -> String {
    let tab_stop = tab_size;
    let mut expanded_str = String::with_capacity(input.len());
    let mut tab_size = tab_stop;
    let mut col_count = 0usize;
    for ch in input.chars() {
        match ch {
            '\t' => {
                let num_spaces = tab_size - col_count;
                col_count += num_spaces;
                let expand = " ".repeat(num_spaces);
                expanded_str.push_str(&expand);
            }
            '\r' | '\n' => {
                expanded_str.push(ch);
                col_count = 0;
                tab_size = 0;
            }
            _ => {
                expanded_str.push(ch);
                col_count += 1;
            }
        }
        if col_count >= tab_size {
            tab_size += tab_stop;
        }
    }
    expanded_str
}

fn split_doc_with_range<'a>(
    body: &'a [ast::Stmt],
    opts: &CompileOpts,
) -> (Option<(String, TextRange)>, &'a [ast::Stmt]) {
    if let Some((ast::Stmt::Expr(expr), body_rest)) = body.split_first() {
        let doc_comment: Option<(&str, TextRange)> = match &*expr.value {
            ast::Expr::StringLiteral(value) => Some((value.value.to_str(), expr.value.range())),
            ast::Expr::Constant(ast::ExprConstant {
                value: ast::ConstantValue::Str(value),
                ..
            }) => Some((value.as_ref(), expr.value.range())),
            // f-strings are not allowed in Python doc comments.
            ast::Expr::FString(_) => None,
            _ => None,
        };
        if let Some((doc, range)) = doc_comment {
            return if opts.optimize < 2 {
                (Some((clean_doc(doc), range)), body_rest)
            } else {
                (None, body_rest)
            };
        }
    }
    (None, body)
}

#[cfg(test)]
fn split_doc<'a>(body: &'a [ast::Stmt], opts: &CompileOpts) -> (Option<String>, &'a [ast::Stmt]) {
    let (doc, body) = split_doc_with_range(body, opts);
    (doc.map(|(doc, _)| doc), body)
}

fn is_docstring_expr(expr: &ast::Expr) -> bool {
    matches!(
        expr,
        ast::Expr::StringLiteral(_)
            | ast::Expr::Constant(ast::ExprConstant {
                value: ast::ConstantValue::Str(_),
                ..
            })
    )
}

pub fn ruff_int_to_bigint(int: &ast::Int) -> Result<BigInt, CodegenErrorType> {
    if let Some(small) = int.as_u64() {
        Ok(BigInt::from(small))
    } else {
        parse_big_integer(int)
    }
}

/// Converts a `ruff` ast integer into a `BigInt`.
/// Unlike small integers, big integers may be stored in one of four possible radix representations.
fn parse_big_integer(int: &ast::Int) -> Result<BigInt, CodegenErrorType> {
    // TODO: Improve ruff API
    // Can we avoid this copy?
    let s = format!("{int}");
    let mut s = s.as_str();
    // See: https://peps.python.org/pep-0515/#literal-grammar
    let radix = match s.get(0..2) {
        Some("0b" | "0B") => {
            s = s.get(2..).unwrap_or(s);
            2
        }
        Some("0o" | "0O") => {
            s = s.get(2..).unwrap_or(s);
            8
        }
        Some("0x" | "0X") => {
            s = s.get(2..).unwrap_or(s);
            16
        }
        _ => 10,
    };

    BigInt::from_str_radix(s, radix).map_err(|e| {
        CodegenErrorType::SyntaxError(format!(
            "unparsed integer literal (radix {radix}): {s} ({e})"
        ))
    })
}

// Note: Not a good practice in general. Keep this trait private only for compiler
trait ToU32 {
    fn to_u32(self) -> u32;
}

impl ToU32 for usize {
    fn to_u32(self) -> u32 {
        self.try_into().unwrap()
    }
}

/// Strip Python comments from f-string debug text (leading/trailing around `=`).
/// A comment starts with `#` and extends to the end of the line.
/// The newline character itself is preserved.
fn strip_fstring_debug_comments(text: &str) -> String {
    let mut result = String::with_capacity(text.len());
    let mut in_comment = false;
    for ch in text.chars() {
        if in_comment {
            if ch == '\n' {
                in_comment = false;
                result.push(ch);
            }
        } else if ch == '#' {
            in_comment = true;
        } else {
            result.push(ch);
        }
    }
    result
}

#[cfg(test)]
mod ruff_tests {
    use super::*;
    use ast::name::Name;

    /// Test if the compiler can correctly identify fstrings containing an `await` expression.
    #[test]
    fn fstring_contains_await() {
        let range = TextRange::default();
        let flags = ast::FStringFlags::empty();

        // f'{x}'
        let expr_x = ast::Expr::Name(ast::ExprName {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            id: Name::new("x"),
            ctx: ast::ExprContext::Load,
        });
        let not_present = &ast::Expr::FString(ast::ExprFString {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            value: ast::FStringValue::single(ast::FString {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                elements: vec![ast::InterpolatedStringElement::Interpolation(
                    ast::InterpolatedElement {
                        node_index: ast::AtomicNodeIndex::NONE,
                        range,
                        expression: Box::new(expr_x),
                        debug_text: None,
                        conversion: ast::ConversionFlag::None,
                        format_spec: None,
                        runtime_str: None,
                        runtime_interpolation_format_spec: None,
                        runtime_formatted_value_format_spec: None,
                    },
                )]
                .into(),
                flags,
            }),
            runtime_joined_str: None,
            runtime_values: None,
        });
        assert!(!Compiler::contains_await(not_present));

        // f'{await x}'
        let expr_await_x = ast::Expr::Await(ast::ExprAwait {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            value: Box::new(ast::Expr::Name(ast::ExprName {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                id: Name::new("x"),
                ctx: ast::ExprContext::Load,
            })),
        });
        let present = &ast::Expr::FString(ast::ExprFString {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            value: ast::FStringValue::single(ast::FString {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                elements: vec![ast::InterpolatedStringElement::Interpolation(
                    ast::InterpolatedElement {
                        node_index: ast::AtomicNodeIndex::NONE,
                        range,
                        expression: Box::new(expr_await_x),
                        debug_text: None,
                        conversion: ast::ConversionFlag::None,
                        format_spec: None,
                        runtime_str: None,
                        runtime_interpolation_format_spec: None,
                        runtime_formatted_value_format_spec: None,
                    },
                )]
                .into(),
                flags,
            }),
            runtime_joined_str: None,
            runtime_values: None,
        });
        assert!(Compiler::contains_await(present));

        // f'{x:{await y}}'
        let expr_x = ast::Expr::Name(ast::ExprName {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            id: Name::new("x"),
            ctx: ast::ExprContext::Load,
        });
        let expr_await_y = ast::Expr::Await(ast::ExprAwait {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            value: Box::new(ast::Expr::Name(ast::ExprName {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                id: Name::new("y"),
                ctx: ast::ExprContext::Load,
            })),
        });
        let present = &ast::Expr::FString(ast::ExprFString {
            node_index: ast::AtomicNodeIndex::NONE,
            range,
            value: ast::FStringValue::single(ast::FString {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                elements: vec![ast::InterpolatedStringElement::Interpolation(
                    ast::InterpolatedElement {
                        node_index: ast::AtomicNodeIndex::NONE,
                        range,
                        expression: Box::new(expr_x),
                        debug_text: None,
                        conversion: ast::ConversionFlag::None,
                        format_spec: Some(Box::new(ast::InterpolatedStringFormatSpec {
                            node_index: ast::AtomicNodeIndex::NONE,
                            range,
                            elements: vec![ast::InterpolatedStringElement::Interpolation(
                                ast::InterpolatedElement {
                                    node_index: ast::AtomicNodeIndex::NONE,
                                    range,
                                    expression: Box::new(expr_await_y),
                                    debug_text: None,
                                    conversion: ast::ConversionFlag::None,
                                    format_spec: None,
                                    runtime_str: None,
                                    runtime_interpolation_format_spec: None,
                                    runtime_formatted_value_format_spec: None,
                                },
                            )]
                            .into(),
                        })),
                        runtime_str: None,
                        runtime_interpolation_format_spec: None,
                        runtime_formatted_value_format_spec: None,
                    },
                )]
                .into(),
                flags,
            }),
            runtime_joined_str: None,
            runtime_values: None,
        });
        assert!(Compiler::contains_await(present));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rustpython_compiler_core::{
        SourceFileBuilder,
        bytecode::{CO_FAST_ARG_KW, CO_FAST_ARG_POS, CodeUnit, OpArg},
    };

    fn assert_scope_exit_locations(code: &CodeObject) {
        for (instr, (location, _)) in code.instructions.iter().zip(code.locations.iter()) {
            if matches!(
                instr.op,
                Instruction::ReturnValue
                    | Instruction::RaiseVarargs { .. }
                    | Instruction::Reraise { .. }
            ) {
                assert!(
                    location.line.get() > 0,
                    "scope-exit instruction {instr:?} is missing a line number"
                );
            }
        }
        for constant in code.constants.iter() {
            if let ConstantData::Code { code } = constant {
                assert_scope_exit_locations(code);
            }
        }
    }

    fn compile_exec(source: &str) -> CodeObject {
        let opts = CompileOpts::default();
        compile_exec_with_options(source, opts)
    }

    fn compile_single(source: &str) -> CodeObject {
        let opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap()
        .into_syntax();
        compile_top(parsed, source_file, Mode::Single, opts).unwrap()
    }

    fn compile_exec_optimized(source: &str) -> CodeObject {
        let opts = CompileOpts {
            optimize: 1,
            ..CompileOpts::default()
        };
        compile_exec_with_options(source, opts)
    }

    fn compile_exec_with_options(source: &str, mut opts: CompileOpts) -> CodeObject {
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let mut ast = parsed.into_syntax();
        opts.future_features |= checked_future_features(&ast, &source_file).unwrap();
        let future_annotations = opts
            .future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        preprocess::preprocess_mod(&mut ast, opts.optimize, future_annotations, false);
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let symbol_table = SymbolTable::scan_program_with_options(
            &ast,
            source_file.clone(),
            opts.allow_top_level_await,
            opts.future_features
                .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS),
            opts.recursion_limit,
        )
        .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
        .unwrap();
        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        compiler.compile_program(&ast, symbol_table).unwrap();
        compiler.exit_scope()
    }

    fn compile_module_instruction_infos(source: &str, mode: Mode) -> Vec<ir::InstructionInfo> {
        let mut opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let mut ast = parsed.into_syntax();
        opts.future_features |= checked_future_features(&ast, &source_file).unwrap();
        let future_annotations = opts
            .future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        if matches!(mode, Mode::Single)
            && let ruff_python_ast::Mod::Module(module) = &mut ast
        {
            preprocess::preprocess_statements(
                &mut module.body,
                opts.optimize,
                future_annotations,
                false,
            );
        } else {
            preprocess::preprocess_mod(&mut ast, opts.optimize, future_annotations, false);
        }
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let symbol_table = SymbolTable::scan_program_with_options(
            &ast,
            source_file.clone(),
            opts.allow_top_level_await,
            opts.future_features
                .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS),
            opts.recursion_limit,
        )
        .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
        .unwrap();
        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        match mode {
            Mode::Single => compiler.compile_program_single(&ast.body, symbol_table),
            _ => compiler.compile_program(&ast, symbol_table),
        }
        .unwrap();

        compiler
            .current_code_info()
            .blocks
            .iter()
            .flat_map(|block| block.used_instructions().iter().copied())
            .collect()
    }

    fn compile_eval_ast_with_options(expr: ast::Expr, opts: CompileOpts) -> CodeObject {
        let source_file = SourceFileBuilder::new("source_path", "").finish();
        let parsed = ruff_python_ast::Mod::Expression(ast::ModExpression {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            body: Box::new(expr),
        });
        compile_top(parsed, source_file, Mode::Eval, opts).unwrap()
    }

    fn set_ast_constant(expr: &mut ast::Expr, constant: ConstantData) {
        let constant = crate::constant_data_to_ast_constant_value(constant);
        let range = expr.range();
        *expr = ast::Expr::Constant(ast::ExprConstant {
            node_index: Default::default(),
            range,
            value: constant,
            kind: None,
            invalid_type: None,
        });
    }

    fn compile_ast_constant_expr(mut expr: ast::Expr, constant: ConstantData) -> CodeObject {
        set_ast_constant(&mut expr, constant);
        compile_eval_ast_with_options(expr, CompileOpts::default())
    }

    fn first_ast_constant_warning(expr: ast::Expr) -> String {
        let opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", "").finish();
        let parsed = ruff_python_ast::Mod::Expression(ast::ModExpression {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            body: Box::new(expr),
        });
        let mut warning = None;
        let mut handler = |location, message: String| {
            warning = Some(message.clone());
            Err(CodegenError {
                location: Some(location),
                error: CodegenErrorType::SyntaxError(message),
                source_path: "source_path".to_owned(),
            })
        };
        compile_top_with_syntax_warning_handler(
            parsed,
            source_file,
            Mode::Eval,
            opts,
            Some(&mut handler),
        )
        .expect_err("expected SyntaxWarning handler to stop compilation");
        warning.expect("expected warning message")
    }

    fn first_exec_warning(source: &str) -> String {
        let opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap()
        .into_syntax();
        let mut warning = None;
        let mut handler = |location, message: String| {
            warning = Some(message.clone());
            Err(CodegenError {
                location: Some(location),
                error: CodegenErrorType::SyntaxError(message),
                source_path: "source_path".to_owned(),
            })
        };
        compile_top_with_syntax_warning_handler(
            parsed,
            source_file,
            Mode::Exec,
            opts,
            Some(&mut handler),
        )
        .expect_err("expected SyntaxWarning handler to stop compilation");
        warning.expect("expected warning message")
    }

    fn frozenset_call_expr() -> ast::Expr {
        ast::Expr::Call(ast::ExprCall {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            func: Box::new(ast::Expr::Name(ast::ExprName {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                id: ast::name::Name::new_static("frozenset"),
                ctx: ast::ExprContext::Load,
            })),
            arguments: ast::Arguments {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                args: Box::default(),
                keywords: Default::default(),
                runtime_args: None,
                runtime_bases: None,
            },
        })
    }

    fn compile_exec_parsed_error(
        source: &str,
        parsed: ruff_python_parser::Parsed<ruff_python_ast::Mod>,
    ) -> CodegenError {
        let mut opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let mut ast = parsed.into_syntax();
        opts.future_features |= match checked_future_features(&ast, &source_file) {
            Ok(features) => features,
            Err(err) => return err,
        };
        let future_annotations = opts
            .future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        preprocess::preprocess_mod(&mut ast, opts.optimize, future_annotations, false);
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let symbol_table = match SymbolTable::scan_program(&ast, source_file.clone()) {
            Ok(symbol_table) => symbol_table,
            Err(err) => return err.into_codegen_error(source_file.name().to_owned()),
        };
        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        compiler.compile_program(&ast, symbol_table).unwrap_err()
    }

    fn compile_exec_error(source: &str) -> CodegenError {
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        compile_exec_parsed_error(source, parsed)
    }

    fn compile_exec_error_message(source: &str) -> String {
        compile_exec_error(source).error.to_string()
    }

    fn compile_exec_unchecked_error_message(source: &str) -> String {
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse_unchecked(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        );
        compile_exec_parsed_error(source, parsed).error.to_string()
    }

    #[test]
    fn ast_constant_frozenset_compiles_as_load_const() {
        let code = compile_ast_constant_expr(
            frozenset_call_expr(),
            ConstantData::Frozenset {
                elements: vec![ConstantData::Integer {
                    value: BigInt::from(1u8),
                }],
            },
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::LoadConst { .. })),
            "public ast.Constant(frozenset(...)) must use CPython Constant_kind LOAD_CONST path, got {ops:?}"
        );
        assert!(
            !ops.iter().any(|op| matches!(
                op,
                Instruction::LoadName { .. }
                    | Instruction::Call { .. }
                    | Instruction::CallKw { .. }
            )),
            "public ast.Constant(frozenset(...)) must not compile as a frozenset() call, got {ops:?}"
        );
        assert!(
            code.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Frozenset { elements }
                    if matches!(
                        elements.as_slice(),
                        [ConstantData::Integer { value }] if *value == BigInt::from(1u8)
                    )
            )),
            "missing frozenset constant in code constants"
        );
    }

    #[test]
    fn ast_constant_is_not_scanned_as_lowered_expression() {
        let mut expr = frozenset_call_expr();
        set_ast_constant(
            &mut expr,
            ConstantData::Frozenset {
                elements: Vec::new(),
            },
        );
        let module = ast::ModExpression {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            body: Box::new(expr),
        };
        let table = SymbolTable::scan_expr_with_options(
            &module,
            SourceFileBuilder::new("source_path", "").finish(),
            false,
            false,
            CompileOpts::default().recursion_limit,
        )
        .unwrap();

        assert!(
            table.lookup("frozenset").is_none(),
            "CPython symtable Constant_kind does not visit the lowered frozenset() expression"
        );
    }

    #[test]
    fn ast_constant_frozenset_call_warns_like_cpython_constant() {
        let mut func = frozenset_call_expr();
        set_ast_constant(
            &mut func,
            ConstantData::Frozenset {
                elements: Vec::new(),
            },
        );
        let message = first_ast_constant_warning(ast::Expr::Call(ast::ExprCall {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            func: Box::new(func),
            arguments: ast::Arguments {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                args: Box::default(),
                keywords: Default::default(),
                runtime_args: None,
                runtime_bases: None,
            },
        }));
        assert!(
            message.contains("'frozenset' object is not callable"),
            "expected public ast.Constant(frozenset()) callable warning, got {message:?}"
        );
    }

    #[test]
    fn ast_constant_frozenset_subscript_warns_like_cpython_constant() {
        let mut value = frozenset_call_expr();
        set_ast_constant(
            &mut value,
            ConstantData::Frozenset {
                elements: Vec::new(),
            },
        );
        let message = first_ast_constant_warning(ast::Expr::Subscript(ast::ExprSubscript {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            value: Box::new(value),
            slice: Box::new(ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                value: ast::Number::Int(ast::Int::ZERO),
            })),
            ctx: ast::ExprContext::Load,
        }));
        assert!(
            message.contains("'frozenset' object is not subscriptable"),
            "expected public ast.Constant(frozenset()) subscript warning, got {message:?}"
        );
    }

    #[test]
    fn ast_constant_str_bad_index_warns_like_cpython_constant() {
        let mut value = frozenset_call_expr();
        set_ast_constant(
            &mut value,
            ConstantData::Str {
                value: "abc".into(),
            },
        );
        let message = first_ast_constant_warning(ast::Expr::Subscript(ast::ExprSubscript {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            value: Box::new(value),
            slice: Box::new(ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                value: ast::Number::Float(1.0),
            })),
            ctx: ast::ExprContext::Load,
        }));
        assert!(
            message.contains("str indices must be integers or slices, not float"),
            "expected public ast.Constant(str) bad-index warning, got {message:?}"
        );
    }

    #[test]
    fn ast_constant_frozenset_is_warns_like_cpython_constant() {
        let mut left = frozenset_call_expr();
        set_ast_constant(
            &mut left,
            ConstantData::Frozenset {
                elements: Vec::new(),
            },
        );
        let message = first_ast_constant_warning(ast::Expr::Compare(ast::ExprCompare {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            left: Box::new(left),
            ops: Box::new([ast::CmpOp::Is]),
            comparators: Box::new([ast::Expr::NoneLiteral(ast::ExprNoneLiteral {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
            })]),
            runtime_comparators: None,
        }));
        assert!(
            message.contains("\"is\" with 'frozenset' literal"),
            "expected public ast.Constant(frozenset()) identity warning, got {message:?}"
        );
    }

    #[test]
    fn ast_constant_tuple_compiles_as_load_const() {
        let expr = ast::Expr::Tuple(ast::ExprTuple {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            elts: Vec::new(),
            ctx: ast::ExprContext::Load,
            parenthesized: true,
            runtime_elts: None,
        });
        let code = compile_ast_constant_expr(
            expr,
            ConstantData::Tuple {
                elements: vec![ConstantData::Integer {
                    value: BigInt::from(1u8),
                }],
            },
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::LoadConst { .. })),
            "public ast.Constant(tuple(...)) must use CPython Constant_kind LOAD_CONST path, got {ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::BuildTuple { .. })),
            "public ast.Constant(tuple(...)) must not compile as a tuple display, got {ops:?}"
        );
        assert!(
            code.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Tuple { elements }
                    if matches!(
                        elements.as_slice(),
                        [ConstantData::Integer { value }] if *value == BigInt::from(1u8)
                    )
            )),
            "missing tuple constant in code constants"
        );
    }

    #[test]
    fn ast_constant_slice_bound_uses_cpython_constant_slice_path() {
        let mut lower = frozenset_call_expr();
        set_ast_constant(
            &mut lower,
            ConstantData::Integer {
                value: BigInt::from(1u8),
            },
        );
        let expr = ast::Expr::Subscript(ast::ExprSubscript {
            node_index: ast::AtomicNodeIndex::NONE,
            range: TextRange::default(),
            value: Box::new(ast::Expr::Name(ast::ExprName {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                id: ast::name::Name::new_static("obj"),
                ctx: ast::ExprContext::Load,
            })),
            slice: Box::new(ast::Expr::Slice(ast::ExprSlice {
                node_index: ast::AtomicNodeIndex::NONE,
                range: TextRange::default(),
                lower: Some(Box::new(lower)),
                upper: Some(Box::new(ast::Expr::NumberLiteral(ast::ExprNumberLiteral {
                    node_index: ast::AtomicNodeIndex::NONE,
                    range: TextRange::default(),
                    value: ast::Number::Int(ast::Int::ZERO),
                }))),
                step: None,
            })),
            ctx: ast::ExprContext::Load,
        });
        let code = compile_eval_ast_with_options(expr, CompileOpts::default());
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        assert!(
            !ops.iter().any(|op| matches!(
                op,
                Instruction::BinarySlice | Instruction::BuildSlice { .. }
            )),
            "public ast.Constant slice bound must follow CPython Constant_kind folded slice path, got {ops:?}"
        );
        assert!(
            code.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Slice { elements }
                    if matches!(
                        elements.as_ref(),
                        [
                            ConstantData::Integer { value },
                            ConstantData::Integer { .. },
                            ConstantData::None,
                        ] if *value == BigInt::from(1u8)
                    )
            )),
            "missing folded slice constant for public ast.Constant bound"
        );
    }

    #[test]
    fn match_pattern_errors_use_cpython_sequence_messages() {
        let many_names = (0..256)
            .map(|i| format!("a{i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let too_many = format!(
            "\
match x:
    case [{many_names}, *rest]:
        pass
"
        );
        assert_eq!(
            compile_exec_error_message(&too_many),
            "too many expressions in star-unpacking sequence pattern"
        );

        assert_eq!(
            compile_exec_error_message(
                "\
match x:
    case [*a, *b]:
        pass
"
            ),
            "multiple starred names in sequence pattern"
        );

        assert_eq!(
            compile_exec_unchecked_error_message(
                "\
match x:
    case {**_}:
        pass
"
            ),
            "invalid syntax"
        );
    }

    #[test]
    fn match_mapping_duplicate_literal_keys_use_cpython_equality() {
        for (source, expected) in [
            (
                "\
match x:
    case {1: a, True: b}:
        pass
",
                "mapping pattern checks duplicate key (True)",
            ),
            (
                "\
match x:
    case {1: a, 1.0: b}:
        pass
",
                "mapping pattern checks duplicate key (1.0)",
            ),
            (
                "\
match x:
    case {0.0: a, -0.0: b}:
        pass
",
                "mapping pattern checks duplicate key (-0.0)",
            ),
            (
                "\
match x:
    case {9007199254740992: a, 9007199254740992.0: b}:
        pass
",
                "mapping pattern checks duplicate key (9007199254740992.0)",
            ),
            (
                "\
match x:
    case {-9007199254740992: a, -9007199254740992.0: b}:
        pass
",
                "mapping pattern checks duplicate key (-9007199254740992.0)",
            ),
            (
                "\
match x:
    case {1 + 0j: a, 1: b}:
        pass
",
                "mapping pattern checks duplicate key (1)",
            ),
            (
                "\
match x:
    case {1: a, 1 + 0j: b}:
        pass
",
                "mapping pattern checks duplicate key ((1+0j))",
            ),
            (
                "\
match x:
    case {0j: a, -0.0: b}:
        pass
",
                "mapping pattern checks duplicate key (-0.0)",
            ),
        ] {
            assert_eq!(compile_exec_error_message(source), expected);
        }
    }

    #[test]
    fn match_mapping_accepts_folded_literal_keys_like_cpython() {
        compile_exec(
            "\
def f(x):
    match x:
        case {-1: a, 1 + 0j: b}:
            return a, b
        case {9007199254740993: a, 9007199254740992.0: b}:
            return a, b
        case {-9007199254740993: a, -9007199254740992.0: b}:
            return a, b
        case {1 + 1j: a, 1: b}:
            return a, b
        case _:
            return None
",
        );
    }

    #[test]
    fn match_mapping_accepts_public_ast_constant_keys_like_cpython() {
        let source = "\
match x:
    case {'a': _, b'b': _, 2: _, 1.5: _, 1j: _, True: _, None: _}:
        pass
";
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let mut ast = parsed.into_syntax();
        let ast::Mod::Module(module) = &mut ast else {
            unreachable!();
        };
        let ast::Stmt::Match(match_stmt) = &mut module.body[0] else {
            unreachable!();
        };
        let ast::Pattern::MatchMapping(mapping) = &mut match_stmt.cases[0].pattern else {
            unreachable!();
        };

        for (key, value) in mapping.keys.iter_mut().zip([
            ast::ConstantValue::Str("a".into()),
            ast::ConstantValue::Bytes(vec![b'b'].into_boxed_slice()),
            ast::ConstantValue::Integer("2".into()),
            ast::ConstantValue::Float(1.5),
            ast::ConstantValue::Complex {
                real: 0.0,
                imag: 1.0,
            },
            ast::ConstantValue::Boolean(true),
            ast::ConstantValue::None,
        ]) {
            let range = key.range();
            *key = ast::Expr::Constant(ast::ExprConstant {
                node_index: ast::AtomicNodeIndex::NONE,
                range,
                value,
                kind: None,
                invalid_type: None,
            });
        }

        compile_top(ast, source_file, Mode::Exec, CompileOpts::default()).unwrap();
    }

    #[test]
    fn match_literal_binop_folding_uses_cpython_complex_shape() {
        assert!(
            Compiler::try_fold_match_pattern_binop(
                ast::Operator::Add,
                &ConstantData::Integer {
                    value: BigInt::from(1)
                },
                &ConstantData::Integer {
                    value: BigInt::from(2)
                },
            )
            .is_none()
        );
        assert!(
            Compiler::try_fold_match_pattern_binop(
                ast::Operator::Add,
                &ConstantData::Float { value: 1.0 },
                &ConstantData::Float { value: 2.0 },
            )
            .is_none()
        );
        assert!(matches!(
            Compiler::try_fold_match_pattern_binop(
                ast::Operator::Add,
                &ConstantData::Integer {
                    value: BigInt::from(1)
                },
                &ConstantData::Complex {
                    value: Complex::new(0.0, 2.0)
                },
            ),
            Some(ConstantData::Complex { value }) if value == Complex::new(1.0, 2.0)
        ));
        assert!(matches!(
            Compiler::try_fold_match_pattern_binop(
                ast::Operator::Sub,
                &ConstantData::Float { value: 1.5 },
                &ConstantData::Complex {
                    value: Complex::new(0.0, 2.0)
                },
            ),
            Some(ConstantData::Complex { value }) if value == Complex::new(1.5, -2.0)
        ));
    }

    #[test]
    fn match_literal_patterns_reject_unexpected_constants_like_cpython() {
        assert!(Compiler::is_unexpected_match_literal_constant(
            &ast::ExprEllipsisLiteral {
                range: TextRange::default(),
                node_index: ast::AtomicNodeIndex::NONE,
            }
            .into()
        ));
    }

    #[test]
    fn unpack_ex_allows_large_after_count_like_cpython() {
        let suffix = (0..256)
            .map(|i| format!("a{i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!(
            "\
def assignment(values):
    *rest, {suffix} = values
    return a255

def pattern(values):
    match values:
        case [*rest, {suffix}]:
            return a255
        case _:
            return None
"
        ));

        let assignment = find_code(&code, "assignment").expect("missing assignment code");
        assert_eq!(
            full_opargs_for(assignment, |op| matches!(op, Instruction::UnpackEx { .. })),
            vec![256 << 8]
        );

        let pattern = find_code(&code, "pattern").expect("missing pattern code");
        assert_eq!(
            full_opargs_for(pattern, |op| matches!(op, Instruction::UnpackEx { .. })),
            vec![256 << 8]
        );
    }

    #[test]
    fn match_irrefutable_pattern_errors_use_cpython_messages() {
        assert_eq!(
            compile_exec_error_message(
                "\
match x:
    case y | 1:
        pass
"
            ),
            "name capture 'y' makes remaining patterns unreachable"
        );

        assert_eq!(
            compile_exec_error_message(
                "\
match x:
    case _ | 1:
        pass
"
            ),
            "wildcard makes remaining patterns unreachable"
        );
    }

    #[test]
    fn empty_module_implicit_return_inherits_resume_location_like_cpython() {
        let code = compile_exec("");
        // codegen emits the implicit LOAD_CONST/RETURN_VALUE with
        // NO_LOCATION, then flowgraph.c::propagate_line_numbers() propagates
        // the module RESUME location, whose line is 0.
        assert_eq!(code.linetable.as_ref(), &[0xf2, 0x03, 0x01, 0x01, 0x01]);
    }

    #[test]
    fn module_docstring_load_uses_doc_location_like_cpython() {
        let code = compile_exec(
            "\
\"doc\"
x = 1
",
        );

        // codegen_body() emits the docstring LOAD_CONST at the
        // string expression location, then emits STORE_NAME __doc__ with
        // NO_LOCATION.
        assert_eq!(
            code.linetable.as_ref(),
            &[
                0xf0, 0x03, 0x01, 0x01, 0x01, 0xd9, 0x00, 0x05, 0xd8, 0x04, 0x05, 0x82, 0x01,
            ],
        );
    }

    #[test]
    fn redundant_nop_location_copies_full_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x, y, z):
    while x:
        if y:
            pass
        elif z:
            if y < 0:
                return y
            if z:
                y = y + 1
        elif y:
            return 1
    return -1
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdf, 0x0a, 0x0b, 0xdf, 0x0b, 0x0c, 0xd9, 0x0c, 0x10, 0xdf, 0x0d, 0x0e,
                0xd8, 0x0f, 0x10, 0x90, 0x31, 0x8c, 0x75, 0xd8, 0x17, 0x18, 0x90, 0x08, 0xdf, 0x0f,
                0x10, 0xd8, 0x14, 0x15, 0x98, 0x01, 0x95, 0x45, 0x92, 0x01, 0xf1, 0x03, 0x00, 0x10,
                0x11, 0xe7, 0x0d, 0x0e, 0x89, 0x51, 0xd9, 0x13, 0x14, 0xd8, 0x0b, 0x0d, 0x80, 0x49,
            ],
            "CPython basicblock_remove_redundant_nops() copies the full NOP location into a following no-location jump"
        );
    }

    fn scan_program_symbol_table(source: &str) -> SymbolTable {
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let ast = parsed.into_syntax();
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        SymbolTable::scan_program(&ast, source_file)
            .map_err(|e| e.into_codegen_error("source_path".to_owned()))
            .unwrap()
    }

    fn find_symbol_table<'a>(table: &'a SymbolTable, name: &str) -> Option<&'a SymbolTable> {
        if table.name == name {
            return Some(table);
        }
        table
            .sub_tables
            .iter()
            .find_map(|sub_table| find_symbol_table(sub_table, name))
    }

    fn compile_exec_late_cfg_trace(source: &str) -> Vec<(String, String)> {
        let opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let ast = parsed.into_syntax();
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let symbol_table = SymbolTable::scan_program(&ast, source_file.clone())
            .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
            .unwrap();
        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        compiler.compile_program(&ast, symbol_table).unwrap();
        compiler.pop_symbol_table();
        let stack_top = compiler.code_stack.pop().unwrap();
        stack_top.debug_late_cfg_trace().unwrap()
    }

    fn compile_single_function_late_cfg_trace(
        source: &str,
        function_name: &str,
    ) -> Vec<(String, String)> {
        let opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let ast = parsed.into_syntax();
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let mut symbol_table = SymbolTable::scan_program(&ast, source_file.clone())
            .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
            .unwrap();
        let function = ast
            .body
            .iter()
            .find_map(|stmt| match stmt {
                ast::Stmt::FunctionDef(f) if f.name.as_str() == function_name => Some(f),
                _ => None,
            })
            .unwrap_or_else(|| panic!("missing function {function_name}"));
        symbol_table.next_sub_table = symbol_table
            .sub_tables
            .iter()
            .position(|table| table.name == function_name)
            .unwrap_or_else(|| panic!("missing symbol table for {function_name}"));

        let name = &function.name;
        let parameters = &function.parameters;
        let body = &function.body;
        let is_async = function.is_async;
        let range = function.range();

        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        compiler.future_annotations = symbol_table.future_annotations;
        compiler.symbol_table_stack.push(symbol_table);
        compiler.set_source_range(range);
        compiler.enter_function(name.as_str(), parameters).unwrap();
        compiler
            .current_code_info()
            .flags
            .set(bytecode::CodeFlags::COROUTINE, is_async);

        let prev_ctx = compiler.ctx;
        compiler.ctx = CompileContext {
            in_class: prev_ctx.in_class,
            func: if is_async {
                FunctionContext::AsyncFunction
            } else {
                FunctionContext::Function
            },
            in_async_scope: is_async,
        };
        compiler.set_qualname();
        let (_, body) = split_doc(body, &compiler.opts);
        let start_label = compiler.use_cpython_function_start_label();
        let is_gen = is_async || compiler.current_symbol_table().is_generator;
        let stop_iteration_block = if is_gen {
            let handler_block = compiler.new_block();
            compiler.insert_cpython_stopiteration_setup_cleanup(handler_block);
            compiler
                .push_fblock_labels(
                    FBlockType::StopIteration,
                    start_label,
                    ir::InstructionSequenceLabel::NO_LABEL,
                    FBlockDatum::None,
                )
                .unwrap();
            Some(handler_block)
        } else {
            None
        };
        compiler.compile_statements(body).unwrap();
        match body.last() {
            Some(ast::Stmt::Return(_)) => {}
            _ => compiler.emit_return_const_no_location(ConstantData::None),
        }
        if compiler.current_code_info().metadata.consts.is_empty() {
            compiler.arg_constant(ConstantData::None);
        }
        if let Some(handler_block) = stop_iteration_block {
            compiler.pop_fblock_label(FBlockType::StopIteration, start_label);
            compiler.use_cpython_label_block(handler_block);
            emit!(
                compiler,
                Instruction::CallIntrinsic1 {
                    func: oparg::IntrinsicFunction1::StopIterationError
                }
            );
            compiler.set_no_location();
            emit!(compiler, Instruction::Reraise { depth: 1u32 });
            compiler.set_no_location();
        }

        compiler.pop_symbol_table();
        let stack_top = compiler.code_stack.pop().unwrap();
        stack_top.debug_late_cfg_trace().unwrap()
    }

    #[test]
    fn try_else_nested_try_const_list_keeps_setup_finally_nop() {
        let trace = compile_single_function_late_cfg_trace(
            r#"
def f(arch):
    try:
        [arch, *_] = g()
    except OSError:
        pass
    else:
        try:
            arch = ['x86', 'MIPS', 'Alpha', 'PowerPC', None,
                    'ARM', 'ia64', None, None,
                    'AMD64', None, None, 'ARM64',
            ][int(arch)]
        except (ValueError, IndexError):
            pass
        else:
            if arch:
                return arch
"#,
            "f",
        );
        let (_, dump) = trace
            .iter()
            .find(|(label, _)| label == "after_convert_pseudo_ops")
            .expect("missing convert_pseudo_ops trace");
        assert!(
            dump.contains("[disp=8:9 raw=8:9-17:28 override=None] Real(Nop)"),
            "SETUP_FINALLY should survive as a line-bearing NOP like CPython"
        );
        assert!(
            dump.contains("[disp=9:20 raw=9:20-12:14 override=None] Real(BuildList"),
            "CPython optimize_lists_and_sets() restores the literal location to BUILD_LIST"
        );
    }

    #[test]
    fn for_try_except_break_keeps_cpython_if_layout() {
        let code = compile_exec(
            "\
def f(support, func, value):
    for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
        try:
            if func() == value:
                break
        except NotImplementedError:
            break
    sink(value)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect::<Vec<_>>();
        let cond = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopJumpIfFalse { .. }))
            .expect("missing CPython-style false jump for if/break");
        assert!(
            matches!(
                ops.get(cond..cond + 5),
                Some([
                    Instruction::PopJumpIfFalse { .. },
                    Instruction::NotTaken,
                    Instruction::PopTop,
                    Instruction::JumpForward { .. },
                    Instruction::JumpBackward { .. },
                ])
            ),
            "CPython codegen_if() keeps the break cleanup in the true-body fallthrough before the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_loop_break_keeps_body_before_protected_backedge() {
        let code = compile_exec(
            "\
def f(input):
    while 1:
        try:
            pass
        except IndexError:
            break
        else:
            key = None
            while key is None:
                key = input()
                if key not in ('', 'q'):
                    key = None
            if key == 'q':
                break
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect::<Vec<_>>();
        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                        Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "CPython codegen_if() keeps the break body before the false backedge into the protected try/except loop, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_nested_if_tail_keeps_duplicate_jump_back_label() {
        let code = compile_exec(
            "\
def f(value, digits):
    for digit in value:
        if isinstance(digit, int) and 0 <= digit <= 9:
            if digits or digit != 0:
                digits.append(digit)
        else:
            raise ValueError('x')
    return digits
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache | Instruction::Nop))
            .collect::<Vec<_>>();
        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. },
                        Instruction::JumpBackward { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "CPython codegen_if() leaves a distinct no-location end label before the loop else/raise path, got ops={ops:?}"
        );
    }

    #[test]
    fn match_for_break_threads_empty_end_label_to_outer_backedge() {
        let code = compile_exec(
            "\
def f(items, T):
    for st in items:
        match st.type:
            case T.TYPE:
                for c in st.children:
                    if c.name == st.name:
                        x = 1
                        break
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache | Instruction::Nop))
            .collect::<Vec<_>>();
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. },
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "CPython codegen_break() threads the match-case inner for break through the empty end label to the outer loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn match_constant_guard_keeps_cpython_guard_nop_before_subject_pop() {
        let code = compile_exec(
            "\
def f(self):
    x = 0
    match x:
        case 0 if True:
            y = 0
        case 0 if True:
            y = 1
    self.assertEqual(x, 0)
    self.assertEqual(y, 0)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect::<Vec<_>>();
        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::Nop,
                        Instruction::PopTop,
                        Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "CPython codegen_match_inner() emits the guard through codegen_jump_if(), and flowgraph.c keeps the folded constant-guard NOP in a separate success block before POP_TOP, got ops={ops:?}"
        );
    }

    #[test]
    fn match_or_default_tail_uses_cpython_load_fast_borrow() {
        let code = compile_exec(
            "\
def f(format, annotationlib, cls, annotation_fields, return_type, MISSING):
    Format = annotationlib.Format
    match format:
        case Format.VALUE | Format.FORWARDREF | Format.STRING:
            cls_annotations = {}
            for base in reversed(cls.__mro__):
                cls_annotations.update(
                    annotationlib.get_annotations(base, format=format)
                )
            new_annotations = {}
            for k in annotation_fields:
                try:
                    new_annotations[k] = cls_annotations[k]
                except KeyError:
                    pass
            if return_type is not MISSING:
                if format == Format.STRING:
                    new_annotations['return'] = annotationlib.type_repr(return_type)
                else:
                    new_annotations['return'] = return_type
            return new_annotations
        case _:
            raise NotImplementedError(format)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let raise = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
            .expect("missing default raise");
        let load_format = &ops[raise - 2];
        let Instruction::LoadFastBorrow { var_num } = load_format.op else {
            panic!(
                "CPython codegen_match_inner() emits the default case without a load-fast barrier, so optimize_load_fast() borrows the raise argument; got ops={ops:?}"
            );
        };
        let arg = OpArg::new(u32::from(u8::from(load_format.arg)));
        assert_eq!(f.varnames[usize::from(var_num.get(arg))], "format");
    }

    #[test]
    fn preceding_match_or_default_tail_keeps_cpython_strong_load_fast() {
        let code = compile_exec(
            "\
def f(format):
    match format:
        case _lazy_annotationlib.Format.VALUE | _lazy_annotationlib.Format.FORWARDREF:
            return checked_types
        case _lazy_annotationlib.Format.STRING:
            return _lazy_annotationlib.annotations_to_string(types)
        case _:
            raise NotImplementedError(format)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let raise = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
            .expect("missing default raise");
        let load_format = &ops[raise - 2];
        let Instruction::LoadFast { var_num } = load_format.op else {
            panic!(
                "CPython keeps the default raise argument strong when an earlier copied OR-pattern precedes the final non-default case; got ops={ops:?}"
            );
        };
        let arg = OpArg::new(u32::from(u8::from(load_format.arg)));
        assert_eq!(f.varnames[usize::from(var_num.get(arg))], "format");
    }

    #[test]
    fn try_else_after_nested_try_except_exit_keeps_cpython_strong_load_fast() {
        let code = compile_exec(
            "\
def f(self):
    try:
        try:
            1 / 0
        except ZeroDivisionError:
            raise OSError
    except OSError as e:
        self.assertIsInstance(e.__context__, ZeroDivisionError)
    else:
        self.fail('No exception raised')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let fail = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "fail"
                }
                _ => false,
            })
            .expect("missing fail load");
        assert!(
            matches!(ops[fail - 1].op, Instruction::LoadFast { .. }),
            "CPython codegen_try_except() keeps the orelse entry after a nested try/except end label strong, got ops={ops:?}"
        );
    }

    #[test]
    fn try_after_inherited_try_barrier_keeps_successor_loads_strong() {
        let code = compile_exec(
            "\
def f(self, x):
    try:
        1 / 0
    except EOFError:
        pass
    except TypeError as msg:
        pass
    except:
        pass
    else:
        pass
    try:
        x
    except (EOFError, TypeError, ZeroDivisionError):
        pass
    with self.assertRaises(SyntaxError):
        pass

def g(self):
    try:
        1 / 0
    except:
        pass
    try:
        1 / 0
    except (EOFError, TypeError, ZeroDivisionError):
        pass
    with self.assertRaises(SyntaxError):
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let x_loads = load_fast_ops_for_var(f, "x");
        assert!(
            x_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() reaches the first try end through USE_LABEL(end); flowgraph.c keeps that barrier state through the following try end, got x loads {x_loads:?}"
        );
        let self_loads = load_fast_ops_for_var(f, "self");
        assert!(
            self_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps successor with-statement loads strong after a try that started from an inherited try barrier, got self loads {self_loads:?}"
        );
        let g = find_code(&code, "g").expect("missing g code");
        let g_self_loads = load_fast_ops_for_var(g, "self");
        assert!(
            g_self_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps a bare-handler try end label as a barrier when the next statement is another try, got self loads {g_self_loads:?}"
        );
    }

    #[test]
    fn loop_continue_try_before_try_else_keeps_orelse_loads_strong() {
        let code = compile_exec(
            "\
def f(candidate_locales, locales):
    for loc in candidate_locales:
        try:
            work(loc)
        except Error:
            continue
        encoding = getencoding()
        try:
            localeconv()
        except Exception as err:
            print(loc, encoding, type(err), err)
        else:
            locales.append(loc)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let locales_loads = load_fast_ops_for_var(f, "locales");
        assert!(
            locales_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() leaves an empty end label after a loop try whose handlers continue; optimize_load_fast() keeps the following try/else append receiver strong, got {locales_loads:?}"
        );
        let loc_loads = load_fast_ops_for_var(f, "loc");
        assert!(
            loc_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps the try/else append argument strong after the inherited end-label barrier, got {loc_loads:?}"
        );
    }

    #[test]
    fn try_else_after_try_finally_conditional_finalbody_keeps_store_attr_loads_strong() {
        let code = compile_exec(
            "\
def f(self, w, pid, prev):
    try:
        try:
            if cond:
                prev = call()
            pid = spawn()
        finally:
            if prev is not None:
                reset(prev)
    except:
        close(w)
        raise
    else:
        self._fd = w
        self._pid = pid
    finally:
        close(r)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let w_self_pairs = load_fast_pair_ops_for_vars(f, "w", "self");
        let pid_self_pairs = load_fast_pair_ops_for_vars(f, "pid", "self");
        assert!(
            w_self_pairs
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastLoadFast { .. }))
                && !w_self_pairs.is_empty(),
            "CPython codegen_try_finally() calls codegen_try_except() inside the active finally try; the else suite starts from the inner try/finally exit label and keeps w/self strong, got {w_self_pairs:?}"
        );
        assert!(
            pid_self_pairs
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastLoadFast { .. }))
                && !pid_self_pairs.is_empty(),
            "CPython keeps the second store-attr source pair strong in the same try/except/else/finally else suite, got {pid_self_pairs:?}"
        );
    }

    #[test]
    fn try_except_end_before_following_try_keeps_protected_attr_loads_strong() {
        let code = compile_exec(
            "\
def f(f, dotlock=True):
    dotlock_done = False
    try:
        if dotlock:
            try:
                pre_lock = _create_temporary(f.name + '.lock')
                pre_lock.close()
            except OSError as e:
                if e.errno in (errno.EACCES, errno.EROFS):
                    return
                else:
                    raise
            try:
                try:
                    os.link(pre_lock.name, f.name + '.lock')
                    dotlock_done = True
                except (AttributeError, PermissionError):
                    os.rename(pre_lock.name, f.name + '.lock')
                    dotlock_done = True
                else:
                    os.unlink(pre_lock.name)
            except FileExistsError:
                os.remove(pre_lock.name)
                raise ExternalClashError('dot lock unavailable: %s' %
                                         f.name)
    except:
        if dotlock_done:
            os.remove(f.name + '.lock')
        raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let pre_lock_loads = load_fast_ops_for_var(f, "pre_lock");
        let strong_pre_lock_loads = pre_lock_loads
            .iter()
            .filter(|op| matches!(op, Instruction::LoadFast { .. }))
            .count();
        assert!(
            strong_pre_lock_loads >= 2,
            "CPython codegen_try_except() emits USE_LABEL(end) before the following try; flowgraph.c::optimize_load_fast() does not push fallthrough through the empty end label, so protected pre_lock attr receivers stay strong, got {pre_lock_loads:?}"
        );
        let f_loads = load_fast_ops_for_var(f, "f");
        assert!(
            f_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps the f.name receiver inside the following protected try strong after the preceding try/except end label, got {f_loads:?}"
        );
    }

    #[test]
    fn try_except_method_probe_end_before_if_keeps_loads_strong() {
        let code = compile_exec(
            "\
def f(param, value=None, quote=True):
    if value is not None and len(value) > 0:
        if isinstance(value, tuple):
            param += '*'
            value = encode(value[2], value[0], value[1])
            return f'{param}={value}'
        else:
            try:
                value.encode('ascii')
            except UnicodeEncodeError:
                param += '*'
                value = encode(value, 'utf-8', '')
                return f'{param}={value}'
        if quote or tspecials.search(value):
            return f'{param}=\"{quote_value(value)}\"'
        else:
            return f'{param}={value}'
    else:
        return param
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let quote_loads = load_fast_ops_for_var(f, "quote");
        assert!(
            quote_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() emits USE_LABEL(end) after a handled method probe; flowgraph.c::optimize_load_fast() leaves the following if-test local strong, got {quote_loads:?}"
        );
        let param_loads = load_fast_ops_for_var(f, "param");
        assert!(
            param_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps the return f-string local loads strong after the protected method-probe end label, got {param_loads:?}"
        );
        let value_loads = load_fast_ops_for_var(f, "value");
        assert!(
            value_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython keeps the post-try value loads strong after the protected method-probe end label, got {value_loads:?}"
        );
    }

    #[test]
    fn try_except_fallthrough_before_return_call_keeps_borrow() {
        let code = compile_exec(
            "\
def f(obj, lock, ctx, cls, class_cache):
    if cond1(obj):
        return Synchronized(obj, lock, ctx)
    elif cond2(obj):
        return SynchronizedArray(obj, lock, ctx)
    else:
        try:
            scls = class_cache[cls]
        except KeyError:
            scls = make_synchronized(cls)
        return scls(obj, lock, ctx)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let scls_loads = load_fast_ops_for_var(f, "scls");
        assert!(
            scls_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython codegen_try_except() emits USE_LABEL(end) and the following return call into the same basic block; flowgraph.c borrows the callable local, got {scls_loads:?}"
        );
        let obj_lock_pairs = load_fast_pair_ops_for_vars(f, "obj", "lock");
        assert!(
            obj_lock_pairs
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrowLoadFastBorrow { .. })),
            "CPython flowgraph.c borrows the return call argument pair after a typed fallthrough handler, got {obj_lock_pairs:?}"
        );
        let ctx_loads = load_fast_ops_for_var(f, "ctx");
        assert!(
            ctx_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython flowgraph.c borrows the trailing return call argument after the try-end label, got {ctx_loads:?}"
        );
    }

    #[test]
    fn try_except_comprehension_handler_before_return_call_keeps_borrow() {
        let code = compile_exec(
            "\
def f(obj, lock, ctx):
    assert not isinstance(obj, SynchronizedBase), 'object already synchronized'
    ctx = ctx or get_context()

    if isinstance(obj, ctypes._SimpleCData):
        return Synchronized(obj, lock, ctx)
    elif isinstance(obj, ctypes.Array):
        if obj._type_ is ctypes.c_char:
            return SynchronizedString(obj, lock, ctx)
        return SynchronizedArray(obj, lock, ctx)
    else:
        cls = type(obj)
        try:
            scls = class_cache[cls]
        except KeyError:
            names = [field[0] for field in cls._fields_]
            d = {name: make_property(name) for name in names}
            classname = 'Synchronized' + cls.__name__
            scls = class_cache[cls] = type(classname, (SynchronizedBase,), d)
        return scls(obj, lock, ctx)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let scls_loads = load_fast_ops_for_var(f, "scls");
        assert!(
            scls_loads
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrow { .. }))
                && scls_loads
                    .iter()
                    .all(|op| !matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() keeps the return call in the end-label block even when the handler contains comprehensions, got {scls_loads:?}"
        );
        let obj_lock_pairs = load_fast_pair_ops_for_vars(f, "obj", "lock");
        assert!(
            obj_lock_pairs
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrowLoadFastBorrow { .. }))
                && obj_lock_pairs
                    .iter()
                    .all(|op| !matches!(op, Instruction::LoadFastLoadFast { .. })),
            "CPython flowgraph.c borrows the return call argument pair after the try-end label and cold handler reordering, got {obj_lock_pairs:?}"
        );
        let instructions = non_cache_instructions(f).collect::<Vec<_>>();
        let ctx_idx = varname_index(f, "ctx");
        let has_borrowed_return_tail = instructions.windows(6).any(|window| {
            matches!(window[0].op, Instruction::LoadFastBorrow { .. })
                && matches!(window[1].op, Instruction::PushNull)
                && matches!(
                    window[2].op,
                    Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
                && matches!(window[3].op, Instruction::LoadFastBorrow { .. })
                && {
                    let Instruction::LoadFastBorrow { var_num } = window[3].op else {
                        return false;
                    };
                    usize::from(var_num.get(OpArg::new(u32::from(u8::from(window[3].arg)))))
                        == ctx_idx
                }
                && matches!(window[4].op, Instruction::Call { .. })
                && matches!(window[5].op, Instruction::ReturnValue)
        });
        assert!(
            has_borrowed_return_tail,
            "CPython flowgraph.c borrows the full final return-call tail after the protected try body, got instructions={instructions:?}"
        );
    }

    #[test]
    fn try_finally_closed_conditional_exit_allows_cpython_borrow() {
        let code = compile_exec(
            "\
def f(self, os, tempfile, oldmode):
    try:
        work()
    finally:
        if os.name == 'nt':
            os.chmod(tempfile.tempdir, oldmode)
        else:
            os.chmod(tempfile.tempdir, oldmode)
    self.assertEqual(os.listdir(tempfile.tempdir), [])
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let assert_equal = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "assertEqual"
                }
                _ => false,
            })
            .expect("missing assertEqual load");
        assert!(
            matches!(ops[assert_equal - 1].op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_try_finally() does not make a load-fast barrier after a closed conditional finalbody, got ops={ops:?}"
        );
    }

    #[test]
    fn handler_resume_after_nested_try_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(x):
    try:
        try:
            import readline
        except ImportError:
            readline = None
        else:
            import rlcompleter
    except ImportError:
        return
    try:
        if x:
            y = 1
    except ImportError:
        return
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let truthiness_load = ops
            .windows(3)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "x"
                ) && matches!(window[1].op, Instruction::ToBool)
                    && matches!(window[2].op, Instruction::PopJumpIfFalse { .. })
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing if x truthiness load: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(truthiness_load[0].op, Instruction::LoadFast { .. }),
            "CPython flowgraph.c leaves an empty try-end label before this successor block, so optimize_load_fast() does not borrow the if-test load: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn nested_finally_handler_try_end_keeps_return_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(sys):
    try:
        import _testinternalcapi
        depth = _testinternalcapi.get_recursion_depth()
    except (ImportError, RecursionError) as exc:
        try:
            depth = 0
            frame = sys._getframe()
            while frame is not None:
                depth += 1
                frame = frame.f_back
        finally:
            frame = None
    return max(depth - 1, 1)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let depth_load = ops
            .windows(3)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "depth"
                ) && matches!(window[1].op, Instruction::LoadSmallInt { .. })
                    && matches!(window[2].op, Instruction::BinaryOp { .. })
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing return depth load: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(depth_load[0].op, Instruction::LoadFast { .. }),
            "CPython flowgraph.c preserves an empty try-end label before this return block, so optimize_load_fast() leaves depth strong: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn try_except_finally_exit_label_keeps_return_load_fast_strong() {
        let code = compile_exec(
            r#"
def f():
    global _importing_zlib
    if _importing_zlib:
        _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE')
        raise ZipImportError("can't decompress data; zlib not available")

    _importing_zlib = True
    try:
        from zlib import decompress
    except Exception:
        _bootstrap._verbose_message('zipimport: zlib UNAVAILABLE')
        raise ZipImportError("can't decompress data; zlib not available")
    finally:
        _importing_zlib = False

    _bootstrap._verbose_message('zipimport: zlib available')
    return decompress
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let return_load = ops
            .windows(2)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "decompress"
                ) && matches!(window[1].op, Instruction::ReturnValue)
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing return decompress load: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(return_load[0].op, Instruction::LoadFast { .. }),
            "CPython codegen_try_finally() emits a JUMP_NO_INTERRUPT to an empty exit label after the normal finally body, and flowgraph.c::optimize_load_fast() does not fall through an empty block: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn bare_except_finally_exit_label_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(self):
    hit = False
    try:
        pass
    except:
        hit = True
    finally:
        done = True
    self.assertFalse(hit)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let assert_false = ops
            .windows(3)
            .find(|window| {
                let self_arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                let attr_arg = OpArg::new(u32::from(u8::from(window[1].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(self_arg))] == "self"
                ) && matches!(
                    window[1].op,
                    Instruction::LoadAttr { namei }
                        if f.names[usize::try_from(namei.get(attr_arg).name_idx()).unwrap()]
                            == "assertFalse"
                ) && matches!(
                    window[2].op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. }
                )
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing assertFalse call: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(assert_false[0].op, Instruction::LoadFast { .. })
                && matches!(assert_false[2].op, Instruction::LoadFast { .. }),
            "CPython codegen_try_finally() wraps codegen_try_except(); with a bare handler, the normal finally body jumps to an empty exit label, and flowgraph.c::optimize_load_fast() does not fall through that empty block: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn typed_except_finally_fallthrough_keeps_successor_load_fast_borrow() {
        let code = compile_exec(
            r#"
def f(self):
    hit = False
    try:
        pass
    except Exception:
        hit = True
    finally:
        done = True
    self.assertFalse(hit)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let assert_false = ops
            .windows(3)
            .find(|window| {
                let self_arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                let attr_arg = OpArg::new(u32::from(u8::from(window[1].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(self_arg))] == "self"
                ) && matches!(
                    window[1].op,
                    Instruction::LoadAttr { namei }
                        if f.names[usize::try_from(namei.get(attr_arg).name_idx()).unwrap()]
                            == "assertFalse"
                ) && matches!(
                    window[2].op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. }
                )
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing assertFalse call: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(assert_false[0].op, Instruction::LoadFastBorrow { .. })
                && matches!(assert_false[2].op, Instruction::LoadFastBorrow { .. }),
            "CPython typed-handler fallthrough keeps this successor reachable for optimize_load_fast(), so the loads remain borrowed: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn bare_except_finally_no_exception_shares_return_target() {
        let code = compile_exec(
            "\
def func():
    try:
        2
    except:
        4
    finally:
        6
",
        );
        let f = find_code(&code, "func").expect("missing func code");
        let ops = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect::<Vec<_>>();
        let first_push_exc = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing PushExcInfo");
        let returns_before_handler = ops[..first_push_exc]
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();

        assert_eq!(
            returns_before_handler, 1,
            "CPython codegen_try_finally() wraps codegen_try_except(); the bare handler jumps back to the normal finally return target instead of forcing duplicate_end_returns() to create a Rust-only return copy, got ops={ops:?}"
        );
    }

    #[test]
    fn for_exhaustion_assert_false_message_borrows_load_fast() {
        let code = compile_exec(
            r#"
def f(arg, opcode):
    for i, nb_op in enumerate(opcode._nb_ops):
        if arg == nb_op[0]:
            return i
    assert False, f"{arg} is not a valid BINARY_OP argument."
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let assertion_arg_load = ops
            .windows(2)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "arg"
                ) && matches!(window[1].op, Instruction::FormatSimple)
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing assertion message arg load: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(assertion_arg_load[0].op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_assert() emits AssertionError directly after the failing test, so flowgraph.c::optimize_load_fast() visits the assertion message block: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn try_except_else_conditional_join_borrows_else_receiver() {
        let code = compile_exec(
            r#"
def f(self):
    try:
        if not self.result_is_file() or not self.sendfile():
            for data in self.result:
                self.write(data)
            self.finish_content()
    except:
        if hasattr(self.result, 'close'):
            self.result.close()
        raise
    else:
        self.close()
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let else_close_load = ops
            .windows(6)
            .find(|window| {
                let load_arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                let attr_arg = OpArg::new(u32::from(u8::from(window[1].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(load_arg))] == "self"
                ) && matches!(
                    window[1].op,
                    Instruction::LoadAttr { namei }
                        if f.names[usize::try_from(namei.get(attr_arg).name_idx()).unwrap()]
                            == "close"
                ) && matches!(window[2].op, Instruction::Call { .. })
                    && matches!(window[3].op, Instruction::PopTop)
                    && matches!(window[4].op, Instruction::LoadConst { .. })
                    && matches!(window[5].op, Instruction::ReturnValue)
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing else self.close return sequence: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });
        assert!(
            matches!(else_close_load[0].op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_try_except() emits Try.orelse directly with VISIT_SEQ(), so flowgraph.c::optimize_load_fast() reaches the else self.close receiver: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn try_finally_exit_label_reuses_empty_block_for_borrow() {
        let code = compile_exec(
            r#"
def f(self, exc):
    try:
        end_time = self.get_time()
    finally:
        result = self.context.__exit__(*exc)
    self.seconds = end_time - self.start_time
    return result
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();
        let seconds_store = ops
            .windows(5)
            .find(|window| {
                let load_pair = OpArg::new(u32::from(u8::from(window[0].arg)));
                let self_load = OpArg::new(u32::from(u8::from(window[3].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFastLoadFast { var_nums }
                        | Instruction::LoadFastBorrowLoadFastBorrow { var_nums }
                        if {
                            let (left, right) = var_nums.get(load_pair).indexes();
                            f.varnames[usize::from(left)] == "end_time"
                                && f.varnames[usize::from(right)] == "self"
                        }
                ) && matches!(window[1].op, Instruction::LoadAttr { .. })
                    && matches!(window[2].op, Instruction::BinaryOp { .. })
                    && matches!(
                        window[3].op,
                        Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                            if f.varnames[usize::from(var_num.get(self_load))] == "self"
                    )
                    && matches!(window[4].op, Instruction::StoreAttr { .. })
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing self.seconds store sequence: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });
        let return_result = ops
            .windows(2)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "result"
                ) && matches!(window[1].op, Instruction::ReturnValue)
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing result return sequence: {:?}",
                    ops.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(
                seconds_store[0].op,
                Instruction::LoadFastBorrowLoadFastBorrow { .. }
            ) && matches!(seconds_store[3].op, Instruction::LoadFastBorrow { .. })
                && matches!(return_result[0].op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_try_finally() emits JUMP_NO_INTERRUPT to the exit label, and flowgraph.c labels the current empty block instead of inserting a b_next barrier before following code: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn with_tail_while_true_break_successor_uses_strong_load() {
        let code = compile_exec(
            r#"
def f(self, cm):
    with cm as out:
        while 1:
            data = out.read()
            if not data:
                break
    self.close()
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let close_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "close"
                }
                _ => false,
            })
            .expect("missing close load");

        assert!(
            matches!(
                instructions[close_attr - 1].op,
                Instruction::LoadFast { .. }
            ),
            "CPython codegen_while() emits USE_LABEL(end) for the tail break target before codegen_with_inner() emits normal __exit__ cleanup, so flowgraph.c::optimize_load_fast() leaves the successor receiver strong: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn folded_ifexp_nested_in_call_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(self, g):
    self.x = g(self.y, optimization='' if __debug__ else 1)
    self.close()
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let close_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "close"
                }
                _ => false,
            })
            .expect("missing close load");

        assert!(
            matches!(
                instructions[close_attr - 1].op,
                Instruction::LoadFast { .. }
            ),
            "CPython codegen_ifexp() emits USE_LABEL(end); with a folded conditional nested in a larger stack expression, flowgraph.c::optimize_load_fast() sees an empty end block and does not visit the successor loads: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn folded_ifexp_assignment_before_with_keeps_context_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(self, cm):
    optlevel = 1 if __debug__ else 0
    with cm as t:
        self.use(t, optlevel)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_exit = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadSpecial { method } => {
                    method.get(OpArg::new(u32::from(u8::from(unit.arg)))) == SpecialMethod::Exit
                }
                _ => false,
            })
            .expect("missing __exit__ load");
        let cm_load = (0..first_exit)
            .rev()
            .find(|idx| {
                let arg = OpArg::new(u32::from(u8::from(instructions[*idx].arg)));
                matches!(
                    instructions[*idx].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "cm"
                )
            })
            .expect("missing cm load before __exit__");

        assert!(
            matches!(instructions[cm_load].op, Instruction::LoadFast { .. }),
            "CPython codegen_ifexp() emits USE_LABEL(end), then codegen_with_inner() starts the with header after that empty block; flowgraph.c::optimize_load_fast() does not push fallthrough successors from empty blocks, so the context manager load stays strong: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn folded_ifexp_assignment_keeps_later_statement_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(self, x):
    optlevel = 1 if __debug__ else 0
    ext = '.pyc'
    self.use(x, ext)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let use_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "use"
                }
                _ => false,
            })
            .expect("missing use load");

        assert!(
            matches!(instructions[use_attr - 1].op, Instruction::LoadFast { .. }),
            "CPython codegen_ifexp() emits USE_LABEL(end) for the folded assignment; flowgraph.c::optimize_load_fast() does not push fallthrough from the empty end block, so the next statement receiver stays strong: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn const_assignment_before_with_keeps_context_load_fast_borrowed() {
        let code = compile_exec(
            r#"
def f(self, cm):
    optlevel = 1
    with cm as t:
        self.use(t, optlevel)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_exit = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadSpecial { method } => {
                    method.get(OpArg::new(u32::from(u8::from(unit.arg)))) == SpecialMethod::Exit
                }
                _ => false,
            })
            .expect("missing __exit__ load");
        let cm_load = (0..first_exit)
            .rev()
            .find(|idx| {
                let arg = OpArg::new(u32::from(u8::from(instructions[*idx].arg)));
                matches!(
                    instructions[*idx].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "cm"
                )
            })
            .expect("missing cm load before __exit__");

        assert!(
            matches!(instructions[cm_load].op, Instruction::LoadFastBorrow { .. }),
            "without CPython's folded if-expression end label, flowgraph.c::optimize_load_fast() sees the following with header in the same reachable state and borrows the context manager load: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn if_end_label_reuse_allows_following_return_borrow() {
        let code = compile_exec(
            r#"
def f(data):
    msgids = []
    reading_msgid = False
    cur_msgid = []
    for line in data.split('\n'):
        if reading_msgid:
            if line.startswith('"'):
                cur_msgid.append(line.strip('"'))
            else:
                msgids.append('\n'.join(cur_msgid))
                cur_msgid = []
                reading_msgid = False
                continue
        if line.startswith('msgid '):
            line = line[len('msgid '):]
            cur_msgid.append(line.strip('"'))
            reading_msgid = True
    else:
        if reading_msgid:
            msgids.append('\n'.join(cur_msgid))

    return msgids
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let return_load = instructions
            .windows(2)
            .find(|window| {
                let arg = OpArg::new(u32::from(u8::from(window[0].arg)));
                matches!(
                    window[0].op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(var_num.get(arg))] == "msgids"
                ) && matches!(window[1].op, Instruction::ReturnValue)
            })
            .unwrap_or_else(|| {
                panic!(
                    "missing return msgids sequence: {:?}",
                    instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
                )
            });

        assert!(
            matches!(return_load[0].op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_if() ends with USE_LABEL(end), and flowgraph.c::cfg_builder_current_block_is_terminated() reuses the current empty block for that label instead of leaving a b_next barrier before the following return: {:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn named_except_continue_resume_try_body_keeps_method_borrows() {
        let code = compile_exec(
            r#"
def f(self, block=True):
    if not block and not self.wait(timeout=0):
        return None
    while self.event_queue.empty():
        while True:
            try:
                self.push_char(self.read(1))
            except OSError as err:
                if err.errno == errno.EINTR:
                    if not self.event_queue.empty():
                        return self.event_queue.get()
                    else:
                        continue
                else:
                    raise
            else:
                break
    return self.event_queue.get()
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        let attr_idx = |name: &str| {
            instructions
                .iter()
                .position(|unit| match unit.op {
                    Instruction::LoadAttr { namei } => {
                        let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                        f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == name
                    }
                    _ => false,
                })
                .unwrap_or_else(|| panic!("missing {name} LOAD_ATTR"))
        };
        let push_char_idx = attr_idx("push_char");
        let read_idx = attr_idx("read");

        assert!(
            matches!(
                instructions[push_char_idx - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "named-except cleanup continue backedge should not deopt the protected try-body method receiver, got instructions={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(
                instructions[read_idx - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "nested protected try-body method receiver should remain borrowed like CPython, got instructions={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn boolop_or_shared_body_keeps_false_jump_before_loop_backedge() {
        let code = compile_exec(
            r#"
def f(value):
    digits = []
    for digit in value:
        if isinstance(digit, int) and 0 <= digit <= 9:
            if digits or digit != 0:
                digits.append(digit)
        else:
            raise ValueError
    return digits
"#,
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(11).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "OR-shared body should keep CPython last-condition false jump before the loop backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "OR-shared body should not be moved after the implicit loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn single_if_loop_backedge_keeps_true_body_fallthrough_backedge_shape() {
        let code = compile_exec(
            r##"
def f(buffer, pos, last_char):
    while pos > 0:
        pos -= 1
        if buffer[pos] == "#":
            last_char = None
    return last_char
"##,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "single-if loop tail should keep CPython true-body plus fallthrough-backedge shape, got ops={ops:?}",
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "single-if loop tail should not be inverted away from CPython shape, got ops={ops:?}",
        );
    }

    fn find_code<'a>(code: &'a CodeObject, name: &str) -> Option<&'a CodeObject> {
        if code.obj_name == name {
            return Some(code);
        }
        code.constants.iter().find_map(|constant| {
            if let ConstantData::Code { code } = constant {
                find_code(code, name)
            } else {
                None
            }
        })
    }

    fn find_direct_child_code<'a>(code: &'a CodeObject, name: &str) -> Option<&'a CodeObject> {
        code.constants.iter().find_map(|constant| {
            if let ConstantData::Code { code } = constant {
                (code.obj_name == name).then_some(code.as_ref())
            } else {
                None
            }
        })
    }

    #[test]
    fn annotated_multiline_function_body_keeps_def_firstlineno_like_cpython() {
        let code = compile_exec(
            r#"
a = 1
def f(
    x: a,
): ...
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        // CPython 3.14 codegen_function() computes firstlineno from the
        // FunctionDef before compiling annotations, then passes it to
        // codegen_function_body().
        assert_eq!(f.linetable.as_ref(), &[0x80, 0x00, 0xe1, 0x03, 0x06]);
    }

    #[test]
    fn annotation_scope_return_uses_function_location_like_cpython() {
        let code = compile_exec(
            r#"
def g():
    def f(x: not (int is int), /): ...
"#,
        );
        let g = find_code(&code, "g").expect("missing g code");
        let annotate = find_code(g, "__annotate__").expect("missing annotation code");
        // CPython 3.14 codegen_function_annotations() receives LOC(function)
        // and uses it for the annotation closure's BUILD_MAP/RETURN_VALUE and
        // for the parent MAKE_FUNCTION annotate sequence.
        assert_eq!(g.linetable.as_ref(), &[0x80, 0x00, 0xdf, 0x04, 0x26]);
        assert_eq!(
            annotate.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd7, 0x04, 0x26, 0xd1, 0x04, 0x26, 0x94, 0x23, 0x9c, 0x13, 0xd0, 0x0d,
                0x1d, 0xd1, 0x04, 0x26,
            ],
        );
    }

    #[test]
    fn starred_arg_annotation_unpack_uses_function_location_like_cpython() {
        let code = compile_exec("def f(*args: *Ts): pass\n");
        let annotate = find_code(&code, "__annotate__").expect("missing annotation code");

        // codegen_argannotation() visits `Ts` at the annotation
        // expression location, then emits UNPACK_SEQUENCE at LOC(function).
        assert_eq!(
            annotate.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd7, 0x00, 0x17, 0xd1, 0x00, 0x17, 0x8c, 0x62, 0xd3, 0x00, 0x17
            ],
        );
    }

    #[test]
    fn module_deferred_annotations_use_start_location_like_cpython() {
        let code = compile_exec(
            "\
import os
X: int
Y: str
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");

        // compile.c::start_location() passes the first module
        // statement location into _PyCodegen_Module(), and
        // codegen_process_deferred_annotations() uses that loc for annotation
        // scope setup, BUILD_MAP, STORE_SUBSCR, and RETURN_VALUE.
        assert_eq!(
            annotate.linetable.as_ref(),
            &[
                0x80, 0x00, 0x87, 0x09, 0x81, 0x09, 0xdf, 0x00, 0x06, 0x82, 0x06, 0x84, 0x33, 0x81,
                0x06, 0xf1, 0x03, 0x00, 0x01, 0x0a, 0xe7, 0x00, 0x06, 0x82, 0x06, 0x84, 0x33, 0x81,
                0x06, 0xf2, 0x05, 0x00, 0x01, 0x0a,
            ]
        );
    }

    #[test]
    fn super_method_call_kw_names_use_attribute_location_like_cpython() {
        let code = compile_exec(
            "\
class C:
    def f(self, x, y):
        super().__init__(
            x=x,
            y=y)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let call_kw_index = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::CallKw { .. }))
            .expect("missing CALL_KW");
        let (kw_names, (location, end_location)) = f
            .instructions
            .iter()
            .zip(&f.locations)
            .take(call_kw_index)
            .rev()
            .find(|(unit, _)| matches!(unit.op, Instruction::LoadConst { .. }))
            .expect("missing CALL_KW names tuple");

        assert!(
            matches!(kw_names.op, Instruction::LoadConst { .. }),
            "expected keyword names tuple before CALL_KW"
        );
        assert_eq!(
            (location.line.get(), end_location.line.get()),
            (3, 3),
            "CPython maybe_optimize_method_call() passes the updated method-attribute loc into codegen_call_simple_kw_helper()"
        );
    }

    #[test]
    fn multiline_super_method_load_uses_expression_start_location_like_cpython() {
        let code = compile_exec(
            "\
class C:
    def f(self):
        return super(
        ).m()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_super_index = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadSuperAttr { namei } => namei
                    .get(OpArg::new(u32::from(u8::from(unit.arg))))
                    .is_load_method(),
                _ => false,
            })
            .expect("missing LOAD_SUPER_METHOD");
        let (load_location, _) = f.locations[load_super_index];

        assert_eq!(
            load_location.line.get(),
            3,
            "CPython maybe_optimize_method_call() emits LOAD_SUPER_METHOD at LOC(meth), before updating to the attribute start"
        );
    }

    #[test]
    fn multiline_non_ascii_attribute_uses_cpython_unicode_length() {
        let code = compile_exec(
            "\
def f(obj):
    return (obj
        .é)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_attr_position = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::LoadAttr { .. }).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing LOAD_ATTR");

        assert_eq!(
            load_attr_position,
            (3, 11, 3, 12),
            "CPython update_start_location_to_match_attr() subtracts PyUnicode_GET_LENGTH(attr), not the UTF-8 byte length; Rust SourceLocation exposes the resulting columns as one-based"
        );
    }

    #[test]
    fn two_arg_super_attr_in_class_body_is_optimized_like_cpython() {
        let code = compile_exec(
            "\
class C:
    x = super(C, self).attr
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            class_code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadSuperAttr { .. })),
            "CPython can_optimize_super_call() does not require function scope for two-argument super()"
        );
    }

    #[test]
    fn module_super_symbol_blocks_zero_arg_super_optimization_like_cpython() {
        let code = compile_exec(
            "\
super
class C:
    def f(self):
        return super().attr
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadSuperAttr { .. })),
            "CPython can_optimize_super_call() rejects any top-level symbol-table entry for super"
        );
    }

    #[test]
    fn lambda_return_uses_body_location_like_cpython() {
        let code = compile_exec(
            "\
def outer():
    return lambda x: x if x else 1
",
        );
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");
        let return_positions: Vec<_> = lambda
            .instructions
            .iter()
            .zip(&lambda.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::ReturnValue).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert_eq!(
            return_positions,
            vec![(2, 22, 2, 35), (2, 22, 2, 35)],
            "CPython codegen_lambda() emits RETURN_VALUE at LOC(lambda body)"
        );
    }

    #[test]
    fn explicit_return_value_locations_match_cpython_codegen_return() {
        let code = compile_exec(
            "\
def dynamic(x):
    return x

def constant():
    return 1

def bare():
    return
",
        );

        let cases = [
            ("dynamic", vec![(2, 5, 2, 13)]),
            ("constant", vec![(5, 12, 5, 13)]),
            ("bare", vec![(8, 5, 8, 11)]),
        ];
        for (name, expected) in cases {
            let function = find_code(&code, name).expect("missing function code");
            let return_positions: Vec<_> = function
                .instructions
                .iter()
                .zip(&function.locations)
                .filter_map(|(unit, (location, end_location))| {
                    matches!(unit.op, Instruction::ReturnValue).then_some((
                        location.line.get(),
                        location.character_offset.get(),
                        end_location.line.get(),
                        end_location.character_offset.get(),
                    ))
                })
                .collect();

            assert_eq!(
                return_positions, expected,
                "CPython codegen_return() emits explicit return at loc for {name}"
            );
        }
    }

    #[test]
    fn continue_jump_keeps_statement_location_like_cpython() {
        let code = compile_exec(
            "\
def continues(xs):
    for x in xs:
        if x:
            continue
        use(x)
",
        );

        {
            let (name, expected_position) = ("continues", (4, 13, 4, 21));
            let function = find_code(&code, name).expect("missing function code");
            let jump_positions: Vec<_> = function
                .instructions
                .iter()
                .zip(&function.locations)
                .filter_map(|(unit, (location, end_location))| {
                    matches!(
                        unit.op,
                        Instruction::JumpForward { .. } | Instruction::JumpBackward { .. }
                    )
                    .then_some((
                        location.line.get(),
                        location.character_offset.get(),
                        end_location.line.get(),
                        end_location.character_offset.get(),
                    ))
                })
                .collect();

            assert!(
                jump_positions.contains(&expected_position),
                "CPython codegen_continue() emits final jump at statement loc for {name}, got {jump_positions:?}"
            );
        }
    }

    #[test]
    fn not_compare_uses_unary_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self, other):
    return not self == other
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // CPython 3.14 parses the Compare inside UnaryOp(Not) with the
        // UnaryOp start location, so codegen_compare() emits COMPARE_OP at
        // the full "not self == other" range before flowgraph folds TO_BOOL.
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0f, 0x13, 0xd2, 0x0b, 0x1c, 0xd0, 0x04, 0x1c,
            ]
        );
    }

    #[test]
    fn not_chained_compare_keeps_compare_location_like_cpython() {
        let code = compile_exec(
            "\
def f(c):
    return not (b\" \" <= c <= b\"~\")
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // CPython's single Compare under UnaryOp(Not) includes "not" in the
        // Compare range, but chained comparisons keep their inner range for
        // compare scaffolding and only use the UnaryOp range for TO_BOOL and
        // UNARY_NOT.
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x10, 0x14, 0x98, 0x01, 0xd7, 0x10, 0x21, 0xd4, 0x10, 0x21, 0x98,
                0x54, 0xd1, 0x10, 0x21, 0xd4, 0x0b, 0x22, 0xd0, 0x04, 0x22, 0xd1, 0x10, 0x21, 0xd4,
                0x0b, 0x22, 0xd0, 0x04, 0x22,
            ]
        );
    }

    #[test]
    fn type_param_scopes_use_cpython_locations() {
        let code = compile_exec("type BoundGenericAlias[X: int] = set[X]\n");
        let type_params = find_code(&code, "<generic parameters of BoundGenericAlias>")
            .expect("missing generic parameters code");
        let bound = find_direct_child_code(type_params, "X").expect("missing X bound code");
        let alias =
            find_direct_child_code(type_params, "BoundGenericAlias").expect("missing alias code");

        // CPython 3.14 codegen_type_params() emits type-parameter ops at
        // LOC(typeparam), bound/default evaluator ops at LOC(e), and type alias
        // body plumbing at LOC(s).
        assert_eq!(
            type_params.linetable.as_ref(),
            &[
                0xf8, 0x80, 0x00, 0xd0, 0x00, 0x27, 0x90, 0x76, 0x9b, 0x23, 0x93, 0x76, 0xd7, 0x00,
                0x27, 0xd1, 0x00, 0x27,
            ],
        );
        assert_eq!(
            bound.linetable.as_ref(),
            &[0x80, 0x00, 0x9f, 0x23, 0x9e, 0x23]
        );
        assert_eq!(
            alias.linetable.as_ref(),
            &[
                0xf8, 0x80, 0x00, 0xd7, 0x00, 0x27, 0xd0, 0x00, 0x27, 0xa4, 0x13, 0xa0, 0x51, 0xa5,
                0x16, 0xd0, 0x00, 0x27,
            ],
        );
    }

    #[test]
    fn typealias_value_scope_has_single_return_like_cpython() {
        let code = compile_exec("type Alias = int\n");
        let alias = find_direct_child_code(&code, "Alias").expect("missing alias code");
        let return_count = alias
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            return_count, 1,
            "CPython codegen_typealias_body() emits one RETURN_VALUE and assembles with addNone=0, got instructions={:?}",
            alias.instructions
        );
    }

    #[test]
    fn generic_typealias_wrapper_return_uses_alias_location_like_cpython() {
        let code = compile_exec("type A[T] = T\n");
        let type_params =
            find_code(&code, "<generic parameters of A>").expect("missing type params code");

        // codegen_typealias() assembles the generic-parameters
        // wrapper with addNone=0 after codegen_typealias_body() leaves the type
        // alias object on the stack. The final RETURN_VALUE keeps LOC(type alias).
        assert_eq!(
            type_params.linetable.as_ref(),
            &[
                0xf8, 0x80, 0x00, 0x80, 0x0d, 0x84, 0x71, 0x87, 0x0d, 0x81, 0x0d
            ],
        );
    }

    #[test]
    fn type_param_bound_scope_has_single_return_like_cpython() {
        let code = compile_exec("type Alias[T: int] = T\n");
        let type_params =
            find_code(&code, "<generic parameters of Alias>").expect("missing type params code");
        let bound = find_direct_child_code(type_params, "T").expect("missing T bound code");
        let return_count = bound
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            return_count, 1,
            "CPython codegen_type_param_bound_or_default() emits one explicit RETURN_VALUE before OptimizeAndAssemble(addNone=1), got instructions={:?}",
            bound.instructions
        );
    }

    #[test]
    fn class_body_scope_has_single_return_like_cpython() {
        let code = compile_exec("class C:\n    pass\n");
        let class_code = find_code(&code, "C").expect("missing class code");
        let return_count = class_code
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            return_count, 1,
            "CPython codegen_class_body() emits one explicit RETURN_VALUE before OptimizeAndAssemble(addNone=1), got instructions={:?}",
            class_code.instructions
        );
    }

    #[test]
    fn generic_function_annotation_scope_uses_function_location_like_cpython() {
        let code = compile_exec("def f[T](x: int): ...\n");
        let type_params =
            find_code(&code, "<generic parameters of f>").expect("missing type params code");
        let annotate =
            find_direct_child_code(type_params, "__annotate__").expect("missing annotation code");

        // CPython 3.14 passes LOC(function) into codegen_function_annotations(),
        // even when the annotation closure is emitted inside the generic
        // parameters scope after codegen_type_params().
        assert_eq!(
            annotate.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd7, 0x00, 0x15, 0xd1, 0x00, 0x15, 0x8c, 0x43, 0xd1, 0x00, 0x15,
            ],
        );
    }

    #[test]
    fn decorated_generic_function_type_params_use_decorator_firstlineno_like_cpython() {
        let code = compile_exec(
            "\
def deco(obj): return obj
@deco
def f[T](): pass
",
        );
        let type_params =
            find_code(&code, "<generic parameters of f>").expect("missing type params code");

        // codegen_function() passes firstlineno, not LOC(s).lineno, to
        // the generic-parameters scope.
        assert_eq!(type_params.first_line_number.unwrap().get(), 2);
    }

    #[test]
    fn generic_class_type_params_store_uses_class_location_like_cpython() {
        let code = compile_exec(
            "\
def outer():
    class X[T]: ...
",
        );
        let type_params =
            find_code(&code, "<generic parameters of X>").expect("missing type params code");

        // CPython 3.14 codegen_class() calls codegen_type_params(), then stores
        // the resulting .type_params cell with codegen_nameop(c, LOC(class), ...).
        assert_eq!(
            type_params.linetable.as_ref(),
            &[
                0xf8, 0x80, 0x00, 0x8c, 0x41, 0x87, 0x4f, 0x87, 0x4f, 0x80, 0x4f,
            ]
        );
    }

    #[test]
    fn generic_class_wrapper_ops_use_class_location_like_cpython() {
        let code = compile_exec(
            "\
def f():
    class X[T](tuple):
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let wrapper_positions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Resume { .. }))
            .take(4)
            .zip(f.locations.iter().filter(|_| true).skip(1))
            .map(|(unit, (location, end_location))| {
                (
                    unit.op,
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                )
            })
            .collect();
        assert_eq!(
            wrapper_positions
                .iter()
                .map(|(_, line, col, end_line, end_col)| (*line, *col, *end_line, *end_col))
                .collect::<Vec<_>>(),
            vec![(2, 5, 3, 13); 4],
            "CPython codegen_class() emits type-params wrapper closure, PUSH_NULL, and CALL at LOC(class)"
        );

        let type_params =
            find_code(f, "<generic parameters of X>").expect("missing generic parameters code");
        let generic_base_position = type_params
            .instructions
            .iter()
            .zip(&type_params.locations)
            .find_map(|(unit, (location, end_location))| {
                let Instruction::LoadFastBorrow { var_num } = unit.op else {
                    return None;
                };
                let idx = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
                let localsplus = type_params
                    .varnames
                    .iter()
                    .chain(type_params.cellvars.iter())
                    .chain(type_params.freevars.iter())
                    .collect::<Vec<_>>();
                localsplus
                    .get(usize::from(idx))
                    .is_some_and(|name| name.as_str() == ".generic_base")
                    .then_some((
                        location.line.get(),
                        location.character_offset.get(),
                        end_location.line.get(),
                        end_location.character_offset.get(),
                    ))
            })
            .expect("missing .generic_base load");
        assert_eq!(
            generic_base_position,
            (2, 5, 3, 13),
            "CPython codegen_class() injects .generic_base with LOC(class)"
        );
    }

    #[test]
    fn try_except_else_finally_child_scopes_follow_cpython_symbol_order() {
        let code = compile_exec(
            "\
def f(x):
    try:
        pass
    except Exception:
        y = 1
        def h():
            return y
    else:
        def e():
            return x
    finally:
        def z():
            return x
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let h = find_code(f, "h").expect("missing handler function code");
        let e = find_code(f, "e").expect("missing else function code");
        let z = find_code(f, "z").expect("missing finally function code");

        assert_eq!(
            h.freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["y"],
            "handler child scope should consume the handler symbol table"
        );
        assert_eq!(
            e.freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["x"],
            "else child scope should be consumed before handler scopes, matching CPython codegen_try_except()"
        );
        assert_eq!(
            z.freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["x"],
            "finally child scope should remain after body/else/handler scopes"
        );
    }

    #[test]
    fn try_star_child_scopes_follow_codegen_order_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    try:
        pass
    except* Exception:
        y = 1
        def h():
            return y
    else:
        def e():
            return x
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let h = find_code(f, "h").expect("missing except* handler function code");
        let e = find_code(f, "e").expect("missing else function code");

        assert_eq!(
            h.freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["y"],
            "except* handler child scope should consume handler symbol table before else"
        );
        assert_eq!(
            e.freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["x"],
            "except* else child scope should be consumed after handler scopes, matching CPython codegen_try_star_except()"
        );
    }

    #[test]
    fn function_default_and_decorator_child_scopes_follow_cpython_symbol_order() {
        fn direct_child_codes<'a>(code: &'a CodeObject, name: &str) -> Vec<&'a CodeObject> {
            code.constants
                .iter()
                .filter_map(|constant| {
                    if let ConstantData::Code { code } = constant
                        && code.obj_name == name
                    {
                        Some(code.as_ref())
                    } else {
                        None
                    }
                })
                .collect()
        }

        let code = compile_exec(
            "\
def outer(x, deco):
    @(lambda f: deco(f))
    def inner(a=(lambda: x)()):
        return a
",
        );
        let outer = find_code(&code, "outer").expect("missing outer function code");
        let lambdas = direct_child_codes(outer, "<lambda>");

        assert_eq!(lambdas.len(), 2);
        assert_eq!(
            lambdas[0]
                .freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["deco"],
            "decorator lambda is emitted first by codegen_function()"
        );
        assert_eq!(
            lambdas[1]
                .freevars
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["x"],
            "default lambda should still consume the default symbol table"
        );
    }

    #[test]
    fn decorated_generic_class_type_params_use_decorator_firstlineno_like_cpython() {
        let code = compile_exec(
            "\
def deco(obj): return obj
@deco
class C[T]: pass
",
        );
        let type_params =
            find_code(&code, "<generic parameters of C>").expect("missing type params code");

        // codegen_class() also enters the generic-parameters scope with
        // firstlineno, which is the first decorator line when decorators exist.
        assert_eq!(type_params.first_line_number.unwrap().get(), 2);
    }

    #[test]
    fn class_deferred_annotations_use_class_body_location_like_cpython() {
        let code = compile_exec(
            r#"
class C:
    "doc"
    x: int
"#,
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        // CPython 3.14 calls codegen_body(c, loc, ...) from codegen_class_body()
        // with LOCATION(firstlineno, firstlineno, 0, 0). Deferred annotation
        // closure setup and following artificial class tail inherit that class
        // body location, not the annotation expression location.
        assert_eq!(
            class_code.linetable.as_ref(),
            &[
                0xf8, 0x87, 0x00, 0x80, 0x00, 0xd9, 0x04, 0x09, 0xf7, 0x03, 0x00, 0x01, 0x01, 0x83,
                0x00,
            ],
        );
    }

    #[test]
    fn future_annotation_string_uses_annotation_location_like_cpython() {
        let code = compile_exec("from __future__ import annotations\nclass Bar:\n    foo: Foo\n");
        let class_code = find_code(&code, "Bar").expect("missing class code");

        // CPython 3.14 codegen_annassign() calls codegen_visit_annexpr(),
        // which emits the stringized annotation at LOC(annotation), then emits
        // the __annotations__ store sequence at LOC(AnnAssign).
        assert_eq!(
            class_code.linetable.as_ref(),
            &[0x87, 0x00, 0xd8, 0x09, 0x0c, 0x87, 0x48]
        );
    }

    #[test]
    fn lambda_dict_literal_ops_use_dict_location_like_cpython() {
        let code = compile_exec(
            "\
f = lambda data: {'x': data}
g = lambda i: {**i}
",
        );
        let f = find_code(&code, "<lambda>").expect("missing f lambda code");
        let g = code
            .constants
            .iter()
            .filter_map(|constant| {
                if let ConstantData::Code { code } = constant {
                    (code.obj_name == "<lambda>").then_some(code.as_ref())
                } else {
                    None
                }
            })
            .nth(1)
            .expect("missing g lambda code");

        // CPython 3.14 codegen_dict()/codegen_subdict() uses LOC(dict) for
        // BUILD_MAP, MAP_ADD, and DICT_UPDATE, so the lambda RETURN_VALUE
        // inherits the full dict literal location after compiling its body.
        assert_eq!(
            f.linetable.as_ref(),
            &[0x80, 0x00, 0x90, 0x23, 0x90, 0x74, 0x91, 0x1b]
        );
        assert_eq!(
            g.linetable.as_ref(),
            &[0x80, 0x00, 0x88, 0x65, 0x90, 0x11, 0x89, 0x65]
        );
    }

    #[test]
    fn dict_unpacking_large_regular_run_uses_subdict_chunks_like_cpython() {
        let pairs = (0..17)
            .map(|i| format!("{i}: {i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let source = format!("def f(x):\n    return {{{pairs}, **x}}\n");
        let code = compile_exec(&source);
        let f = find_code(&code, "f").expect("missing f code");
        let first_dict_update = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::DictUpdate { .. }))
            .expect("missing DICT_UPDATE");
        let prefix = &f.instructions[..first_dict_update];
        let build_map_args: Vec<_> = prefix
            .iter()
            .filter_map(|unit| {
                matches!(unit.op, Instruction::BuildMap { .. }).then_some(u8::from(unit.arg))
            })
            .collect();
        let map_adds = prefix
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::MapAdd { .. }))
            .count();

        assert_eq!(
            build_map_args,
            vec![0],
            "CPython codegen_dict() routes a 17-pair run before ** through codegen_subdict(), got instructions={:?}",
            f.instructions
        );
        assert_eq!(
            map_adds, 17,
            "CPython codegen_subdict() uses MAP_ADD for all 17 pairs before **, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn class_function_like_scopes_set_method_flag_like_cpython() {
        let code = compile_exec_with_options(
            r#"
class C:
    def m(self):
        pass

    async def am(self):
        pass

    f = lambda self: self
    y = (i for i in ())

def f():
    pass
"#,
            CompileOpts::default(),
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let method = find_code(class_code, "m").expect("missing method code");
        let async_method = find_code(class_code, "am").expect("missing async method code");
        let lambda = find_code(class_code, "<lambda>").expect("missing lambda code");
        let genexpr = find_code(class_code, "<genexpr>").expect("missing genexpr code");
        let module_function = find_code(&code, "f").expect("missing module function code");

        for code in [method, async_method, lambda, genexpr] {
            assert!(
                code.flags.contains(bytecode::CodeFlags::METHOD),
                "class-scope function-like code should carry CO_METHOD like CPython 3.14, got {:?}",
                code.flags
            );
        }
        assert!(
            !module_function.flags.contains(bytecode::CodeFlags::METHOD),
            "module-scope function must not carry CO_METHOD"
        );
    }

    #[test]
    fn inlined_comprehension_lambda_in_class_is_not_method_like_cpython() {
        let code = compile_exec(
            "\
class C:
    def method(self):
        super()
        return __class__
    items = [(lambda: i) for i in range(5)]
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let lambda = find_code(class_code, "<lambda>").expect("missing lambda code");
        assert!(
            lambda.flags.contains(bytecode::CodeFlags::NESTED),
            "lambda under inlined class comprehension should stay nested"
        );
        assert!(
            !lambda.flags.contains(bytecode::CodeFlags::METHOD),
            "CPython creates this lambda while the current symtable block is the comprehension, not the class"
        );
    }

    #[test]
    fn class_inlined_comprehension_pushes_only_bound_locals_like_cpython() {
        let code = compile_exec(
            "\
class C:
    x = 1
    items = [x for i in range(3)]
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let cleared_names = class_code
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadFastAndClear { var_num } => {
                    let idx = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    Some(class_code.varnames[usize::from(idx)].as_str())
                }
                _ => None,
            })
            .collect::<Vec<_>>();

        assert!(
            cleared_names.contains(&"i"),
            "the comprehension iteration variable should be isolated, got {cleared_names:?}"
        );
        assert!(
            !cleared_names.contains(&"x"),
            "CPython applies the class-block special case while tweaking scopes, but codegen_push_inlined_comprehension_locals() runs after u_in_inlined_comp is set and only clears DEF_LOCAL names; got {cleared_names:?}"
        );
    }

    #[test]
    fn genexpr_implicit_iterator_is_not_posonly_like_cpython() {
        let code = compile_exec("x = (i for i in ())");
        let genexpr = find_code(&code, "<genexpr>").expect("missing genexpr code");

        assert_eq!(genexpr.arg_count, 1);
        assert_eq!(
            genexpr.posonlyarg_count, 0,
            "CPython codegen_comprehension() sets u_argcount=1 and leaves u_posonlyargcount=0"
        );
    }

    #[test]
    fn posonly_function_argcount_metadata_matches_cpython_assemble_split() {
        let code = compile_exec("def f(a, /, b):\n    pass\n");
        let func = find_code(&code, "f").expect("missing function code");

        assert_eq!(
            func.arg_count, 2,
            "CPython assemble.c exposes co_argcount as u_posonlyargcount + u_argcount"
        );
        assert_eq!(func.posonlyarg_count, 1);
        assert_eq!(func.varnames.as_ref(), &["a".to_owned(), "b".to_owned()]);
        assert_eq!(
            func.localspluskinds[0] & (CO_FAST_ARG_POS | CO_FAST_ARG_KW),
            CO_FAST_ARG_POS,
            "CPython compute_localsplus_info marks only u_posonlyargcount slots as positional-only"
        );
        assert_eq!(
            func.localspluskinds[1] & (CO_FAST_ARG_POS | CO_FAST_ARG_KW),
            CO_FAST_ARG_POS | CO_FAST_ARG_KW,
            "CPython compute_localsplus_info marks u_argcount slots after posonly as positional-or-keyword"
        );
    }

    #[test]
    fn async_generator_uses_cpython_async_generator_flag() {
        let code = compile_exec_with_options(
            r#"
def g():
    yield 1

async def c():
    return 1

async def ag():
    yield 1
"#,
            CompileOpts::default(),
        );
        let generator = find_code(&code, "g").expect("missing generator code");
        let coroutine = find_code(&code, "c").expect("missing coroutine code");
        let async_generator = find_code(&code, "ag").expect("missing async generator code");

        assert!(generator.flags.contains(bytecode::CodeFlags::GENERATOR));
        assert!(!generator.flags.contains(bytecode::CodeFlags::COROUTINE));
        assert!(
            !generator
                .flags
                .contains(bytecode::CodeFlags::ASYNC_GENERATOR)
        );

        assert!(coroutine.flags.contains(bytecode::CodeFlags::COROUTINE));
        assert!(!coroutine.flags.contains(bytecode::CodeFlags::GENERATOR));
        assert!(
            !coroutine
                .flags
                .contains(bytecode::CodeFlags::ASYNC_GENERATOR)
        );

        assert!(
            async_generator
                .flags
                .contains(bytecode::CodeFlags::ASYNC_GENERATOR)
        );
        assert!(
            !async_generator
                .flags
                .contains(bytecode::CodeFlags::GENERATOR)
        );
        assert!(
            !async_generator
                .flags
                .contains(bytecode::CodeFlags::COROUTINE)
        );
    }

    #[test]
    fn is_none_jump_preserves_cpython_const_order() {
        let code = compile_exec_with_options(
            r#"
def f(self, payload):
    "doc"
    if self.x is None:
        self.x = [payload]
    else:
        raise TypeError("bad")
"#,
            CompileOpts::default(),
        );
        let function = find_code(&code, "f").expect("missing function code");
        assert!(
            matches!(
                function.constants.as_ref(),
                [
                    ConstantData::Str { value: doc },
                    ConstantData::None,
                    ConstantData::Str { value: message },
                ] if doc.as_ref() == "doc" && message.as_ref() == "bad"
            ),
            "CPython registers None from the pre-folded `is None` comparison before the else-body string"
        );
    }

    #[test]
    fn stop_iteration_handler_starts_at_scope_start_resume_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def g():
    yield 1

async def c():
    return 1

x = (i for i in ())
"#,
            CompileOpts::default(),
        );

        fn assert_stop_iteration_table_starts_at_resume(code: &CodeObject) {
            let resume_idx = u32::try_from(
                code.instructions
                    .iter()
                    .position(|unit| {
                        matches!(
                            unit.op,
                            Instruction::Resume { context }
                                if matches!(
                                    context
                                        .get(OpArg::new(u32::from(u8::from(unit.arg))))
                                        .location(),
                                    oparg::ResumeLocation::AtFuncStart
                                )
                        )
                    })
                    .expect("missing function-start RESUME"),
            )
            .unwrap();
            let entries = bytecode::decode_exception_table(&code.exceptiontable);
            assert!(
                entries.iter().any(|entry| entry.start == resume_idx),
                "CPython codegen_wrap_in_stopiteration_handler() inserts SETUP_CLEANUP before RESUME so the StopIteration table starts at RESUME; resume_idx={resume_idx}, entries={entries:?}, instructions={:?}",
                code.instructions
            );
        }

        assert_stop_iteration_table_starts_at_resume(find_code(&code, "g").expect("missing g"));
        assert_stop_iteration_table_starts_at_resume(find_code(&code, "c").expect("missing c"));
        assert_stop_iteration_table_starts_at_resume(
            find_code(&code, "<genexpr>").expect("missing genexpr"),
        );
    }

    #[test]
    fn inlined_comprehension_cleanup_starts_at_result_build_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def f(self):
    return [k for k, v in self._headers]
"#,
            CompileOpts::default(),
        );
        let f = find_code(&code, "f").expect("missing f");
        let build_list_idx = u32::try_from(
            f.instructions
                .iter()
                .position(|unit| matches!(unit.op, Instruction::BuildList { .. }))
                .expect("missing BUILD_LIST"),
        )
        .unwrap();
        let entries = bytecode::decode_exception_table(&f.exceptiontable);
        assert!(
            entries.iter().any(|entry| {
                entry.start == build_list_idx && entry.depth == 3 && !entry.push_lasti
            }),
            "CPython codegen_push_inlined_comprehension_locals() emits SETUP_FINALLY before BUILD_LIST, so the virtual cleanup table starts at BUILD_LIST with saved locals depth; build_list_idx={build_list_idx}, entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn or_return_not_taken_before_jump_target_splits_exception_table_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def f(self, maintype):
    if maintype != "multipart" or not self.is_multipart():
        return
    yield 1
"#,
            CompileOpts::default(),
        );
        let f = find_code(&code, "f").expect("missing f");
        let not_taken_before_return = u32::try_from(
            f.instructions
                .windows(3)
                .position(|window| {
                    matches!(
                        window,
                        [
                            CodeUnit {
                                op: Instruction::NotTaken,
                                ..
                            },
                            CodeUnit {
                                op: Instruction::LoadConst { .. },
                                ..
                            },
                            CodeUnit {
                                op: Instruction::ReturnValue,
                                ..
                            },
                        ]
                    )
                })
                .expect("missing NOT_TAKEN before return"),
        )
        .unwrap();
        let return_load = not_taken_before_return + 1;
        let entries = bytecode::decode_exception_table(&f.exceptiontable);

        assert!(
            entries.iter().all(|entry| {
                not_taken_before_return < entry.start || not_taken_before_return >= entry.end
            }),
            "CPython normalize_jumps() can leave a NOT_TAKEN before a separately labelled jump target outside the generator StopIteration range; entries={entries:?}, instructions={:?}",
            f.instructions
        );
        assert!(
            entries
                .iter()
                .any(|entry| entry.start <= return_load && return_load < entry.end),
            "the return block after that NOT_TAKEN is still protected by the StopIteration handler; entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn loop_break_condition_splits_exception_table_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def f(start, items):
    if start:
        for x in items:
            if x == start:
                break
    yield 1
"#,
            CompileOpts::default(),
        );
        let f = find_code(&code, "f").expect("missing f");
        let break_jump = u32::try_from(
            f.instructions
                .windows(3)
                .position(|window| {
                    matches!(
                        window,
                        [
                            CodeUnit {
                                op: Instruction::PopJumpIfTrue { .. },
                                ..
                            },
                            CodeUnit {
                                op: Instruction::Cache,
                                ..
                            },
                            CodeUnit {
                                op: Instruction::NotTaken,
                                ..
                            },
                        ]
                    ) || matches!(
                        window,
                        [
                            CodeUnit {
                                op: Instruction::PopJumpIfTrue { .. },
                                ..
                            },
                            CodeUnit {
                                op: Instruction::NotTaken,
                                ..
                            },
                            CodeUnit {
                                op: Instruction::JumpBackward { .. },
                                ..
                            },
                        ]
                    )
                })
                .expect("missing loop break conditional jump"),
        )
        .unwrap();
        let entries = bytecode::decode_exception_table(&f.exceptiontable);

        assert!(
            entries
                .iter()
                .all(|entry| break_jump < entry.start || break_jump >= entry.end),
            "CPython normalize_jumps() leaves the loop-break conditional before the synthetic NOT_TAKEN/JUMP_BACKWARD block outside the StopIteration table; break_jump={break_jump}, entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn nested_ifexp_not_taken_splits_exception_table_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def f(flag, subparts):
    if flag:
        candidate = subparts[0] if subparts else None
    yield 1
"#,
            CompileOpts::default(),
        );
        let f = find_code(&code, "f").expect("missing f");
        let conditional_expr_not_taken = u32::try_from(
            f.instructions
                .iter()
                .enumerate()
                .find_map(|(idx, unit)| {
                    if !matches!(unit.op, Instruction::NotTaken) {
                        return None;
                    }
                    let prev = f.instructions[..idx]
                        .iter()
                        .rev()
                        .find(|unit| !matches!(unit.op, Instruction::Cache))?;
                    let mut following = f.instructions[idx + 1..]
                        .iter()
                        .filter(|unit| !matches!(unit.op, Instruction::Cache));
                    let next = following.next()?;
                    let after_next = following.next()?;
                    (matches!(prev.op, Instruction::PopJumpIfFalse { .. })
                        && matches!(next.op, Instruction::LoadFastBorrow { .. })
                        && matches!(after_next.op, Instruction::LoadSmallInt { .. }))
                    .then_some(idx)
                })
                .expect("missing conditional expression NOT_TAKEN"),
        )
        .unwrap();
        let body_start = conditional_expr_not_taken + 1;
        let entries = bytecode::decode_exception_table(&f.exceptiontable);

        assert!(
            entries.iter().all(|entry| {
                conditional_expr_not_taken < entry.start || conditional_expr_not_taken >= entry.end
            }),
            "CPython codegen_ifexp() uses a separate orelse label inside conditional statements, leaving the normalize_jumps NOT_TAKEN outside the StopIteration table; not_taken={conditional_expr_not_taken}, entries={entries:?}, instructions={:?}",
            f.instructions
        );
        assert!(
            entries
                .iter()
                .any(|entry| entry.start <= body_start && body_start < entry.end),
            "the conditional-expression body after that NOT_TAKEN remains protected; body_start={body_start}, entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn bool_not_taken_after_conditional_yield_splits_like_cpython() {
        let code = compile_exec_with_options(
            r#"
def f(a, b, c):
    if a:
        yield 1
    if b:
        x = 2
    if c:
        x = 3
    yield 4
"#,
            CompileOpts::default(),
        );
        let f = find_code(&code, "f").expect("missing f");
        let split_not_taken = f
            .instructions
            .iter()
            .enumerate()
            .filter_map(|(idx, unit)| {
                if !matches!(unit.op, Instruction::NotTaken) {
                    return None;
                }
                let prev = f.instructions[..idx]
                    .iter()
                    .rev()
                    .find(|unit| !matches!(unit.op, Instruction::Cache))?;
                matches!(
                    prev.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
                .then(|| u32::try_from(idx).unwrap())
            })
            .nth(1)
            .expect("missing second bool conditional NOT_TAKEN");
        let entries = bytecode::decode_exception_table(&f.exceptiontable);

        assert!(
            entries
                .iter()
                .all(|entry| split_not_taken < entry.start || split_not_taken >= entry.end),
            "CPython labels exception targets before normalize_jumps(), so the general bool-jump NOT_TAKEN after a conditional yield is outside the StopIteration table; not_taken={split_not_taken}, entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    fn non_cache_instructions(code: &CodeObject) -> impl Iterator<Item = &CodeUnit> {
        code.instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
    }

    fn full_opargs_for(
        code: &CodeObject,
        mut predicate: impl FnMut(Instruction) -> bool,
    ) -> Vec<u32> {
        let mut extended = 0u32;
        let mut args = Vec::new();
        for unit in non_cache_instructions(code) {
            let byte = u32::from(u8::from(unit.arg));
            if matches!(unit.op, Instruction::ExtendedArg) {
                extended = (extended << 8) | byte;
                continue;
            }
            let oparg = (extended << 8) | byte;
            extended = 0;
            if predicate(unit.op) {
                args.push(oparg);
            }
        }
        args
    }

    fn varname_index(code: &CodeObject, name: &str) -> usize {
        code.varnames
            .iter()
            .position(|varname| varname.as_str() == name)
            .unwrap_or_else(|| panic!("missing {name} local"))
    }

    fn load_fast_ops_for_var(code: &CodeObject, name: &str) -> Vec<Instruction> {
        let var_idx = varname_index(code, name);
        non_cache_instructions(code)
            .filter_map(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    (usize::from(var_num) == var_idx).then_some(unit.op)
                }
                _ => None,
            })
            .collect()
    }

    fn load_fast_pair_ops_for_vars(
        code: &CodeObject,
        left_name: &str,
        right_name: &str,
    ) -> Vec<Instruction> {
        let left_idx = varname_index(code, left_name);
        let right_idx = varname_index(code, right_name);
        non_cache_instructions(code)
            .filter_map(|unit| {
                let var_nums = match unit.op {
                    Instruction::LoadFastLoadFast { var_nums }
                    | Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => var_nums,
                    _ => return None,
                };
                let (left, right) = var_nums
                    .get(OpArg::new(u32::from(u8::from(unit.arg))))
                    .indexes();
                (usize::from(left) == left_idx && usize::from(right) == right_idx)
                    .then_some(unit.op)
            })
            .collect()
    }

    fn count_strong_loads_for_vars(code: &CodeObject, names: &[&str]) -> usize {
        let var_indices = names
            .iter()
            .map(|name| varname_index(code, name))
            .collect::<Vec<_>>();
        non_cache_instructions(code)
            .filter(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let var_num = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    var_indices.contains(&usize::from(var_num))
                }
                _ => false,
            })
            .count()
    }

    fn count_strong_loads(code: &CodeObject) -> usize {
        non_cache_instructions(code)
            .filter(|unit| matches!(unit.op, Instruction::LoadFast { .. }))
            .count()
    }

    #[test]
    fn match_or_default_block_keeps_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(format, other):
    match format:
        case 1 | 2:
            return other
        case _:
            raise NotImplementedError(other)
"#,
        );
        let function = find_code(&code, "f").expect("missing function code");
        let loads = load_fast_ops_for_var(function, "other");
        assert!(
            matches!(
                loads.as_slice(),
                [
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadFast { .. },
                ]
            ),
            "CPython optimize_load_fast() keeps trailing OR-pattern default loads strong, got {loads:?}",
        );
    }

    #[test]
    fn match_nested_or_default_block_keeps_load_fast_strong() {
        let code = compile_exec(
            r#"
def f(format, other):
    match format:
        case [1 | 2, value]:
            return other
        case _:
            raise NotImplementedError(other)
"#,
        );
        let function = find_code(&code, "f").expect("missing function code");
        let loads = load_fast_ops_for_var(function, "other");
        assert!(
            loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython 3.14 optimize_load_fast() borrows nested OR-pattern default loads, got {loads:?}",
        );
    }

    #[test]
    fn match_success_next_location_preserves_pass_nop() {
        let code = compile_exec(
            r#"
def f(command):
    match command:
        case "":
            pass
        case _ as unknown:
            sink(unknown)
    return False
"#,
        );
        let function = find_code(&code, "f").expect("missing function code");
        let ops = non_cache_instructions(function)
            .map(|unit| unit.op)
            .collect::<Vec<_>>();
        assert!(
            ops.windows(3).any(|window| matches!(
                window,
                [
                    Instruction::PopTop,
                    Instruction::Nop,
                    Instruction::LoadConst { .. },
                ]
            )),
            "CPython NEXT_LOCATION keeps the pass NOP after match subject POP_TOP, got {ops:?}",
        );
    }

    #[test]
    fn match_subject_copy_uses_case_pattern_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case 1:
            return True
        case 2:
            return False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let copy_line = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, _))| {
                let Instruction::Copy { i } = unit.op else {
                    return None;
                };
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                (i.get(arg) == 1).then_some(location.line.get())
            })
            .expect("missing match subject COPY");
        assert_eq!(
            copy_line, 3,
            "CPython codegen_match_inner() emits ADDOP_I(c, LOC(m->pattern), COPY, 1)"
        );
    }

    #[test]
    fn match_or_alternative_copies_use_alternative_locations_like_cpython() {
        let code = compile_exec(
            "\
def f():
    x = False
    match 0:
        case 0 | 1 | 2 | 3:
            x = True
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x08, 0x0d, 0x80, 0x41, 0xd8, 0x0a, 0x0b, 0xdf, 0x0d, 0x0e, 0x97,
                0x11, 0x97, 0x51, 0x9f, 0x11, 0x88, 0x5d, 0xe0, 0x0b, 0x0c, 0x80, 0x48, 0xf0, 0x05,
                0x00, 0x0e, 0x1b, 0xd8, 0x10, 0x14, 0x88, 0x41, 0xd8, 0x0b, 0x0c, 0x80, 0x48,
            ],
            "CPython codegen_pattern_or() emits each alternative COPY with LOC(alt)"
        );
    }

    #[test]
    fn match_or_conflicting_bind_error_uses_or_pattern_location_like_cpython() {
        let error = compile_exec_error(
            "\
def f(x):
    match x:
        case (
            a
            | b
        ):
            pass
",
        );
        let location = error.location.expect("missing error location");
        assert_eq!(
            location.line.get(),
            4,
            "CPython codegen_pattern_or() reports alternative binding mismatches at LOC(p), not LOC(alt)"
        );
    }

    #[test]
    fn match_or_duplicate_store_error_uses_or_pattern_location_like_cpython() {
        let error = compile_exec_error(
            "\
def f(value):
    match value:
        case [
            x,
            (x | x),
        ]:
            pass
",
        );
        let location = error.location.expect("missing error location");
        assert_eq!(
            location.line.get(),
            5,
            "CPython codegen_pattern_or() reports merge-time duplicate stores at LOC(p)"
        );
    }

    #[test]
    fn match_success_jump_uses_no_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self):
    match 0:
        case 0:
            x = True
        case 0:
            x = False
    self.assertIs(x, True)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0a, 0x0b, 0xde, 0x0d, 0x0e, 0xd9, 0x10, 0x14, 0x89, 0x41, 0xdd,
                0x0d, 0x0e, 0xd8, 0x10, 0x15, 0x88, 0x41, 0xd8, 0x04, 0x08, 0x87, 0x4d, 0x81, 0x4d,
                0x90, 0x21, 0x90, 0x54, 0xd6, 0x04, 0x1a,
            ],
            "CPython codegen_match_inner() emits the success jump with NO_LOCATION"
        );
    }

    #[test]
    fn match_default_simple_guard_jump_uses_guard_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x, y):
    match x:
        case 0:
            return 1
        case _ if y:
            return 2
    return 3
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let guard_jump_location = f
            .instructions
            .iter()
            .enumerate()
            .find_map(|(idx, unit)| {
                let (Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }) =
                    unit.op
                else {
                    return None;
                };
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                if f.varnames[usize::from(var_num.get(arg))] != "y" {
                    return None;
                }
                f.instructions
                    .iter()
                    .zip(&f.locations)
                    .skip(idx + 1)
                    .take(8)
                    .find_map(|(unit, (location, _))| {
                        matches!(unit.op, Instruction::PopJumpIfFalse { .. }).then_some(*location)
                    })
            })
            .expect("missing default guard jump");

        assert_eq!(
            (
                guard_jump_location.line.get(),
                guard_jump_location.character_offset.get()
            ),
            (5, 19),
            "CPython codegen_jump_if() receives LOC(pattern), but the simple guard fallback emits TO_BOOL/jump at LOC(guard)"
        );
    }

    #[test]
    fn match_mapping_keys_scaffolding_uses_mapping_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self):
    x = {}
    y = None
    match x:
        case {0: 0}:
            y = 0
    self.assertIs(y, None)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x08, 0x0a, 0x80, 0x41, 0xd8, 0x08, 0x0c, 0x80, 0x41, 0xd8, 0x0a,
                0x0b, 0xdf, 0x0d, 0x13, 0x8f, 0x56, 0x8a, 0x56, 0x95, 0x11, 0x89, 0x56, 0xd8, 0x10,
                0x11, 0x89, 0x41, 0xf2, 0x03, 0x00, 0x0e, 0x14, 0xe0, 0x04, 0x08, 0x87, 0x4d, 0x81,
                0x4d, 0x90, 0x21, 0x90, 0x54, 0xd6, 0x04, 0x1a,
            ],
            "CPython codegen_pattern_mapping() returns to LOC(p) for BUILD_TUPLE/MATCH_KEYS scaffolding"
        );
    }

    #[test]
    fn match_mapping_rest_cleanup_uses_mapping_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case {
            0: _,
            **rest,
        }:
            return rest
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let rest_cleanup_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::BuildMap { .. }))
            .expect("missing BUILD_MAP");
        for expected in [
            "BUILD_MAP",
            "DICT_UPDATE",
            "DELETE_SUBSCR",
            "rest cleanup COPY",
            "rest cleanup SWAP",
        ] {
            let location = f
                .instructions
                .iter()
                .zip(&f.locations)
                .skip(rest_cleanup_start)
                .find_map(|(unit, (location, _))| {
                    let found = matches!(
                        (expected, unit.op),
                        ("BUILD_MAP", Instruction::BuildMap { .. })
                            | ("DICT_UPDATE", Instruction::DictUpdate { .. })
                            | ("DELETE_SUBSCR", Instruction::DeleteSubscr)
                            | ("rest cleanup COPY", Instruction::Copy { .. })
                            | ("rest cleanup SWAP", Instruction::Swap { .. })
                    );
                    found.then_some(*location)
                })
                .unwrap_or_else(|| panic!("missing {expected}"));
            assert_eq!(
                location.line.get(),
                3,
                "CPython codegen_pattern_mapping() emits {expected} with LOC(p)"
            );
        }
    }

    #[test]
    fn match_class_scaffolding_uses_class_pattern_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case bool(z):
            y = 0
    return y, z
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0a, 0x0b, 0xdc, 0x0d, 0x11, 0x8f, 0x57, 0x88, 0x57, 0xd8, 0x10,
                0x11, 0x88, 0x41, 0xd8, 0x0b, 0x0c, 0x88, 0x34, 0x80, 0x4b, 0xf0, 0x05, 0x00, 0x0e,
                0x15, 0xe0, 0x0b, 0x0c, 0x88, 0x61, 0x88, 0x34, 0x80, 0x4b,
            ],
            "CPython codegen_pattern_class() returns to LOC(p) after VISIT(cls)"
        );
    }

    #[test]
    fn match_class_wildcard_pop_uses_class_pattern_location_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case bool(
            _
        ):
            return True
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let unpack_index = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::UnpackSequence { .. }))
            .expect("missing class pattern UNPACK_SEQUENCE");
        let wildcard_pop_location = f
            .instructions
            .iter()
            .zip(&f.locations)
            .skip(unpack_index + 1)
            .find_map(|(unit, (location, _))| {
                matches!(unit.op, Instruction::PopTop).then_some(*location)
            })
            .expect("missing wildcard POP_TOP");
        assert_eq!(
            wildcard_pop_location.line.get(),
            3,
            "CPython codegen_pattern_class() emits wildcard POP_TOP with LOC(p)"
        );
    }

    #[test]
    fn while_try_body_layout_keeps_false_jump_to_anchor() {
        let code = compile_exec(
            r#"
def f(stack, itstack, node_to_stack_index):
    while True:
        while stack:
            try:
                node = itstack[-1]()
                break
            except StopIteration:
                del node_to_stack_index[stack.pop()]
                itstack.pop()
        else:
            break
"#,
        );
        let function = find_code(&code, "f").expect("missing function code");
        let ops = non_cache_instructions(function)
            .map(|unit| unit.op)
            .collect::<Vec<_>>();
        let stack_test = ops
            .windows(5)
            .find(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::Nop,
                    ]
                )
            })
            .unwrap_or_else(|| {
                panic!("expected CPython-style while/try false jump to anchor, got {ops:?}")
            });
        assert!(matches!(stack_test[2], Instruction::PopJumpIfFalse { .. }));
    }

    #[test]
    fn while_if_not_break_keeps_body_call() {
        let code = compile_exec(
            r#"
def f(waiters):
    while waiters:
        waiter = waiters.popleft()
        if not waiter.done():
            waiter.set_result(None)
            break
"#,
        );
        let function = find_code(&code, "f").expect("missing function code");
        let ops = non_cache_instructions(function)
            .map(|unit| unit.op)
            .collect::<Vec<_>>();
        assert!(
            ops.windows(4).any(|window| matches!(
                window,
                [
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::LoadAttr { .. },
                    Instruction::LoadConst { .. },
                    Instruction::Call { .. },
                ]
            )),
            "CPython keeps waiter.set_result(None) before the break, got {ops:?}",
        );
    }

    fn localsplus_name(code: &CodeObject, idx: usize) -> Option<&str> {
        if idx < code.varnames.len() {
            return Some(code.varnames[idx].as_str());
        }

        let mut extra_idx = idx - code.varnames.len();
        for cellvar in &code.cellvars {
            if !code.varnames.iter().any(|varname| varname == cellvar) {
                if extra_idx == 0 {
                    return Some(cellvar.as_str());
                }
                extra_idx -= 1;
            }
        }
        code.freevars.get(extra_idx).map(|name| name.as_str())
    }

    fn has_common_constant(code: &CodeObject, expected: bytecode::CommonConstant) -> bool {
        code.instructions.iter().any(|unit| match unit.op {
            Instruction::LoadCommonConstant { idx } => {
                idx.get(OpArg::new(u32::from(u8::from(unit.arg)))) == expected
            }
            _ => false,
        })
    }

    fn has_intrinsic_1(code: &CodeObject, expected: IntrinsicFunction1) -> bool {
        code.instructions.iter().any(|unit| match unit.op {
            Instruction::CallIntrinsic1 { func } => {
                func.get(OpArg::new(u32::from(u8::from(unit.arg)))) == expected
            }
            _ => false,
        })
    }

    #[test]
    fn trace_assert_true_try_pair() {
        let trace = compile_exec_late_cfg_trace(
            "\
try:
    assert True
except AssertionError as e:
    fail()
try:
    assert True, 'msg'
except AssertionError as e:
    fail()
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_for_unpack_list_literal() {
        let trace = compile_exec_late_cfg_trace(
            "\
result = []
for x, in [(1,), (2,), (3,)]:
    result.append(x)
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_break_in_finally_function() {
        let trace = compile_single_function_late_cfg_trace(
            "\
def f(self):
    count = 0
    while count < 2:
        count += 1
        try:
            pass
        finally:
            break
    self.assertEqual(count, 1)
",
            "f",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn import_originated_name_disables_method_call_optimization_even_with_local_import() {
        let code = compile_exec(
            "\
import warnings

def f(ch):
    import warnings
    warnings.warn(
        '\"\\\\%c\" is an invalid escape sequence' % ch
        if 0x20 <= ch < 0x7F
        else '\"\\\\x%02x\" is an invalid escape sequence' % ch,
        DeprecationWarning,
        stacklevel=2,
    )
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f.instructions.iter().map(|unit| unit.op).collect();
        let warn_attr = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing LOAD_ATTR for warnings.warn");
        let push_null = ops[warn_attr + 10..]
            .iter()
            .position(|op| matches!(op, Instruction::PushNull))
            .map(|idx| warn_attr + 10 + idx)
            .expect("expected PUSH_NULL after plain LOAD_ATTR");

        let load_attr = match f.instructions[warn_attr].op {
            Instruction::LoadAttr { namei } => namei.get(OpArg::new(u32::from(u8::from(
                f.instructions[warn_attr].arg,
            )))),
            _ => unreachable!(),
        };
        assert!(
            !load_attr.is_method(),
            "import-originated names should use plain LOAD_ATTR"
        );
        assert!(
            matches!(ops[push_null + 1], Instruction::LoadSmallInt { .. }),
            "expected warning message expression to start after PUSH_NULL, got ops={ops:?}"
        );
    }

    #[test]
    fn trace_constant_false_elif_chain() {
        let trace = compile_exec_late_cfg_trace(
            "\
if 0: pass
elif 0: pass
elif 0: pass
elif 0: pass
else: pass
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_multi_pass_suite() {
        let trace = compile_exec_late_cfg_trace(
            "\
if 1:
    #
    #
    #
    pass
    pass
    #
    pass
    #
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_single_compare_if() {
        let trace = compile_exec_late_cfg_trace(
            "\
if 1 == 1:
    pass
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_comparison_suite() {
        let trace = compile_exec_late_cfg_trace(
            "\
if 1: pass
x = (1 == 1)
if 1 == 1: pass
if 1 != 1: pass
if 1 < 1: pass
if 1 > 1: pass
if 1 <= 1: pass
if 1 >= 1: pass
if x is x: pass
if x is not x: pass
if 1 in (): pass
if 1 not in (): pass
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn trace_if_for_except_layout() {
        let trace = compile_exec_late_cfg_trace(
            "\
from sys import maxsize
if maxsize == 2147483647:
    for s in ('2147483648', '0o40000000000', '0x100000000', '0b10000000000000000000000000000000'):
        try:
            x = eval(s)
        except OverflowError:
            fail(\"OverflowError on huge integer literal %r\" % s)
elif maxsize == 9223372036854775807:
    pass
",
        );
        for (stage, dump) in trace {
            eprintln!("=== {stage} ===\n{dump}");
        }
    }

    #[test]
    fn break_in_finally_tail_loads_borrow_through_empty_fallthrough_block() {
        let code = compile_exec(
            "\
def f(self):
    count = 0
    while count < 2:
        count += 1
        try:
            pass
        finally:
            break
    self.assertEqual(count, 1)
",
        );
        let code = find_code(&code, "f").unwrap();
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::Call { .. }
                    ]
                )
            }),
            "{:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn plain_constant_bool_op_folds_to_selected_operand() {
        let code = compile_exec(
            "\
x = 1 or 2 or 3
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let folded_small_int = code.instructions.iter().any(|unit| {
            matches!(
                unit.op,
                Instruction::LoadSmallInt { i }
                    if i.get(OpArg::new(u32::from(u8::from(unit.arg)))) == 1
            )
        });
        let folded_const_one = code
            .instructions
            .iter()
            .find_map(|unit| match unit.op {
                Instruction::LoadConst { .. } => code.constants.get(usize::from(u8::from(unit.arg))),
                _ => None,
            })
            .is_some_and(|constant| {
                matches!(constant, ConstantData::Integer { value } if *value == BigInt::from(1))
            });

        assert!(
            folded_small_int || folded_const_one,
            "expected folded constant 1, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| {
                matches!(
                    op,
                    Instruction::Copy { .. }
                        | Instruction::ToBool
                        | Instruction::PopJumpIfTrue { .. }
                        | Instruction::PopJumpIfFalse { .. }
                )
            }),
            "plain constant BoolOp should not leave short-circuit scaffolding, got ops={ops:?}"
        );
    }

    #[test]
    fn taken_constant_boolop_load_const_uses_literal_location_like_cpython() {
        let code = compile_exec(
            "\
def and_false(x):
    return False and x

def or_true(x):
    return True or x
",
        );
        let and_false = find_code(&code, "and_false").expect("missing and_false code");
        let or_true = find_code(&code, "or_true").expect("missing or_true code");

        // CPython 3.14 codegen_boolop() VISITs the selected literal before the
        // short-circuit jump is optimized away, so the surviving LOAD_CONST
        // keeps the literal range rather than the whole BoolOp range.
        assert_eq!(
            and_false.linetable.as_ref(),
            &[0x80, 0x00, 0xd8, 0x0b, 0x10, 0xd0, 0x04, 0x16]
        );
        assert_eq!(
            or_true.linetable.as_ref(),
            &[0x80, 0x00, 0xd8, 0x0b, 0x0f, 0xd0, 0x04, 0x14]
        );
    }

    #[test]
    fn assert_false_message_call_uses_assert_location_like_cpython() {
        let code = compile_exec(
            "\
def f():
    assert False, \"x\"
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // CPython 3.14 codegen_assert() emits LOAD_COMMON_CONSTANT and CALL
        // at LOC(assert statement), then RAISE_VARARGS at LOC(test).
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x04, 0x15, 0x90, 0x23, 0xd3, 0x04, 0x15, 0x88, 0x35,
            ]
        );
    }

    #[test]
    fn static_swap_implicit_return_keeps_preswap_store_location_like_cpython() {
        let code = compile_exec(
            "\
def f(a, b):
    a, b = a, b
    b, a = a, b
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // CPython 3.14 flowgraph.c resolves line numbers before
        // optimize_basic_block() turns BUILD_TUPLE/UNPACK_SEQUENCE into SWAP
        // and apply_static_swaps() reorders the STORE_FAST pair.  The
        // synthetic return epilogue therefore keeps the pre-swap final store
        // location.
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0b, 0x0c, 0x80, 0x71, 0xd8, 0x0b, 0x0c, 0x82, 0x71,
            ]
        );
    }

    #[test]
    fn unpack_store_pair_jump_uses_second_target_location_like_cpython() {
        let code = compile_exec(
            "\
def f(value):
    if value.startswith('=?'):
        try:
            token, value = get_encoded_word(value)
        except E:
            token, value = get_atext(value)
    else:
        token, value = get_atext(value)
    atom.append(token)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let jump_position = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::JumpForward { .. }).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing post-try JUMP_FORWARD");

        // CPython 3.14 flowgraph.c turns the second STORE_FAST into a NOP
        // during STORE_FAST_STORE_FAST fusion, then NOP removal copies that
        // second target location onto the following no-location jump.
        assert_eq!(jump_position, (4, 20, 4, 25));
    }

    #[test]
    fn chained_store_pair_jump_keeps_copy_target_location_like_cpython() {
        let code = compile_exec(
            "\
def f(flag):
    if flag:
        a = b = True
    else:
        a = False
        b = False
    g(a, b)
    return a
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let jump_position = f
            .instructions
            .windows(2)
            .zip(f.locations.windows(2))
            .find_map(|(units, locations)| {
                matches!(units[0].op, Instruction::StoreFastStoreFast { .. })
                    .then(|| {
                        matches!(units[1].op, Instruction::JumpForward { .. }).then_some((
                            locations[1].0.line.get(),
                            locations[1].0.character_offset.get(),
                            locations[1].1.line.get(),
                            locations[1].1.character_offset.get(),
                        ))
                    })
                    .flatten()
            })
            .expect("missing jump after chained STORE_FAST_STORE_FAST");

        // CPython 3.14 flowgraph.c preserves the second chained-assignment
        // target location on the jump that skips the else body.
        assert_eq!(jump_position, (3, 13, 3, 14));
    }

    #[test]
    fn tuple_store_pair_jump_keeps_fused_store_location_like_cpython() {
        let code = compile_exec(
            "\
def f(flag, n, exp):
    if flag:
        n, d = n * 10**exp, 1
    else:
        d = -exp
    g(n, d)
    return n
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let jump_position = f
            .instructions
            .windows(2)
            .zip(f.locations.windows(2))
            .find_map(|(units, locations)| {
                matches!(units[0].op, Instruction::StoreFastStoreFast { .. })
                    .then(|| {
                        matches!(units[1].op, Instruction::JumpForward { .. }).then_some((
                            locations[1].0.line.get(),
                            locations[1].0.character_offset.get(),
                            locations[1].1.line.get(),
                            locations[1].1.character_offset.get(),
                        ))
                    })
                    .flatten()
            })
            .expect("missing jump after tuple STORE_FAST_STORE_FAST");

        // Without COPY before the fused stores, CPython keeps the fused
        // STORE_FAST_STORE_FAST location on the following jump.
        assert_eq!(jump_position, (3, 12, 3, 13));
    }

    #[test]
    fn genexpr_make_closure_and_call_use_genexpr_location_like_cpython() {
        let code = compile_exec(
            "\
def f(parameters):
    return ((p, type(p)) for p in parameters)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let genexpr = find_code(f, "<genexpr>").expect("missing genexpr code");

        // CPython 3.14 codegen_comprehension() uses LOC(e) for
        // codegen_make_closure(), the outer CALL, and the implicit .0 load
        // in codegen_sync_comprehension_generator().
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd9, 0x0b, 0x2d, 0xa1, 0x2a, 0xd3, 0x0b, 0x2d, 0xd0, 0x04, 0x2d,
            ]
        );
        assert_eq!(
            genexpr.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0b, 0x2d, 0xa1, 0x2a, 0x98, 0x51, 0x94, 0x04, 0x90,
                0x51, 0x93, 0x07, 0x8d, 0x4c, 0xa3, 0x2a, 0xf9,
            ]
        );
    }

    #[test]
    fn implicit_call_genexpr_range_includes_call_parens_like_cpython() {
        let code = compile_exec(
            "\
def implicit():
    return list(x for x in range(10))

def explicit():
    return list((x for x in range(10)))
",
        );
        let implicit = find_code(&code, "implicit").expect("missing implicit code");
        let implicit_gen = find_code(implicit, "<genexpr>").expect("missing implicit genexpr code");
        let explicit = find_code(&code, "explicit").expect("missing explicit code");
        let explicit_gen = find_code(explicit, "<genexpr>").expect("missing explicit genexpr code");

        // CPython's parser gives an unparenthesized sole GeneratorExp call
        // argument the call-parenthesized range, and codegen_comprehension()
        // uses LOC(e) for MAKE_FUNCTION, the outer CALL, and the implicit .0
        // LOAD_FAST.  Explicitly parenthesized genexprs already carry their own
        // parentheses and must not be widened again.
        assert_eq!(
            implicit.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x0b, 0x0f, 0xd1, 0x0f, 0x25, 0x9c, 0x35, 0xa0, 0x12, 0x9c, 0x39,
                0xd3, 0x0f, 0x25, 0xd3, 0x0b, 0x25, 0xd0, 0x04, 0x25,
            ]
        );
        assert_eq!(
            implicit_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0f, 0x25, 0x99, 0x39, 0x90, 0x61, 0x94, 0x01, 0x9b,
                0x39, 0xf9,
            ]
        );
        assert_eq!(
            explicit_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x10, 0x26, 0x99, 0x49, 0x90, 0x71, 0x94, 0x11, 0x9b,
                0x49, 0xf9,
            ]
        );
    }

    #[test]
    fn implicit_call_genexpr_parenthesized_element_range_like_cpython() {
        let code = compile_exec(
            "\
def bytes_binop():
    return bytes((x ^ 0x5C) for x in range(256))

def dict_tuple(d):
    return dict((v, k) for (k, v) in d.items())

def plain_tuple_elt(xs):
    return list((x, y) for x, y in xs)

def explicit_gen(xs):
    return list(((x, y) for x, y in xs))
",
        );
        let bytes_binop = find_code(&code, "bytes_binop").expect("missing bytes_binop code");
        let bytes_gen = find_code(bytes_binop, "<genexpr>").expect("missing bytes genexpr code");
        let dict_tuple = find_code(&code, "dict_tuple").expect("missing dict_tuple code");
        let dict_gen = find_code(dict_tuple, "<genexpr>").expect("missing dict genexpr code");
        let plain_tuple_elt =
            find_code(&code, "plain_tuple_elt").expect("missing plain_tuple_elt code");
        let plain_gen =
            find_code(plain_tuple_elt, "<genexpr>").expect("missing plain genexpr code");
        let explicit_gen = find_code(&code, "explicit_gen").expect("missing explicit_gen code");
        let explicit_inner =
            find_code(explicit_gen, "<genexpr>").expect("missing explicit genexpr code");

        // CPython 3.14's parser includes the call argument parentheses in
        // LOC(GeneratorExp) for implicit sole-argument generator expressions,
        // even when the element expression itself starts with parentheses.
        assert_eq!(
            bytes_binop.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x0b, 0x10, 0xd1, 0x10, 0x30, 0xa4, 0x55, 0xa8, 0x33, 0xa4, 0x5a,
                0xd3, 0x10, 0x30, 0xd3, 0x0b, 0x30, 0xd0, 0x04, 0x30,
            ]
        );
        assert_eq!(
            bytes_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x10, 0x30, 0xa1, 0x5a, 0xa0, 0x01, 0x90, 0x64, 0x97,
                0x28, 0x92, 0x28, 0xa3, 0x5a, 0xf9,
            ]
        );
        assert_eq!(
            dict_tuple.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x0b, 0x0f, 0xd1, 0x0f, 0x2f, 0xa0, 0x51, 0xa7, 0x57, 0xa1, 0x57,
                0xa4, 0x59, 0xd3, 0x0f, 0x2f, 0xd3, 0x0b, 0x2f, 0xd0, 0x04, 0x2f,
            ]
        );
        assert_eq!(
            dict_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0f, 0x2f, 0xa1, 0x59, 0x99, 0x36, 0x98, 0x41, 0x90,
                0x11, 0x95, 0x06, 0xa3, 0x59, 0xf9,
            ]
        );
        assert_eq!(
            plain_tuple_elt.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x0b, 0x0f, 0xd1, 0x0f, 0x26, 0xa1, 0x32, 0xd3, 0x0f, 0x26, 0xd3,
                0x0b, 0x26, 0xd0, 0x04, 0x26,
            ]
        );
        assert_eq!(
            plain_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0f, 0x26, 0xa1, 0x32, 0x99, 0x34, 0x98, 0x31, 0x90,
                0x11, 0x95, 0x06, 0xa3, 0x32, 0xf9,
            ]
        );
        assert_eq!(
            explicit_gen.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x0b, 0x0f, 0xd1, 0x10, 0x27, 0xa1, 0x42, 0xd3, 0x10, 0x27, 0xd3,
                0x0b, 0x28, 0xd0, 0x04, 0x28,
            ]
        );
        assert_eq!(
            explicit_inner.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x10, 0x27, 0xa1, 0x42, 0x99, 0x44, 0x98, 0x41, 0x90,
                0x21, 0x95, 0x16, 0xa3, 0x42, 0xf9,
            ]
        );
    }

    #[test]
    fn genexpr_filter_cleanup_jumps_use_element_location_like_cpython() {
        let code = compile_exec(
            "\
def simple(names):
    return (x for x in names if not _ishidden(x))

def boolop(fields):
    return (f for f in fields if f.init and not f.kw_only)
",
        );
        let simple = find_code(&code, "simple").expect("missing simple code");
        let simple_gen = find_code(simple, "<genexpr>").expect("missing simple genexpr code");
        let boolop = find_code(&code, "boolop").expect("missing boolop code");
        let boolop_gen = find_code(boolop, "<genexpr>").expect("missing boolop genexpr code");

        // codegen_sync_comprehension_generator() emits the
        // comprehension guard jump to if_cleanup, then emits the if_cleanup
        // backedge with elt_loc. flowgraph.c::jump_thread() copies that target
        // jump location to the threaded POP_JUMP/NOT_TAKEN cleanup path.
        assert_eq!(
            simple_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0b, 0x31, 0x91, 0x75, 0x90, 0x21, 0xa4, 0x49, 0xa8,
                0x61, 0xa7, 0x4c, 0x8f, 0x41, 0x8a, 0x41, 0x93, 0x75, 0xf9,
            ]
        );
        assert_eq!(
            boolop_gen.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd0, 0x0b, 0x3a, 0x91, 0x76, 0x90, 0x21, 0xa7, 0x16, 0xa5,
                0x16, 0x8c, 0x41, 0xb0, 0x01, 0xb7, 0x09, 0xb5, 0x09, 0x8f, 0x41, 0x8a, 0x41, 0x93,
                0x76, 0xf9,
            ]
        );
    }

    #[test]
    fn try_finally_exception_scaffolding_uses_no_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self, node):
    self.flag = True
    try:
        self.body(node)
    finally:
        self.flag = False
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // codegen_try_finally() emits the exception path
        // SETUP_CLEANUP/PUSH_EXC_INFO and POP_EXCEPT_AND_RERAISE with
        // NO_LOCATION; flowgraph line propagation then gives only the
        // finalbody's direct RERAISE the finalbody location.
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x10, 0x14, 0x80, 0x44, 0x84, 0x49, 0xf0, 0x02, 0x03, 0x05, 0x1a,
                0xd8, 0x08, 0x0c, 0x8f, 0x09, 0x89, 0x09, 0x90, 0x24, 0x8c, 0x0f, 0xe0, 0x14, 0x19,
                0x88, 0x04, 0x8e, 0x09, 0xf8, 0x90, 0x45, 0x88, 0x04, 0x8d, 0x09, 0xfa,
            ]
        );
    }

    #[test]
    fn return_debug_in_finally_uses_cpython_preprocessed_constant_order() {
        let code = compile_exec(
            "\
def f(close):
    try:
        return __debug__
    finally:
        close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let call_pos = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::Call { .. }))
            .expect("missing finally-body call");
        let debug_load_pos = f
            .instructions
            .iter()
            .position(|unit| {
                let Instruction::LoadConst { consti } = unit.op else {
                    return false;
                };
                let constant = &f.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))];
                matches!(constant, ConstantData::Boolean { value: true })
            })
            .expect("missing __debug__ constant load");

        assert!(
            call_pos < debug_load_pos,
            "CPython ast_preprocess.c folds __debug__ to Constant before codegen_return(), so the return constant is loaded after finally cleanup; ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn debug_statement_is_preprocessed_constant_like_cpython() {
        for code in [
            compile_exec("__debug__\n"),
            compile_exec_optimized("__debug__\n"),
        ] {
            let ops = non_cache_instructions(&code)
                .map(|unit| unit.op)
                .collect::<Vec<_>>();
            assert!(
                !ops.iter().any(|op| matches!(op, Instruction::PopTop)),
                "CPython ast_preprocess.c folds __debug__ to Constant before codegen_stmt_expr(), so it must not compile as LOAD_CONST/POP_TOP; ops={ops:?}"
            );
        }
    }

    #[test]
    fn statement_expr_pop_top_uses_no_location_like_cpython() {
        let infos = compile_module_instruction_infos("x + 1\n", Mode::Exec);
        let pop = infos
            .iter()
            .find(|info| matches!(info.instr.real(), Some(Instruction::PopTop)))
            .expect("missing expression-statement POP_TOP");

        assert_eq!(
            pop.lineno_override,
            Some(ir::NO_LOCATION_OVERRIDE),
            "CPython codegen_stmt_expr() emits artificial expression-statement POP_TOP at NO_LOCATION"
        );
    }

    #[test]
    fn interactive_statement_expr_pop_top_uses_no_location_like_cpython() {
        let infos = compile_module_instruction_infos("x + 1\n", Mode::Single);
        let print = infos
            .iter()
            .position(|info| {
                matches!(
                    info.instr.real(),
                    Some(Instruction::CallIntrinsic1 { func })
                        if func.get(info.arg) == bytecode::IntrinsicFunction1::Print
                )
            })
            .expect("missing interactive PRINT intrinsic");
        let pop = infos
            .get(print + 1)
            .expect("missing POP_TOP after interactive PRINT");

        assert!(
            matches!(pop.instr.real(), Some(Instruction::PopTop)),
            "CPython codegen_stmt_expr() emits POP_TOP immediately after INTRINSIC_PRINT; got {pop:?}"
        );
        assert_eq!(
            pop.lineno_override,
            Some(ir::NO_LOCATION_OVERRIDE),
            "CPython codegen_stmt_expr() emits interactive PRINT cleanup POP_TOP at NO_LOCATION"
        );
    }

    #[test]
    fn import_star_pop_top_uses_no_location_like_cpython() {
        let infos = compile_module_instruction_infos("from m import *\n", Mode::Exec);
        let import_star = infos
            .iter()
            .position(|info| {
                matches!(
                    info.instr.real(),
                    Some(Instruction::CallIntrinsic1 { func })
                        if func.get(info.arg) == bytecode::IntrinsicFunction1::ImportStar
                )
            })
            .expect("missing IMPORT_STAR intrinsic");
        let pop = infos
            .get(import_star + 1)
            .expect("missing POP_TOP after IMPORT_STAR");

        assert!(
            matches!(pop.instr.real(), Some(Instruction::PopTop)),
            "CPython codegen_from_import() emits POP_TOP immediately after INTRINSIC_IMPORT_STAR; got {pop:?}"
        );
        assert_eq!(
            pop.lineno_override,
            Some(ir::NO_LOCATION_OVERRIDE),
            "CPython codegen_from_import() emits import-star cleanup POP_TOP at NO_LOCATION"
        );
    }

    #[test]
    fn adjacent_no_location_entries_merge_like_cpython() {
        let code = compile_exec(
            "\
def f(file):
    if sys.platform == \"win32\":
        try:
            import nt
            if not nt._supports_virtual_terminal():
                return False
        except (ImportError, AttributeError):
            return False
    try:
        return os.isatty(file.fileno())
    except OSError:
        return hasattr(file, \"isatty\") and file.isatty()
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        // CPython's NO_LOCATION is {-1, -1, -1, -1}, and
        // assemble.c::assemble_location_info() merges adjacent instructions
        // with the same NO_LOCATION into one linetable entry.
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdc, 0x07, 0x0a, 0x87, 0x7c, 0x81, 0x7c, 0x90, 0x77, 0xd4, 0x07, 0x1e,
                0xf0, 0x02, 0x05, 0x09, 0x19, 0xdb, 0x0c, 0x15, 0xd8, 0x13, 0x15, 0xd7, 0x13, 0x30,
                0xd1, 0x13, 0x30, 0xd7, 0x13, 0x32, 0xd2, 0x13, 0x32, 0xd9, 0x17, 0x1c, 0xf0, 0x03,
                0x00, 0x14, 0x33, 0xf0, 0x08, 0x03, 0x05, 0x39, 0xdc, 0x0f, 0x11, 0x8f, 0x79, 0x89,
                0x79, 0x98, 0x14, 0x9f, 0x1b, 0x99, 0x1b, 0x9b, 0x1d, 0xd3, 0x0f, 0x27, 0xd0, 0x08,
                0x27, 0xf8, 0xf4, 0x07, 0x00, 0x11, 0x1c, 0x9c, 0x5e, 0xd0, 0x0f, 0x2c, 0xf4, 0x00,
                0x01, 0x09, 0x19, 0xda, 0x13, 0x18, 0xf0, 0x03, 0x01, 0x09, 0x19, 0xfb, 0xf4, 0x08,
                0x00, 0x0c, 0x13, 0xf4, 0x00, 0x01, 0x05, 0x39, 0xdc, 0x0f, 0x16, 0x90, 0x74, 0x98,
                0x58, 0xd3, 0x0f, 0x26, 0xd7, 0x0f, 0x38, 0xd0, 0x0f, 0x38, 0xa8, 0x34, 0xaf, 0x3b,
                0xa9, 0x3b, 0xab, 0x3d, 0xd2, 0x08, 0x38, 0xf0, 0x03, 0x01, 0x05, 0x39, 0xfa,
            ]
        );
    }

    #[test]
    fn fstring_format_ops_use_formatted_value_location_like_cpython() {
        let code = compile_exec(
            "\
def simple(self):
    return f'{self.value}'

def spec(x):
    return f'{x!r:>3}'
",
        );
        let simple = find_code(&code, "simple").expect("missing simple code");
        let spec = find_code(&code, "spec").expect("missing spec code");

        // CPython 3.14 codegen_formatted_value() VISITs the inner expression
        // first, then emits CONVERT_VALUE / FORMAT_* at LOC(FormattedValue).
        assert_eq!(
            simple.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0e, 0x12, 0x8f, 0x6a, 0x89, 0x6a, 0x88, 0x5c, 0xd0, 0x04, 0x1a,
            ]
        );
        assert_eq!(
            spec.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x0e, 0x0f, 0x88, 0x58, 0x90, 0x22, 0x88, 0x58, 0xd0, 0x04, 0x16,
            ]
        );
    }

    #[test]
    fn debug_fstring_literal_location_like_cpython() {
        fn string_load_position(code: &CodeObject, expected: &str) -> (usize, usize, usize, usize) {
            code.instructions
                .iter()
                .zip(&code.locations)
                .find_map(|(unit, (location, end_location))| {
                    let Instruction::LoadConst { consti } = unit.op else {
                        return None;
                    };
                    let constant =
                        &code.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))];
                    matches!(constant, ConstantData::Str { value } if value.to_string() == expected)
                        .then_some((
                            location.line.get(),
                            location.character_offset.get(),
                            end_location.line.get(),
                            end_location.character_offset.get(),
                        ))
                })
                .expect("missing debug f-string literal")
        }

        let code = compile_exec(
            "\
def simple(x):
    return f'{x=}'

def prefixed(x):
    return f'a {x=} b'
",
        );
        let simple = find_code(&code, "simple").expect("missing simple code");
        let prefixed = find_code(&code, "prefixed").expect("missing prefixed code");

        assert_eq!(
            string_load_position(simple, "x="),
            (2, 15, 2, 17),
            "CPython represents f'{{x=}}' debug text as a literal at the expression/debug-text location"
        );
        assert_eq!(
            string_load_position(prefixed, "x="),
            (5, 17, 5, 19),
            "CPython keeps debug text as a separate JoinedStr Constant instead of merging it with the preceding literal"
        );
    }

    #[test]
    fn fstring_format_spec_build_string_location_like_cpython() {
        let code = compile_exec(
            "\
def simple(lbl, label_width):
    return f'{lbl:>{label_width}}'

def padded(digits, int_len):
    return f'{digits:0>{int_len + 1}d}'
",
        );
        let simple = find_code(&code, "simple").expect("missing simple code");
        let padded = find_code(&code, "padded").expect("missing padded code");

        let build_string_position = |code: &CodeObject| {
            code.instructions
                .iter()
                .zip(&code.locations)
                .find_map(|(unit, (location, end_location))| {
                    matches!(unit.op, Instruction::BuildString { .. }).then_some((
                        location.line.get(),
                        location.character_offset.get(),
                        end_location.line.get(),
                        end_location.character_offset.get(),
                    ))
                })
                .expect("missing format-spec BUILD_STRING")
        };

        assert_eq!(
            build_string_position(simple),
            (2, 18, 2, 33),
            "CPython uses the format-spec JoinedStr location, including the ':' prefix, for BUILD_STRING"
        );
        assert_eq!(
            build_string_position(padded),
            (5, 21, 5, 38),
            "CPython format-spec JoinedStr location spans from ':' through the final literal"
        );
    }

    #[test]
    fn joined_string_literals_extend_pending_literal_location_like_cpython() {
        let code = compile_exec(
            "\
def f(a):
    return (
        'x'
        f'y{a}z'
        'w'
    )
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xf0, 0x04, 0x01, 0x09, 0x0c, 0xd8, 0x0c, 0x0d, 0x88, 0x33, 0xf0, 0x00,
                0x01, 0x0f, 0x0c, 0xf0, 0x03, 0x02, 0x09, 0x0c, 0xf0, 0x03, 0x04, 0x05, 0x06,
            ],
            "CPython parser/codegen represents adjacent f-string literal fragments as Constant ranges spanning the merged fragments"
        );
    }

    #[test]
    fn starred_call_preserves_bool_op_short_circuit_shape() {
        let code = compile_exec(
            "\
def f(g):
    return g(*(() or (1,)))
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter().any(|op| matches!(op, Instruction::Copy { .. })),
            "starred BoolOp should keep short-circuit COPY, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(op, Instruction::ToBool)),
            "starred BoolOp should keep TO_BOOL, got ops={ops:?}"
        );
        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::PopJumpIfTrue { .. })),
            "starred BoolOp should keep POP_JUMP_IF_TRUE, got ops={ops:?}"
        );
    }

    #[test]
    fn partial_constant_bool_op_folds_prefix_in_value_context() {
        let code = compile_exec(
            "\
def outer(null):
    @False or null
    def f(x):
        pass
",
        );
        let outer = find_code(&code, "outer").expect("missing outer code");
        let ops: Vec<_> = outer
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. }
                )
            }),
            "expected surviving decorator expression to load null directly, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| {
                matches!(
                    op,
                    Instruction::Copy { .. }
                        | Instruction::ToBool
                        | Instruction::PopJumpIfTrue { .. }
                        | Instruction::PopJumpIfFalse { .. }
                )
            }),
            "partial constant BoolOp should not leave short-circuit scaffolding, got ops={ops:?}"
        );
    }

    #[test]
    fn decorated_definitions_use_cpython_locations() {
        let code = compile_exec(
            "\
def dec(f): return f

class C:
    @dec
    def f(self):
        yield

@dec
class D:
    pass

class E:
    @dec
    def g(self, flags: int, /) -> memoryview:
        raise NotImplementedError
",
        );
        let c = find_code(&code, "C").expect("missing C code");
        let d = find_code(&code, "D").expect("missing D code");
        let e = find_code(&code, "E").expect("missing E code");
        let annotate = find_code(e, "__annotate__").expect("missing annotation code");

        // CPython 3.14 codegen_function()/codegen_class() evaluate
        // decorators first, then use LOC(s) for codegen_make_closure() and
        // codegen_nameop(); codegen_apply_decorators() emits CALL at each
        // decorator expression's location.
        assert_eq!(
            c.linetable.as_ref(),
            &[
                0xf8, 0x87, 0x00, 0x80, 0x00, 0xd8, 0x05, 0x08, 0xf1, 0x02, 0x01, 0x05, 0x0e, 0xf3,
                0x03, 0x00, 0x06, 0x09, 0xf6, 0x02, 0x01, 0x05, 0x0e,
            ]
        );
        assert_eq!(d.linetable.as_ref(), &[0x86, 0x00, 0xe3, 0x04, 0x08]);
        assert_eq!(
            e.linetable.as_ref(),
            &[
                0xf8, 0x87, 0x00, 0x80, 0x00, 0xd8, 0x05, 0x08, 0xf7, 0x02, 0x01, 0x05, 0x22, 0xf3,
                0x03, 0x00, 0x06, 0x09, 0xf6, 0x02, 0x01, 0x05, 0x22,
            ]
        );
        assert_eq!(
            annotate.linetable.as_ref(),
            &[
                0xf8, 0x80, 0x00, 0xf7, 0x00, 0x01, 0x05, 0x22, 0xf1, 0x00, 0x01, 0x05, 0x22, 0x91,
                0x73, 0xf0, 0x00, 0x01, 0x05, 0x22, 0xa1, 0x2a, 0xf1, 0x00, 0x01, 0x05, 0x22,
            ]
        );
    }

    #[test]
    fn taken_constant_boolop_jump_disables_following_borrows() {
        for source in [
            "\
def f(self):
    if 0 and self.h:
        self.x = self.y
    elif self.a and self.b:
        self.x = self.y
    self.z = self.w
",
            "\
def f(self):
    if 1 or self.h:
        self.x = self.y
    self.z = self.w
",
        ] {
            let code = compile_exec(source);
            let f = find_code(&code, "f").expect("missing f code");
            let ops: Vec<_> = f
                .instructions
                .iter()
                .map(|unit| unit.op)
                .filter(|op| !matches!(op, Instruction::Cache))
                .collect();
            assert!(
                ops.iter()
                    .any(|op| matches!(op, Instruction::LoadFast { .. })),
                "CPython keeps plain LOAD_FAST after an always-taken constant bool-op jump, got ops={ops:?}"
            );
            assert!(
                !ops.iter()
                    .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
                "always-taken constant bool-op jump should suppress later LOAD_FAST_BORROW, got ops={ops:?}"
            );
        }
    }

    #[test]
    fn not_taken_constant_boolop_jump_keeps_following_borrows() {
        for source in [
            "\
def f(self):
    if 1 and self.h:
        self.x = self.y
    self.z = self.w
",
            "\
def f(self):
    if 0 or self.h:
        self.x = self.y
    self.z = self.w
",
        ] {
            let code = compile_exec(source);
            let f = find_code(&code, "f").expect("missing f code");
            let ops: Vec<_> = f
                .instructions
                .iter()
                .map(|unit| unit.op)
                .filter(|op| !matches!(op, Instruction::Cache))
                .collect();
            assert!(
                ops.iter()
                    .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
                "constant bool-op jump that is not taken should keep CPython-style borrows, got ops={ops:?}"
            );
        }
    }

    #[test]
    fn while_before_folded_boolop_if_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            "\
def f(running, errors):
    try:
        while running:
            pass
        if __debug__ and errors:
            raise ExceptionGroup('x', errors)
        return errors
    finally:
        del errors
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let errors_loads = load_fast_ops_for_var(f, "errors");
        assert!(
            errors_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_while() emits USE_LABEL(end), then codegen_jump_if() emits a folded constant BoolOp prefix; flowgraph.c::basicblock_optimize_load_const() and optimize_load_fast() leave the successor errors loads strong, got {errors_loads:?}"
        );
    }

    #[test]
    fn with_try_except_tail_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            "\
def f(self, cm, value):
    with cm:
        try:
            self.run()
        except OSError as e:
            if e.errno:
                raise ConnectionError
            else:
                raise
    self.run_loop(value.done)
    self.assertTrue(value.nbytes)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let value_loads = load_fast_ops_for_var(f, "value");
        assert!(
            value_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() leaves USE_LABEL(end) before codegen_with_inner() emits normal __exit__ cleanup, so optimize_load_fast() leaves with-successor loads strong; got {value_loads:?}"
        );
    }

    #[test]
    fn with_try_except_conditional_body_allows_successor_borrow() {
        let code = compile_exec(
            "\
def f(max_decode, gzf, cm, decoded):
    with cm:
        try:
            if max_decode < 0:
                decoded = gzf.read()
            else:
                decoded = gzf.read(max_decode + 1)
        except OSError:
            raise ValueError('invalid data')
    if max_decode >= 0 and len(decoded) > max_decode:
        raise ValueError('too large')
    return decoded
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let max_decode_loads = load_fast_ops_for_var(f, "max_decode");
        assert!(
            max_decode_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython codegen_try_except() keeps borrowing through a with tail when the protected try body ends with a conditional label, got {max_decode_loads:?}"
        );
    }

    #[test]
    fn loop_try_orelse_nested_try_before_next_try_keeps_load_fast_strong() {
        let code = compile_exec(
            "\
def f(test_cases):
    for src, dest in test_cases:
        try:
            os.symlink(src, dest)
        except FileNotFoundError:
            pass
        else:
            try:
                os.remove(dest)
            except OSError:
                pass
        try:
            os.symlink(os.fsencode(src), os.fsencode(dest))
        except FileNotFoundError:
            pass
        else:
            try:
                os.remove(dest)
            except OSError:
                pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let strong_src_dest_loads = count_strong_loads_for_vars(f, &["src", "dest"]);
        assert!(
            strong_src_dest_loads >= 2,
            "CPython codegen_try_except() emits orelse then USE_LABEL(end) before the following loop try, so optimize_load_fast() leaves fsencode arguments strong; got {strong_src_dest_loads} strong src/dest loads"
        );
    }

    #[test]
    fn try_orelse_with_before_next_try_keeps_load_fast_strong() {
        let code = compile_exec(
            "\
def f(self, f, cm):
    try:
        f = C(0)
    except ValueError:
        pass
    else:
        self.assertTrue(f.readable())
        with cm:
            with C(False):
                pass
    try:
        f = C(1)
    except ValueError:
        pass
    else:
        self.assertFalse(f.readable())
",
        );
        let f_code = find_code(&code, "f").expect("missing function code");
        let strong_self_or_f_loads = count_strong_loads_for_vars(f_code, &["self", "f"]);
        assert!(
            strong_self_or_f_loads >= 2,
            "CPython codegen_try_except() emits orelse with nested with cleanup before USE_LABEL(end), so optimize_load_fast() leaves loads in the following try/else strong; got {strong_self_or_f_loads} strong self/f loads"
        );
    }

    #[test]
    fn try_orelse_single_with_before_next_try_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self, cm):
    try:
        import _testcapi
    except ImportError:
        pass
    else:
        code = 'x'
        with cm:
            out = self.run_xdev('-c', code)
        self.assertEqual(out, 'x')
    try:
        import faulthandler
    except ImportError:
        pass
    else:
        code = 'y'
        out = self.run_xdev('-c', code)
        self.assertEqual(out, 'y')
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let final_return = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .expect("missing return");
        let tail = &instructions[..final_return];
        let borrowed_self_loads = tail
            .iter()
            .filter(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == "self"
                }
                _ => false,
            })
            .count();
        assert!(
            borrowed_self_loads >= 4,
            "CPython codegen_with() for a single with in try/else does not make the following try/else a load-fast barrier; expected borrowed self loads, got instructions={instructions:?}"
        );
    }

    #[test]
    fn with_try_finally_nested_with_keeps_successor_load_fast_strong() {
        let code = compile_exec(
            "\
def f(self, cm):
    with cm as cm1:
        try:
            work()
        finally:
            with cm as cm2:
                work()
    e1 = cm1.exception
    e12 = e1.__cause__
    self.assertIsInstance(e12, Error)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let strong_loads = count_strong_loads(f);
        assert!(
            strong_loads >= 3,
            "CPython codegen_try_finally() inlines a finalbody with codegen_with_inner() cleanup before the with exit label, so optimize_load_fast() leaves successor loads strong; got {strong_loads} strong loads"
        );
    }

    #[test]
    fn nonliteral_constant_bool_op_preserves_short_circuit_shape() {
        let code = compile_exec(
            "\
x = (\"a\"[0]) or 2
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BinaryOp { op }
                    if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        == oparg::BinaryOperator::Subscr
            )),
            "constant subscript should fold before bool-op lowering, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(op, Instruction::Copy { .. })),
            "folded non-literal BoolOp operand should keep COPY, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(op, Instruction::ToBool)),
            "folded non-literal BoolOp operand should keep TO_BOOL, got ops={ops:?}"
        );
        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::PopJumpIfTrue { .. })),
            "folded non-literal BoolOp operand should keep POP_JUMP_IF_TRUE, got ops={ops:?}"
        );
    }

    #[test]
    fn unary_positive_complex_constant_folds_to_load_const() {
        let code = compile_exec(
            "\
x = +0.0j
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::CallIntrinsic1 { .. })),
            "unary positive complex constant should not leave CALL_INTRINSIC_1, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadConst { .. },
                    Instruction::StoreName { .. },
                    Instruction::LoadConst { .. },
                    Instruction::ReturnValue
                ]
            ),
            "expected module assignment to fold +0.0j into LOAD_CONST, got ops={ops:?}"
        );
    }

    #[test]
    fn folded_nonliteral_bool_op_tail_keeps_plain_load_fast() {
        let code = compile_exec(
            "\
def and_true(x):
    return True and x

def or_false(x):
    return False or x
",
        );

        for name in ["and_true", "or_false"] {
            let function = find_code(&code, name).unwrap_or_else(|| panic!("missing {name} code"));
            let ops: Vec<_> = function
                .instructions
                .iter()
                .map(|unit| unit.op)
                .filter(|op| !matches!(op, Instruction::Cache))
                .collect();

            assert!(
                ops.iter()
                    .any(|op| matches!(op, Instruction::LoadFast { .. })),
                "expected folded bool-op tail to keep LOAD_FAST in {name}, got ops={ops:?}"
            );
            assert!(
                !ops.iter().any(|op| {
                    matches!(
                        op,
                        Instruction::LoadFastBorrow { .. }
                            | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                    )
                }),
                "folded bool-op tail should not introduce borrow loads in {name}, got ops={ops:?}"
            );
        }
    }

    #[test]
    fn folded_nonliteral_bool_op_direct_tail_load_keeps_plain_load_fast() {
        let code = compile_exec(
            "\
def return_tail(x):
    return False or x

def assign_tail(x):
    y = False or x
    return y

def call_arg(x, g):
    return g(False or x)

def attr_tail(x):
    return False or x.y

def class_tail(class_decorator):
    @False or class_decorator
    class H:
        pass
",
        );

        for name in ["return_tail", "assign_tail", "call_arg", "class_tail"] {
            let function = find_code(&code, name).unwrap_or_else(|| panic!("missing {name} code"));
            let local = if name == "class_tail" {
                "class_decorator"
            } else {
                "x"
            };
            let loads = load_fast_ops_for_var(function, local);
            assert!(
                loads
                    .iter()
                    .any(|op| matches!(op, Instruction::LoadFast { .. })),
                "CPython codegen_boolop() emits USE_LABEL(end) after the folded BoolOp tail, so optimize_load_fast() leaves the direct tail load strong in {name}; got {loads:?}"
            );
        }

        let attr_tail = find_code(&code, "attr_tail").expect("missing attr_tail code");
        let attr_receiver_loads = load_fast_ops_for_var(attr_tail, "x");
        assert!(
            attr_receiver_loads
                .iter()
                .all(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython only keeps direct folded tail local loads strong; an attribute receiver is consumed before the BoolOp end label, got {attr_receiver_loads:?}"
        );
    }

    #[test]
    fn folded_nonliteral_tuple_unpack_tail_keeps_plain_load_fast() {
        let code = compile_exec(
            "\
def f(self, mod):
    optimize, opt = (1, 1) if __debug__ else (0, '')
    mod.call(self.path, optimize=optimize)
    cached = mod.cache(self.source_path, optimization=opt)
    self.assertTrue(cached)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let tail_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadFast { .. }))
            .expect("missing folded assignment tail load");
        let tail = &ops[tail_start..];

        assert!(
            tail.iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "expected folded nonliteral tuple-unpack tail to use strong LOAD_FAST, got tail={tail:?}"
        );
        assert!(
            !tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "folded nonliteral tuple-unpack tail should not borrow local loads, got tail={tail:?}"
        );
    }

    #[test]
    fn scope_exit_instructions_keep_line_numbers() {
        let code = compile_exec(
            "\
async def test():
    for stop_exc in (StopIteration('spam'), StopAsyncIteration('ham')):
        with self.subTest(type=type(stop_exc)):
            try:
                async with egg():
                    raise stop_exc
            except Exception as ex:
                self.assertIs(ex, stop_exc)
            else:
                self.fail(f'{stop_exc} was suppressed')
",
        );
        assert_scope_exit_locations(&code);
    }

    #[test]
    fn attribute_ex_call_uses_plain_load_attr() {
        let code = compile_exec(
            "\
def f(cls, args, kwargs):
    cls.__new__(cls, *args)
    cls.__new__(cls, *args, **kwargs)
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        let ex_call_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::CallFunctionEx))
            .count();
        let load_attr_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::LoadAttr { .. }))
            .count();

        assert_eq!(ex_call_count, 2);
        assert_eq!(load_attr_count, 2);

        for unit in f.instructions.iter() {
            if let Instruction::LoadAttr { namei } = unit.op {
                let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                assert!(
                    !load_attr.is_method(),
                    "CALL_FUNCTION_EX should use plain LOAD_ATTR"
                );
            }
        }
    }

    #[test]
    fn method_call_at_stack_guideline_uses_plain_load_attr_like_cpython() {
        let params = (0..STACK_USE_GUIDELINE)
            .map(|i| format!("a{i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!(
            "def f(obj, {params}):\n    return obj.m({params})\n"
        ));
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let plain_load_attr = f.instructions.iter().any(|unit| {
            if let Instruction::LoadAttr { namei } = unit.op {
                !namei
                    .get(OpArg::new(u32::from(u8::from(unit.arg))))
                    .is_method()
            } else {
                false
            }
        });
        let direct_call_30 = f.instructions.iter().any(|unit| match unit.op {
            Instruction::Call { argc } => {
                argc.get(OpArg::new(u32::from(u8::from(unit.arg)))) == STACK_USE_GUIDELINE
            }
            _ => false,
        });

        assert!(
            plain_load_attr && direct_call_30,
            "CPython maybe_optimize_method_call rejects arg count at the guideline, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::CallFunctionEx)),
            "exactly guideline-sized method call should stay direct after LOAD_ATTR fallback, got ops={ops:?}"
        );
    }

    #[test]
    fn method_call_many_keywords_stays_load_method_call_kw_like_cpython() {
        let params = (0..16)
            .map(|i| format!("a{i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let keywords = (0..16)
            .map(|i| format!("k{i}=a{i}"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!(
            "def f(obj, {params}):\n    return obj.m({keywords})\n"
        ));
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let method_load_attr = f.instructions.iter().any(|unit| {
            if let Instruction::LoadAttr { namei } = unit.op {
                namei
                    .get(OpArg::new(u32::from(u8::from(unit.arg))))
                    .is_method()
            } else {
                false
            }
        });
        let call_kw_16 = f.instructions.iter().any(|unit| match unit.op {
            Instruction::CallKw { argc } => {
                argc.get(OpArg::new(u32::from(u8::from(unit.arg)))) == 16
            }
            _ => false,
        });

        assert!(
            method_load_attr && call_kw_16,
            "CPython maybe_optimize_method_call emits LOAD_METHOD/CALL_KW under its own stack threshold, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::CallFunctionEx)),
            "method-call keyword path should not reuse codegen_call_helper_impl's lower kw threshold, got ops={ops:?}"
        );
    }

    #[test]
    fn large_plain_call_uses_direct_call_until_stack_guideline() {
        let code = compile_exec(
            "\
def f(g):
    return g(a0, a1, a2, a3, a4, a5, a6, a7, a8,
             a9, a10, a11, a12, a13, a14, a15, a16, a17)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let direct_call_18 = f.instructions.iter().any(|unit| match unit.op {
            Instruction::Call { argc } => argc.get(OpArg::new(u32::from(u8::from(unit.arg)))) == 18,
            _ => false,
        });
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            direct_call_18,
            "18 positional arguments should stay on CPython's direct CALL path, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::CallFunctionEx)),
            "18 positional arguments should not use CALL_FUNCTION_EX, got ops={ops:?}"
        );
    }

    #[test]
    fn too_large_plain_call_uses_cpython_tuple_ex_call_path() {
        let args = (0..=STACK_USE_GUIDELINE)
            .map(|i| format!("'v{i}'"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!("def f(g):\n    return g({args})\n"));
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::CallFunctionEx)),
            "CPython routes calls over _PY_STACK_USE_GUIDELINE through CALL_FUNCTION_EX, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| matches!(
                op,
                Instruction::BuildTuple { .. }
                    | Instruction::ListAppend { .. }
                    | Instruction::CallIntrinsic1 { .. }
            )),
            "CPython flowgraph.c folds the starunpack tuple for constant too-large calls, got ops={ops:?}"
        );
        assert!(
            f.constants.iter().any(|constant| {
                matches!(
                    constant,
                    ConstantData::Tuple { elements }
                        if elements.len() == usize::try_from(STACK_USE_GUIDELINE + 1).unwrap()
                )
            }),
            "expected CPython folded tuple constant for too-large call args, got constants={:?}",
            f.constants.iter().collect::<Vec<_>>()
        );
    }

    #[test]
    fn simple_attribute_call_keeps_method_load() {
        let code = compile_exec(
            "\
def f(obj, arg):
    return obj.method(arg)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let load_attr = f
            .instructions
            .iter()
            .find_map(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    Some(namei.get(OpArg::new(u32::from(u8::from(unit.arg)))))
                }
                _ => None,
            })
            .expect("missing LOAD_ATTR");

        assert!(
            load_attr.is_method(),
            "simple method calls should stay optimized"
        );
    }

    #[test]
    fn starred_super_call_keeps_attr_line_nop() {
        let code = compile_exec(
            "\
def outer(log):
    class DelegatingHTTPRequestHandler(BaseHTTPRequestHandler):
        def log_message(self, format, *args):
            if log:
                super(DelegatingHTTPRequestHandler,
                      self).log_message(format, *args)
",
        );
        let log_message = find_code(&code, "log_message").expect("missing log_message code");
        let ops: Vec<_> = log_message
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadSuperAttr { .. },
                        Instruction::Nop,
                        Instruction::PushNull,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "starred super call should keep CPython's attr-line NOP after LOAD_SUPER_ATTR, got ops={ops:?}"
        );
    }

    #[test]
    fn builtin_any_genexpr_call_is_optimized() {
        let code = compile_exec(
            "\
def f(xs):
    return any(x for x in xs)
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(has_common_constant(f, bytecode::CommonConstant::BuiltinAny));
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::PopJumpIfTrue { .. }))
        );
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::NotTaken))
        );
        assert_eq!(
            f.instructions
                .iter()
                .filter(|unit| matches!(unit.op, Instruction::PushNull))
                .count(),
            1,
            "fallback call path should remain for shadowed any()"
        );
        let genexpr_const_count = f
            .constants
            .iter()
            .filter(|constant| {
                matches!(constant, ConstantData::Code { code } if code.obj_name == "<genexpr>")
            })
            .count();
        assert_eq!(
            genexpr_const_count, 1,
            "optimized and fallback any(genexpr) paths should share the same CPython-range code const"
        );
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdf, 0x0b, 0x0e, 0x8b, 0x33, 0x89, 0x6f, 0x99, 0x22, 0x8b, 0x6f, 0x8f,
                0x33, 0x8c, 0x33, 0xd0, 0x04, 0x1d, 0x8a, 0x33, 0xd0, 0x04, 0x1d, 0x88, 0x33, 0x89,
                0x6f, 0x99, 0x22, 0x8b, 0x6f, 0xd3, 0x0b, 0x1d, 0xd0, 0x04, 0x1d,
            ]
        );
    }

    #[test]
    fn builtin_any_async_genexpr_call_is_not_optimized() {
        let code = compile_exec(
            "\
async def f(xs):
    return any(x async for x in xs)
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            !has_common_constant(f, bytecode::CommonConstant::BuiltinAny),
            "CPython maybe_optimize_function_call() skips coroutine generator expressions"
        );
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Call { .. })),
            "async genexpr any() should stay on the normal call path"
        );
    }

    #[test]
    fn builtin_any_genexpr_outermost_await_is_optimized_like_cpython() {
        let code = compile_exec(
            "\
async def f(get_xs):
    return any(x for x in await get_xs())
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            has_common_constant(f, bytecode::CommonConstant::BuiltinAny),
            "CPython checks the generator expression symtable entry, so await in the outermost iterator does not make the genexpr coroutine"
        );
    }

    #[test]
    fn builtin_tuple_genexpr_call_is_optimized_but_list_set_are_not() {
        let code = compile_exec(
            "\
def tuple_f(xs):
    return tuple(x for x in xs)

def list_f(xs):
    return list(x for x in xs)

def set_f(xs):
    return set(x for x in xs)
",
        );

        let tuple_f = find_code(&code, "tuple_f").expect("missing tuple_f code");
        assert!(has_common_constant(
            tuple_f,
            bytecode::CommonConstant::BuiltinTuple
        ));
        assert!(has_intrinsic_1(tuple_f, IntrinsicFunction1::ListToTuple));
        let tuple_list_append = tuple_f
            .instructions
            .iter()
            .find_map(|unit| match unit.op {
                Instruction::ListAppend { .. } => Some(u32::from(u8::from(unit.arg))),
                _ => None,
            })
            .expect("tuple(genexpr) fast path should emit LIST_APPEND");
        assert_eq!(tuple_list_append, 2);
        assert_eq!(
            tuple_f.linetable.as_ref(),
            &[
                0x80, 0x00, 0xdf, 0x0b, 0x10, 0x8c, 0x35, 0x91, 0x0f, 0x99, 0x42, 0x93, 0x0f, 0x8f,
                0x35, 0xd0, 0x04, 0x1f, 0x88, 0x35, 0x91, 0x0f, 0x99, 0x42, 0x93, 0x0f, 0xd3, 0x0b,
                0x1f, 0xd0, 0x04, 0x1f,
            ]
        );

        let list_f = find_code(&code, "list_f").expect("missing list_f code");
        assert!(
            list_f
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Call { .. })),
            "list(genexpr) should stay on the normal call path"
        );
        assert!(
            !has_common_constant(list_f, bytecode::CommonConstant::BuiltinList),
            "CPython 3.14.5 does not optimize list(genexpr)"
        );

        let set_f = find_code(&code, "set_f").expect("missing set_f code");
        assert!(
            set_f
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Call { .. })),
            "set(genexpr) should stay on the normal call path"
        );
        assert!(
            !has_common_constant(set_f, bytecode::CommonConstant::BuiltinSet),
            "CPython 3.14.5 does not optimize set(genexpr)"
        );
    }

    #[test]
    fn builtin_tuple_genexpr_try_assignment_uses_shared_tail() {
        let code = compile_exec(
            "\
def f(xs):
    global y
    try:
        y = tuple(int(i) for i in xs.split('.'))
    except ValueError:
        y = ()
    return y
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let intrinsic = ops
            .iter()
            .position(|op| matches!(op, Instruction::CallIntrinsic1 { .. }))
            .expect("tuple(genexpr) fast path should emit LIST_TO_TUPLE");
        let first_fallback = ops[intrinsic + 1..]
            .iter()
            .position(|op| matches!(op, Instruction::PushNull))
            .map(|offset| intrinsic + 1 + offset)
            .expect("shadowed tuple fallback call should remain after fast path");
        let first_store = ops[intrinsic + 1..]
            .iter()
            .position(|op| matches!(op, Instruction::StoreGlobal { .. }))
            .map(|offset| intrinsic + 1 + offset)
            .expect("tuple(genexpr) result should be stored after fast or fallback call");

        assert!(
            matches!(ops[intrinsic + 1], Instruction::JumpForward { .. })
                && first_fallback < first_store,
            "tuple(genexpr) fast path should jump over fallback to CPython-style shared store tail, got ops={ops:?}"
        );
    }

    #[test]
    fn builtin_tuple_genexpr_unprotected_assignment_return_duplicates_tail() {
        let code = compile_exec(
            "\
def f(arg):
    if isinstance(arg, (list, tuple)):
        arg = tuple(a for a in arg)
    elif not p(arg):
        raise TypeError(f'bad {arg}')
    return arg
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let intrinsic = ops
            .iter()
            .position(|op| matches!(op, Instruction::CallIntrinsic1 { .. }))
            .expect("tuple(genexpr) fast path should emit LIST_TO_TUPLE");

        assert!(
            matches!(ops[intrinsic + 1], Instruction::StoreFast { .. })
                && matches!(
                    ops[intrinsic + 2],
                    Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. }
                )
                && matches!(ops[intrinsic + 3], Instruction::ReturnValue),
            "unprotected tuple(genexpr) assignment before return should inline CPython's assignment-return tail, got ops={ops:?}"
        );
    }

    #[test]
    fn unprotected_builtin_any_prefix_before_returning_try_keeps_borrow() {
        let code = compile_exec(
            "\
def f(template):
    if any(part.expression.strip() == '' for part in template.interpolations):
        return ctor(template)
    try:
        parsed = tuple(
            ast.parse(f'({part.expression})', mode='eval').body
            for part in template.interpolations
        )
    except SyntaxError:
        return ctor(template)
    return lit(template, parsed)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_try_nop = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::Nop))
            .expect("missing try entry NOP");
        let mut saw_interpolations = false;
        for window in instructions[..first_try_nop].windows(2) {
            let [receiver, attr] = window else {
                continue;
            };
            let Instruction::LoadAttr { namei } = attr.op else {
                continue;
            };
            let load_attr = namei.get(OpArg::new(u32::from(u8::from(attr.arg))));
            if f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() != "interpolations"
            {
                continue;
            }
            saw_interpolations = true;
            assert!(
                matches!(receiver.op, Instruction::LoadFastBorrow { .. }),
                "unprotected builtin any(genexpr) prefix before a later returning try should keep CPython-style borrowed receiver, got instructions={instructions:?}"
            );
        }
        assert!(
            saw_interpolations,
            "missing interpolations attr load in builtin any prefix, got instructions={instructions:?}"
        );
    }

    #[test]
    fn module_store_uses_store_global_when_nested_scope_declares_global() {
        let code = compile_exec(
            "\
_address_fmt_re = None

class C:
    def f(self):
        global _address_fmt_re
        if _address_fmt_re is None:
            _address_fmt_re = 1
",
        );

        assert!(code.instructions.iter().any(|unit| match unit.op {
            Instruction::StoreGlobal { namei } => {
                let idx = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                code.names[usize::try_from(idx).unwrap()].as_str() == "_address_fmt_re"
            }
            _ => false,
        }));
    }

    #[test]
    fn conditional_return_epilogue_is_duplicated() {
        let code = compile_exec(
            "\
def f(base, cls, state):
    if base is object:
        obj = object.__new__(cls)
    else:
        obj = base.__new__(cls, state)
    return obj
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let return_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();

        assert_eq!(return_count, 2);
    }

    #[test]
    fn loop_store_subscr_threads_direct_backedge() {
        let code = compile_exec(
            "\
def f(kwonlyargs, kw_only_defaults, arg2value):
    missing = 0
    for kwarg in kwonlyargs:
        if kwarg not in arg2value:
            if kw_only_defaults and kwarg in kw_only_defaults:
                arg2value[kwarg] = kw_only_defaults[kwarg]
            else:
                missing += 1
    return missing
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let store_subscr = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreSubscr))
            .expect("missing STORE_SUBSCR");
        let next_op = ops
            .get(store_subscr + 1)
            .expect("missing jump after STORE_SUBSCR");
        let window_start = store_subscr.saturating_sub(3);
        let window_end = (store_subscr + 5).min(ops.len());
        let window = &ops[window_start..window_end];

        assert!(
            matches!(next_op, Instruction::JumpBackward { .. }),
            "expected direct loop backedge after STORE_SUBSCR, got {next_op:?}; ops={window:?}"
        );
    }

    #[test]
    fn protected_store_subscr_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(cache, lock, format):
    with lock:
        format_regex = cache.get(format)
        if not format_regex:
            try:
                format_regex = cache.compile(format)
            except KeyError as err:
                bad_directive = err.args[0]
                del err
                raise ValueError(bad_directive) from None
            cache[format] = format_regex
    return format_regex.match('x')
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastLoadFast { .. },
                        Instruction::LoadFast { .. },
                        Instruction::StoreSubscr,
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "expected CPython-style strong loads before protected STORE_SUBSCR tail, got ops={ops:?}"
        );

        let code = compile_exec(
            "\
cache = {}
def g(lock, format):
    with lock:
        format_regex = cache.get(format)
        if not format_regex:
            try:
                format_regex = compile(format)
            except KeyError as err:
                bad_directive = err.args[0]
                del err
                raise ValueError(bad_directive) from None
            cache[format] = format_regex
    return format_regex.match('x')
",
        );
        let g = find_code(&code, "g").expect("missing function code");
        let ops: Vec<_> = g
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadFast { .. },
                        Instruction::StoreSubscr,
                    ]
                )
            }),
            "expected CPython-style strong value/key loads around global STORE_SUBSCR tail, got ops={ops:?}"
        );
    }

    #[test]
    fn try_except_inner_for_cleanup_allows_try_end_borrow() {
        let code = compile_exec(
            "\
def f(self, futures, already_completed, future, short_timeout):
    for timeout in (0, short_timeout):
        with self.subTest(timeout):
            completed_futures = set()
            try:
                for item in futures.as_completed(already_completed | {future}, timeout):
                    completed_futures.add(item)
            except futures.TimeoutError:
                pass
            self.assertEqual(completed_futures, already_completed)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let borrow_pair_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::LoadFastBorrowLoadFastBorrow { .. }))
            .count();

        assert!(
            borrow_pair_count >= 2,
            "expected CPython-style borrowed pair loads before and after inner for cleanup, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn augassign_two_part_slice_uses_slice_opcodes() {
        let code = compile_exec(
            "\
def aug(x, a, b, y):
    x[a:b] += y
",
        );
        let aug = find_code(&code, "aug").expect("missing aug code");
        let ops: Vec<_> = aug
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert_eq!(
            ops.iter()
                .filter(|op| matches!(op, Instruction::BinarySlice))
                .count(),
            1,
            "expected one BINARY_SLICE in augassign slice path, got ops={ops:?}"
        );
        assert_eq!(
            ops.iter()
                .filter(|op| matches!(op, Instruction::StoreSlice))
                .count(),
            1,
            "expected one STORE_SLICE in augassign slice path, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| {
                matches!(
                    op,
                    Instruction::BuildSlice { .. } | Instruction::StoreSubscr
                )
            }),
            "two-part augassign slice should avoid BUILD_SLICE/STORE_SUBSCR, got ops={ops:?}"
        );
        assert!(
            ops.windows(10).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::Copy { .. },
                        Instruction::Copy { .. },
                        Instruction::BinarySlice,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::Swap { .. },
                        Instruction::Swap { .. },
                        Instruction::Swap { .. },
                        Instruction::StoreSlice,
                    ]
                )
            }),
            "expected CPython-style augassign slice window, got ops={ops:?}"
        );
    }

    #[test]
    fn augassign_constant_slice_copy_uses_subscript_location_like_cpython() {
        let code = compile_exec(
            "\
def aug_const(x, y):
    x[1:2] += y
",
        );
        let aug_const = find_code(&code, "aug_const").expect("missing aug_const code");

        // CPython 3.14 codegen_augassign() visits a constant slice, then emits
        // COPY/COPY/BINARY_OP NB_SUBSCR at LOC(target), not at LOC(slice).
        assert_eq!(
            aug_const.linetable.as_ref(),
            &[
                0x80, 0x00, 0xd8, 0x04, 0x05, 0x80, 0x63, 0x87, 0x46, 0x88, 0x61, 0x85, 0x4b, 0x85,
                0x46,
            ]
        );
    }

    #[test]
    fn augassign_attribute_copy_uses_target_location_like_cpython() {
        let code = compile_exec(
            "\
def f(obj, value):
    obj.attr += value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let copy_position = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                let Instruction::Copy { i } = unit.op else {
                    return None;
                };
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                (i.get(arg) == 1).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing augmented attribute COPY");

        assert_eq!(
            copy_position,
            (2, 5, 2, 13),
            "CPython codegen_augassign() emits COPY 1 at LOC(target) before updating to attr location"
        );
    }

    #[test]
    fn loop_return_reorders_backedge_before_exit_cleanup() {
        let code = compile_exec(
            "\
def f(obj):
    for base in obj.__mro__:
        if base is not object:
            doc = base.__doc__
            if doc is not None:
                return doc
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let has_cpython_shape = ops.windows(7).any(|window| {
            matches!(
                window,
                [
                    Instruction::PopJumpIfNotNone { .. },
                    Instruction::NotTaken,
                    Instruction::JumpBackward { .. },
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::Swap { .. },
                    Instruction::PopTop,
                    Instruction::ReturnValue,
                ]
            )
        });
        assert!(
            has_cpython_shape,
            "expected loop return null-check to keep the backedge adjacent to the return cleanup, got ops={ops:?}"
        );

        let end_for_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::EndFor))
            .expect("missing END_FOR");
        let return_before_end = ops[..end_for_idx]
            .iter()
            .rposition(|op| matches!(op, Instruction::ReturnValue))
            .expect("missing loop-body RETURN_VALUE");
        assert!(
            matches!(ops.get(return_before_end - 1), Some(Instruction::PopTop)),
            "expected POP_TOP before loop-body RETURN_VALUE, got {:?}; ops={ops:?}",
            ops.get(return_before_end.saturating_sub(1))
        );
    }

    #[test]
    fn nested_try_finally_cleanup_reorder_does_not_invert_forward_jumps() {
        compile_exec(include_str!("../../../Lib/poplib.py"));
    }

    #[test]
    fn conditional_body_is_preserved_before_final_return() {
        let code = compile_exec(
            "\
def f(x, y):
    if x == y:
        print('then', flush=True)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cond_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopJumpIfFalse { .. }))
            .expect("missing POP_JUMP_IF_FALSE");
        let first_return_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ReturnValue))
            .expect("missing RETURN_VALUE");

        assert!(
            ops[cond_idx..first_return_idx]
                .iter()
                .any(|op| matches!(op, Instruction::CallKw { .. })),
            "expected conditional body call before final return, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_conditional_body_is_preserved_before_final_return() {
        let code = compile_exec(
            "\
def outer():
    def side():
        print('side', flush=True)
    def cb():
        flag = True
        if flag:
            side()
    return cb
",
        );
        let cb = find_code(&code, "cb").expect("missing nested cb code");
        let ops: Vec<_> = cb
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cond_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopJumpIfFalse { .. }))
            .expect("missing POP_JUMP_IF_FALSE");
        let first_return_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ReturnValue))
            .expect("missing RETURN_VALUE");

        assert!(
            ops[cond_idx..first_return_idx]
                .iter()
                .any(|op| matches!(op, Instruction::Call { .. })),
            "expected nested conditional body call before final return, got ops={ops:?}"
        );
    }

    #[test]
    fn try_line_nop_is_preserved_before_setup_finally() {
        let code = compile_exec(
            "\
def f(msg):
    try:
        fw = _wm.formatwarning
    except AttributeError:
        pass
    else:
        if fw is not _formatwarning_orig:
            return fw(msg.message, msg.category, msg.filename, msg.lineno, msg.line)
    return _wm._formatwarnmsg_impl(msg)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            matches!(
                ops.as_slice(),
                [Instruction::Resume { .. }, Instruction::Nop, ..]
            ),
            "expected CPython try-line NOP before setup/fetch, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_try_line_nops_after_for_cleanup_are_preserved() {
        let code = compile_exec(
            "\
def f(xs, env):
    for x in xs:
        pass
    try:
        try:
            if env is not None:
                env_list = []
            else:
                env_list = None
        finally:
            pass
    finally:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::PopJumpIfNone { .. },
                    ]
                )
            }),
            "expected CPython-style outer and inner try-line NOPs after for cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_assert_keeps_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(x):
    try:
        assert x
    finally:
        g()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::LoadGlobal { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "assert in try/finally should preserve CPython finalbody-entry NOP after the raise edge, got ops={ops:?}"
        );
        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadCommonConstant { .. },
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "assert true edge should land on a distinct finalbody-entry NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_if_break_false_edge_keeps_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(self, pid):
    while True:
        try:
            if pid == self.pid:
                self.h()
                break
        finally:
            self.r()
        self.g()
    return self.x
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ReturnValue,
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "expected CPython-style if-line NOP before fallthrough finally body, got ops={ops:?}"
        );
    }

    #[test]
    fn try_percent_format_preprocess_removes_redundant_try_nop() {
        let code = compile_exec(
            "\
def f(self, signal):
    if self.returncode and self.returncode < 0:
        try:
            return \"Command '%s' died with %r.\" % (
                self.cmd, signal.Signals(-self.returncode))
        except ValueError:
            return \"Command '%s' died with unknown signal %d.\" % (
                self.cmd, -self.returncode)
    return \"Command '%s' returned non-zero exit status %d.\" % (
        self.cmd, self.returncode)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::NotTaken,
                        Instruction::LoadConst { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "expected preprocessed percent-format body immediately after condition, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::NotTaken,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "percent-format preprocessing should let CFG remove the try-line NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_try_except_in_finally_exception_path_shares_continuation() {
        let code = compile_exec(
            "\
def f(self, exc_type, KeyboardInterrupt, TimeoutExpired):
    try:
        if self.stdin:
            self.stdin.close()
    finally:
        if exc_type == KeyboardInterrupt:
            if self._sigint_wait_secs > 0:
                try:
                    self._wait(timeout=self._sigint_wait_secs)
                except TimeoutExpired:
                    pass
            self._sigint_wait_secs = 0
        else:
            self.wait()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let store_reraise_tails = ops
            .windows(2)
            .filter(|window| {
                matches!(
                    window,
                    [Instruction::StoreAttr { .. }, Instruction::Reraise { .. },]
                )
            })
            .count();

        assert_eq!(
            store_reraise_tails, 1,
            "nested try/except inside an exceptional finally body should share the remaining finalbody tail before RERAISE, got ops={ops:?}"
        );
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadSmallInt { .. },
                        Instruction::LoadFastBorrow { .. },
                        Instruction::StoreAttr { .. },
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "normal finally body should keep CPython-style borrowed load before STORE_ATTR, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_return_keeps_nop_before_final_call_return() {
        let code = compile_exec(
            "\
def f(msg):
    try:
        fw = _wm.formatwarning
    except AttributeError:
        pass
    else:
        if fw is not _formatwarning_orig:
            return fw(msg.message, msg.category, msg.filename, msg.lineno, msg.line)
    return _wm._formatwarnmsg_impl(msg)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ReturnValue,
                        Instruction::Nop,
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::Call { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected CPython-style NOP between conditional return and final call return, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_conditional_scope_exit_keeps_pop_block_nop() {
        let code = compile_exec(
            "\
def f(values, check):
    found = ''
    for value in values:
        try:
            if check(value):
                raise UnicodeError
        except UnicodeError:
            pass
        else:
            found = value
            break
    return found
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::StoreFast { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "try-else after conditional scope exit should keep CPython's POP_BLOCK NOP anchor, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_loop_fallthrough_keeps_end_jump_nop_before_finally() {
        let code = compile_exec(
            "\
def f(locale, category, locales):
    try:
        orig_locale = locale.setlocale(category)
    except AttributeError:
        raise
    except Exception:
        locale = orig_locale = None
        if '' not in locales:
            raise SkipTest('no locales')
    else:
        for loc in locales:
            try:
                locale.setlocale(category, loc)
                break
            except locale.Error:
                pass
        else:
            if '' not in locales:
                raise SkipTest(locales)
    try:
        yield
    finally:
        if locale and orig_locale:
            locale.setlocale(category, orig_locale)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::YieldValue { .. },
                    ]
                )
            }),
            "try-else loop fallthrough should keep CPython's end-label NOP before following try/finally, got ops={ops:?}"
        );
    }

    #[test]
    fn conditional_compare_uses_bool_compare_oparg() {
        let code = compile_exec(
            "\
def f(x, y):
    if x == y:
        return 1
    return 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let compare = f
            .instructions
            .iter()
            .find(|unit| matches!(unit.op, Instruction::CompareOp { .. }))
            .expect("missing COMPARE_OP");

        assert_eq!(u8::from(compare.arg), 88);
    }

    #[test]
    fn multiline_is_none_conditional_keeps_comparator_nop() {
        let code = compile_exec(
            "\
def f(x):
    if x.find(
            'a') is not None:
        return 1
    return 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Call { .. },
                        Instruction::Nop,
                        Instruction::PopJumpIfNone { .. },
                    ]
                )
            }),
            "expected CPython-style comparator NOP before folded POP_JUMP_IF_NONE, got ops={ops:?}"
        );
    }

    #[test]
    fn chained_conditional_compares_use_bool_compare_oparg() {
        let code = compile_exec(
            "\
def f(a, b, c):
    if a < b < c:
        return 1
    return 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let compare_args: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::CompareOp { .. }))
            .map(|unit| u8::from(unit.arg))
            .collect();

        assert_eq!(compare_args, vec![18, 18]);
    }

    #[test]
    fn shared_final_return_is_cloned_for_jump_target() {
        let code = compile_exec(
            "\
def f(node):
    if not isinstance(
        node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)
    ) or len(node.body) < 1:
        return None
    node = node.body[0]
    if not isinstance(node, Expr):
        return None
    node = node.value
    if isinstance(node, Constant) and isinstance(node.value, str):
        return node
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let return_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            return_count, 5,
            "expected cloned return sites for each shared return edge, got ops={ops:?}"
        );
    }

    #[test]
    fn for_break_uses_poptop_cleanup() {
        let code = compile_exec(
            "\
def f(parts):
    for value in parts:
        if value:
            break
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let pop_iter_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::PopIter))
            .count();
        assert_eq!(
            pop_iter_count, 1,
            "expected only the loop-exhaustion POP_ITER, got ops={ops:?}"
        );

        let break_cleanup_idx = ops
            .windows(3)
            .position(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue
                    ]
                )
            })
            .expect("missing POP_TOP/LOAD_CONST/RETURN_VALUE break cleanup");
        let end_for_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::EndFor))
            .expect("missing END_FOR");
        assert!(
            break_cleanup_idx < end_for_idx,
            "expected break cleanup before END_FOR, got ops={ops:?}"
        );
    }

    #[test]
    fn for_exit_before_elif_does_not_leave_line_anchor_nop() {
        let code = compile_exec(
            "\
from sys import maxsize
if maxsize == 2147483647:
    for s in ('2147483648', '0o40000000000', '0x100000000', '0b10000000000000000000000000000000'):
        try:
            x = eval(s)
        except OverflowError:
            fail('OverflowError on huge integer literal %r' % s)
elif maxsize == 9223372036854775807:
    pass
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected for-exit epilogue without extra NOP, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "unexpected line-anchor NOP before for-exit epilogue, got ops={ops:?}"
        );
    }

    #[test]
    fn for_tuple_target_does_not_leave_loop_header_nop() {
        let code = compile_exec(
            "\
def f(pairs):
    for left, right in pairs:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ForIter { .. },
                        Instruction::UnpackSequence { .. }
                    ]
                )
            }),
            "expected FOR_ITER to flow directly into UNPACK_SEQUENCE, got ops={ops:?}"
        );
        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ForIter { .. },
                        Instruction::Nop,
                        Instruction::UnpackSequence { .. },
                    ]
                )
            }),
            "unexpected loop-header NOP before tuple unpack, got ops={ops:?}"
        );
    }

    #[test]
    fn tstring_build_template_matches_cpython_stack_order() {
        let code = compile_exec("t = t\"{0}\"");
        let units: Vec<_> = code
            .instructions
            .iter()
            .copied()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            units.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        a,
                        b,
                        c,
                        d,
                        e,
                        f,
                    ]
                    if matches!(a.op, Instruction::LoadConst { .. })
                        && matches!(b.op, Instruction::LoadSmallInt { .. })
                        && matches!(c.op, Instruction::LoadConst { .. })
                        && matches!(d.op, Instruction::BuildInterpolation { .. })
                        && u8::from(d.arg) == 2
                        && matches!(e.op, Instruction::BuildTuple { .. })
                        && u8::from(e.arg) == 1
                        && matches!(f.op, Instruction::BuildTemplate)
                )
            }),
            "expected CPython-style t-string lowering, got units={units:?}"
        );
        assert!(
            !units
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Swap { .. })),
            "unexpected SWAP in t-string lowering, got units={units:?}"
        );
    }

    #[test]
    fn tstring_debug_specifier_uses_debug_literal_and_repr_default() {
        let code = compile_exec(
            "\
value = 42
t = t\"Value: {value=}\"
",
        );

        let string_consts = code
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadConst { consti } => {
                    Some(&code.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))])
                }
                _ => None,
            })
            .collect::<Vec<_>>();

        assert!(
            string_consts.iter().any(|constant| matches!(
                constant,
                ConstantData::Tuple { elements }
                    if matches!(
                        &elements[..],
                        [
                            ConstantData::Str { value: first },
                            ConstantData::Str { value: second },
                        ] if first.to_string() == "Value: value=" && second.is_empty()
                    )
            )),
            "expected debug literal prefix in t-string constants, got {string_consts:?}"
        );
        assert!(
            code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BuildInterpolation { .. }
            ) && u8::from(unit.arg) == 10),
            "expected default repr conversion for debug t-string"
        );
    }

    #[test]
    fn tstring_ops_restore_template_and_interpolation_locations_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    return t\"{x}\"
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let mut build_interpolation = None;
        let mut build_tuple = None;
        let mut build_template = None;
        for (unit, (location, end_location)) in f.instructions.iter().zip(&f.locations) {
            let range = (
                location.line.get(),
                location.character_offset.get(),
                end_location.line.get(),
                end_location.character_offset.get(),
            );
            match unit.op {
                Instruction::BuildInterpolation { .. } => build_interpolation = Some(range),
                Instruction::BuildTuple { .. } => build_tuple = Some(range),
                Instruction::BuildTemplate => build_template = Some(range),
                _ => {}
            }
        }

        assert_eq!(
            build_interpolation,
            Some((2, 14, 2, 17)),
            "CPython codegen_interpolation() restores LOC(Interpolation) after visiting the value; this direct codegen path uses the parser's Interpolation range"
        );
        assert_eq!(
            build_tuple,
            Some((2, 12, 2, 18)),
            "CPython codegen_template_str() emits the interpolations tuple at LOC(TemplateStr); this direct codegen path uses the parser's TemplateStr range"
        );
        assert_eq!(
            build_template,
            Some((2, 12, 2, 18)),
            "CPython codegen_template_str() emits BUILD_TEMPLATE at LOC(TemplateStr); this direct codegen path uses the parser's TemplateStr range"
        );
    }

    #[test]
    fn regular_call_push_null_uses_callee_location_like_cpython() {
        let code = compile_exec(
            "\
def f(g, x):
    return (
        g
    )(x)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let push_null = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::PushNull).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing PUSH_NULL");

        assert_eq!(
            push_null,
            (3, 9, 3, 10),
            "CPython codegen_call() resets loc to LOC(func) before emitting PUSH_NULL; this direct codegen path uses the parser's callee range"
        );
    }

    #[test]
    fn tstring_literal_preserves_surrogate_wtf8() {
        let code = compile_exec("t = t\"\\ud800\"");

        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Str { value } if value.clone().into_bytes() == [0xED, 0xA0, 0x80]
        )));
    }

    #[test]
    fn break_in_finally_after_return_keeps_load_fast_check_for_loop_locals() {
        let code = compile_exec(
            "\
def g2(x):
    for count in [0, 1]:
        for count2 in [10, 20]:
            try:
                return count + count2
            finally:
                if x:
                    break
    return 'end', count, count2
",
        );
        let g2 = find_code(&code, "g2").expect("missing g2 code");
        let ops: Vec<_> = g2
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadConst { .. },
                        Instruction::LoadFastCheck { .. },
                        Instruction::LoadFastCheck { .. },
                        Instruction::BuildTuple { .. },
                    ]
                )
            }),
            "expected LOAD_FAST_CHECK pair for after-return loop locals, got ops={ops:?}"
        );
    }

    #[test]
    fn high_index_parameter_stays_initialized_in_fast_scan() {
        let params = (0..65)
            .map(|idx| format!("p{idx}"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!(
            "\
def f({params}):
    return p64
"
        ));
        let f = find_code(&code, "f").expect("missing f code");

        assert!(
            f.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::LoadFastCheck { var_num }
                    if f.varnames
                        [usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))))]
                        == "p64"
            )),
            "CPython 3.14 fast_scan_many_locals() checks high-index parameters per block; expected p64 to use LOAD_FAST_CHECK, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn deleted_high_index_parameter_uses_load_fast_check() {
        let params = (0..65)
            .map(|idx| format!("p{idx}"))
            .collect::<Vec<_>>()
            .join(", ");
        let code = compile_exec(&format!(
            "\
def f({params}):
    del p64
    return p64
"
        ));
        let f = find_code(&code, "f").expect("missing f code");

        assert!(
            f.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::LoadFastCheck { var_num }
                    if f.varnames
                        [usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))))]
                        == "p64"
            )),
            "expected deleted high-index parameter p64 to use LOAD_FAST_CHECK, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn assert_without_message_raises_class_directly() {
        let code = compile_exec(
            "\
def f(x):
    assert x
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let call_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::Call { .. }))
            .count();
        let push_null_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::PushNull))
            .count();

        assert_eq!(call_count, 0);
        assert_eq!(push_null_count, 0);
    }

    #[test]
    fn assert_with_message_uses_common_constant_direct_call() {
        let code = compile_exec(
            "\
def f(x, y):
    assert x, y
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_assertion = f
            .instructions
            .iter()
            .position(|unit| {
                matches!(unit.op, Instruction::LoadCommonConstant { .. })
                    && matches!(
                        unit.op,
                        Instruction::LoadCommonConstant { idx }
                            if idx.get(OpArg::new(u32::from(u8::from(unit.arg))))
                                == bytecode::CommonConstant::AssertionError
                    )
            })
            .expect("missing LOAD_COMMON_CONSTANT AssertionError");

        assert!(
            !matches!(
                f.instructions.get(load_assertion + 1).map(|unit| unit.op),
                Some(Instruction::PushNull)
            ),
            "assert message path should not use PUSH_NULL, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            matches!(
                f.instructions.get(load_assertion + 2).map(|unit| unit.op),
                Some(Instruction::Call { .. })
            ),
            "expected direct CALL after loading assert message, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );

        let call_arg = f.instructions[load_assertion + 2].arg;
        assert_eq!(u8::from(call_arg), 0);
    }

    #[test]
    fn conditional_assert_message_target_uses_strong_load_fast() {
        let code = compile_exec(
            "\
def f(fname):
    if fname == 'a':
        return 1
    assert False, 'Unknown attrname %s' % fname
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let assertion_error = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadCommonConstant { .. }))
            .expect("missing LOAD_COMMON_CONSTANT AssertionError");
        let window = &ops[assertion_error..(assertion_error + 5).min(ops.len())];
        assert!(
            matches!(
                window,
                [
                    Instruction::LoadCommonConstant { .. },
                    Instruction::LoadConst { .. },
                    Instruction::LoadFast { .. },
                    Instruction::BinaryOp { .. },
                    Instruction::Call { .. },
                    ..
                ]
            ),
            "expected CPython-style strong LOAD_FAST in targeted assert message block, got {window:?}"
        );
    }

    #[test]
    fn chained_compare_assert_message_keeps_borrowed_load_fast() {
        let code = compile_exec(
            "\
def f(month):
    assert 1 <= month <= 12, f'month must be in 1..12, not {month}'
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let assertion_error = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadCommonConstant { .. }))
            .expect("missing LOAD_COMMON_CONSTANT AssertionError");
        let raise = ops[assertion_error..]
            .iter()
            .position(|op| matches!(op, Instruction::RaiseVarargs { .. }))
            .map(|idx| assertion_error + idx)
            .expect("missing assert raise");
        let message_path = &ops[assertion_error..raise];

        assert!(
            message_path
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "CPython keeps assert message loads borrowed for same-line chained compare failure blocks, got {message_path:?}"
        );
        assert!(
            !message_path
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "same-line chained compare assert message should not be deoptimized to LOAD_FAST, got {message_path:?}"
        );
    }

    #[test]
    fn assert_message_after_condition_in_same_block_keeps_borrowed_loads() {
        let code = compile_exec(
            "\
def f(expected_ns, namespace):
    try:
        assert expected_ns == namespace, ('expected %s, got %s' % (expected_ns, namespace))
    except AssertionError as e:
        raise RuntimeError(e)
    setattr(namespace, 'spam', expected_ns)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let assertion_error = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::LoadCommonConstant { .. }))
            .expect("missing LOAD_COMMON_CONSTANT AssertionError");
        let raise = ops[assertion_error..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
            .map(|idx| assertion_error + idx)
            .expect("missing assert raise");
        let message_path = &ops[assertion_error..raise];

        let load_fast_name = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let borrow_name = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        assert!(
            message_path
                .iter()
                .filter_map(load_fast_name)
                .all(|name| name != "expected_ns" && name != "namespace"),
            "assert message after same-block condition should keep borrowed loads, got {message_path:?}"
        );
        for name in ["expected_ns", "namespace"] {
            assert!(
                message_path
                    .iter()
                    .filter_map(borrow_name)
                    .any(|var| var == name),
                "expected borrowed {name} load in assert message path, got {message_path:?}"
            );
        }

        let setattr = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::LoadGlobal { .. }))
            .expect("missing final setattr load");
        let tail = &ops[setattr..];
        for name in ["expected_ns", "namespace"] {
            assert!(
                tail.iter()
                    .filter_map(load_fast_name)
                    .any(|var| var == name),
                "expected strong {name} load in post-try tail, got {tail:?}"
            );
        }
    }

    #[test]
    fn bare_function_annotations_check_attribute_and_subscript_expressions() {
        let code = compile_exec(
            "\
def f(one: int):
    int.new_attr: int
    [list][0].new_attr: [int, str]
    my_lst = [1]
    my_lst[one]: int
    return my_lst
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let loads_global = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadGlobal { namei } => {
                    let namei = namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) >> 1;
                    f.names[usize::try_from(namei).unwrap()].as_str() == name
                }
                _ => false,
            })
        };
        assert!(
            loads_global("int"),
            "bare attribute annotations should evaluate int, got ops={:?}",
            f.instructions
        );
        assert!(
            loads_global("list"),
            "bare subscript annotations should evaluate list, got ops={:?}",
            f.instructions
        );
    }

    #[test]
    fn function_local_annassign_annotation_does_not_capture_outer_local() {
        let code = compile_exec(
            "\
def f():
    from collections import namedtuple

    class MyHandler:
        def __init__(self, resource):
            self.resource: namedtuple = resource

    return namedtuple
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let class_code = find_code(&code, "MyHandler").expect("missing MyHandler code");
        let init = find_code(&code, "__init__").expect("missing __init__ code");

        assert!(
            !f.cellvars.iter().any(|name| name == "namedtuple"),
            "function-local AnnAssign annotation must not make namedtuple a cell, got cellvars={:?}",
            f.cellvars
        );
        assert!(
            !class_code.freevars.iter().any(|name| name == "namedtuple"),
            "class body must not close over function-local annotation-only name, got freevars={:?}",
            class_code.freevars
        );
        assert!(
            !init.freevars.iter().any(|name| name == "namedtuple"),
            "method body must not close over function-local annotation-only name, got freevars={:?}",
            init.freevars
        );
    }

    #[test]
    fn finally_exception_path_inlines_except_pass_reraise_tail() {
        let source = "\
def f(self, file, backupfilename):
    try:
        if file:
            file.close()
    finally:
        backupfilename = self._backupfilename
        self._backupfilename = None
        if backupfilename and not self._backup:
            try:
                os.unlink(backupfilename)
            except OSError:
                pass
        self._isstdin = False
";
        let code = compile_exec(source);
        let f = find_code(&code, "f").expect("missing f code");
        assert!(
            f.instructions.windows(9).any(|window| {
                matches!(
                    [
                        window[0].op,
                        window[1].op,
                        window[2].op,
                        window[3].op,
                        window[8].op,
                    ],
                    [
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::LoadFast { .. },
                        Instruction::StoreAttr { .. },
                        Instruction::Reraise { .. },
                    ]
                ) && match window[8].op {
                    Instruction::Reraise { depth } => {
                        depth.get(OpArg::new(u32::from(u8::from(window[8].arg)))) == 0
                    }
                    _ => false,
                }
            }),
            "except-pass normal exit in a finally exception path should inline the CPython reraise tail, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn nested_finally_exception_path_prunes_dead_normal_cleanup() {
        let code = compile_exec(
            "\
def f():
    try:
        raise ValueError
    finally:
        try:
            raise KeyError
        finally:
            1/0
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let load_global_name = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadGlobal { namei } => {
                let name = namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) >> 1;
                Some(f.names[usize::try_from(name).unwrap()].as_str())
            }
            _ => None,
        };
        let value_error_pos = ops
            .iter()
            .position(|unit| load_global_name(unit) == Some("ValueError"))
            .expect("missing ValueError load");
        let key_error_pos = ops
            .iter()
            .position(|unit| load_global_name(unit) == Some("KeyError"))
            .expect("missing KeyError load");
        let first_push_exc_after_value_error = ops[value_error_pos..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .map(|pos| pos + value_error_pos)
            .expect("missing finally exception entry");
        let first_copy_after_value_error = ops[value_error_pos..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::Copy { .. }))
            .map(|pos| pos + value_error_pos)
            .expect("missing finally cleanup copy");

        assert!(
            first_push_exc_after_value_error < key_error_pos,
            "CPython codegen_try_finally() enters the outer finally exception path before compiling the nested try body; got ops={ops:?}"
        );
        assert!(
            first_push_exc_after_value_error < first_copy_after_value_error,
            "CPython remove_unreachable() must not keep cleanup targets from dead normal-finally paths before the live exception path; got ops={ops:?}"
        );
    }

    #[test]
    fn non_simple_bare_name_annotation_does_not_create_local_binding() {
        let code = compile_exec(
            "\
def f2bad():
    (no_such_global): int
    print(no_such_global)
",
        );
        let f = find_code(&code, "f2bad").expect("missing f2bad code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadGlobal { .. })),
            "expected LOAD_GLOBAL for non-simple bare annotated name, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastCheck { .. })),
            "non-simple bare annotated name should not become a local binding, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn negative_constant_binop_folds_after_unary_folding() {
        let code = compile_exec(
            "\
def f():
    return -2147483647 - 1
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "negative constant expression should fold to a single constant, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadConst { .. })),
            "expected folded constant load, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn genexpr_filter_header_uses_store_fast_load_fast() {
        let code = compile_exec(
            "\
def f(it):
    return (x for x in it if x)
",
        );
        let genexpr = find_code(&code, "<genexpr>").expect("missing <genexpr> code");
        let store_fast_load_fast_idx = genexpr
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::StoreFastLoadFast { .. }))
            .expect("missing STORE_FAST_LOAD_FAST in genexpr header");

        assert!(
            matches!(
                genexpr
                    .instructions
                    .get(store_fast_load_fast_idx + 1)
                    .map(|unit| unit.op),
                Some(Instruction::ToBool)
            ),
            "expected TO_BOOL immediately after STORE_FAST_LOAD_FAST, got ops={:?}",
            genexpr
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn generator_filter_keeps_cpython_style_forward_yield_body_entry() {
        let code = compile_exec(
            "\
def gen(it):
    for f in it:
        if f.name:
            yield f.name
",
        );
        let gen_code = find_code(&code, "gen").expect("missing gen code");
        let ops: Vec<_> = gen_code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::YieldValue { .. },
                    ]
                )
            }),
            "expected CPython-style generator filter to jump on true into the yield body and fall through into the loop backedge on false, got ops={ops:?}"
        );
    }

    #[test]
    fn generator_negated_filter_keeps_cpython_style_false_edge_into_yield_body() {
        let code = compile_exec(
            "\
def gen(fields):
    for f in fields:
        if f.init and not f.kw_only:
            yield f
",
        );
        let gen_code = find_code(&code, "gen").expect("missing gen code");
        let ops: Vec<_> = gen_code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::YieldValue { .. },
                        Instruction::Resume { .. },
                    ]
                )
            }),
            "expected CPython-style negated generator filter to jump on false into the yield body and fall through into the loop backedge on true, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_filter_with_nested_loop_body_uses_cpython_implicit_continue_layout() {
        let code = compile_exec(
            "\
def f(values):
    for fmt, items in values:
        nd = make(items, fmt)
        for i in range(-5, 5):
            check(nd[i], items[i])
        check(nd[-6])
        check(nd[5])
        if is_memoryview_format(fmt):
            mv = memoryview(nd)
            check(mv, nd)
            for i in range(-5, 5):
                check(mv[i], items[i])
            check(mv[-6])
            check(mv[5])
    return None
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style nested loop filter to fall through into the implicit continue and jump on true into the body, got ops={ops:?}"
        );
    }

    #[test]
    fn final_elif_with_inlined_comprehensions_threads_backedge_before_body() {
        let code = compile_exec(
            "\
def f(checks, enumeration, named):
    for check in checks:
        if check == 1:
            pass
        elif check is named:
            member_names = enumeration._member_names_
            member_values = [m.value for m in enumeration]
            missing_names = []
            missing_value = 0
            for name, alias in enumeration._member_map_.items():
                if name in member_names:
                    continue
                if alias.value < 0:
                    continue
                values = list(_iter_bits_lsb(alias.value))
                missed = [v for v in values if v not in member_values]
                if missed:
                    missing_names.append(name)
                    for val in missed:
                        missing_value |= val
            if missing_names:
                raise ValueError('x')
    return enumeration
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::IsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "expected CPython-style final elif to put loop backedge before the inlined-comprehension body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::IsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "unexpected final elif body before loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn multi_with_header_uses_store_fast_load_fast() {
        let code = compile_exec(
            "\
def f(manager):
    with manager() as x, manager():
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::StoreFastLoadFast { .. })),
            "expected STORE_FAST_LOAD_FAST in multi-with header, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn sequential_store_then_load_uses_store_fast_load_fast() {
        let code = compile_exec(
            "\
def f(self):
    x = ''; y = \"\"; self.assertTrue(len(x) == 0 and x == y)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::StoreFastLoadFast { .. })),
            "expected STORE_FAST_LOAD_FAST in sequential statement body, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn match_guard_capture_uses_store_fast_load_fast() {
        let code = compile_exec(
            "\
def f():
    match 0:
        case x if x:
            z = 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::StoreFastLoadFast { .. })),
            "expected STORE_FAST_LOAD_FAST in match guard capture path, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn match_nested_capture_uses_store_fast_store_fast() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case ((0 as w) as z):
            return w, z
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::StoreFastStoreFast { .. })),
            "expected STORE_FAST_STORE_FAST in nested match capture path, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn match_value_real_zero_minus_zero_complex_folds_to_negative_zero_imag() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case 0 - 0j:
            return 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        assert!(
            f.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Complex { value }
                    if value.re == 0.0 && value.im == 0.0 && value.im.is_sign_negative()
            )),
            "expected folded -0j constant in match value"
        );
    }

    #[test]
    fn match_negative_value_const_precedes_implicit_none_like_cpython() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case -0.0:
            y = 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let negative_zero_index = f
            .constants
            .iter()
            .position(|constant| {
                matches!(
                    constant,
                    ConstantData::Float { value } if *value == 0.0 && value.is_sign_negative()
                )
            })
            .expect("missing folded -0.0 match value");
        let none_index = f
            .constants
            .iter()
            .position(|constant| matches!(constant, ConstantData::None))
            .expect("missing implicit None");
        assert!(
            negative_zero_index < none_index,
            "CPython ast_preprocess.c folds MatchValue constants before codegen registers the implicit None"
        );
    }

    #[test]
    fn match_or_uses_shared_success_block() {
        let code = compile_exec(
            "\
def http_error(status):
    match status:
        case 400:
            return 'Bad request'
        case 401 | 403 | 404:
            return 'Not allowed'
        case 418:
            return 'I am a teapot'
",
        );
        let f = find_code(&code, "http_error").expect("missing http_error code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let jump_positions: Vec<_> = ops
            .iter()
            .enumerate()
            .filter_map(|(i, op)| matches!(op, Instruction::JumpForward { .. }).then_some(i))
            .collect();

        assert!(
            jump_positions.len() >= 4,
            "expected shared-success JumpForward ops in OR pattern, got ops={ops:?}"
        );

        let first_pop_top_pair = ops
            .windows(2)
            .position(|window| matches!(window, [Instruction::PopTop, Instruction::PopTop]))
            .expect("missing POP_TOP/POP_TOP success cleanup");

        assert!(
            jump_positions
                .iter()
                .take(3)
                .all(|&idx| idx < first_pop_top_pair),
            "expected OR-alternative jumps before shared success cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn match_try_body_keeps_setup_nop_after_success_pop() {
        let code = compile_exec(
            "\
def f(x):
    match x:
        case 1:
            try:
                y = 2
            except Exception:
                pass
        case 2:
            y = 3
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| matches!(
                window,
                [
                    Instruction::PopTop,
                    Instruction::Nop,
                    Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. }
                ]
            )),
            "expected CPython-style match success POP_TOP followed by try-entry NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn match_mapping_attribute_key_keeps_plain_load_fast_without_block_disable() {
        let code = compile_exec(
            "\
def f(self):
    class Keys:
        KEY = 'a'
    x = {'a': 0, 'b': 1}
    with self.assertRaises(ValueError):
        match x:
            case {Keys.KEY: y, 'a': z}:
                w = 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let assert_raises_attr = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "assertRaises"
                }
                _ => false,
            })
            .expect("missing assertRaises attribute load");
        let assert_raises_receiver = f.instructions[assert_raises_attr - 1].op;
        assert!(
            matches!(assert_raises_receiver, Instruction::LoadFastBorrow { .. }),
            "mapping attribute key handling must not disable borrow optimization for the whole block; got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        let key_load_idx = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "KEY"
                }
                _ => false,
            })
            .expect("missing Keys.KEY attribute load");
        let prev = f.instructions[key_load_idx - 1].op;
        assert!(
            matches!(prev, Instruction::LoadFast { .. }),
            "CPython optimize_load_fast() records MATCH_KEYS' no-input pseudo-ref with the produced-value loop index, so this consumed Keys load stays strong; got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn if_false_body_blocks_following_load_fast_borrow() {
        let code = compile_exec(
            "\
def f(self, groupby):
    self.a()
    if False:
        self.dead()
    self.b(groupby)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let units: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let b_attr_idx = units
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "b"
                }
                _ => false,
            })
            .expect("missing self.b attribute load");
        assert!(
            matches!(units[b_attr_idx - 1].op, Instruction::LoadFast { .. }),
            "CPython keeps plain LOAD_FAST after an if False dead-body placeholder, got ops={:?}",
            units.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(units[b_attr_idx + 1].op, Instruction::LoadFast { .. }),
            "CPython keeps the argument LOAD_FAST plain after an if False dead-body placeholder, got ops={:?}",
            units.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn imap_append_untagged_assert_tail_keeps_load_fast() {
        let code = compile_exec(
            "\
def f(self, typ, dat):
    if self._idle_capture:
        if (not self._idle_responses or
            isinstance(self._idle_responses[-1][1][-1], bytes)):
            self._idle_responses.append((typ, [dat]))
        else:
            response = self._idle_responses[-1]
            assert response[0] == typ
            response[1].append(dat)
        if __debug__ and self.debug >= 5:
            self._mesg(f'idle: queue untagged {typ} {dat!r}')
        return
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let units: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let debug_attr_idx = units
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "debug"
                }
                _ => false,
            })
            .expect("missing debug attribute load");
        assert!(
            matches!(units[debug_attr_idx - 1].op, Instruction::LoadFast { .. }),
            "CPython keeps the debug tail after an emptied bool-op block as LOAD_FAST, got ops={:?}",
            units.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );

        let mesg_attr_idx = units
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "_mesg"
                }
                _ => false,
            })
            .expect("missing _mesg attribute load");
        assert!(
            matches!(units[mesg_attr_idx - 1].op, Instruction::LoadFast { .. })
                && matches!(units[mesg_attr_idx + 2].op, Instruction::LoadFast { .. })
                && matches!(units[mesg_attr_idx + 5].op, Instruction::LoadFast { .. }),
            "CPython keeps LOAD_FAST in the debug message after the empty join block, got ops={:?}",
            units.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn assert_success_empty_boolop_block_keeps_load_fast() {
        let code = compile_exec(
            "\
def f(self):
    imap = self._imap
    assert not imap._idle_responses
    assert not imap._idle_capture
    if __debug__ and imap.debug >= 4:
        imap._mesg(f'idle start duration={self._duration}')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let units: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let debug_attr_idx = units
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "debug"
                }
                _ => false,
            })
            .expect("missing debug attribute load");
        assert!(
            matches!(units[debug_attr_idx - 1].op, Instruction::LoadFast { .. }),
            "CPython preserves the empty assert-success bool-op block as a LOAD_FAST barrier, got ops={:?}",
            units.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn try_except_else_with_finally_keeps_with_handler_before_outer_except() {
        let code = compile_exec(
            "\
def f(i):
    try:
        1 / 0
    except ZeroDivisionError:
        print('e')
    else:
        with i as dodgy:
            print('w')
    finally:
        print('d')
",
        );
        let jumpy = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = jumpy
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let with_except_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::WithExceptStart))
            .expect("missing WITH_EXCEPT_START");
        let check_exc_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::CheckExcMatch))
            .expect("missing CHECK_EXC_MATCH");
        assert!(
            with_except_idx < check_exc_idx,
            "expected with-except cleanup to be emitted before outer except matching like CPython, got ops={ops:?}",
        );

        let with_cleanup_end = ops
            .windows(5)
            .position(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            })
            .expect("missing with success cleanup")
            + 5;
        assert!(
            !matches!(ops.get(with_cleanup_end), Some(Instruction::Nop)),
            "expected with success cleanup to fall straight into the surrounding continuation without a synthetic NOP target, got ops={ops:?}",
        );
    }

    #[test]
    fn nested_try_finally_keeps_inner_finally_cleanup_nop() {
        let code = compile_exec(
            "\
def f(a, b, d):
    try:
        try:
            a()
        finally:
            b()
    finally:
        d()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::PopTop, 6),
                        (Instruction::Nop, 6),
                        (
                            Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                            8
                        ),
                    ]
                )
            }),
            "expected CPython-style inner finally cleanup NOP before outer finalbody, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn nested_finally_open_conditional_falls_through_without_entry_nop() {
        let code = compile_exec(
            "\
def f(self, f, closed, new_key):
    try:
        try:
            work()
        finally:
            if self._locked:
                _unlock_file(f)
    finally:
        if not closed:
            _sync_close(f)
    return new_key
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache | Instruction::NotTaken))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "expected CPython-style fallthrough from inner finally body into outer finalbody condition, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "unexpected preserved inner-finally entry NOP before outer finalbody condition, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_finally_closed_conditional_falls_through_without_extra_entry_nop() {
        let code = compile_exec(
            "\
def f(was_enabled, faulthandler, sys, orig_stderr):
    try:
        try:
            faulthandler.enable()
            faulthandler.disable()
        finally:
            if was_enabled:
                faulthandler.enable()
            else:
                faulthandler.disable()
    finally:
        sys.stderr = orig_stderr
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache | Instruction::NotTaken))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::StoreAttr { .. },
                    ]
                )
            }),
            "CPython keeps the inner finally cleanup anchor before the outer finalbody, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::Nop,
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::StoreAttr { .. },
                    ]
                )
            }),
            "closed conditional inner finalbody should not add a second outer finalbody-entry NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn with_try_finally_normal_cleanup_keeps_redundant_jump_nop() {
        let code = compile_exec(
            "\
def f(cm):
    with cm:
        try:
            x = 1
        finally:
            del x
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::DeleteFast { .. }, 6),
                        (Instruction::Nop, 6),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::Call { .. }, 2),
                    ]
                )
            }),
            "expected CPython-style redundant finally cleanup jump to become a line NOP before with-exit cleanup, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn with_try_except_normal_cleanup_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm, names, modname):
    with cm:
        try:
            exec('import %s' % modname, names)
        except:
            raise FailedImport(modname)
    return names
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "try/except inside with should preserve the CPython body-exit NOP before with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn with_try_except_return_handler_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm):
    with cm:
        try:
            x = 1
        except OSError:
            return False
    return True
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "scope-exiting except handler inside with should preserve the CPython body-exit NOP before with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn with_try_except_else_return_handler_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm, func, check):
    with cm:
        try:
            func()
        except ValueError:
            return False
        else:
            check()
    return True
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "try/except/else inside with with scope-exiting handler should preserve the CPython body-exit NOP before with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn with_try_except_else_continue_handler_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(meta_path, cm):
    for finder in meta_path:
        with cm:
            try:
                find_spec = finder.find_spec
            except AttributeError:
                continue
            else:
                spec = find_spec()
        if spec is not None:
            return spec
    return None
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::Call { .. }, 9),
                        (Instruction::StoreFast { .. }, 9),
                        (Instruction::Nop, 9),
                        (Instruction::LoadConst { .. }, 3),
                        (Instruction::LoadConst { .. }, 3),
                        (Instruction::LoadConst { .. }, 3),
                    ]
                )
            }),
            "try/except/else with continue handler should preserve the CPython body-exit NOP before with cleanup, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn elif_boolop_skips_following_elif_with_forward_jumpback_block() {
        let code = compile_exec(
            r#"
def f(module, fromlist, import_, recursive=False):
    for x in fromlist:
        if not isinstance(x, str):
            raise TypeError
        elif x == '*':
            if not recursive and hasattr(module, '__all__'):
                _handle_fromlist(module, module.__all__, import_, recursive=True)
        elif not hasattr(module, x):
            pass
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_load_global =
            |unit: &&rustpython_compiler_core::bytecode::CodeUnit, name: &str| match unit.op {
                Instruction::LoadGlobal { namei } => {
                    let namei = namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) >> 1;
                    f.names[usize::try_from(namei).unwrap()].as_str() == name
                }
                _ => false,
            };

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        unit0,
                        unit1,
                        unit2,
                        unit3,
                    ] if matches!(unit0.op, Instruction::ToBool)
                        && matches!(unit1.op, Instruction::PopJumpIfTrue { .. })
                        && matches!(unit2.op, Instruction::NotTaken)
                        && is_load_global(unit3, "hasattr")
                )
            }),
            "boolop branch in elif should keep CPython's forward jump-back block before hasattr, got ops={ops:?}",
        );
    }

    #[test]
    fn with_nonterminal_try_except_normal_cleanup_drops_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm):
    with cm:
        try:
            x = 1
        except Exception:
            pass
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "non-terminal except inside with should not preserve a body-exit NOP before with cleanup, got ops={ops:?}"
        );
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "expected CPython-style direct fallthrough into with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn with_try_except_scope_exit_body_handler_fallthrough_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm, ValueError):
    with cm:
        try:
            raise ValueError
        except 42:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::Nop, 6),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::Call { .. }, 2),
                    ]
                )
            }),
            "handler fallthrough target should preserve the CPython NOP before with cleanup, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn with_try_except_nested_with_normal_cleanup_drops_body_exit_nop() {
        let code = compile_exec(
            "\
def f(open, src, dst, copyfileobj):
    with open(src) as fsrc:
        try:
            with open(dst) as fdst:
                copyfileobj(fsrc, fdst)
        except IsADirectoryError:
            raise
    return dst
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "nested with normal cleanup in try/except should fall directly into outer with cleanup, got ops={ops:?}"
        );
        assert!(
            !ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "nested with normal cleanup in try/except should not preserve a body-exit NOP before outer with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn with_nested_if_try_except_normal_cleanup_drops_body_exit_nop() {
        let code = compile_exec(
            "\
def f(cm, root):
    with cm:
        if root:
            try:
                x = 1
            except Exception as e:
                raise ValueError from e
    return root
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "nested try/except should not preserve a body-exit NOP before with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn try_except_finally_normal_cleanup_keeps_body_exit_nop() {
        let code = compile_exec(
            "\
def f(self, x):
    if x and self.sock:
        saved = self.sock.gettimeout()
        self.sock.settimeout(x)
        try:
            resp = self._get_line()
        except TimeoutError as err:
            raise self._timeout from err
        finally:
            self.sock.settimeout(saved)
    else:
        resp = self._get_line()
    return resp
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let resp_store = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == "resp"
                }
                _ => false,
            })
            .expect("missing resp store");

        assert!(
            matches!(
                ops.get(resp_store + 1).map(|unit| unit.op),
                Some(Instruction::Nop)
            ),
            "expected CPython-style NOP between try/except normal body exit and finally cleanup, got ops={ops:?}",
        );
    }

    #[test]
    fn try_except_finally_open_conditional_fallthrough_drops_body_exit_nop() {
        let code = compile_exec(
            "\
def f(err, ov, self):
    try:
        if err:
            assert ov
    except:
        ov.cancel()
        raise
    finally:
        self.cleanup()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let assert_raise = ops
            .iter()
            .position(|op| matches!(op, Instruction::RaiseVarargs { .. }))
            .expect("missing assertion raise");

        assert!(
            !matches!(ops.get(assert_raise + 1), Some(Instruction::Nop)),
            "open conditional fallthrough should go directly into finally cleanup, got ops={ops:?}",
        );
    }

    #[test]
    fn try_finally_loop_fallthrough_keeps_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(close, dup, first, second):
    try:
        retries = 0
        while second != first + 1:
            close(first)
            retries += 1
            if retries > 10:
                raise RuntimeError
            first, second = second, dup(second)
    finally:
        close(second)
    close(first)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::PushNull,
                    ]
                )
            }),
            "try/finally loop fallthrough should preserve CPython finalbody-entry NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_boolop_while_fallthrough_drops_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(active, socket_map, asyncore):
    try:
        while active and socket_map:
            asyncore.loop(timeout=0.1, count=1)
    finally:
        asyncore.close_all(ignore_all=True)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "CPython removes the no-location POP_BLOCK NOP before a boolop-while try/finally finalbody, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. },
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "boolop-while try/finally finalbody should not keep a POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_with_infinite_loop_body_drops_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(self, func, args, kwargs):
    try:
        with self.assertRaises(ZeroDivisionError) as cm:
            while True:
                self.setAlarm(self.alarm_time)
                func(*args, **kwargs)
    finally:
        self.setAlarm(0)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Reraise { .. },
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "CPython removes the no-location POP_BLOCK NOP before the normal finalbody after a with-wrapped infinite loop, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "with-wrapped infinite loop try/finally should not keep a finalbody-entry NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_with_finalbody_blocks_following_with_borrow() {
        let code = compile_exec(
            "\
def f(self, sock, socket, HOST, OSError, TypeError):
    try:
        sock.bind((HOST, 0))
        socket.close(sock.fileno())
        with self.assertRaises(OSError):
            sock.listen(1)
    finally:
        with self.assertRaises(OSError):
            sock.close()
    with self.assertRaises(TypeError):
        socket.close(42, 42)
    with self.assertRaises(OSError):
        socket.close(-1)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let strong_self_loads = count_strong_loads_for_vars(f, &["self"]);
        assert!(
            strong_self_loads >= 2,
            "CPython codegen_try_finally() emits USE_LABEL(exit) after a with finalbody, so optimize_load_fast() leaves following with receivers strong; got {strong_self_loads} strong self loads"
        );
    }

    #[test]
    fn try_finally_loop_direct_break_drops_finalbody_entry_nop() {
        let code = compile_exec(
            "\
def f(lines, close):
    try:
        while lines:
            if lines[0]:
                break
            close(1)
    finally:
        close(2)
    close(3)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::PushNull,
                    ]
                )
            }),
            "direct loop break should enter CPython finalbody without a NOP, got ops={ops:?}",
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::PushNull,
                    ]
                )
            }),
            "direct loop break should not preserve finalbody-entry NOP, got ops={ops:?}",
        );
    }

    #[test]
    fn try_finally_return_inside_with_pops_unwound_fblocks_for_finalbody() {
        let code = compile_exec(
            "\
def f(cm):
    try:
        with cm:
            return 1
    finally:
        return 2
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ReturnValue)),
            "return inside with/try-finally should compile without leaving an invalid CFG"
        );
    }

    #[test]
    fn except_star_return_after_with_unwind_uses_no_location_like_cpython() {
        let err = compile_exec_error(
            "\
def f(cm):
    try:
        pass
    except* Exception:
        with cm:
            return 1
",
        );
        assert!(matches!(
            err.error,
            CodegenErrorType::BreakContinueReturnInExceptStar
        ));
        assert!(
            err.location.is_none(),
            "CPython codegen_unwind_fblock(WITH) sets *ploc = NO_LOCATION before the except* error"
        );
    }

    #[test]
    fn async_generator_return_value_error_message_matches_cpython() {
        assert_eq!(
            compile_exec_error_message(
                "\
async def f():
    yield 1
    return 2
"
            ),
            "'return' with value in async generator"
        );
    }

    #[test]
    fn try_except_finally_handler_normal_exit_keeps_nointerrupt_jump() {
        let code = compile_exec(
            "\
def f():
    try:
        2
    except:
        4
    finally:
        6
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::JumpBackwardNoInterrupt { .. }
                    ]
                )
            }),
            "CPython codegen_try_except() emits JUMP_NO_INTERRUPT to the inner end label; when wrapped by codegen_try_finally(), push_cold_blocks_to_end() preserves it as a backward no-interrupt jump, got ops={ops:?}",
        );
        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "try/except/finally handler normal exit should not inline the function epilogue over CPython's no-interrupt jump, got ops={ops:?}",
        );
    }

    #[test]
    fn nested_while_break_keeps_cpython_unreachable_end_epilogue() {
        let code = compile_exec(
            "\
def f():
    TRUE = 1
    while TRUE:
        while TRUE:
            break
        break
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let returns = ops
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();

        assert_eq!(
            returns, 3,
            "CPython codegen_while() emits separate anchor/end labels and codegen_break() jumps to loop->fb_exit; after redundant jump removal, the b_next return epilogue still remains, got ops={ops:?}",
        );
    }

    #[test]
    fn while_else_break_keeps_separate_continue_backedges() {
        let code = compile_exec(
            "\
def func():
    TRUE = 1
    x = [1]
    while x:
        x.pop()
        while TRUE:
            break
        else:
            continue
",
        );
        let func = find_code(&code, "func").expect("missing func code");
        let ops: Vec<_> = func
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let jump_backwards = ops
            .iter()
            .filter(|op| matches!(op, Instruction::JumpBackward { .. }))
            .count();

        assert_eq!(
            jump_backwards, 2,
            "CPython codegen_break() emits a line-bearing jump to the inner while end, and codegen_while() keeps the else anchor separate from the end label; the break path and else-continue path should remain distinct backedges, got ops={ops:?}",
        );
    }

    #[test]
    fn break_through_finally_assert_tail_keeps_borrow_loads() {
        let code = compile_exec(
            "\
def func():
    a, c, d, i = 1, 1, 1, 99
    try:
        for i in range(3):
            try:
                a = 5
                if i > 0:
                    break
                a = 8
            finally:
                c = 10
    except:
        d = 12
    assert a == 5 and c == 10 and d == 1
",
        );
        let func = find_code(&code, "func").expect("missing func code");
        for name in ["a", "c", "d"] {
            let loads = load_fast_ops_for_var(func, name);
            assert!(
                loads
                    .iter()
                    .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
                "CPython flowgraph.c::optimize_load_fast() keeps assert-tail {name} loads borrowed after a resuming bare except; got loads={loads:?}",
            );
        }
    }

    #[test]
    fn try_except_finally_suppressing_handler_drops_body_exit_nop() {
        let code = compile_exec(
            "\
def f(self):
    try:
        self.sock.shutdown(socket.SHUT_RDWR)
    except OSError as exc:
        if exc.errno != errno.ENOTCONN:
            raise
    finally:
        self.sock.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let shutdown_pop = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopTop))
            .expect("missing shutdown POP_TOP");

        assert!(
            !matches!(ops.get(shutdown_pop + 1), Some(Instruction::Nop)),
            "suppressing except handler should fall directly into finally cleanup without a CPython body-exit NOP, got ops={ops:?}",
        );
        assert!(
            matches!(
                ops.get(shutdown_pop + 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "suppressing except handler should keep CPython-style borrowed finally cleanup receiver, got ops={ops:?}",
        );
    }

    #[test]
    fn conditional_break_finally_does_not_keep_break_cleanup_nop() {
        let code = compile_exec(
            "\
def f(tar1, x):
    try:
        while True:
            if x:
                break
            x = 1
    finally:
        tar1.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            !ops_lines.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::Nop, 5),
                        (
                            Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                            8
                        ),
                    ]
                )
            }),
            "expected CPython-style break cleanup to jump directly into finally body, got ops_lines={ops_lines:?}",
        );

        let close_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "close"
                }
                _ => false,
            })
            .expect("missing close load");
        assert!(
            matches!(
                instructions[close_attr - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython visits the finalbody through the loop fallthrough when break is not the loop body tail; got instructions={instructions:?}",
        );
    }

    #[test]
    fn tail_conditional_break_finally_uses_empty_end_label_barrier() {
        let code = compile_exec(
            "\
def f(tar1, x):
    try:
        while True:
            if x:
                break
    finally:
        tar1.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let close_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "close"
                }
                _ => false,
            })
            .expect("missing close load");
        assert!(
            matches!(
                instructions[close_attr - 1].op,
                Instruction::LoadFast { .. }
            ),
            "CPython leaves an empty while-end label before finalbody when the direct break is the loop body tail; got instructions={instructions:?}",
        );
    }

    #[test]
    fn with_break_cleanup_makes_following_jump_artificial() {
        let code = compile_exec(
            "\
def f(self):
    while self.returncode is None:
        with self._waitpid_lock:
            if self.returncode is not None:
                break
            self.work()
    return self.returncode
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            !ops_lines.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::Nop, 5),
                        (
                            Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                            7
                        ),
                    ]
                )
            }),
            "expected CPython-style artificial jump after with-break cleanup, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn while_exit_before_with_cleanup_materializes_anchor_nop() {
        let code = compile_exec(
            "\
def f(selector, self):
    with selector:
        while selector.get_map():
            pass
    try:
        self.wait()
    except Exception:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::JumpBackward { .. }, 4),
                        (Instruction::Nop, 3),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::LoadConst { .. }, 2),
                        (Instruction::Call { .. }, 2),
                    ]
                )
            }),
            "expected CPython-style while-exit anchor NOP before with cleanup, got ops_lines={ops_lines:?}",
        );
    }

    #[test]
    fn nested_boolop_same_or_prefixes_compile_without_extra_boolop_block() {
        let code = compile_exec(
            "\
def f(c, encodeO, encodeWS):
    return (
        (c > 127 or utf7_special[c] == 1)
        or (encodeWS and (utf7_special[c] == 2))
        or (encodeO and (utf7_special[c] == 3))
    )
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let pop_jump_if_true_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::PopJumpIfTrue { .. }))
            .count();

        assert!(
            pop_jump_if_true_count >= 3,
            "expected nested boolop prefix path to compile short-circuit jumps, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn nested_opposite_boolop_threads_to_fallthrough_like_cpython() {
        for source in [
            "\
def f(a, b, c):
    return ((a and b)
            or c)
",
            "\
def f(a, b, c):
    return ((a or b)
            and c)
",
        ] {
            let code = compile_exec(source);
            let f = find_code(&code, "f").expect("missing f code");
            let jumps: Vec<_> = f
                .instructions
                .iter()
                .filter(|unit| {
                    matches!(
                        unit.op,
                        Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                    )
                })
                .collect();

            assert_eq!(
                jumps.len(),
                2,
                "expected two conditional jumps, got {jumps:?}"
            );
            assert!(
                u8::from(jumps[0].arg) > u8::from(jumps[1].arg),
                "expected CPython-style first jump to bypass the opposite short-circuit test, got jumps={jumps:?}"
            );
        }
    }

    #[test]
    fn loop_or_continue_keeps_boolop_true_edge_to_continue() {
        let code = compile_exec(
            "\
def f(numpy_array, lshape, rshape, litems, fmt, tl):
    for _ in range(3):
        if numpy_array:
            if 0 in lshape or 0 in rshape:
                continue
            zl = numpy_array_from_structure(litems, fmt, tl)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadSmallInt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                    ]
                )
            }),
            "expected CPython-style `or` continue test to keep first true edge to continue, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadSmallInt { .. },
                    ]
                )
            }),
            "unexpected inverted first `or` continue condition before second operand, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_and_or_expression_threads_same_false_short_circuit() {
        let code = compile_exec(
            "\
def f(fmt, MEMORYVIEW):
    x = len(fmt)
    return ((x == 1 or (x == 2 and fmt[0] == '@')) and
            fmt[x - 1] in MEMORYVIEW)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let false_jumps: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::PopJumpIfFalse { .. }))
            .collect();

        assert!(
            false_jumps.len() >= 2,
            "expected nested boolop false jumps, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            u8::from(false_jumps[0].arg) > u8::from(false_jumps[1].arg),
            "expected CPython-style same-false short-circuit threading to outer end, got false_jumps={false_jumps:?}"
        );
    }

    #[test]
    fn broad_exception_import_keeps_borrow_in_common_tail() {
        let code = compile_exec(
            "\
def f(msg):
    if msg.source is not None:
        try:
            import tracemalloc
        except Exception:
            suggest_tracemalloc = False
            tb = None
        suggest_tracemalloc = not tracemalloc.is_tracing()
        tb = tracemalloc.get_object_traceback(msg.source)
        if tb is not None:
            for frame in tb:
                pass
    return 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let import_idx = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");

        assert!(
            f.instructions[import_idx + 1..]
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })),
            "expected common tail after broad-exception import to keep LOAD_FAST_BORROW, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn try_import_return_handler_deopts_common_tail_borrow() {
        let code = compile_exec(
            "\
def f():
    try:
        import pwd, grp
    except ImportError:
        return False
    if pwd.getpwuid(0)[0] != 'root':
        return False
    if grp.getgrgid(0)[0] != 'root':
        return False
    return True
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "expected CPython-style LOAD_FAST after protected import common tail, got ops={ops:?}",
        );
    }

    #[test]
    fn try_import_return_handler_deopts_later_protected_tail_borrow() {
        let code = compile_exec(
            "\
def f(info_add):
    try:
        import pwd
    except ImportError:
        return
    import os
    uid = os.getuid()
    try:
        entry = pwd.getpwuid(uid)
    except KeyError:
        entry = None
    info_add(uid, entry)
    if entry is None:
        return
    if hasattr(os, 'getgrouplist'):
        groups = os.getgrouplist(entry.pw_name, entry.pw_gid)
        groups = ', '.join(map(str, groups))
        info_add('os.getgrouplist', groups)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let import_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let protected_tail = &ops[import_idx + 1..];

        assert!(
            !protected_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "CPython keeps strong LOAD_FAST ops after protected import with return handler, even across later protected tails, got tail={protected_tail:?}"
        );
    }

    #[test]
    fn try_import_continue_handler_deopts_loop_tail_borrow() {
        let code = compile_exec(
            "\
def f(size):
    pos = 0
    while pos < size:
        try:
            import unicodedata
        except ImportError:
            continue
        if pos < size:
            pos += 1
    return pos
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let import_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[import_idx + 1..handler_start];
        let return_idx = normal_tail
            .iter()
            .position(|op| matches!(op, Instruction::ReturnValue))
            .unwrap_or(normal_tail.len());
        let loop_tail = &normal_tail[..return_idx.saturating_sub(1)];

        assert!(
            !loop_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "CPython keeps strong LOAD_FAST ops in the loop tail after protected import with continue handler, got tail={loop_tail:?}",
        );
    }

    #[test]
    fn try_import_continue_inside_loop_keeps_earlier_loop_body_borrows() {
        let code = compile_exec(
            r#"
def f(s, size, errors):
    p = []
    pos = 0
    while pos < size:
        if s[pos] != ord("\\"):
            p.append(chr(s[pos]))
            pos += 1
            continue
        if pos < size:
            try:
                import unicodedata
            except ImportError:
                errors(pos, size)
                continue
            if pos < size:
                p.append(chr(s[pos]))
        pos += 1
    return p, pos
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let import_idx = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let is_pair = |unit: &&CodeUnit, left_name: &str, right_name: &str, borrowed: bool| {
            let Some(var_nums) = (match (unit.op, borrowed) {
                (Instruction::LoadFastBorrowLoadFastBorrow { var_nums }, true)
                | (Instruction::LoadFastLoadFast { var_nums }, false) => Some(var_nums),
                _ => None,
            }) else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };
        let before_import = &instructions[..import_idx];

        assert!(
            before_import
                .iter()
                .any(|unit| is_pair(unit, "s", "pos", true)),
            "loop body before protected import should keep CPython-style borrowed s/pos pair, got instructions={instructions:?}"
        );
        assert!(
            !before_import
                .iter()
                .any(|unit| is_pair(unit, "s", "pos", false)),
            "protected import later in the loop should not deopt earlier s/pos pair to strong LOAD_FAST_LOAD_FAST, got instructions={instructions:?}"
        );
    }

    #[test]
    fn try_import_pass_else_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        from _ctypes import set_conversion_mode
    except ImportError:
        pass
    else:
        self.prev_conv_mode = set_conversion_mode('ascii', 'strict')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[..handler_start];

        assert!(
            normal_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "try-import pass/else normal path should keep CPython-style borrows, got tail={normal_tail:?}"
        );
    }

    #[test]
    fn try_import_broad_handler_implicit_return_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, record):
    try:
        import smtplib
        port = self.mailport
        if not port:
            port = smtplib.SMTP_PORT
        smtp = smtplib.SMTP(self.mailhost, port, timeout=self.timeout)
        smtp.quit()
    except Exception:
        self.handleError(record)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &instructions[..handler_start];
        let local_name = |unit: &&CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        for name in ["self", "smtplib", "smtp"] {
            assert!(
                normal_tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })
                        && local_name(unit) == Some(name)),
                "broad except handler with implicit return should keep CPython-style borrowed {name} loads, got tail={normal_tail:?}"
            );
            assert!(
                !normal_tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })
                        && local_name(unit) == Some(name)),
                "broad except handler with implicit return should not force strong {name} loads, got tail={normal_tail:?}"
            );
        }
    }

    #[test]
    fn try_import_handler_assignment_resume_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f():
    try:
        import subprocess
        out = subprocess.check_output(['/usr/bin/lslpp', '-Lqc', 'bos.rte'])
    except ImportError:
        out = _read_cmd_output('/usr/bin/lslpp -Lqc bos.rte')
    out = out.decode('utf-8')
    out = out.strip().split(':')
    _bd = int(out[-1]) if out[-1] != '' else 9988
    return (str(out[2]), _bd)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &instructions[..handler_start];
        let out_idx = f
            .varnames
            .iter()
            .position(|name| name == "out")
            .expect("missing out local");
        let load_out_is = |unit: &&CodeUnit, borrowed: bool| match (unit.op, borrowed) {
            (Instruction::LoadFastBorrow { var_num }, true)
            | (Instruction::LoadFast { var_num }, false) => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                usize::from(var_num.get(arg)) == out_idx
            }
            _ => false,
        };

        assert!(
            normal_tail.iter().any(|unit| load_out_is(unit, true)),
            "handler assignment resume tail should keep CPython-style borrowed out loads, got tail={normal_tail:?}"
        );
        assert!(
            !normal_tail.iter().any(|unit| load_out_is(unit, false)),
            "handler assignment resume tail should not force strong out loads, got tail={normal_tail:?}"
        );
    }

    #[test]
    fn empty_fallthrough_handler_assignment_tail_keeps_borrows() {
        let code = compile_exec(
            "\
def f(value):
    obs_local_part = ObsLocalPart()
    try:
        token, value = get_word(value)
    except HeaderParseError:
        if value[0] not in CFWS_LEADER:
            raise
        token, value = get_cfws(value)
    obs_local_part.append(token)
    return obs_local_part, value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_path = &ops[..handler_start];
        let load_name = |unit: &&CodeUnit, name: &str, borrowed: bool| {
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            match (unit.op, borrowed) {
                (Instruction::LoadFastBorrow { var_num }, true)
                | (Instruction::LoadFast { var_num }, false) => {
                    f.varnames[usize::from(var_num.get(arg))].as_str() == name
                }
                _ => false,
            }
        };

        for name in ["obs_local_part", "token"] {
            assert!(
                normal_path.iter().any(|unit| load_name(unit, name, true)),
                "handler assignment tail should keep CPython-style borrowed {name} loads, got path={normal_path:?}"
            );
            assert!(
                !normal_path.iter().any(|unit| load_name(unit, name, false)),
                "handler assignment tail should not force strong {name}, got path={normal_path:?}"
            );
        }
    }

    #[test]
    fn protected_store_of_preinitialized_local_keeps_return_borrow() {
        let code = compile_exec(
            "\
def f(obj):
    maybe_routine = obj
    try:
        maybe_routine = inspect.unwrap(maybe_routine)
    except ValueError:
        pass
    return inspect.isroutine(maybe_routine)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_path = &ops[..handler_start];
        let maybe_routine_idx = f
            .varnames
            .iter()
            .position(|name| name == "maybe_routine")
            .expect("missing maybe_routine local");
        let loads_maybe_routine = |unit: &&CodeUnit, borrowed: bool| match (unit.op, borrowed) {
            (Instruction::LoadFastBorrow { var_num }, true)
            | (Instruction::LoadFast { var_num }, false) => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                usize::from(var_num.get(arg)) == maybe_routine_idx
            }
            _ => false,
        };

        assert!(
            normal_path
                .iter()
                .any(|unit| loads_maybe_routine(unit, true)),
            "preinitialized protected-store tail should keep CPython-style borrowed local, got path={normal_path:?}"
        );
        assert!(
            !normal_path
                .iter()
                .any(|unit| loads_maybe_routine(unit, false)),
            "preinitialized protected-store tail should not force strong local, got path={normal_path:?}"
        );
    }

    #[test]
    fn protected_attr_direct_return_keeps_borrow() {
        let code = compile_exec(
            "\
def f(obj):
    try:
        x = 1
    except ValueError:
        return False
    return obj.values()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let protected_tail = &ops[..handler_start];

        assert!(
            protected_tail.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::Call { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected protected direct attr-call return to keep LOAD_FAST_BORROW, got tail={protected_tail:?}"
        );
    }

    #[test]
    fn protected_store_normal_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(tarfile, tarinfo, self):
    try:
        filtered = tarfile.tar_filter(tarinfo, '')
    except UnicodeEncodeError:
        return None
    self.assertIs(filtered.name, tarinfo.name)
    return filtered
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let filtered_store = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing filtered store");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[filtered_store + 1..handler_start];

        assert!(
            !normal_tail.iter().any(|op| matches!(
                op,
                Instruction::LoadFastBorrow { .. }
                    | Instruction::LoadFastBorrowLoadFastBorrow { .. }
            )),
            "expected CPython-style strong LOAD_FAST in protected store normal tail, got tail={normal_tail:?}",
        );
    }

    #[test]
    fn protected_subscript_store_normal_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, d, option, fallback):
    try:
        value = d[option]
    except KeyError:
        return fallback
    return self.convert(value, option)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let value_store = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing value store");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[value_store + 1..handler_start];

        assert!(
            !normal_tail.iter().any(|op| matches!(
                op,
                Instruction::LoadFastBorrow { .. }
                    | Instruction::LoadFastBorrowLoadFastBorrow { .. }
            )),
            "expected CPython-style strong LOAD_FAST after protected subscript store, got tail={normal_tail:?}",
        );
    }

    #[test]
    fn protected_call_arm_final_store_return_uses_strong_load() {
        let code = compile_exec(
            "\
def f(self, action, default_metavar):
    get_metavar = self._metavar_formatter(action, default_metavar)
    if action.nargs is None:
        result = '%s' % get_metavar(1)
    elif action.nargs == OPTIONAL:
        result = '[%s]' % get_metavar(1)
    elif action.nargs == ZERO_OR_MORE:
        metavar = get_metavar(1)
        if len(metavar) == 2:
            result = '[%s [%s ...]]' % metavar
        else:
            result = '[%s ...]' % metavar
    elif action.nargs == ONE_OR_MORE:
        result = '%s [%s ...]' % get_metavar(2)
    elif action.nargs == REMAINDER:
        result = '...'
    elif action.nargs == PARSER:
        result = '%s ...' % get_metavar(1)
    elif action.nargs == SUPPRESS:
        result = ''
    else:
        try:
            formats = ['%s' for _ in range(action.nargs)]
        except TypeError:
            raise ValueError(\"invalid nargs value\") from None
        result = ' '.join(formats) % get_metavar(action.nargs)
    return result
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let modulo = ops
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::BinaryOp { op }
                        if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                            == BinaryOperator::Remainder
                )
            })
            .expect("missing final format modulo");
        let tail = &ops[modulo..];
        assert!(
            tail.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        bytecode::CodeUnit {
                            op: Instruction::StoreFast { .. },
                            ..
                        },
                        bytecode::CodeUnit {
                            op: Instruction::LoadFast { .. },
                            ..
                        },
                        bytecode::CodeUnit {
                            op: Instruction::ReturnValue,
                            ..
                        },
                    ]
                )
            }),
            "protected call arm final store-return should keep CPython-style strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn protected_store_try_else_tail_keeps_borrowed_loads() {
        let code = compile_exec(
            "\
def f(value):
    message_id = MessageID()
    try:
        token, value = get_msg_id(value)
        message_id.append(token)
    except HeaderParseError as ex:
        token = get_unstructured(value)
        message_id = InvalidMessageID(token)
        message_id.defects.append(InvalidHeaderDefect('Invalid msg-id: {!r}'.format(ex)))
    else:
        if value:
            message_id.defects.append(InvalidHeaderDefect('Unexpected {!r}'.format(value)))
    return message_id
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[..handler_start];

        assert!(
            normal_tail.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        CodeUnit {
                            op: Instruction::LoadFastBorrow { .. },
                            ..
                        },
                        CodeUnit {
                            op: Instruction::ToBool,
                            ..
                        },
                        CodeUnit {
                            op: Instruction::PopJumpIfFalse { .. }
                                | Instruction::PopJumpIfTrue { .. },
                            ..
                        },
                    ]
                )
            }),
            "try/except/else bool guard should keep CPython-style borrowed load, got tail={normal_tail:?}",
        );

        let defects_idx = normal_tail
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "defects"
                }
                _ => false,
            })
            .expect("missing defects LOAD_ATTR in else tail");
        assert!(
            matches!(
                normal_tail[defects_idx - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "try/except/else method receiver should stay borrowed like CPython, got tail={normal_tail:?}",
        );

        let format_idx = normal_tail
            .iter()
            .rposition(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "format"
                }
                _ => false,
            })
            .expect("missing format LOAD_ATTR in else tail");
        assert!(
            matches!(
                normal_tail[format_idx + 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "try/except/else format argument should stay borrowed like CPython, got tail={normal_tail:?}",
        );
    }

    #[test]
    fn nested_try_except_common_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(value):
    address = Address()
    try:
        token, value = get_group(value)
    except HeaderParseError:
        try:
            token, value = get_mailbox(value)
        except HeaderParseError:
            raise HeaderParseError('expected {}'.format(value))
    address.append(token)
    return address, value
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFast { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::LoadFastLoadFast { .. },
                    ]
                )
            }),
            "nested try/except common tail should use CPython-style strong loads, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_try_except_branch_tail_with_following_try_uses_strong_loads() {
        let code = compile_exec(
            r#"
def f(value):
    msg_id = MsgID()
    try:
        token, value = get_dot_atom_text(value)
    except HeaderParseError:
        try:
            token, value = get_obs_local_part(value)
            msg_id.defects.append(ObsoleteHeaderDefect("obsolete id-left in msg-id"))
        except HeaderParseError:
            raise HeaderParseError("expected {}".format(value))
    msg_id.append(token)
    if not value or value[0] != "@":
        msg_id.defects.append(InvalidHeaderDefect("msg-id with no id-right"))
        if value and value[0] == ">":
            msg_id.append(ValueTerminal(">", "msg-id-end"))
            value = value[1:]
        return msg_id, value
    msg_id.append(ValueTerminal("@", "address-at-symbol"))
    value = value[1:]
    try:
        token, value = get_dot_atom_text(value)
    except HeaderParseError:
        pass
    return msg_id, value
"#,
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(16).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ReturnValue,
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::LoadFast { .. },
                        Instruction::LoadConst { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadFast { .. },
                    ]
                )
            }),
            "nested try branch tail before a following try should use CPython-style strong loads, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_try_store_subscr_following_try_tail_uses_strong_loads() {
        let code = compile_exec(
            r#"
def f(value):
    local_part = LocalPart()
    try:
        token, value = get_dot_atom(value)
    except HeaderParseError:
        try:
            token, value = get_word(value)
        except HeaderParseError:
            token = TokenList()
    if value:
        obs_local_part, value = get_obs_local_part(str(local_part) + value)
        if obs_local_part.token_type == "invalid-obs-local-part":
            local_part.defects.append(InvalidHeaderDefect("invalid"))
        else:
            local_part.defects.append(ObsoleteHeaderDefect("obsolete"))
        local_part[0] = obs_local_part
    try:
        local_part.value.encode("ascii")
    except UnicodeEncodeError:
        local_part.defects.append(NonASCIILocalPartDefect("non-ascii"))
    return local_part, value
"#,
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(10).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreSubscr,
                        Instruction::Nop,
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::LoadFastLoadFast { .. },
                        Instruction::BuildTuple { .. },
                    ]
                )
            }),
            "nested try STORE_SUBSCR tail before a following try should use CPython-style strong loads, got ops={ops:?}"
        );
    }

    #[test]
    fn resuming_except_in_loop_keeps_post_try_store_tail_borrowed() {
        let code = compile_exec(
            "\
def f(part, lines, maxlen, encoding):
    for name, value in part.params:
        charset = encoding
        error_handler = 'strict'
        try:
            value.encode(encoding)
            encoding_required = False
        except UnicodeEncodeError:
            encoding_required = True
            charset = 'utf-8'
        if encoding_required:
            encoded_value = quote(value, safe='', errors=error_handler)
            tstr = \"{}*={}''{}\".format(name, charset, encoded_value)
        else:
            tstr = '{}={}'.format(name, quote_string(value))
        if len(lines[-1]) + len(tstr) + 1 < maxlen:
            lines[-1] = lines[-1] + ' ' + tstr
            continue
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. },
                    ]
                )
            }),
            "resuming except handler should keep CPython-style borrowed bool guard, got ops={ops:?}"
        );
        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreSubscr,
                    ]
                )
            }),
            "resuming except handler should not deopt the post-try STORE_SUBSCR tail, got ops={ops:?}"
        );
    }

    #[test]
    fn handler_resume_loop_latch_method_call_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(phrase, value):
    while value and value[0] not in PHRASE_ENDS:
        if value[0] == '.':
            phrase.append(DOT)
            phrase.defects.append(ObsoleteHeaderDefect('period in phrase'))
            value = value[1:]
        else:
            try:
                token, value = get_word(value)
            except HeaderParseError:
                if value[0] in CFWS_LEADER:
                    token, value = get_cfws(value)
                    phrase.defects.append(ObsoleteHeaderDefect('comment found without atom'))
                else:
                    raise
            phrase.append(token)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFast { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. },
                    ]
                )
            }) || ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFast { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "exception-handler resume loop latch should match CPython's strong method-call loads, got ops={ops:?}"
        );
    }

    #[test]
    fn single_handler_multiple_resume_branches_keep_post_try_tail_borrowed() {
        let code = compile_exec(
            "\
def f(part, lines, maxlen, encoding):
    for name, value in part.params:
        charset = encoding
        error_handler = 'strict'
        try:
            value.encode(encoding)
            encoding_required = False
        except UnicodeEncodeError:
            encoding_required = True
            if utils._has_surrogates(value):
                charset = 'unknown-8bit'
                error_handler = 'surrogateescape'
            else:
                charset = 'utf-8'
        if encoding_required:
            encoded_value = quote(value, safe='', errors=error_handler)
            tstr = \"{}*={}''{}\".format(name, charset, encoded_value)
        else:
            tstr = '{}={}'.format(name, quote_string(value))
        if len(lines[-1]) + len(tstr) + 1 < maxlen:
            lines[-1] = lines[-1] + ' ' + tstr
            continue
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. },
                    ]
                )
            }),
            "single except handler with multiple resume branches should keep the post-try bool guard borrowed, got ops={ops:?}"
        );
        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreSubscr,
                    ]
                )
            }),
            "single except handler with multiple resume branches should keep the post-try STORE_SUBSCR tail borrowed, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_exception_handler_resume_update_tail_uses_strong_load() {
        let code = compile_exec(
            "\
def f(inpos, size, g, replacement):
    while inpos < size:
        try:
            g()
        except KeyError:
            try:
                for y in replacement:
                    g(y)
            except KeyError:
                raise ValueError(inpos)
        inpos += 1
    return inpos
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let arg = |unit: &&bytecode::CodeUnit| OpArg::new(u32::from(u8::from(unit.arg)));
        let is_inpos_load = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                f.varnames[usize::from(var_num.get(arg(unit)))].as_str() == "inpos"
            }
            _ => false,
        };
        let is_inpos_store = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::StoreFast { var_num } => {
                f.varnames[usize::from(var_num.get(arg(unit)))].as_str() == "inpos"
            }
            _ => false,
        };
        let update = ops
            .windows(4)
            .find(|window| {
                is_inpos_load(&window[0])
                    && matches!(
                        window[1].op,
                        Instruction::LoadSmallInt { i } if i.get(arg(&window[1])) == 1
                    )
                    && matches!(
                        window[2].op,
                        Instruction::BinaryOp { op }
                            if op.get(arg(&window[2])) == BinaryOperator::InplaceAdd
                    )
                    && is_inpos_store(&window[3])
            })
            .expect("missing inpos += 1 update");

        assert!(
            matches!(update[0].op, Instruction::LoadFast { .. }),
            "CPython keeps a strong LOAD_FAST for nested-handler resumed inplace update, got update={update:?}"
        );
    }

    #[test]
    fn protected_store_finally_cleanup_keeps_borrow_tail() {
        let code = compile_exec(
            "\
def f(re, f):
    try:
        try:
            m = re.search('x', f.read())
        finally:
            f.close()
        if m is not None:
            return m.group(1)
    except OSError:
        pass
    return None
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_m_borrow = |unit: &bytecode::CodeUnit| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))].as_str() == "m"
            }
            _ => false,
        };

        assert!(
            ops.windows(3).any(|window| {
                is_m_borrow(window[0])
                    && matches!(window[1].op, Instruction::PopJumpIfNone { .. })
                    && matches!(window[2].op, Instruction::NotTaken)
            }) && ops.windows(2).any(|window| {
                is_m_borrow(window[0]) && matches!(window[1].op, Instruction::LoadAttr { .. })
            }),
            "finally cleanup RERAISE should not make the outer except deopt the normal m tail, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_finally_cleanup_keeps_borrow_tail() {
        let code = compile_exec(
            "\
def f(re, open):
    global _SYSTEM_VERSION
    if _SYSTEM_VERSION is None:
        _SYSTEM_VERSION = ''
        try:
            f = open('/System/Library/CoreServices/SystemVersion.plist', encoding='utf-8')
        except OSError:
            pass
        else:
            try:
                m = re.search('x', f.read())
            finally:
                f.close()
            if m is not None:
                _SYSTEM_VERSION = '.'.join(m.group(1).split('.')[:2])
    return _SYSTEM_VERSION
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_m_borrow = |unit: &bytecode::CodeUnit| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))].as_str() == "m"
            }
            _ => false,
        };

        assert!(
            ops.windows(3).any(|window| {
                is_m_borrow(window[0])
                    && matches!(window[1].op, Instruction::PopJumpIfNone { .. })
                    && matches!(window[2].op, Instruction::NotTaken)
            }) && ops.windows(2).any(|window| {
                is_m_borrow(window[0]) && matches!(window[1].op, Instruction::LoadAttr { .. })
            }),
            "try/else finally cleanup should keep CPython-style borrowed m tail, got ops={ops:?}"
        );
    }

    #[test]
    fn typed_terminal_attr_store_deopts_later_protected_store_subscr() {
        let code = compile_exec(
            "\
def f(instance, self, _NOT_FOUND):
    try:
        cache = instance.__dict__
    except AttributeError:
        raise TypeError('missing dict') from None
    val = cache.get(self.attrname, _NOT_FOUND)
    if val is _NOT_FOUND:
        val = self.func(instance)
        try:
            cache[self.attrname] = val
        except TypeError:
            raise TypeError('bad cache') from None
    return val
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let store_subscr = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreSubscr))
            .expect("missing STORE_SUBSCR");
        let window = &ops[store_subscr.saturating_sub(3)..=store_subscr];

        assert!(
            matches!(
                window,
                [
                    Instruction::LoadFastLoadFast { .. },
                    Instruction::LoadFast { .. },
                    Instruction::LoadAttr { .. },
                    Instruction::StoreSubscr,
                ]
            ),
            "CPython keeps strong loads before protected STORE_SUBSCR after a typed terminal attr-store try, got window={window:?}; ops={ops:?}"
        );
    }

    #[test]
    fn generator_protected_store_subscr_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(names, modules):
    for name in names:
        try:
            mod = __import__(name)
        except ImportError:
            continue
        modules[name] = mod
        yield mod
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let store_subscr = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreSubscr))
            .expect("missing STORE_SUBSCR");
        let window = &ops[store_subscr.saturating_sub(2)..(store_subscr + 3).min(ops.len())];

        assert!(
            matches!(
                window,
                [
                    Instruction::LoadFastLoadFast { .. },
                    Instruction::LoadFast { .. },
                    Instruction::StoreSubscr,
                    Instruction::LoadFast { .. },
                    Instruction::YieldValue { .. },
                    ..
                ]
            ),
            "expected CPython-style strong LOAD_FAST around protected STORE_SUBSCR generator tail, got {window:?}"
        );
    }

    #[test]
    fn protected_call_function_ex_store_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(func, *args):
    try:
        result = func(*args)
    except Exception:
        return None
    return type(result)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let tail_call = ops
            .iter()
            .rposition(|op| matches!(op, Instruction::Call { .. }))
            .expect("missing tail CALL");
        let result_store = ops[..tail_call]
            .iter()
            .rposition(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing protected result STORE_FAST");
        let tail = &ops[result_store + 1..tail_call];

        assert!(
            tail.iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "expected CPython-style strong LOAD_FAST after protected CALL_FUNCTION_EX store, got ops={ops:?}",
        );
        assert!(
            !tail
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "protected CALL_FUNCTION_EX store tail should not borrow result, got ops={ops:?}",
        );
    }

    #[test]
    fn protected_attr_subscript_tail_uses_strong_load_fast() {
        let code = compile_exec(
            "\
def f(obj, idx):
    try:
        x = 1
    except ValueError:
        return False
    return obj.__closure__[idx]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let protected_tail = &ops[..handler_start];

        assert!(
            !protected_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected attr-subscript tail to keep strong LOAD_FAST ops, got tail={protected_tail:?}"
        );
    }

    #[test]
    fn protected_direct_subscript_tail_uses_strong_load_fast() {
        let code = compile_exec(
            "\
def f(seq):
    try:
        items = [int(item) for item in seq]
    except ValueError:
        return None
    return items[0] + items[1]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let protected_store = ops[..handler_start]
            .iter()
            .rposition(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing protected local store");
        let tail = &ops[protected_store + 1..handler_start];

        assert!(
            !tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected direct-subscript tail to keep strong LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn protected_attr_iter_chain_uses_strong_load_fast() {
        let code = compile_exec(
            "\
def f(fields):
    try:
        x = 1
    except ValueError:
        return False
    return tuple(v for v in fields.values())
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let protected_tail = &ops[..handler_start];

        assert!(
            !protected_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected attr-iter chain to keep strong LOAD_FAST ops, got tail={protected_tail:?}"
        );
    }

    #[test]
    fn generator_except_return_handler_deopts_normal_tail_borrows() {
        let code = compile_exec(
            "\
def f(fields):
    try:
        x = 1
    except ValueError:
        return
    for fielddesc in fields:
        yield fielddesc
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[..handler_start];

        assert!(
            normal_tail
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "generator tail after non-yielding except return should keep CPython-style strong LOAD_FAST, got tail={normal_tail:?}"
        );
        assert!(
            !normal_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "generator tail after non-yielding except return should not borrow, got tail={normal_tail:?}"
        );
    }

    #[test]
    fn generator_except_yielding_handler_keeps_normal_tail_borrows() {
        let code = compile_exec(
            "\
def f(tp, parent=None):
    try:
        fields = tp._fields_
    except AttributeError:
        yield parent
    else:
        for fielddesc in fields:
            yield fielddesc
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &ops[..handler_start];

        assert!(
            normal_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "generator tail after yielding except handler should keep CPython-style borrows, got tail={normal_tail:?}"
        );
    }

    #[test]
    fn generator_returning_except_keeps_yield_from_resume_tail_borrow() {
        let code = compile_exec(
            "\
def f(self, action):
    try:
        get_subactions = action._get_subactions
    except AttributeError:
        pass
    else:
        self._indent()
        yield from get_subactions()
        self._dedent()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let end_send = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::EndSend))
            .expect("missing END_SEND");
        let dedent_attr = instructions[end_send..]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "_dedent"
                }
                _ => false,
            })
            .map(|idx| end_send + idx)
            .expect("missing _dedent LOAD_ATTR");

        assert!(
            matches!(
                instructions[dedent_attr - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython keeps yield-from resume receiver borrowed after END_SEND, got instructions={instructions:?}"
        );
    }

    #[test]
    fn generator_except_pass_resume_tail_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self, msg):
    if self.log_queue is not None:
        yield
        output = []
        try:
            while True:
                output.append(self.log_queue.get_nowait().getMessage())
        except queue.Empty:
            pass
    else:
        with self.assertLogs('concurrent.futures', 'CRITICAL') as cm:
            yield
        output = cm.output
    self.assertTrue(any(msg in line for line in output), output)
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        let has_strong_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };
        let has_borrow_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };

        for name in ["msg", "output"] {
            assert!(
                has_borrow_load(name),
                "generator except-pass resume tail should borrow {name}, got instructions={:?}",
                f.instructions
            );
            assert!(
                !has_strong_load(name),
                "generator except-pass resume tail should not force strong LOAD_FAST for {name}, got instructions={:?}",
                f.instructions
            );
        }
    }

    #[test]
    fn async_for_cleanup_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
async def f(g, self, x):
    async for val in g:
        break
    self.x(x)
    await g.aclose()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();
        let aclose_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "aclose"
                }
                _ => false,
            })
            .expect("missing aclose load");

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFast { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "async-for cleanup resume tail should use strong LOAD_FAST ops before the await, got ops={ops:?}"
        );
        assert!(
            matches!(
                instructions
                    .get(aclose_idx.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFast { .. })
            ),
            "async-for cleanup resume tail should keep g strong before aclose, got ops={ops:?}"
        );
    }

    #[test]
    fn async_generator_async_with_yield_keeps_borrow() {
        let code = compile_exec(
            "\
async def f(self, my_cm):
    async with self.exit_stack() as stack:
        await stack.enter_async_context(my_cm())
        yield stack
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();
        let wrap_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::CallIntrinsic1 { func } => {
                    func.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        == IntrinsicFunction1::AsyncGenWrap
                }
                _ => false,
            })
            .expect("missing async generator wrap");

        assert!(
            matches!(
                ops.get(wrap_idx.saturating_sub(1)),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "async generator yield inside async-with should borrow stack like CPython, got ops={ops:?}"
        );
    }

    #[test]
    fn deoptimized_async_with_enter_continuation_uses_strong_loads() {
        let code = compile_exec(
            "\
async def f():
    async def cm():
        pass
    try:
        async with cm():
            1 / 0
    except ZeroDivisionError as e:
        frames = e
    class E(RuntimeError):
        pass
    try:
        async with cm():
            raise E(42)
    except E as e:
        frames = e
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::PushNull,
                        Instruction::LoadSmallInt { .. },
                        Instruction::Call { .. },
                        Instruction::RaiseVarargs { .. },
                    ]
                )
            }),
            "async-with enter continuation after a deoptimized setup block should keep raised class strong, got ops={ops:?}"
        );
    }

    #[test]
    fn async_with_bare_raise_continuation_keeps_borrow() {
        let code = compile_exec(
            "\
async def f(tg):
    class E(Exception):
        pass
    try:
        async with tg:
            raise E
    except ExceptionGroup:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let raise_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::RaiseVarargs { .. }))
            .expect("missing raise");

        assert!(
            matches!(
                ops.get(raise_idx.saturating_sub(1)),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "bare async-with raise continuation should keep the raised class borrowed like CPython, got ops={ops:?}"
        );
    }

    #[test]
    fn except_star_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self):
    try:
        pass
    except* ValueError:
        pass
    self.fail('x')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let fail_attr = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing self.fail load");

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "except* tail should use strong LOAD_FAST like CPython, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "except* tail should not borrow the receiver after the handler region, got ops={ops:?}"
        );
        assert!(
            !matches!(
                ops.get(fail_attr.saturating_sub(2)),
                Some(Instruction::JumpForward { .. })
            ),
            "except* end label should not compile as an extra jump before the continuation, got ops={ops:?}"
        );
    }

    #[test]
    fn protected_attr_subscript_store_tail_uses_strong_load_fast() {
        let code = compile_exec(
            "\
def f(f, oldcls, newcls):
    try:
        idx = f.__code__.co_freevars.index('__class__')
    except ValueError:
        return False
    closure = f.__closure__[idx]
    if closure.cell_contents is oldcls:
        closure.cell_contents = newcls
        return True
    return False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let protected_tail = &ops[..handler_start];
        let store_closure_idx = protected_tail
            .windows(2)
            .position(|window| {
                matches!(
                    window,
                    [Instruction::BinaryOp { .. }, Instruction::StoreFast { .. }]
                )
            })
            .map(|idx| idx + 1)
            .expect("missing STORE_FAST for closure");
        let post_store_tail = &protected_tail[store_closure_idx + 1..];

        assert!(
            !post_store_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected attr-subscript store tail to keep strong LOAD_FAST ops, got tail={post_store_tail:?}"
        );
    }

    #[test]
    fn plain_attr_subscript_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, name):
    annotations = self.method_annotations[name]
    return annotations
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastBorrow { .. },
                        Instruction::BinaryOp { .. },
                    ]
                )
            }),
            "expected plain attr-subscript tail to keep borrowed receiver/index loads, got ops={ops:?}"
        );
    }

    #[test]
    fn plain_attr_iter_chain_keeps_borrow() {
        let code = compile_exec(
            "\
def f(fields):
    return tuple(v for v in fields.values())
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::Call { .. },
                        Instruction::GetIter,
                    ]
                )
            }),
            "expected plain attr-iter chain to keep borrowed receiver, got ops={ops:?}"
        );
    }

    #[test]
    fn genexpr_true_filter_omits_bool_scaffolding() {
        let code = compile_exec(
            "\
def f(it):
    return (x for x in it if True)
",
        );
        let genexpr = find_code(&code, "<genexpr>").expect("missing <genexpr> code");
        assert!(
            !genexpr.instructions.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadConst { .. })
                    && matches!(
                        genexpr.constants.get(usize::from(u8::from(unit.arg))),
                        Some(ConstantData::Boolean { value: true })
                    )
            }),
            "constant-true filter should not load True, got ops={:?}",
            genexpr
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            !genexpr
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::PopJumpIfTrue { .. })),
            "constant-true filter should not leave POP_JUMP_IF_TRUE scaffolding, got ops={:?}",
            genexpr
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn classdictcell_uses_load_closure_path_and_borrows_after_optimize() {
        let code = compile_exec(
            "\
class C:
    def method(self):
        return 1
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let store_classdictcell = class_code
            .instructions
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__classdictcell__"
                )
            })
            .expect("missing STORE_NAME __classdictcell__");

        assert!(
            matches!(
                class_code
                    .instructions
                    .get(store_classdictcell.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "expected LOAD_FAST_BORROW before __classdictcell__ store, got ops={:?}",
            class_code
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn conditional_class_body_duplicates_no_location_exit_tail() {
        let code = compile_exec(
            "\
flag = False
class C:
    if flag:
        value = 1
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let ops: Vec<_> = class_code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let return_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();
        let static_attrs_count = class_code
            .instructions
            .iter()
            .filter(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__static_attributes__"
                )
            })
            .count();

        assert_eq!(
            return_count, 2,
            "conditional class body should duplicate CPython no-location return tail, got ops={ops:?}"
        );
        assert_eq!(
            static_attrs_count, 2,
            "conditional class body should duplicate __static_attributes__ tail, got ops={ops:?}"
        );
    }

    #[test]
    fn class_lambda_assignment_does_not_create_classdictcell() {
        let code = compile_exec(
            "\
class C:
    data = start = end = lambda *a: None
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            !class_code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__classdictcell__"
                )
            }),
            "lambda-only class should not create __classdictcell__, got ops={:?}",
            class_code
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn nested_function_static_attributes_are_collected() {
        let code = compile_exec(
            "\
class C:
    def f(self):
        self.x = 1
        self.y = 2
        self.x = 3

    def g(self, obj):
        self.y = 4
        self.z = 5

        def h(self, a):
            self.u = 6
            self.v = 7

        obj.self = 8
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            class_code.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Tuple { elements }
                    if elements
                        == &[
                            ConstantData::Str { value: "u".into() },
                            ConstantData::Str { value: "v".into() },
                            ConstantData::Str { value: "x".into() },
                            ConstantData::Str { value: "y".into() },
                            ConstantData::Str { value: "z".into() },
                        ]
            )),
            "expected nested function static attributes in class consts"
        );
    }

    #[test]
    fn static_attributes_match_cpython_store_rule() {
        let code = compile_exec(
            "\
class C:
    @staticmethod
    def f():
        self.x = 1

    @classmethod
    def g(cls):
        self.y = 2

    def h(obj):
        obj.z = 3
        tarinfo.uid = 4

    def i(self):
        self.a: int
        self.b: int = 1
        self.c += 1
        del self.d
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            class_code.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Tuple { elements }
                    if elements
                        == &[
                            ConstantData::Str { value: "b".into() },
                            ConstantData::Str { value: "x".into() },
                            ConstantData::Str { value: "y".into() },
                        ]
            )),
            "expected only CPython-collected static attributes in class consts"
        );
    }

    #[test]
    fn decorated_class_uses_first_decorator_for_firstlineno() {
        let code = compile_exec(
            "\
@dec1
@dec2
class C:
    pass
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let store_firstlineno = class_code
            .instructions
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__firstlineno__"
                )
            })
            .expect("missing STORE_NAME __firstlineno__");
        let load_firstlineno = class_code
            .instructions
            .get(store_firstlineno.saturating_sub(1))
            .expect("missing LOAD_CONST for __firstlineno__");

        let expected = ConstantData::Integer {
            value: BigInt::from(1),
        };
        assert!(
            matches!(
                load_firstlineno.op,
                Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. }
            ),
            "expected LOAD_SMALL_INT/LOAD_CONST before __firstlineno__, got {:?}",
            load_firstlineno.op
        );
        if let Instruction::LoadConst { consti } = load_firstlineno.op {
            let value = &class_code.constants
                [consti.get(OpArg::new(u32::from(u8::from(load_firstlineno.arg))))];
            assert_eq!(value, &expected);
        } else {
            assert_eq!(u32::from(u8::from(load_firstlineno.arg)), 1);
        }
    }

    #[test]
    fn class_firstlineno_store_uses_name_resolution() {
        let code = compile_exec(
            "\
def f():
    __firstlineno__ = 1
    class C:
        nonlocal __firstlineno__
    return C
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            class_code
                .freevars
                .iter()
                .any(|name| name == "__firstlineno__"),
            "class should close over nonlocal __firstlineno__, got freevars={:?}",
            class_code.freevars
        );
        assert!(
            class_code.instructions.iter().any(|unit| match unit.op {
                Instruction::StoreDeref { i } => {
                    let idx = i.get(OpArg::new(u32::from(u8::from(unit.arg)))).as_usize();
                    localsplus_name(class_code, idx) == Some("__firstlineno__")
                }
                _ => false,
            }),
            "CPython routes __firstlineno__ through name resolution and emits STORE_DEREF for __firstlineno__, got ops={:?} freevars={:?}",
            class_code.instructions,
            class_code.freevars
        );
        assert!(
            !class_code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__firstlineno__"
                )
            }),
            "nonlocal __firstlineno__ should not be stored with STORE_NAME, got ops={:?}",
            class_code.instructions
        );
    }

    #[test]
    fn lambda_parent_qualname_includes_locals() {
        let code = compile_exec(
            "\
def f():
    return lambda: (lambda: None)
",
        );
        let mut lambda_qualnames = Vec::new();
        fn collect_lambda_qualnames(code: &CodeObject, out: &mut Vec<String>) {
            if code.obj_name == "<lambda>" {
                out.push(code.qualname.to_string());
            }
            for constant in code.constants.iter() {
                if let ConstantData::Code { code } = constant {
                    collect_lambda_qualnames(code, out);
                }
            }
        }
        collect_lambda_qualnames(&code, &mut lambda_qualnames);

        assert!(
            lambda_qualnames
                .iter()
                .any(|name| name == "f.<locals>.<lambda>"),
            "missing outer lambda qualname, got {lambda_qualnames:?}"
        );
        assert!(
            lambda_qualnames
                .iter()
                .any(|name| name == "f.<locals>.<lambda>.<locals>.<lambda>"),
            "nested lambda parent should include .<locals> like CPython, got {lambda_qualnames:?}"
        );
    }

    #[test]
    fn future_annotations_class_uses_direct_annotation_store() {
        let code = compile_exec(
            "\
from __future__ import annotations
class C:
    x: int
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            !class_code
                .cellvars
                .iter()
                .any(|name| name.as_str() == "__conditional_annotations__"),
            "future annotations should not create __conditional_annotations__ cellvar, got cellvars={:?}",
            class_code.cellvars
        );
        let ops: Vec<_> = class_code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::SetupAnnotations)),
            "future annotations should emit SETUP_ANNOTATIONS, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(op, Instruction::StoreSubscr)),
            "future annotations should store directly into __annotations__, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::BuildSet { .. })),
            "future annotations should not initialize __conditional_annotations__, got ops={ops:?}"
        );
    }

    #[test]
    fn future_annotations_module_keeps_conditional_annotations_cell() {
        let code = compile_exec(
            "\
from __future__ import annotations
x: int = 1
",
        );

        assert!(
            code.cellvars
                .iter()
                .any(|name| name.as_str() == "__conditional_annotations__"),
            "module annotations should create __conditional_annotations__ cellvar, got cellvars={:?}",
            code.cellvars
        );
    }

    #[test]
    fn future_annotations_conditional_class_keeps_conditional_annotations_cell() {
        let code = compile_exec(
            "\
from __future__ import annotations
class C:
    if True:
        x: int = 1
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");

        assert!(
            class_code
                .cellvars
                .iter()
                .any(|name| name.as_str() == "__conditional_annotations__"),
            "conditional class annotations should create __conditional_annotations__ cellvar, got cellvars={:?}",
            class_code.cellvars
        );
    }

    #[test]
    fn future_annotations_setup_precedes_docstring() {
        let code = compile_exec(
            "\
\"module doc\"
from __future__ import annotations
x: int = 1

class C:
    \"class doc\"
    x: int = 1
",
        );
        let module_setup = code
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::SetupAnnotations))
            .expect("missing module SETUP_ANNOTATIONS");
        let module_doc = code
            .instructions
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__doc__"
                )
            })
            .expect("missing module doc store");
        assert!(
            module_setup < module_doc,
            "module SETUP_ANNOTATIONS should precede docstring store, got instructions={:?}",
            code.instructions
        );

        let class_code = find_code(&code, "C").expect("missing class code");
        let class_setup = class_code
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::SetupAnnotations))
            .expect("missing class SETUP_ANNOTATIONS");
        let class_doc = class_code
            .instructions
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__doc__"
                )
            })
            .expect("missing class doc store");
        assert!(
            class_setup < class_doc,
            "class SETUP_ANNOTATIONS should precede docstring store, got instructions={:?}",
            class_code.instructions
        );
    }

    #[test]
    fn optimize_two_strips_docstrings_during_preprocess() {
        let code = compile_exec_with_options(
            "\
\"module doc\"

def f():
    \"function doc\"
    return 1

class C:
    \"class doc\"
    x = 1
",
            CompileOpts {
                optimize: 2,
                ..CompileOpts::default()
            },
        );

        assert!(
            !code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__doc__"
                )
            }),
            "module docstring should be stripped before codegen, got instructions={:?}",
            code.instructions
        );

        let function_code = find_code(&code, "f").expect("missing function code");
        assert!(
            !function_code
                .flags
                .contains(bytecode::CodeFlags::HAS_DOCSTRING),
            "function docstring should not set HAS_DOCSTRING when optimize=2"
        );

        let class_code = find_code(&code, "C").expect("missing class code");
        assert!(
            !class_code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreName { namei }
                        if class_code.names
                            [namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) as usize]
                            .as_str()
                            == "__doc__"
                )
            }),
            "class docstring should be stripped before codegen, got instructions={:?}",
            class_code.instructions
        );
    }

    #[test]
    fn future_annotations_flag_is_inherited_like_cpython() {
        let code = compile_exec(
            "\
from __future__ import annotations

def f():
    class C:
        pass
    return C
",
        );
        assert!(code.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS));
        let f = find_code(&code, "f").expect("missing f code");
        assert!(f.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS));
        let class_code = find_code(f, "C").expect("missing C code");
        assert!(
            class_code
                .flags
                .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS)
        );
    }

    #[test]
    fn future_flags_from_compile_options_are_merged_like_cpython() {
        let opts = CompileOpts {
            future_features: bytecode::CodeFlags::FUTURE_ANNOTATIONS
                | bytecode::CodeFlags::FUTURE_DIVISION,
            ..CompileOpts::default()
        };
        let code = compile_exec_with_options(
            "\
x: int
def f():
    pass
",
            opts,
        );
        assert!(code.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS));
        assert!(code.flags.contains(bytecode::CodeFlags::FUTURE_DIVISION));
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::SetupAnnotations))
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert!(f.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS));
        assert!(f.flags.contains(bytecode::CodeFlags::FUTURE_DIVISION));
    }

    #[test]
    fn future_barry_as_flufl_is_accepted_but_ignored() {
        let code = compile_exec(
            "\
from __future__ import barry_as_FLUFL

def f():
    pass
",
        );
        let future_flags = bytecode::CodeFlags::FUTURE_DIVISION
            | bytecode::CodeFlags::FUTURE_ABSOLUTE_IMPORT
            | bytecode::CodeFlags::FUTURE_WITH_STATEMENT
            | bytecode::CodeFlags::FUTURE_PRINT_FUNCTION
            | bytecode::CodeFlags::FUTURE_UNICODE_LITERALS
            | bytecode::CodeFlags::FUTURE_GENERATOR_STOP
            | bytecode::CodeFlags::FUTURE_ANNOTATIONS;
        assert!((code.flags & future_flags).is_empty());
        let f = find_code(&code, "f").expect("missing f code");
        assert!((f.flags & future_flags).is_empty());
    }

    #[test]
    fn relative_future_import_does_not_enable_annotations_like_cpython() {
        let code = compile_exec(
            "\
from .__future__ import annotations
x: int
",
        );
        assert!(!code.flags.contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS));
    }

    #[test]
    fn future_braces_uses_cpython_special_error() {
        assert_eq!(
            compile_exec_error_message("from __future__ import braces\n"),
            "not a chance"
        );
    }

    #[test]
    fn invalid_future_feature_is_checked_before_ast_preprocess_like_cpython() {
        assert_eq!(
            compile_exec_error_message("from __future__ import spam, annotations\nx: (y := int)\n"),
            "future feature spam is not defined"
        );
    }

    #[test]
    fn allow_top_level_await_marks_module_coroutine_like_cpython() {
        let opts = CompileOpts {
            allow_top_level_await: true,
            ..CompileOpts::default()
        };
        let code = compile_exec_with_options("await f()\n", opts);
        assert!(code.flags.contains(bytecode::CodeFlags::COROUTINE));
    }

    #[test]
    fn allow_top_level_await_accepts_module_async_for_like_cpython() {
        let opts = CompileOpts {
            allow_top_level_await: true,
            ..CompileOpts::default()
        };
        let code = compile_exec_with_options(
            "\
async for x in y:
    pass
",
            opts,
        );
        assert!(code.flags.contains(bytecode::CodeFlags::COROUTINE));
    }

    #[test]
    fn annotation_scope_nested_flag_matches_cpython() {
        let code = compile_exec(
            "\
class C:
    x: int

def outer():
    class D:
        y: int
",
        );
        let class_code = find_code(&code, "C").expect("missing C code");
        let class_annotate =
            find_code(class_code, "__annotate__").expect("missing class annotation code");
        assert!(
            !class_annotate.flags.contains(bytecode::CodeFlags::NESTED),
            "module-level class annotation scope should not be nested"
        );

        let outer = find_code(&code, "outer").expect("missing outer code");
        let nested_class = find_code(outer, "D").expect("missing nested class code");
        let nested_annotate =
            find_code(nested_class, "__annotate__").expect("missing nested annotation code");
        assert!(
            nested_annotate.flags.contains(bytecode::CodeFlags::NESTED),
            "annotation scope under a nested class should be nested"
        );
    }

    #[test]
    fn function_like_parent_marks_child_nested_like_cpython() {
        let code = compile_exec(
            "\
x = lambda: (lambda: None)
type A[T] = T
",
        );
        let outer_lambda = find_code(&code, "<lambda>").expect("missing outer lambda code");
        assert!(
            !outer_lambda.flags.contains(bytecode::CodeFlags::NESTED),
            "module-level lambda should not be nested"
        );
        let inner_lambda =
            find_direct_child_code(outer_lambda, "<lambda>").expect("missing inner lambda code");
        assert!(
            inner_lambda.flags.contains(bytecode::CodeFlags::NESTED),
            "lambda inside lambda should be nested"
        );

        let type_params =
            find_code(&code, "<generic parameters of A>").expect("missing type params code");
        assert!(
            !type_params.flags.contains(bytecode::CodeFlags::NESTED),
            "module-level type-parameter scope should not be nested"
        );
        let type_alias = find_direct_child_code(type_params, "A").expect("missing type alias code");
        assert!(
            type_alias.flags.contains(bytecode::CodeFlags::NESTED),
            "type alias body inside type-parameter scope should be nested"
        );
    }

    #[test]
    fn plain_super_call_keeps_class_freevar() {
        let code = compile_exec(
            "\
class A:
    pass

class B(A):
    def method(self):
        return super()
",
        );
        let method = find_code(&code, "method").expect("missing method code");
        assert!(
            method.freevars.iter().any(|name| name == "__class__"),
            "plain super() must keep __class__ freevar, got freevars={:?}",
            method.freevars
        );
        assert!(
            method
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::CopyFreeVars { .. })),
            "plain super() must keep COPY_FREE_VARS prelude, got ops={:?}",
            method
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn nested_class_super_does_not_create_outer_class_closure() {
        let code = compile_exec(
            "\
class C:
    def outer(self):
        class D:
            def __init__(self):
                super().__init__()
",
        );
        let outer_class = find_code(&code, "C").expect("missing outer class code");
        let nested_class = find_code(&code, "D").expect("missing nested class code");
        let init = find_code(&code, "__init__").expect("missing nested __init__ code");

        assert!(
            !outer_class.cellvars.iter().any(|name| name == "__class__"),
            "nested super() must not force __class__ on outer class, got cellvars={:?}",
            outer_class.cellvars
        );
        assert!(
            nested_class.cellvars.iter().any(|name| name == "__class__"),
            "nested class should own __class__ cell, got cellvars={:?}",
            nested_class.cellvars
        );
        assert!(
            init.freevars.iter().any(|name| name == "__class__"),
            "method using super() should close over nested class, got freevars={:?}",
            init.freevars
        );
    }

    #[test]
    fn nested_closure_parameter_class_does_not_create_outer_class_closure() {
        let code = compile_exec(
            "\
class C:
    def m(self):
        def create_closure(__class__):
            return (lambda: __class__).__closure__
",
        );
        let outer_class = find_code(&code, "C").expect("missing class code");
        let create_closure =
            find_code(&code, "create_closure").expect("missing create_closure code");
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");

        assert!(
            !outer_class.cellvars.iter().any(|name| name == "__class__"),
            "nested __class__ parameter must not force outer class cell, got cellvars={:?}",
            outer_class.cellvars
        );
        assert!(
            create_closure
                .cellvars
                .iter()
                .any(|name| name == "__class__"),
            "create_closure should own __class__ parameter cell, got cellvars={:?}",
            create_closure.cellvars
        );
        assert!(
            lambda.freevars.iter().any(|name| name == "__class__"),
            "lambda should close over create_closure parameter, got freevars={:?}",
            lambda.freevars
        );
    }

    #[test]
    fn chained_compare_jump_uses_single_cleanup_copy() {
        let code = compile_exec(
            "\
def f(code):
    if not 1 <= code <= 2147483647:
        raise ValueError('x')
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let copy_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::Copy { .. }))
            .count();
        let pop_top_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::PopTop))
            .count();

        assert_eq!(copy_count, 1);
        assert_eq!(pop_top_count, 1);
    }

    #[test]
    fn yield_from_cleanup_jumps_to_shared_end_send() {
        let code = compile_exec(
            "\
def outer():
    def inner():
        yield from outer_gen
    return inner
",
        );
        let inner = find_code(&code, "inner").expect("missing inner code");
        let ops: Vec<_> = inner
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cleanup_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::CleanupThrow))
            .expect("missing CLEANUP_THROW");
        assert!(
            matches!(
                ops.get(cleanup_idx + 1),
                Some(Instruction::JumpBackwardNoInterrupt { .. } | Instruction::JumpForward { .. })
            ),
            "expected CLEANUP_THROW to jump to shared END_SEND block, got ops={ops:?}"
        );
        assert!(
            !matches!(ops.get(cleanup_idx + 1), Some(Instruction::EndSend)),
            "CLEANUP_THROW should not inline END_SEND directly, got ops={ops:?}"
        );
    }

    #[test]
    fn try_except_falls_through_to_post_handler_code() {
        let code = compile_exec(
            "\
def f():
    try:
        line = 2
        raise KeyError
    except:
        line = 5
    line = 6
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let first_pop_except = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopExcept))
            .expect("missing POP_EXCEPT");
        assert!(
            !matches!(
                ops.get(first_pop_except + 1),
                Some(Instruction::JumpForward { .. })
            ),
            "expected except body to fall through to post-handler code, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.get(first_pop_except + 1),
                Some(Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. })
            ),
            "expected line-after-except code immediately after POP_EXCEPT, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_loop_fallthrough_pop_block_bounds_exception_table() {
        let code = compile_exec(
            "\
def f(os, E, data):
    try:
        while True:
            part = os.read(3, 50000)
            data += part
            if not part or len(data) > 50000:
                break
    finally:
        os.close(3)
    if data:
        raise E(2, 'x')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let raise_idx = u32::try_from(
            f.instructions
                .iter()
                .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
                .expect("missing post-finally raise"),
        )
        .unwrap();
        let entries = bytecode::decode_exception_table(&f.exceptiontable);

        assert!(
            entries
                .iter()
                .all(|entry| raise_idx < entry.start || raise_idx >= entry.end),
            "post-finally raise should not remain protected by the try/finally table; entries={entries:?}, instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn except_as_alias_cleanup_exception_table_matches_cpython() {
        let code = compile_exec(
            "\
def bug():
    try:
        1/0
    except Exception as e:
        tb = e.__traceback__
    return tb
",
        );
        let bug = find_code(&code, "bug").expect("missing bug code");
        let entries = bytecode::decode_exception_table(&bug.exceptiontable);
        let not_taken_idx = u32::try_from(
            bug.instructions
                .iter()
                .position(|unit| matches!(unit.op, Instruction::NotTaken))
                .expect("missing NOT_TAKEN"),
        )
        .unwrap();
        let alias_store_idx = not_taken_idx + 1;
        let copy_idx = u32::try_from(
            bug.instructions
                .iter()
                .position(|unit| {
                    matches!(
                        unit.op,
                        Instruction::Copy { i }
                            if i.get(OpArg::new(u32::from(u8::from(unit.arg)))) == 3
                    )
                })
                .expect("missing outer cleanup COPY"),
        )
        .unwrap();

        assert!(
            entries.iter().any(|entry| {
                entry.start <= not_taken_idx
                    && alias_store_idx < entry.end
                    && entry.target == copy_idx
                    && entry.depth == 1
                    && entry.push_lasti
            }),
            "CPython codegen_try_except() stores the exception alias before the inner SETUP_CLEANUP, so NOT_TAKEN and the alias store stay covered by the outer cleanup entry; entries={entries:?}, instructions={:?}",
            bug.instructions
        );
    }

    #[test]
    fn try_except_while_body_preserves_while_exit_line_nop() {
        let code = compile_exec(
            "\
def f(x, E):
    try:
        while x:
            x -= 1
    except E:
        if not x:
            return None
    assert x
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let assertion_error = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadCommonConstant { .. }))
            .expect("missing assertion error load");

        assert!(
            ops[..assertion_error].windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. },
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "try/except while body should preserve CPython while-exit NOP before following assert, got ops={ops:?}"
        );
    }

    #[test]
    fn constant_true_while_preserves_loop_line_nop() {
        let code = compile_exec(
            "\
def f(self, callback):
    i = 1
    while True:
        for j in 1, 2, 5:
            number = i * j
            if callback:
                callback(number, j)
            return number, j
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let store_i = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing i store");

        assert!(
            matches!(ops.get(store_i + 1), Some(Instruction::Nop)),
            "constant-true while should keep CPython loop-line NOP after setup, got ops={ops:?}"
        );
    }

    #[test]
    fn try_except_for_direct_break_preserves_normal_exhaustion_nop() {
        let code = compile_exec(
            "\
def f(xs, g, E):
    try:
        for x in xs:
            if x:
                break
            g()
    except E:
        pass
    g()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "try/except for-body with direct break should keep CPython normal-exhaustion NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_except_for_without_direct_break_drops_normal_exhaustion_nop() {
        let code = compile_exec(
            "\
def f(xs, g, E):
    try:
        for x in xs:
            g()
    except E:
        pass
    g()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "try/except for-body without direct break should not keep a redundant normal-exhaustion NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn terminal_except_before_conditional_tail_uses_strong_load() {
        let code = compile_exec(
            "\
def f(self, Exception):
    try:
        tree = self.g()
    except Exception:
        return False
    if tree.body:
        return True
    return False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let tree_load_before_body_attr = instructions.windows(2).find(|window| {
            let loads_tree = match window[0].op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    f.varnames
                        [usize::from(var_num.get(OpArg::new(u32::from(u8::from(window[0].arg)))))]
                        == "tree"
                }
                _ => false,
            };
            loads_tree && matches!(window[1].op, Instruction::LoadAttr { .. })
        });

        assert!(
            matches!(
                tree_load_before_body_attr.map(|window| window[0].op),
                Some(Instruction::LoadFast { .. })
            ),
            "conditional tail after terminal except should match CPython's strong LOAD_FAST, got instructions={instructions:?}",
        );
    }

    #[test]
    fn try_except_continuation_folded_tuple_drops_operand_nop() {
        let code = compile_exec(
            "\
def f():
    try:
        import sqlite3
    except ImportError:
        return

    attributes = ('sqlite_version',)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython nop_out-style folded tuple operand NOP to be removed, got ops={ops:?}",
        );
    }

    #[test]
    fn if_else_normal_fallthrough_end_label_drops_return_anchor_nop() {
        let code = compile_exec(
            "\
def f(s):
    if s[0] in (0o200, 0o377):
        n = 0
        for i in range(len(s) - 1):
            n <<= 8
            n += s[i + 1]
        if s[0] == 0o377:
            n = -(256 ** (len(s) - 1) - n)
    else:
        try:
            s = nts(s, 'ascii', 'strict')
            n = int(s.strip() or '0', 8)
        except ValueError:
            raise InvalidHeaderError('invalid header')
    return n
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "normal fallthrough into an if-end final return should not keep a CPython return-anchor NOP, got ops={ops:?}",
        );
    }

    #[test]
    fn explicit_final_return_none_is_not_duplicated() {
        let code = compile_exec(
            "\
def f(src, dst, length, exception, bufsize):
    if length == 0:
        return
    if length is None:
        copyfileobj(src, dst, bufsize)
        return

    blocks, remainder = divmod(length, bufsize)
    for b in range(blocks):
        buf = src.read(bufsize)
        if len(buf) < bufsize:
            raise exception('unexpected end of data')
        dst.write(buf)

    if remainder != 0:
        buf = src.read(remainder)
        if len(buf) < remainder:
            raise exception('unexpected end of data')
        dst.write(buf)
    return
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let return_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();

        assert_eq!(
            return_count,
            3,
            "explicit final return None should not be duplicated as a synthetic no-location epilogue, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn named_except_cleanup_keeps_jump_over_cleanup_and_next_try() {
        let code = compile_exec(
            r#"
def f(self):
    try:
        assert 0, 'msg'
    except AssertionError as e:
        self.assertEqual(e.args[0], 'msg')
    else:
        self.fail("AssertionError not raised by assert 0")

    try:
        assert False
    except AssertionError as e:
        self.assertEqual(len(e.args), 0)
    else:
        self.fail("AssertionError not raised by 'assert False'")
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let first_pop_except = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopExcept))
            .expect("missing POP_EXCEPT");
        let window = &ops[first_pop_except..(first_pop_except + 6).min(ops.len())];
        assert!(
            matches!(
                window,
                [
                    Instruction::PopExcept,
                    Instruction::LoadConst { .. },
                    Instruction::StoreName { .. } | Instruction::StoreFast { .. },
                    Instruction::DeleteName { .. } | Instruction::DeleteFast { .. },
                    Instruction::JumpForward { .. },
                    ..
                ]
            ),
            "expected named except cleanup to jump over cleanup reraise block, got ops={window:?}"
        );
    }

    #[test]
    fn named_except_with_suppress_does_not_duplicate_following_with() {
        let code = compile_exec(
            "\
def f(StringIO, captured_output, print):
    try:
        raise KeyError
    except KeyError as e:
        with captured_output('stderr') as tbstderr:
            print('x')
        with captured_output('stderr') as tbstderr:
            print('y')
    else:
        print('else')
    s = StringIO()
    return s
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_y_count = f
            .instructions
            .iter()
            .filter(|unit| match unit.op {
                Instruction::LoadConst { consti } => {
                    matches!(
                        &f.constants
                            [consti.get(OpArg::new(u32::from(u8::from(unit.arg))))],
                        ConstantData::Str { value } if value.as_str() == Ok("y")
                    )
                }
                _ => false,
            })
            .count();

        assert_eq!(
            load_y_count, 1,
            "following with body should not be duplicated into the previous with suppress path"
        );
    }

    #[test]
    fn bare_except_deopts_post_handler_load_fast_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        1 / 0
    except:
        pass
    with self.assertRaises(SyntaxError):
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let attr_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing LOAD_ATTR for assertRaises");
        assert!(
            matches!(ops.get(attr_idx - 1), Some(Instruction::LoadFast { .. })),
            "bare except tail should deopt self to LOAD_FAST, got ops={ops:?}"
        );
    }

    #[test]
    fn bare_except_before_if_deopts_successor_load_fast_borrow() {
        let code = compile_exec(
            "\
def f(self, x):
    try:
        x = g()
    except:
        self.fail('raised')
    if x:
        self.fail('unexpected')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let fail_loads = instructions
            .iter()
            .enumerate()
            .filter_map(|(idx, unit)| {
                let Instruction::LoadAttr { namei } = unit.op else {
                    return None;
                };
                let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                (f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "fail")
                    .then_some(idx)
            })
            .collect::<Vec<_>>();
        assert!(
            fail_loads.len() >= 2,
            "expected handler and successor fail calls, got instructions={instructions:?}"
        );
        assert!(
            matches!(
                instructions.get(fail_loads[1] - 1).map(|unit| unit.op),
                Some(Instruction::LoadFast { .. })
            ),
            "CPython codegen_try_except() sends a fallthrough bare handler through USE_LABEL(end); flowgraph.c::optimize_load_fast() stops at that empty end label before the following if, got instructions={instructions:?}"
        );
    }

    #[test]
    fn typed_except_keeps_post_handler_load_fast_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        1 / 0
    except ZeroDivisionError:
        pass
    with self.assertRaises(SyntaxError):
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let attr_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing LOAD_ATTR for assertRaises");
        assert!(
            matches!(
                ops.get(attr_idx - 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "typed except tail should keep LOAD_FAST_BORROW, got ops={ops:?}"
        );
    }

    #[test]
    fn bare_except_terminal_handler_store_subscr_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(g, cache, filename, mtime, result):
    try:
        module = g()
    except:
        return None
    cache[filename] = (mtime, result)
    return result
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_pair = |unit: &&CodeUnit, left_name: &str, right_name: &str| {
            let Instruction::LoadFastLoadFast { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };
        let is_borrow_pair = |unit: &&CodeUnit, left_name: &str, right_name: &str| {
            let Instruction::LoadFastBorrowLoadFastBorrow { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };

        assert!(
            ops.iter().any(|unit| is_pair(unit, "mtime", "result"))
                && ops.iter().any(|unit| is_pair(unit, "cache", "filename")),
            "CPython optimize_load_fast() stops at the empty try-end block for a terminal bare handler, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|unit| is_borrow_pair(unit, "mtime", "result")
                    || is_borrow_pair(unit, "cache", "filename")),
            "terminal bare handler post-try store tail should not be borrowed, got ops={ops:?}"
        );
    }

    #[test]
    fn while_true_try_else_break_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(path, prefix, self, cache, read, E, stat):
    while True:
        try:
            st = stat(path)
        except E:
            path = path.dirname
        else:
            if st.mode:
                raise E
            break
    if path not in cache:
        cache[path] = read(path)
    self.archive = path
    self.prefix = prefix
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_pair = |unit: &&CodeUnit, left_name: &str, right_name: &str| {
            let Instruction::LoadFastLoadFast { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };
        let is_borrow_pair = |unit: &&CodeUnit, left_name: &str, right_name: &str| {
            let Instruction::LoadFastBorrowLoadFastBorrow { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };

        assert!(
            ops.iter().any(|unit| is_pair(unit, "path", "cache"))
                && ops.iter().any(|unit| is_pair(unit, "path", "self"))
                && ops.iter().any(|unit| is_pair(unit, "prefix", "self")),
            "CPython codegen_while() leaves an empty break end label that stops optimize_load_fast(), got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|unit| is_borrow_pair(unit, "path", "cache")
                || is_borrow_pair(unit, "path", "self")
                || is_borrow_pair(unit, "prefix", "self")),
            "while-true break successor should not be reached through a Rust-only fallthrough, got ops={ops:?}"
        );
    }

    #[test]
    fn except_handler_resume_return_call_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(class_cache, cls, KeyError, make, obj, lock, ctx):
    try:
        scls = class_cache[cls]
    except KeyError:
        scls = make(cls)
    return scls(obj, lock, ctx)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let borrows_name = |unit: &&CodeUnit, name: &str| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
            }
            _ => false,
        };
        let strong_loads_name = |unit: &&CodeUnit, name: &str| match unit.op {
            Instruction::LoadFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            Instruction::LoadFastLoadFast { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
            }
            _ => false,
        };
        let return_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .expect("missing return");
        let tail = &ops[..return_idx];

        for name in ["scls", "obj", "lock", "ctx"] {
            assert!(
                tail.iter().any(|unit| borrows_name(unit, name)),
                "handler resume to CPython codegen_try_except() end label should keep return-call {name} borrowed, got tail={tail:?}"
            );
            assert!(
                !tail.iter().any(|unit| strong_loads_name(unit, name)),
                "handler resume return-call tail should not be separated by a Rust-only empty end block for {name}, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn typed_except_named_handler_closure_tail_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self):
    filename = TESTFN
    ICACLS = expandvars('icacls')
    try:
        check_output([ICACLS, filename])
    except CalledProcessError as ex:
        self.skipTest('Unable to create inaccessible file')
    def cleanup():
        check_output([ICACLS, filename])
    self.addCleanup(cleanup)
    stat1 = stat(filename)
    stat2 = stat(filename)
    self.assertEqual(stat1, stat2)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let make_function = ops
            .iter()
            .position(|op| matches!(op, Instruction::MakeFunction))
            .expect("missing MAKE_FUNCTION for cleanup closure");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &ops[make_function.saturating_sub(2)..handler_start];

        assert!(
            tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "typed except closure continuation should be visited by optimize_load_fast(), got tail={tail:?}",
        );
        assert!(
            !tail
                .iter()
                .any(|op| matches!(op, Instruction::LoadFast { .. })),
            "CPython codegen_try_except() uses USE_LABEL(end), so the handler continuation should be a shared passthrough and post-handler closure/tail loads should borrow; got tail={tail:?}",
        );
    }

    #[test]
    fn named_terminal_raise_handler_keeps_return_pair_borrowed() {
        let code = compile_exec(
            "\
def f(factory, worker_json, test_name, stdout, E):
    try:
        result = factory(worker_json)
    except E as exc:
        raise RuntimeError(test_name, stdout, exc)
    return result, stdout
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let has_borrowed_pair = instructions.iter().any(|unit| {
            let Instruction::LoadFastBorrowLoadFastBorrow { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == "result" && f.varnames[usize::from(right)] == "stdout"
        });

        assert!(
            has_borrowed_pair,
            "named terminal-raise handler should follow CPython codegen_try_except()/flowgraph.c cleanup reachability and keep return pair borrowed; got instructions={instructions:?}"
        );
    }

    #[test]
    fn conditional_typed_except_return_join_keeps_borrow() {
        let code = compile_exec(
            "\
def f(cond, obj, xs, E):
    if cond:
        try:
            obj.m()
        except E:
            return 1
    for x in xs:
        obj.n(x)
    return obj
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_tail = &instructions[..handler_start];
        let load_name = |unit: &&CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        for name in ["xs", "obj", "x"] {
            assert!(
                normal_tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })
                        && load_name(unit) == Some(name)),
                "conditional typed except return join should keep CPython-style borrowed {name} loads, got tail={normal_tail:?}"
            );
            assert!(
                !normal_tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })
                        && load_name(unit) == Some(name)),
                "conditional typed except return join should not force strong {name} loads, got tail={normal_tail:?}"
            );
        }
    }

    #[test]
    fn typed_except_pass_resume_store_subscr_tail_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self, sys, KeyError):
    mod_name = self.mod_name
    try:
        self._saved_module.append(sys.modules[mod_name])
    except KeyError:
        pass
    sys.modules[mod_name] = self.module
    return self
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let store_subscr_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreSubscr))
            .expect("missing STORE_SUBSCR tail");
        assert!(
            matches!(
                ops.get(store_subscr_idx - 5),
                Some(Instruction::LoadFastBorrow { .. })
            ) && matches!(
                ops.get(store_subscr_idx - 3),
                Some(Instruction::LoadFastBorrow { .. })
            ) && matches!(
                ops.get(store_subscr_idx - 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "typed except pass tail should keep STORE_SUBSCR operands borrowed, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.get(store_subscr_idx + 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "typed except pass return should keep self borrowed, got ops={ops:?}"
        );
    }

    #[test]
    fn reraising_typed_except_deopts_post_handler_loads() {
        let code = compile_exec(
            "\
def f(x, os, self, pid, exitcode):
    try:
        y = 1
    except RuntimeError:
        raise
    if x:
        os._exit(exitcode)
    self.wait_impl(pid, exitcode=exitcode)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let guard_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ToBool))
            .and_then(|idx| idx.checked_sub(1))
            .expect("missing post-handler bool guard");
        assert!(
            matches!(ops.get(guard_idx), Some(Instruction::LoadFast { .. })),
            "reraising typed except tail should deopt guard load, got ops={ops:?}"
        );

        let wait_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::CallKw { .. }))
            .expect("missing wait_impl CALL_KW");
        let call_args = &ops[wait_idx.saturating_sub(3)..wait_idx];
        assert!(
            call_args.iter().any(|op| matches!(
                op,
                Instruction::LoadFastLoadFast { .. } | Instruction::LoadFast { .. }
            )),
            "reraising typed except tail should keep strong fast loads for call args, got ops={ops:?}"
        );
        assert!(
            !call_args.iter().any(|op| matches!(
                op,
                Instruction::LoadFastBorrowLoadFastBorrow { .. }
                    | Instruction::LoadFastBorrow { .. }
            )),
            "reraising typed except tail should not borrow call args, got ops={ops:?}"
        );
    }

    #[test]
    fn reraising_outer_handler_keeps_explicit_raise_call_arg_borrow() {
        let code = compile_exec(
            "\
def f(file, os, stat, errno, self, fd):
    try:
        self._stat_atopen = os.fstat(fd)
        try:
            if stat.S_ISDIR(self._stat_atopen.st_mode):
                raise IsADirectoryError(errno.EISDIR, os.strerror(errno.EISDIR), file)
        except AttributeError:
            pass
        self.name = file
        try:
            os.lseek(fd, 0, SEEK_END)
        except OSError as e:
            if e.errno != errno.ESPIPE:
                raise
    except OSError:
        raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let file_borrow_before_raise_call = instructions.windows(3).any(|window| {
            let is_file_borrow = match window[0].op {
                Instruction::LoadFastBorrow { var_num } => {
                    f.varnames
                        [usize::from(var_num.get(OpArg::new(u32::from(u8::from(window[0].arg)))))]
                        == "file"
                }
                _ => false,
            };
            is_file_borrow
                && matches!(window[1].op, Instruction::Call { .. })
                && matches!(window[2].op, Instruction::RaiseVarargs { .. })
        });

        assert!(
            file_borrow_before_raise_call,
            "outer reraising handler should not deopt explicit raise call args; CPython keeps file as LOAD_FAST_BORROW, got instructions={instructions:?}"
        );
    }

    #[test]
    fn reraising_except_loop_backedge_keeps_loop_header_borrow() {
        let code = compile_exec(
            "\
def f(self, tag, expect_bye):
    while 1:
        result = self.tagged_commands[tag]
        if result is not None:
            del self.tagged_commands[tag]
            return result
        if expect_bye:
            typ = 'BYE'
            bye = self.untagged_responses.pop(typ, None)
            if bye is not None:
                return (typ, bye)
        self._check_bye()
        try:
            self._get_response()
        except self.abort as val:
            if __debug__:
                if self.debug >= 1:
                    self.print_log()
            raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_ops: Vec<_> = instructions[..handler_start]
            .iter()
            .map(|unit| unit.op)
            .collect();

        assert!(
            warm_ops.iter().any(|op| matches!(
                op,
                Instruction::LoadFastBorrow { .. }
                    | Instruction::LoadFastBorrowLoadFastBorrow { .. }
            )),
            "expected loop body before reraising handler to keep borrowed loads, got ops={warm_ops:?}"
        );
        assert!(
            warm_ops
                .iter()
                .all(|op| !matches!(op, Instruction::LoadFast { .. })),
            "loop backedge into reraising handler should not deopt warm loop loads, got ops={warm_ops:?}"
        );
    }

    #[test]
    fn protected_store_break_handler_deopts_bool_guard_tail() {
        let code = compile_exec(
            "\
def f(self, size):
    parts = []
    while size > 0:
        try:
            buf = self.sock.recv(DEFAULT_BUFFER_SIZE)
        except ConnectionError:
            break
        if not buf:
            break
        self._readbuf.append(buf)
        size -= len(buf)
    return b''.join(parts)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let guard_bool = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ToBool))
            .expect("missing bool guard");
        let store_buf = instructions[..guard_bool]
            .iter()
            .rposition(|unit| matches!(unit.op, Instruction::StoreFast { .. }))
            .expect("missing protected STORE_FAST before bool guard");
        let guard_load = instructions[store_buf + 1].op;
        let append_call = instructions[store_buf + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::Call { .. }))
            .map(|idx| idx + store_buf + 1)
            .expect("missing append call");
        let append_arg = instructions[append_call - 1].op;

        assert!(
            matches!(guard_load, Instruction::LoadFast { .. }),
            "CPython uses strong LOAD_FAST for protected-store break guard, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(append_arg, Instruction::LoadFast { .. }),
            "CPython uses strong LOAD_FAST for protected-store append arg, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn assertion_success_join_keeps_following_debug_tail_borrowed() {
        let code = compile_exec(
            "\
def f(self, typ, dat):
    if self._idle_capture:
        if self._idle_responses:
            response = self._idle_responses[-1]
            assert response[0] == typ
            response[1].append(dat)
        else:
            self._idle_responses.append((typ, [dat]))
        if self.debug >= 5:
            self._mesg(f'idle: queue untagged {typ} {dat!r}')
        return
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let debug_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "debug"
                }
                _ => false,
            })
            .expect("missing debug LOAD_ATTR");
        let mesg_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "_mesg"
                }
                _ => false,
            })
            .expect("missing _mesg LOAD_ATTR");

        assert!(
            matches!(
                instructions[debug_attr - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython keeps LOAD_FAST_BORROW after assertion success join, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(
                instructions[mesg_attr - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython keeps LOAD_FAST_BORROW in assertion-success debug body, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn multi_protected_method_call_terminal_handler_keeps_try_body_borrows() {
        let code = compile_exec(
            "\
def f(self, literal):
    try:
        self.send(literal)
        self.send(CRLF)
    except OSError as val:
        raise self.abort('socket error: %s' % val)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_send = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "send"
                }
                _ => false,
            })
            .expect("missing send LOAD_ATTR");
        let first_literal = instructions[first_send + 1].op;
        let second_send = instructions[first_send + 1..]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "send"
                }
                _ => false,
            })
            .map(|idx| idx + first_send + 1)
            .expect("missing second send LOAD_ATTR");

        assert!(
            matches!(
                instructions[first_send - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython keeps first protected send receiver borrowed, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(first_literal, Instruction::LoadFastBorrow { .. }),
            "CPython keeps first protected send arg borrowed, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
        assert!(
            matches!(
                instructions[second_send - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "CPython keeps second protected send receiver borrowed, got ops={:?}",
            instructions.iter().map(|unit| unit.op).collect::<Vec<_>>()
        );
    }

    #[test]
    fn dunder_debug_constant_false_if_deopts_tail_borrow() {
        let code = compile_exec(
            "\
def f(self):
    if not __debug__:
        self.skipTest('need asserts, run without -O')
    self.do_disassembly_test()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let attr_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "do_disassembly_test"
                }
                _ => false,
            })
            .expect("missing LOAD_ATTR for do_disassembly_test");
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();
        assert!(
            matches!(ops.get(attr_idx - 1), Some(Instruction::LoadFast { .. })),
            "constant-false __debug__ tail should deopt self to LOAD_FAST, got ops={ops:?}"
        );
    }

    #[test]
    fn constant_slice_folds_constant_bounds() {
        let code = compile_exec(
            "\
def f(obj):
    return obj['a':123456789012345678901234567890]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let folded_slice = f
            .constants
            .iter()
            .find_map(|constant| match constant {
                ConstantData::Slice { elements } => Some(elements),
                _ => None,
            })
            .expect("missing folded slice constant");
        assert!(
            matches!(
                folded_slice.as_ref(),
                [
                    ConstantData::Str { .. },
                    ConstantData::Integer { .. },
                    ConstantData::None,
                ]
            ),
            "expected folded slice('a', 123456789012345678901234567890, None), got {folded_slice:?}"
        );
        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadConst { .. },
                    Instruction::BinaryOp { .. },
                    Instruction::ReturnValue,
                ]
            ),
            "expected CPython-style LOAD_CONST(slice(...)) path for constant bounds, got ops={ops:?}"
        );
    }

    #[test]
    fn negative_step_slice_uses_build_slice() {
        let code = compile_exec(
            "\
def f(obj):
    return obj[::-1]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadConst { .. },
                    Instruction::LoadConst { .. },
                    Instruction::LoadConst { .. },
                    Instruction::BuildSlice { .. },
                    Instruction::BinaryOp { .. },
                    Instruction::ReturnValue,
                ]
            ),
            "expected CPython-style BUILD_SLICE path for non-literal negative step, got ops={ops:?}"
        );
    }

    #[test]
    fn slice_none_bounds_and_build_slice_use_slice_location_like_cpython() {
        let code = compile_exec(
            "\
def f(obj, step):
    return obj[::step]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let slice_positions: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, end_location))| {
                let op = match unit.op {
                    Instruction::LoadConst { .. } => "LOAD_CONST",
                    Instruction::BuildSlice { .. } => "BUILD_SLICE",
                    _ => return None,
                };
                Some((
                    op,
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert_eq!(
            slice_positions,
            vec![
                ("LOAD_CONST", 2, 16, 2, 22),
                ("LOAD_CONST", 2, 16, 2, 22),
                ("BUILD_SLICE", 2, 16, 2, 22),
            ],
            "CPython codegen_slice() emits missing bounds and BUILD_SLICE at LOC(slice)"
        );
    }

    #[test]
    fn bool_int_binop_constants_fold() {
        let code = compile_exec(
            "\
def f():
    return False + 2, True + 2, False + False, True / 1, True & False

def g():
    return False + 2
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::BinaryOp { .. })),
            "expected CPython-style folded bool/int binops, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadConst { .. },
                    Instruction::ReturnValue
                ]
            ),
            "expected folded constants for bool/int binops, got ops={ops:?}"
        );

        let g = find_code(&code, "g").expect("missing function code");
        let g_ops: Vec<_> = g
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        assert!(
            !g_ops
                .iter()
                .any(|op| matches!(op, Instruction::BinaryOp { .. })),
            "expected top-level bool/int binop to fold, got ops={g_ops:?}"
        );
    }

    #[test]
    fn double_not_expression_folds_to_bool_conversion() {
        let code = compile_exec(
            "\
def f(x):
    return not not x
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::ToBool,
                    Instruction::ReturnValue,
                ]
            ),
            "expected CPython-style double-not bool conversion, got ops={ops:?}"
        );
    }

    #[test]
    fn tuple_bound_slice_uses_two_part_slice_path() {
        let code = compile_exec(
            "\
def f(obj):
    return obj[(1, 2):]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            matches!(
                ops.as_slice(),
                [
                    Instruction::Resume { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadConst { .. },
                    Instruction::LoadConst { .. },
                    Instruction::BinarySlice,
                    Instruction::ReturnValue,
                ]
            ),
            "expected CPython-style BINARY_SLICE path for tuple lower bound, got ops={ops:?}"
        );
    }

    #[test]
    fn exception_cleanup_jump_to_return_is_inlined() {
        let code = compile_exec(
            "\
def f(names, cls):
    try:
        cls.attr = names
    except:
        pass
    return names
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let return_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();

        assert_eq!(
            return_count, 2,
            "expected CPython-style distinct return sites for normal and except paths"
        );
    }

    #[test]
    fn except_break_preserves_plain_jump_when_inlining_no_lineno_tail() {
        let code = compile_exec(
            "\
def f(compiler_so, cc_args):
    strip_sysroot = True
    if '-arch' in cc_args:
        while True:
            try:
                index = compiler_so.index('-arch')
                del compiler_so[index:index + 2]
            except ValueError:
                break
    if strip_sysroot:
        while True:
            indices = [i for i, x in enumerate(compiler_so) if x.startswith('-isysroot')]
            if not indices:
                break
            index = indices[0]
            del compiler_so[index:index + 1]
    return compiler_so
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [Instruction::PopExcept, Instruction::JumpBackward { .. }]
                )
            }) && !ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::JumpBackwardNoInterrupt { .. }
                    ]
                )
            }),
            "except-break cleanup should preserve CPython's plain JUMP when a no-lineno tail is inlined, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_with_bare_except_keeps_handler_cleanup_before_following_code() {
        let code = compile_exec(
            "\
def f(cm, self):
    try:
        with cm:
            raise Exception
    except:
        pass
    self.g()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let outer_handler = ops
            .iter()
            .enumerate()
            .filter_map(|(idx, op)| matches!(op, Instruction::PushExcInfo).then_some(idx))
            .next_back()
            .expect("missing outer handler");
        assert!(
            ops[outer_handler..].windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::JumpForward { .. },
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::LoadFast { .. },
                    ]
                )
            }),
            "expected CPython-style handler cleanup before following code, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_for_cleanup_drops_redundant_jump_nop() {
        let code = compile_exec(
            "\
def f(self, xs, ys, cm1, cm2):
    for x in xs:
        with self.subTest(x=x):
            try:
                with cm1:
                    self.a()
            except Exception:
                if x:
                    pass
                else:
                    raise
            else:
                for y in ys:
                    with self.subTest(y=y):
                        with cm2:
                            self.b()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "expected inner for cleanup to fall directly into surrounding with cleanup, got ops={ops:?}",
        );
        assert!(
            !ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "expected CPython-style removal of the redundant jump NOP after for cleanup, got ops={ops:?}",
        );
    }

    #[test]
    fn non_none_final_return_is_not_duplicated() {
        let code = compile_exec(
            "\
def f(p, s):
    if p == '':
        if s == '':
            return 0
    return -1
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let minus_one_loads = f
            .instructions
            .iter()
            .filter(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadConst { consti }
                        if matches!(
                            f.constants.get(
                                consti
                                    .get(OpArg::new(u32::from(u8::from(unit.arg))))
                                    .as_usize()
                            ),
                            Some(ConstantData::Integer { value }) if value == &BigInt::from(-1)
                        )
                )
            })
            .count();

        assert_eq!(
            minus_one_loads,
            1,
            "expected a single final return -1 epilogue, got ops={:?}",
            f.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn for_return_unary_constant_preserves_value_over_iterator_cleanup() {
        let code = compile_exec(
            "\
def f(xs):
    for x in xs:
        return -1
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let units: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            units.windows(4).any(|window| {
                matches!(
                    window[0].op,
                    Instruction::LoadConst { .. } | Instruction::LoadSmallInt { .. }
                ) && matches!(
                    window[1].op,
                    Instruction::Swap { i }
                        if i.get(OpArg::new(u32::from(u8::from(window[1].arg)))) == 2
                ) && matches!(window[2].op, Instruction::PopTop)
                    && matches!(window[3].op, Instruction::ReturnValue)
            }),
            "expected CPython-style LOAD_CONST/SWAP/POP_TOP/RETURN_VALUE cleanup, got units={units:?}"
        );
    }

    #[test]
    fn try_else_if_return_keeps_conditional_target_nop() {
        let code = compile_exec(
            "\
def f(cond):
    try:
        x = cond
    except E:
        pass
    else:
        if x:
            return 1
    return 2
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let has_cpython_nop_target = ops.windows(5).any(|window| {
            matches!(
                window,
                [
                    Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. },
                    Instruction::ReturnValue,
                    Instruction::Nop,
                    Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. },
                    Instruction::ReturnValue,
                ]
            )
        });
        assert!(
            has_cpython_nop_target,
            "expected CPython-style try-else conditional target NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_nested_if_return_drops_inner_conditional_target_nop() {
        let code = compile_exec(
            "\
def f(obj, Sig):
    try:
        sig = obj.__signature__
    except AttributeError:
        pass
    else:
        if sig is not None:
            if not isinstance(sig, Sig):
                raise TypeError(sig)
            return sig
    return obj
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "inner try-else if target should not materialize as a NOP before the return, got ops={ops:?}"
        );
        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                        Instruction::ReturnValue,
                        Instruction::Nop,
                    ]
                )
            }),
            "expected only the outer try-else if false target after the return, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_nested_final_if_return_drops_nested_conditional_target_nop() {
        let code = compile_exec(
            "\
def f(cond, outer):
    try:
        x = cond
    except E:
        pass
    else:
        if outer:
            if x:
                return 1
    return 2
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ReturnValue,
                        Instruction::Nop,
                        Instruction::LoadSmallInt { .. } | Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "nested try-else conditional target should fall through directly to following code, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_conditional_branch_duplicates_cleanup_return() {
        let code = compile_exec(
            "\
def f(self):
    try:
        raise TypeError('x')
    except TypeError as e:
        if '+' not in str(e):
            self.fail('join() ate exception message')
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cleanup_return_count = ops
            .windows(6)
            .filter(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. } | Instruction::StoreName { .. },
                        Instruction::DeleteFast { .. } | Instruction::DeleteName { .. },
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            })
            .count();

        assert_eq!(
            cleanup_return_count, 2,
            "expected duplicated named-except cleanup return blocks, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_conditional_before_explicit_return_shares_cleanup_return() {
        let code = compile_exec(
            "\
def f(onerror, err, OSError):
    try:
        x()
    except OSError as err:
        if onerror is not None:
            onerror(err)
        return
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cleanup_return_count = ops
            .windows(6)
            .filter(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. } | Instruction::StoreName { .. },
                        Instruction::DeleteFast { .. } | Instruction::DeleteName { .. },
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            })
            .count();

        assert_eq!(
            cleanup_return_count, 1,
            "explicit return after the conditional should share the named-except cleanup return block, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_boolop_condition_shares_cleanup_return() {
        let code = compile_exec(
            "\
def f(self, module_name, ModuleNotFoundError):
    try:
        return importlib.import_module(module_name)
    except ModuleNotFoundError as error:
        if self._warn_on_extension_import and module_name in builtin_hashes:
            logging.getLogger(__name__).warning('msg', error, exc_info=error)
    return None
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cleanup_return_count = ops
            .windows(6)
            .filter(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. } | Instruction::StoreName { .. },
                        Instruction::DeleteFast { .. } | Instruction::DeleteName { .. },
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            })
            .count();

        assert_eq!(
            cleanup_return_count, 1,
            "CPython keeps a shared named-except cleanup return when multiple BoolOp false edges target the same cleanup block, got ops={ops:?}"
        );
    }

    #[test]
    fn listcomp_cleanup_tail_keeps_split_store_fast_pair() {
        let code = compile_exec(
            "\
def f(escaped_string, quote_types):
    possible_quotes = [q for q in quote_types if q not in escaped_string]
    return possible_quotes
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let pop_iter_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopIter))
            .expect("missing POP_ITER");
        let tail = &ops[pop_iter_idx + 1..];

        assert!(
            matches!(
                tail,
                [
                    Instruction::StoreFast { .. },
                    Instruction::StoreFast { .. },
                    Instruction::LoadFastBorrow { .. },
                    Instruction::ReturnValue,
                    ..
                ]
            ),
            "expected split STORE_FAST pair after listcomp cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn dictcomp_cleanup_tail_keeps_split_store_fast_pair() {
        let code = compile_exec(
            "\
def f(obj, g):
    return {g(k): g(v) for k, v in obj.items()}
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let pop_iter_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopIter))
            .expect("missing POP_ITER");
        let tail = &ops[pop_iter_idx + 1..];

        assert!(
            matches!(
                tail,
                [
                    Instruction::Swap { .. },
                    Instruction::StoreFast { .. },
                    Instruction::StoreFast { .. },
                    Instruction::ReturnValue,
                    ..
                ]
            ),
            "expected split STORE_FAST pair after dictcomp cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn static_swap_triple_assign_keeps_store_fast_store_fast() {
        let code = compile_exec(
            "\
def f(x, y, z):
    a, b, a = x, y, z
    return a
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Swap { .. },
                        Instruction::StoreFastStoreFast { .. },
                        Instruction::StoreFast { .. }
                    ]
                )
            }),
            "expected CPython-style SWAP/STORE_FAST_STORE_FAST/STORE_FAST sequence, got ops={ops:?}"
        );
    }

    #[test]
    fn static_swap_duplicate_pair_eliminates_swap() {
        let code = compile_exec(
            "\
def f(x, y):
    a, a = x, y
    return a
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter().any(|op| matches!(op, Instruction::Swap { .. })),
            "duplicate pair assignment should statically eliminate SWAP, got ops={ops:?}"
        );
        assert!(
            ops.windows(2).any(|window| {
                matches!(window, [Instruction::StoreFast { .. }, Instruction::PopTop])
            }),
            "expected CPython-style STORE_FAST/POP_TOP duplicate assignment, got ops={ops:?}"
        );
    }

    #[test]
    fn static_swap_duplicate_prefix_eliminates_swap() {
        let code = compile_exec(
            "\
def f(x, y, z):
    a, a, b = x, y, z
    return a
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter().any(|op| matches!(op, Instruction::Swap { .. })),
            "duplicate-prefix assignment should statically eliminate SWAP, got ops={ops:?}"
        );
        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [Instruction::StoreFastStoreFast { .. }, Instruction::PopTop]
                )
            }),
            "expected CPython-style STORE_FAST_STORE_FAST/POP_TOP duplicate prefix, got ops={ops:?}"
        );
    }

    #[test]
    fn constant_if_expression_stmt_in_loop_removes_empty_body() {
        let code = compile_exec(
            "\
def f(x):
    while x:
        0 if 1 else 0
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::LoadSmallInt { .. })),
            "expected constant if-expression statement to compile away inside loop, got ops={ops:?}"
        );
    }

    #[test]
    fn if_expression_in_jump_context_skips_constant_true_arm_load() {
        let code = compile_exec(
            "\
def f():
    a if (1 if b else c) else d
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::LoadSmallInt { .. })),
            "expected jump-context if-expression to avoid materializing constant truthy arm, got ops={ops:?}"
        );
    }

    #[test]
    fn with_suppress_tail_duplicates_final_return_none() {
        let code = compile_exec(
            "\
def f(cm, cond):
    if cond:
        with cm():
            pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let return_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();

        assert_eq!(
            return_count, 3,
            "expected duplicated return-none epilogues, got ops={ops:?}"
        );
        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::JumpBackwardNoInterrupt { .. })),
            "with suppress tail should not jump back to shared return block, got ops={ops:?}"
        );
    }

    #[test]
    fn with_conditional_bare_return_keeps_return_line_nop_before_exit_cleanup() {
        let code = compile_exec(
            "\
def f(cm, registry, altkey):
    with cm:
        if registry.get(altkey):
            return
        registry[altkey] = 1
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::LoadConst { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected CPython-style return-line NOP before with-exit cleanup return, got ops={ops:?}"
        );
    }

    #[test]
    fn multiline_nested_with_return_finally_keeps_inner_cleanup_anchor_nop() {
        let code = compile_exec(
            "\
def f(a, b, path):
    try:
        with cm(a) as x, \\
             cm(b):
            return g(x).copy()
    finally:
        try:
            cleanup(path)
        except ValueError:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "multi-line nested with return/finally cleanup should keep CPython's inner item anchor NOP before outer __exit__, got ops={ops:?}"
        );
    }

    #[test]
    fn with_return_value_uses_context_expr_location_like_cpython() {
        let code = compile_exec(
            "\
def f(cm, func, args, kwds):
    with cm:
        return func(*args, **kwds)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let return_positions: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::ReturnValue).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert_eq!(
            return_positions,
            vec![(2, 10, 2, 12), (2, 10, 2, 12)],
            "CPython codegen_unwind_fblock(WITH) leaves RETURN_VALUE inheriting the context expression location"
        );
    }

    #[test]
    fn with_normal_cleanup_jump_uses_context_expr_location_like_cpython() {
        let source = "\
with cm:
    pass
x = 1
";
        let mut opts = CompileOpts::default();
        let source_file = SourceFileBuilder::new("source_path", source).finish();
        let parsed = ruff_python_parser::parse(
            source_file.source_text(),
            ruff_python_parser::Mode::Module.into(),
        )
        .unwrap();
        let mut ast = parsed.into_syntax();
        opts.future_features |= preprocess::future_features(&ast);
        let future_annotations = opts
            .future_features
            .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS);
        preprocess::preprocess_mod(&mut ast, opts.optimize, future_annotations, false);
        let ast = match ast {
            ruff_python_ast::Mod::Module(stmts) => stmts,
            _ => unreachable!(),
        };
        let symbol_table = SymbolTable::scan_program_with_options(
            &ast,
            source_file.clone(),
            opts.allow_top_level_await,
            opts.future_features
                .contains(bytecode::CodeFlags::FUTURE_ANNOTATIONS),
            opts.recursion_limit,
        )
        .map_err(|e| e.into_codegen_error(source_file.name().to_owned()))
        .unwrap();
        let mut compiler =
            Compiler::new_with_syntax_warning_handler(opts, source_file, "<module>", None);
        compiler.compile_program(&ast, symbol_table).unwrap();

        let jump_positions = compiler
            .current_code_info()
            .blocks
            .iter()
            .flat_map(|block| block.used_instructions())
            .filter_map(|info| {
                matches!(
                    info.instr,
                    AnyInstruction::Pseudo(PseudoInstruction::Jump { .. })
                )
                .then_some((
                    (
                        info.location.line.get(),
                        info.location.character_offset.get(),
                        info.end_location.line.get(),
                        info.end_location.character_offset.get(),
                    ),
                    info.lineno_override,
                ))
            })
            .collect::<Vec<_>>();

        assert!(
            jump_positions
                .iter()
                .any(|(position, lineno_override)| *position == (1, 6, 1, 8)
                    && *lineno_override != Some(ir::NO_LOCATION_OVERRIDE)),
            "CPython codegen_with_inner() emits the normal-exit JUMP at LOC(context_expr), not NO_LOCATION; got {jump_positions:?}"
        );
    }

    #[test]
    fn async_with_return_value_uses_context_expr_location_like_cpython() {
        let code = compile_exec(
            "\
async def f(cm, func, args, kwds):
    async with cm:
        return await func(*args, **kwds)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let return_positions: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::ReturnValue).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert_eq!(
            return_positions,
            vec![(2, 16, 2, 18), (2, 16, 2, 18)],
            "CPython codegen_unwind_fblock(ASYNC_WITH) leaves RETURN_VALUE inheriting the context expression location"
        );
    }

    #[test]
    fn try_finally_conditional_return_duplicates_finally_exit_return() {
        let code = compile_exec(
            "\
def f(flag, data, callback):
    try:
        if flag:
            return
        value = 1
    finally:
        if data:
            callback(data)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let return_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            return_count, 4,
            "try-finally return unwind should keep CPython-style distinct true/false finalbody exits, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_conditional_cleanup_is_inlined_per_branch() {
        let code = compile_exec(
            "\
def f(self, logger):
    try:
        work()
    except A as exc:
        if not self.closing:
            self.fatal(exc, 'msg')
        elif self.loop.get_debug():
            logger.debug('closing', exc_info=True)
    finally:
        if self.length > -1:
            self.recv()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cleanup_after_branch_count = ops
            .windows(6)
            .filter(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::PopExcept,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                        Instruction::DeleteFast { .. },
                        Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            })
            .count();
        assert_eq!(
            cleanup_after_branch_count, 2,
            "named except branch exits should inline cleanup like CPython, got ops={ops:?}"
        );
    }

    #[test]
    fn try_finally_exception_path_duplicates_conditional_reraise() {
        let code = compile_exec(
            "\
def f(flag, callback):
    try:
        work()
    finally:
        if flag:
            callback()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let reraise_count = ops
            .iter()
            .filter(|op| matches!(op, Instruction::Reraise { .. }))
            .count();
        assert_eq!(
            reraise_count, 3,
            "try-finally exception finalbody should duplicate CPython no-location RERAISE exits, got ops={ops:?}"
        );
    }

    #[test]
    fn genexpr_compare_header_uses_store_fast_load_fast_like_cpython() {
        let code = compile_exec(
            "\
def f(it):
    return (offset == (4, 10) for offset in it)
",
        );
        let genexpr = find_code(&code, "<genexpr>").expect("missing <genexpr> code");
        let ops: Vec<_> = genexpr
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFastLoadFast { .. },
                        Instruction::LoadConst { .. },
                        Instruction::CompareOp { .. },
                    ]
                )
            }),
            "expected CPython-style STORE_FAST_LOAD_FAST compare header, got ops={ops:?}"
        );
    }

    #[test]
    fn fstring_adjacent_literals_are_merged() {
        let code = compile_exec(
            "\
def f(cls, proto):
    raise TypeError(
        f\"cannot pickle {cls.__name__!r} object: \"
        f\"a class that defines __slots__ without \"
        f\"defining __getstate__ cannot be pickled \"
        f\"with protocol {proto}\"
    )
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let string_consts = f
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadConst { consti } => {
                    Some(&f.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))])
                }
                _ => None,
            })
            .filter_map(|constant| match constant {
                ConstantData::Str { value } => Some(value.to_string()),
                _ => None,
            })
            .collect::<Vec<_>>();

        assert!(
            string_consts.iter().any(|value| {
                value
                    == " object: a class that defines __slots__ without defining __getstate__ cannot be pickled with protocol "
            }),
            "expected merged trailing f-string literal, got {string_consts:?}"
        );
        assert!(
            !string_consts.iter().any(|value| value == " object: "),
            "did not expect split trailing literal, got {string_consts:?}"
        );
    }

    #[test]
    fn literal_only_fstring_statement_keeps_const_like_cpython() {
        let code = compile_exec(
            "\
def f():
    f'''Not a docstring'''
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            f.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Str { value } if value.to_string() == "Not a docstring"
            )),
            "constant f-string statement should survive in co_consts like CPython"
        );
    }

    #[test]
    fn empty_fstring_literals_are_elided_around_interpolation() {
        let code = compile_exec(
            "\
def f(x):
    if '' f'{x}':
        return 1
    return 2
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        let empty_string_loads = f
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadConst { consti } => {
                    Some(&f.constants[consti.get(OpArg::new(u32::from(u8::from(unit.arg))))])
                }
                _ => None,
            })
            .filter(|constant| {
                matches!(
                    constant,
                    ConstantData::Str { value } if value.is_empty()
                )
            })
            .count();
        let build_string_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::BuildString { .. }))
            .count();

        assert_eq!(empty_string_loads, 0);
        assert_eq!(build_string_count, 0);
    }

    #[test]
    fn large_fstring_uses_join_list_like_cpython() {
        let mut source = String::from("def f(x):\n    return f\"");
        for _ in 0..=STACK_USE_GUIDELINE {
            source.push_str("{x}");
        }
        source.push_str("\"\n");

        let code = compile_exec(&source);
        let f = find_code(&code, "f").expect("missing function code");
        let build_string_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::BuildString { .. }))
            .count();
        let list_append_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ListAppend { .. }))
            .count();
        let join_attr_count = f
            .instructions
            .iter()
            .filter(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    load_attr.is_method()
                        && f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                            == "join"
                }
                _ => false,
            })
            .count();

        assert_eq!(build_string_count, 0);
        assert_eq!(
            list_append_count,
            usize::try_from(STACK_USE_GUIDELINE + 1).unwrap()
        );
        assert_eq!(join_attr_count, 1);
    }

    #[test]
    fn large_fstring_join_scaffolding_uses_joinedstr_location_like_cpython() {
        let mut source = String::from("def f(x):\n    return f\"");
        for _ in 0..=STACK_USE_GUIDELINE {
            source.push_str("{x}");
        }
        source.push_str("\"\n");

        let code = compile_exec(&source);
        let f = find_code(&code, "f").expect("missing function code");
        let fstring_end = "    return ".len()
            + 3
            + 3 * usize::try_from(STACK_USE_GUIDELINE + 1).expect("guideline overflowed")
            + 1;
        let expected = (2, 12, 2, fstring_end);

        for (unit, (location, end_location)) in f.instructions.iter().zip(&f.locations) {
            if matches!(
                unit.op,
                Instruction::BuildList { .. }
                    | Instruction::ListAppend { .. }
                    | Instruction::Call { .. }
            ) {
                assert_eq!(
                    (
                        location.line.get(),
                        location.character_offset.get(),
                        end_location.line.get(),
                        end_location.character_offset.get(),
                    ),
                    expected,
                    "CPython codegen_joined_str() emits join scaffolding at LOC(JoinedStr); this direct codegen path uses the parser's FString range, op={:?}",
                    unit.op
                );
            }
        }
    }

    #[test]
    fn large_power_is_not_constant_folded() {
        let code = compile_exec("x = 2**100\n");

        assert!(code.instructions.iter().any(|unit| match unit.op {
            Instruction::BinaryOp { op } => {
                op.get(OpArg::new(u32::from(u8::from(unit.arg)))) == oparg::BinaryOperator::Power
            }
            _ => false,
        }));
    }

    #[test]
    fn string_and_bytes_binops_constant_fold_like_cpython() {
        let code = compile_exec(
            "\
x = b'\\\\' + b'u1881'\n\
y = 103 * 'a' + 'x'\n",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "unexpected runtime BINARY_OP in folded string/bytes constants: {:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Bytes { value } if value == b"\\u1881"
        )));
        let expected = format!("{}x", "a".repeat(103));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Str { value }
                if value.to_string() == expected
        )));
    }

    #[test]
    fn float_floor_division_constant_folds_like_cpython() {
        let code = compile_exec(
            "\
x = 1.0 // 0.1\n\
y = 1.0 % 0.1\n\
z = 1e300 * 1e300 * 0\n",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "float constant floor-div/mod should fold away, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Float { value } if value.to_bits() == 9.0f64.to_bits()
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Float { value }
                if value.to_bits() == 0.09999999999999995f64.to_bits()
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Float { value } if value.is_nan()
        )));
    }

    #[test]
    fn float_power_overflow_constant_does_not_fold() {
        let code = compile_exec("x = 1e300 ** 2\n");

        assert!(
            code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BinaryOp { op }
                    if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        == oparg::BinaryOperator::Power
            )),
            "overflowing float power should stay runtime like CPython, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn large_string_and_bytes_binops_constant_fold_like_cpython() {
        let code = compile_exec(
            r#"
encoded = b'\xff\xfe\x00\x00' + b'\x00\x00\x01\x00' * 1024
text = '\U00010000' * 1024
"#,
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "large safe string/bytes constants should fold away, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Bytes { value } if value.len() == 4100
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Str { value } if value.code_points().count() == 1024
        )));
    }

    #[test]
    fn constant_string_subscript_folds_inside_collection() {
        let code = compile_exec(
            "\
values = [item for item in [r\"\\\\'a\\\\'\", r\"\\t3\", r\"\\\\\"[0]]]\n",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "unexpected runtime BINARY_OP after constant subscript folding: {:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if elements.len() == 3
                    && matches!(&elements[2], ConstantData::Str { value } if value.to_string() == "\\")
        )));
    }

    #[test]
    fn constant_string_subscript_with_surrogate_skips_lossy_fold() {
        let code = compile_exec("value = \"\\ud800\"[0]\n");

        assert!(
            code.instructions.iter().any(|unit| match unit.op {
                Instruction::BinaryOp { op } => {
                    op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        == oparg::BinaryOperator::Subscr
                }
                _ => false,
            }),
            "expected runtime subscript for surrogate literal, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn constant_subscript_folds_in_load_context() {
        let cases = [
            ("value = (1, 2, 3)[0]\n", Some(BigInt::from(1)), None),
            ("value = b\"abc\"[0]\n", Some(BigInt::from(97)), None),
            ("value = \"abc\"[0]\n", None, Some("a")),
        ];

        for (source, expected_int, expected_str) in cases {
            let code = compile_exec(source);
            assert!(
                !code.instructions.iter().any(|unit| matches!(
                    unit.op,
                    Instruction::BinaryOp { op }
                        if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                            == oparg::BinaryOperator::Subscr
                )),
                "expected folded constant subscript for {source:?}, got instructions={:?}",
                code.instructions
            );

            if let Some(expected_int) = expected_int.as_ref() {
                let has_small_int = code.instructions.iter().any(|unit| {
                    matches!(
                        unit.op,
                        Instruction::LoadSmallInt { i }
                            if BigInt::from(i.get(OpArg::new(u32::from(u8::from(unit.arg)))))
                                == *expected_int
                    )
                });
                let has_const_int = code.constants.iter().any(|constant| {
                    matches!(constant, ConstantData::Integer { value } if value == expected_int)
                });
                assert!(
                    has_small_int || has_const_int,
                    "missing folded integer constant {expected_int} for {source:?}, instructions={:?}",
                    code.instructions
                );
            }

            if let Some(expected_str) = expected_str {
                assert!(
                    code.constants.iter().any(|constant| {
                        matches!(constant, ConstantData::Str { value } if value.to_string() == expected_str)
                    }),
                    "missing folded string constant {expected_str:?} for {source:?}",
                );
            }
        }
    }

    #[test]
    fn constant_subscript_registers_source_const_before_result_like_cpython() {
        let code = compile_exec("value = 'string'[3]\n");
        let source_index = code
            .constants
            .iter()
            .position(|constant| {
                matches!(constant, ConstantData::Str { value } if value.to_string() == "string")
            })
            .expect("missing source string constant");
        let result_index = code
            .constants
            .iter()
            .position(|constant| {
                matches!(constant, ConstantData::Str { value } if value.to_string() == "i")
            })
            .expect("missing folded subscript result");
        assert!(
            source_index < result_index,
            "CPython codegen_subscript emits the source constant before flowgraph.c folds NB_SUBSCR"
        );
    }

    #[test]
    fn constant_slice_subscript_folds_in_load_context() {
        let code = compile_exec(
            "\
a = 'hello'[:4]\n\
b = b'abcd'[1:3]\n\
c = (1, 2, 3)[:2]\n",
        );

        assert!(
            !code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BinaryOp { op }
                    if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        == oparg::BinaryOperator::Subscr
            )),
            "expected folded constant slice subscripts, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Str { value } if value.to_string() == "hell"
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Bytes { value } if value == b"bc"
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { value: a },
                        ConstantData::Integer { value: b },
                    ] if *a == BigInt::from(1)
                        && *b == BigInt::from(2)
                )
        )));
    }

    #[test]
    fn list_of_constant_tuples_uses_list_extend() {
        let code = compile_exec(
            "\
deprecated_cases = [('a', 'b'), ('c', 'd'), ('e', 'f'), ('g', 'h'), ('i', 'j')]
",
        );

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListExtend { .. })),
            "expected constant tuple list folding"
        );
    }

    #[test]
    fn large_list_of_unary_constants_uses_list_extend() {
        let code = compile_exec(
            "\
values = [-1, not True, ~0, +True, 5]
",
        );

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListExtend { .. })),
            "expected unary-folded constants to participate in list folding, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if elements.len() == 5
                    && matches!(&elements[0], ConstantData::Integer { value } if *value == BigInt::from(-1))
                    && matches!(&elements[1], ConstantData::Boolean { value } if !value)
                    && matches!(&elements[2], ConstantData::Integer { value } if *value == BigInt::from(-1))
                    && matches!(&elements[3], ConstantData::Integer { value } if *value == BigInt::from(1))
                    && matches!(&elements[4], ConstantData::Integer { value } if *value == BigInt::from(5))
        )));
    }

    #[test]
    fn outer_unary_after_binop_folds_before_list_folding() {
        let code = compile_exec(
            "\
values = [2.0**53, -0.5, -2.0**-54]
",
        );

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListExtend { .. })),
            "expected binop-folded constants to participate in list folding, got instructions={:?}",
            code.instructions
        );
        assert!(
            !code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BinaryOp { .. } | Instruction::UnaryNegative
            )),
            "constant expression list should not leave runtime ops, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if elements.len() == 3
                    && matches!(&elements[0], ConstantData::Float { value } if *value == 9007199254740992.0)
                    && matches!(&elements[1], ConstantData::Float { value } if *value == -0.5)
                    && matches!(&elements[2], ConstantData::Float { value } if value.is_sign_negative())
        )));
    }

    #[test]
    fn negative_integer_power_folds_to_float_constant() {
        let code = compile_exec("value = -3.0 * 2**(-333)\n");

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "negative integer power should fold through the enclosing multiply, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Float { value }
                if value.is_sign_negative() && *value < 0.0 && value.abs() < 1.0e-90
        )));
    }

    #[test]
    fn complex_power_constants_fold_like_cpython() {
        let code = compile_exec(
            "\
one = 3j ** 0j
zero = 0j ** 2
",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "safe complex power constants should fold away, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Complex { value } if value.re == 1.0 && value.im == 0.0
        )));
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Complex { value } if value.re == 0.0 && value.im == 0.0
        )));
    }

    #[test]
    fn folded_nan_constants_are_not_deduplicated_like_cpython() {
        let code = compile_exec(
            "\
def f():
    repr(1e300 * 1e300 * 0)
    repr(-1e300 * 1e300 * 0)
    str(1e300 * 1e300 * 0)
    str(-1e300 * 1e300 * 0)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let nan_count = f
            .constants
            .iter()
            .filter(|constant| matches!(constant, ConstantData::Float { value } if value.is_nan()))
            .count();
        assert_eq!(
            nan_count, 4,
            "CPython _PyCode_ConstantKey keeps folded NaN constants distinct"
        );
    }

    #[test]
    fn zero_complex_power_exception_constants_do_not_fold() {
        let code = compile_exec("value = 0j ** (3 - 2j)\n");

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "zero complex to complex power should stay runtime so ZeroDivisionError is preserved, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn large_constant_list_keeps_streaming_build() {
        let source = format!(
            "values = [{}]\n",
            (0..31)
                .map(|i| format!("'v{i}'"))
                .collect::<Vec<_>>()
                .join(", ")
        );
        let code = compile_exec(&source);

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListAppend { .. })),
            "large constant lists should keep LIST_APPEND streaming form, got instructions={:?}",
            code.instructions
        );
        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListExtend { .. })),
            "large constant lists should not fold to LIST_EXTEND, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn large_constant_tuple_stream_folds_to_tuple_const() {
        let source = format!(
            "values = ({},)\n",
            (0..31)
                .map(|i| format!("'v{i}'"))
                .collect::<Vec<_>>()
                .join(", ")
        );
        let code = compile_exec(&source);

        assert!(
            !code.instructions.iter().any(|unit| matches!(
                unit.op,
                Instruction::BuildList { .. }
                    | Instruction::ListAppend { .. }
                    | Instruction::CallIntrinsic1 { .. }
            )),
            "large constant tuple should fold the LIST_TO_TUPLE stream, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements } if elements.len() == 31
        )));
    }

    #[test]
    fn annotation_closure_uses_format_varname() {
        let code = compile_exec(
            "\
class C:
    x: int
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");
        let varnames = annotate
            .varnames
            .iter()
            .map(|name| name.as_str())
            .collect::<Vec<_>>();
        assert_eq!(varnames, vec!["format"]);
    }

    #[test]
    fn future_function_signature_annotation_uses_hidden_block_like_cpython() {
        let code = compile_exec(
            "\
from __future__ import annotations
def f(x: T): pass
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");
        let varnames = annotate
            .varnames
            .iter()
            .map(|name| name.as_str())
            .collect::<Vec<_>>();
        assert_eq!(varnames, vec!["format"]);
        assert!(
            find_code(&code, "f").is_some(),
            "function body symbol-table cursor must skip the hidden AnnotationBlock"
        );
    }

    #[test]
    fn deferred_annotation_format_name_does_not_capture_helper_parameter() {
        let code = compile_exec(
            "\
format = object()
x: format
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");
        let varnames = annotate
            .varnames
            .iter()
            .map(|name| name.as_str())
            .collect::<Vec<_>>();
        assert_eq!(varnames, vec!["format"]);
        assert!(
            annotate.names.iter().any(|name| name.as_str() == "format"),
            "CPython keeps the helper parameter as internal .format during symbol analysis, so annotation expression `format` must remain a separate name; got names={:?}",
            annotate.names
        );

        let helper_param_loads = annotate
            .instructions
            .iter()
            .filter(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    annotate.varnames[usize::from(var_num.get(arg))].as_str() == "format"
                }
                _ => false,
            })
            .count();
        assert_eq!(
            helper_param_loads, 1,
            "only the CPython format-validation prologue should load the helper parameter; annotation expression `format` must not compile as LOAD_FAST"
        );
    }

    #[test]
    fn non_simple_class_annotation_is_not_deferred_like_cpython() {
        let code = compile_exec(
            "\
class C:
    x.y: list = []
    z: int
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");
        let names = annotate
            .names
            .iter()
            .map(|name| name.as_str())
            .collect::<Vec<_>>();
        assert_eq!(names, vec!["int"]);
    }

    #[test]
    fn non_simple_annotation_only_consumes_symbol_table_cursor() {
        let code = compile_exec(
            "\
class C:
    x.y: (lambda: str) = []
    z: (lambda: int)
",
        );
        let annotate = find_code(&code, "__annotate__").expect("missing __annotate__ code");
        let lambdas = annotate
            .constants
            .iter()
            .filter_map(|constant| match constant {
                ConstantData::Code { code } if code.obj_name == "<lambda>" => Some(code.as_ref()),
                _ => None,
            })
            .collect::<Vec<_>>();
        assert_eq!(lambdas.len(), 1);
        assert_eq!(
            lambdas[0]
                .names
                .iter()
                .map(|name| name.as_str())
                .collect::<Vec<_>>(),
            vec!["int"]
        );
    }

    #[test]
    fn class_deferred_annotations_guard_only_conditional_entries_like_cpython() {
        let code = compile_exec(
            "\
class C:
    x: int
    if flag:
        y: str
    z: float
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let class_ops: Vec<_> = class_code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let class_set_adds = class_ops
            .iter()
            .filter(|op| matches!(op, Instruction::SetAdd { .. }))
            .count();
        assert_eq!(
            class_set_adds, 1,
            "CPython _PyCompile_AddDeferredAnnotation() adds class annotations to __conditional_annotations__ only inside conditional blocks, got ops={class_ops:?}"
        );
        assert!(
            class_code.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadDeref { i } => {
                    let idx = i.get(OpArg::new(u32::from(u8::from(unit.arg)))).as_usize();
                    localsplus_name(class_code, idx) == Some("__conditional_annotations__")
                }
                _ => false,
            }),
            "CPython codegen_annassign() emits LOAD_DEREF for class __conditional_annotations__, got ops={class_ops:?}"
        );
        assert!(
            !class_code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFromDictOrDeref { .. })),
            "CPython codegen_annassign() bypasses codegen_nameop for class __conditional_annotations__, got ops={class_ops:?}"
        );

        let annotate = find_code(class_code, "__annotate__").expect("missing __annotate__ code");
        let annotate_ops: Vec<_> = annotate
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let annotation_body = annotate_ops
            .iter()
            .position(|op| matches!(op, Instruction::BuildMap { .. }))
            .map(|idx| &annotate_ops[idx..])
            .expect("missing annotation map build");
        let guarded_entries = annotation_body
            .iter()
            .filter(|op| matches!(op, Instruction::PopJumpIfFalse { .. }))
            .count();
        assert_eq!(
            guarded_entries, 1,
            "CPython codegen_deferred_annotations_body() guards only conditional class annotations, got ops={annotate_ops:?}"
        );
    }

    #[test]
    fn future_annotations_non_simple_target_checks_target_but_not_annotation_like_cpython() {
        let code = compile_exec(
            "\
from __future__ import annotations
class C:
    target[item]: missing
",
        );
        let class_code = find_code(&code, "C").expect("missing class code");
        let loaded_names: Vec<_> = class_code
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadName { namei } => {
                    let idx = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    Some(class_code.names[usize::try_from(idx).unwrap()].as_str())
                }
                _ => None,
            })
            .collect();

        assert!(
            ["target", "item"]
                .iter()
                .all(|name| loaded_names.contains(name)),
            "CPython codegen_annassign() still checks bare complex annotation targets under future annotations, got loaded_names={loaded_names:?}"
        );
        assert!(
            !loaded_names.contains(&"missing"),
            "CPython codegen_check_annotation() skips the annotation expression under future annotations, got loaded_names={loaded_names:?}"
        );
    }

    #[test]
    fn type_param_evaluator_uses_dot_format_varname() {
        let code = compile_exec(
            "\
class C[T: int]:
    pass
",
        );
        let evaluator = find_code(&code, "T").expect("missing type parameter evaluator");
        let varnames = evaluator
            .varnames
            .iter()
            .map(|name| name.as_str())
            .collect::<Vec<_>>();
        assert_eq!(varnames, vec![".format"]);
    }

    #[test]
    fn generic_class_double_star_bases_use_tuple_ex_call_path() {
        let code = compile_exec(
            "\
def f(Base, kwargs):
    class C[T](Base, **kwargs):
        pass
    return C
",
        );
        let type_params =
            find_code(&code, "<generic parameters of C>").expect("missing type params code");
        let ops: Vec<_> = type_params
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !has_intrinsic_1(type_params, IntrinsicFunction1::ListToTuple),
            "generic class call with **kwargs but no starred bases should not use list-to-tuple, got ops={ops:?}"
        );
        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::BuildTuple { .. },
                        Instruction::BuildMap { .. },
                        Instruction::LoadDeref { .. } | Instruction::LoadFast { .. },
                        Instruction::DictMerge { .. },
                    ]
                )
            }),
            "expected CPython-style BUILD_TUPLE/BUILD_MAP/DICT_MERGE ex-call path, got ops={ops:?}"
        );
    }

    #[test]
    fn generic_function_defaults_call_type_params_like_cpython() {
        let code = compile_exec(
            "\
def func[T](a: T = 'a', *, b: T = 'b'):
    return a, b
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Swap { .. },
                        Instruction::LoadConst { .. },
                        Instruction::MakeFunction,
                        Instruction::Swap { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "expected CPython generic defaults call pattern SWAP/MAKE_FUNCTION/SWAP/CALL, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::MakeFunction,
                        Instruction::Swap { .. },
                        Instruction::Swap { .. },
                        Instruction::PushNull,
                        Instruction::Swap { .. },
                    ]
                )
            }),
            "CPython generic defaults use SWAP/CALL after codegen_make_closure(), not a PUSH_NULL reshuffle, got ops={ops:?}"
        );
    }

    #[test]
    fn generic_function_type_params_omit_defaults_without_defaults_like_cpython() {
        let code = compile_exec(
            "\
def func[T]():
    pass
",
        );
        let type_params =
            find_code(&code, "<generic parameters of func>").expect("missing type params code");
        assert_eq!(type_params.arg_count, 0);
        assert_eq!(
            type_params
                .varnames
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["T"]
        );
    }

    #[test]
    fn generic_function_type_params_split_defaults_like_cpython() {
        let code = compile_exec(
            "\
def with_pos[T](a: T = 1):
    pass
def with_kw[U](*, a: U = 1):
    pass
",
        );
        let with_pos =
            find_code(&code, "<generic parameters of with_pos>").expect("missing type params code");
        let with_kw =
            find_code(&code, "<generic parameters of with_kw>").expect("missing type params code");

        assert!(with_pos.varnames.iter().any(|name| name == ".defaults"));
        assert!(!with_pos.varnames.iter().any(|name| name == ".kwdefaults"));
        assert!(!with_kw.varnames.iter().any(|name| name == ".defaults"));
        assert!(with_kw.varnames.iter().any(|name| name == ".kwdefaults"));
    }

    #[test]
    fn class_type_param_bound_prefers_classdict_over_outer_function_local() {
        let code = compile_exec(
            "\
def f(self):
    class X:
        T = int
        def foo[U: T](self): ...
    T, U = X.foo.__type_params__
    return T.__bound__, U.__bound__
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert!(
            !f.cellvars.iter().any(|name| name == "T"),
            "class-local type-param bound must not force outer function T cell, got cellvars={:?}",
            f.cellvars
        );

        let class_code = find_code(f, "X").expect("missing X class code");
        assert!(
            !class_code.freevars.iter().any(|name| name == "T"),
            "class body must not close over outer T for class-local bound, got freevars={:?}",
            class_code.freevars
        );

        let type_params =
            find_code(class_code, "<generic parameters of foo>").expect("missing type params code");
        assert_eq!(
            type_params
                .freevars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["__classdict__"],
            "type params scope should close only over __classdict__, got freevars={:?}",
            type_params.freevars
        );

        let bound = find_code(type_params, "U").expect("missing U bound code");
        assert_eq!(
            bound
                .freevars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["__classdict__"],
            "bound evaluator should close only over __classdict__, got freevars={:?}",
            bound.freevars
        );
        assert!(
            bound
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFromDictOrGlobals { .. })),
            "bound evaluator should use LOAD_FROM_DICT_OR_GLOBALS for class-local T, got instructions={:?}",
            bound.instructions
        );
    }

    #[test]
    fn class_type_param_bound_respects_class_global_over_outer_function_local() {
        let code = compile_exec(
            "\
def f(self):
    T = int
    class X:
        global T
        def foo[U: T](self): ...
    return X.foo.__type_params__
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert!(
            f.cellvars.is_empty(),
            "class global type-param bound must not force outer function cells, got cellvars={:?}",
            f.cellvars
        );

        let class_code = find_code(f, "X").expect("missing X class code");
        let type_params =
            find_code(class_code, "<generic parameters of foo>").expect("missing type params code");
        let bound = find_code(type_params, "U").expect("missing U bound code");
        assert!(
            bound
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadGlobal { .. })),
            "explicit class global should resolve as LOAD_GLOBAL in bound evaluator, got instructions={:?}",
            bound.instructions
        );
        assert!(
            !bound.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFromDictOrGlobals { .. }
                        | Instruction::LoadFromDictOrDeref { .. }
                )
            }),
            "explicit class global should not use classdict/deref lookup, got instructions={:?}",
            bound.instructions
        );
    }

    #[test]
    fn generic_type_alias_in_class_does_not_capture_module_name() {
        let code = compile_exec(
            r#"
T = U = "global"
class C:
    T = "class"
    U = "class"
    type Alias[T] = lambda: (T, U)
"#,
        );
        assert!(
            code.cellvars.is_empty(),
            "module T must remain a global name, got cellvars={:?}",
            code.cellvars
        );

        let class_code = find_code(&code, "C").expect("missing class code");
        assert!(
            class_code.freevars.is_empty(),
            "plain module-level class must not close over module T, got freevars={:?}",
            class_code.freevars
        );

        let type_params = find_code(class_code, "<generic parameters of Alias>")
            .expect("missing alias type params");
        assert_eq!(
            type_params
                .cellvars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["T"],
            "alias type parameter T should be local to the type-params scope, got cellvars={:?}",
            type_params.cellvars
        );
        assert_eq!(
            type_params
                .freevars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["__classdict__"],
            "alias type params should close only over the classdict, got freevars={:?}",
            type_params.freevars
        );

        let alias = find_code(type_params, "Alias").expect("missing alias value code");
        assert_eq!(
            alias
                .freevars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["T", "__classdict__"],
            "alias value should close over its type parameter and classdict, got freevars={:?}",
            alias.freevars
        );
        let lambda = find_code(alias, "<lambda>").expect("missing alias lambda");
        assert_eq!(
            lambda
                .freevars
                .iter()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            vec!["T"],
            "lambda should close over alias type parameter T only, got freevars={:?}",
            lambda.freevars
        );
    }

    #[test]
    fn nested_generic_class_base_child_free_keeps_classdict_lookup() {
        for (child_name, base_expr) in [
            ("<genexpr>", "make_base(T for _ in (1,))"),
            ("<listcomp>", "make_base([T for _ in (1,)])"),
            ("<lambda>", "make_base(lambda: T)"),
        ] {
            let code = compile_exec(&format!(
                "\
class C[T]:
    T = 'class'
    class Inner[U]({base_expr}, make_base(T)):
        pass
"
            ));
            let type_params = find_code(&code, "<generic parameters of Inner>")
                .expect("missing inner type params code");
            assert_eq!(
                type_params
                    .freevars
                    .iter()
                    .map(String::as_str)
                    .collect::<Vec<_>>(),
                vec!["T", "__classdict__"],
                "inner type params should keep T as a child-only freevar for {child_name}, got freevars={:?}",
                type_params.freevars
            );
            assert!(
                type_params
                    .instructions
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFromDictOrGlobals { .. })),
                "direct class-local T lookup should still use classdict/global path for {child_name}, got instructions={:?}",
                type_params.instructions
            );

            let child = find_code(type_params, child_name).expect("missing child code");
            assert_eq!(
                child
                    .freevars
                    .iter()
                    .map(String::as_str)
                    .collect::<Vec<_>>(),
                vec!["T"],
                "{child_name} should close over T from the type-params scope, got freevars={:?}",
                child.freevars
            );
        }
    }

    #[test]
    fn non_inlined_listcomp_return_uses_comprehension_location_like_cpython() {
        let code = compile_exec(
            "\
class C[T]:
    class Inner[U](
        make_base([T for _ in (1,)])
    ):
        pass
",
        );
        let listcomp = find_code(&code, "<listcomp>").expect("missing listcomp code");
        let return_positions: Vec<_> = listcomp
            .instructions
            .iter()
            .zip(&listcomp.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::ReturnValue).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert_eq!(
            return_positions,
            vec![(3, 19, 3, 36)],
            "CPython codegen_comprehension() emits non-gen RETURN_VALUE at LOC(e)"
        );
    }

    #[test]
    fn class_annotation_global_resolution_matches_cpython() {
        let class_global = compile_exec(
            "\
X = 'global'
class C:
    locals()['X'] = 'class'
    global X
    y: X
",
        );
        let annotate =
            find_code(&class_global, "__annotate__").expect("missing class __annotate__ code");
        assert!(
            annotate
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadGlobal { .. })),
            "expected explicit class global to use LOAD_GLOBAL, got instructions={:?}",
            annotate.instructions
        );
        assert!(
            !annotate
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFromDictOrGlobals { .. })),
            "did not expect class explicit global to use LOAD_FROM_DICT_OR_GLOBALS, got instructions={:?}",
            annotate.instructions
        );

        let outer_global = compile_exec(
            "\
def f():
    global X
    class C:
        locals()['X'] = 'class'
        y: X
",
        );
        let annotate = find_code(&outer_global, "__annotate__")
            .expect("missing nested class __annotate__ code");
        assert!(
            annotate
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFromDictOrGlobals { .. })),
            "expected outer explicit global in class annotation to use LOAD_FROM_DICT_OR_GLOBALS, got instructions={:?}",
            annotate.instructions
        );
    }

    #[test]
    fn constant_tuple_binops_fold_like_cpython() {
        let code = compile_exec("value = (1,) * 17 + ('spam',)\n");

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BinaryOp { .. })),
            "tuple constant binops should fold away, got instructions={:?}",
            code.instructions
        );
        assert!(code.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if elements.len() == 18
                    && elements[..17]
                        .iter()
                        .all(|elt| matches!(elt, ConstantData::Integer { value } if *value == BigInt::from(1)))
                    && matches!(&elements[17], ConstantData::Str { value } if value.to_string() == "spam")
        )));
    }

    #[test]
    fn tuple_not_keeps_to_bool_unary_not_like_cpython() {
        let code = compile_exec(
            "\
def f():
    return not ()
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();

        assert!(
            ops.windows(3).any(|window| {
                matches!(window[0].op, Instruction::LoadConst { consti }
                if matches!(
                    &f.constants[consti.get(OpArg::new(u32::from(u8::from(window[0].arg))))],
                    ConstantData::Tuple { elements } if elements.is_empty()
                )) && matches!(window[1].op, Instruction::ToBool)
                    && matches!(window[2].op, Instruction::UnaryNot)
            }),
            "CPython codegen emits TO_BOOL; UNARY_NOT for UnaryOp(Not), while flowgraph.c folds tuple literals only after the LOAD_CONST+TO_BOOL pass, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn tuple_if_test_keeps_to_bool_jump_like_cpython() {
        let code = compile_exec(
            "\
def f():
    if ():
        return 1
    return 2
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect::<Vec<_>>();

        assert!(
            ops.windows(3).any(|window| {
                matches!(window[0].op, Instruction::LoadConst { consti }
                if matches!(
                    &f.constants[consti.get(OpArg::new(u32::from(u8::from(window[0].arg))))],
                    ConstantData::Tuple { elements } if elements.is_empty()
                )) && matches!(window[1].op, Instruction::ToBool)
                    && matches!(window[2].op, Instruction::PopJumpIfFalse { .. })
            }),
            "CPython leaves tuple literal truth tests as LOAD_CONST tuple; TO_BOOL; POP_JUMP_IF_FALSE because tuple folding happens after constant jump folding, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn constant_list_iterable_uses_tuple() {
        let code = compile_exec(
            "\
def f():
    return {x: y for x, y in [(1, 2), ]}
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildList { .. })),
            "constant list iterable should avoid BUILD_LIST before GET_ITER"
        );
        assert!(f.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if matches!(
                    elements.as_slice(),
                    [ConstantData::Tuple { elements: inner }]
                        if matches!(
                            inner.as_slice(),
                            [
                                ConstantData::Integer { .. },
                                ConstantData::Integer { .. }
                            ]
                        )
                )
        )));
    }

    #[test]
    fn constant_list_iterable_preserves_cpython_const_order() {
        let code = compile_exec(
            "\
def f():
    for x in ['a', 'b', 'c']:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let constants = f.constants.iter().collect::<Vec<_>>();

        assert!(
            matches!(constants[0], ConstantData::Str { value } if value.to_string() == "a"),
            "CPython emits list elements as LOAD_CONST before flowgraph folds GET_ITER lists"
        );
        assert!(matches!(constants[1], ConstantData::None));
        assert!(matches!(
            constants[2],
            ConstantData::Tuple { elements }
                if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Str { value: first },
                        ConstantData::Str { value: second },
                        ConstantData::Str { value: third },
                    ] if first.to_string() == "a"
                        && second.to_string() == "b"
                        && third.to_string() == "c"
                )
        ));
    }

    #[test]
    fn try_except_folded_tuple_consts_follow_cpython_block_order() {
        let code = compile_exec(
            "\
def f(macrelease):
    try:
        g()
    except ValueError:
        macrelease = (10, 3)
    if macrelease >= (10, 4):
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let constants = f.constants.iter().collect::<Vec<_>>();

        assert!(
            constants.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        ConstantData::Tuple { elements: first },
                        ConstantData::Tuple { elements: second },
                    ] if matches!(
                        (first.as_slice(), second.as_slice()),
                        (
                            [
                                ConstantData::Integer { value: a },
                                ConstantData::Integer { value: b },
                            ],
                            [
                                ConstantData::Integer { value: c },
                                ConstantData::Integer { value: d },
                            ],
                        ) if a == &BigInt::from(10)
                            && b == &BigInt::from(3)
                            && c == &BigInt::from(10)
                            && d == &BigInt::from(4)
                    )
                )
            }),
            "CPython flowgraph.c walks b_next order, so the except-body tuple is folded before the following if-test tuple; got {constants:?}"
        );
    }

    #[test]
    fn small_set_membership_folds_before_later_unary_const_like_cpython() {
        let code = compile_exec(
            r#"
def f(method, n):
    if method not in {"linear", "ranked"}:
        pass
    if method == "ranked":
        start = (n - 1) / -2
"#,
        );
        let f = find_code(&code, "f").expect("missing function code");
        let constants = f.constants.iter().collect::<Vec<_>>();
        let frozenset_index = constants
            .iter()
            .position(|constant| matches!(constant, ConstantData::Frozenset { .. }))
            .expect("missing folded membership frozenset");
        let negative_two_index = constants
            .iter()
            .position(|constant| {
                matches!(
                    constant,
                    ConstantData::Integer { value } if value == &BigInt::from(-2)
                )
            })
            .expect("missing folded -2 constant");

        assert!(
            frozenset_index < negative_two_index,
            "CPython flowgraph.c optimizes BUILD_SET+CONTAINS_OP inline before folding the later unary -2; got {constants:?}"
        );
    }

    #[test]
    fn boolop_const_order_keeps_cpython_codegen_constants() {
        let code = compile_exec(
            "\
def or_false(x):
    return False or x

def zero_or_tuple():
    return 0 or (1, -1)

def tuple_or_tuple():
    return (1, -1) or (-1, 1)
",
        );

        let or_false = find_code(&code, "or_false").expect("missing or_false code");
        let constants = or_false.constants.iter().collect::<Vec<_>>();
        assert_eq!(constants.len(), 1);
        assert!(
            matches!(constants[0], ConstantData::Boolean { value: false }),
            "CPython registers the skipped boolop literal before flowgraph removes the branch"
        );

        let zero_or_tuple = find_code(&code, "zero_or_tuple").expect("missing zero_or_tuple code");
        let constants = zero_or_tuple.constants.iter().collect::<Vec<_>>();
        assert_eq!(constants.len(), 2);
        assert!(
            matches!(
                constants[0],
                ConstantData::Integer { value } if value == &BigInt::from(0)
            ) && matches!(
                constants[1],
                ConstantData::Tuple { elements }
                    if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { value: one },
                        ConstantData::Integer { value: minus_one },
                    ] if one == &BigInt::from(1) && minus_one == &BigInt::from(-1)
                )
            ),
            "CPython keeps the skipped scalar literal before the folded tuple constant"
        );

        let tuple_or_tuple =
            find_code(&code, "tuple_or_tuple").expect("missing tuple_or_tuple code");
        let constants = tuple_or_tuple.constants.iter().collect::<Vec<_>>();
        assert_eq!(constants.len(), 3);
        assert!(
            matches!(
                constants[0],
                ConstantData::Integer { value } if value == &BigInt::from(1)
            ) && matches!(
                constants[1],
                ConstantData::Tuple { elements }
                    if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { value: one },
                        ConstantData::Integer { value: minus_one },
                    ] if one == &BigInt::from(1) && minus_one == &BigInt::from(-1)
                )
            ) && matches!(
                constants[2],
                ConstantData::Tuple { elements }
                    if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { value: minus_one },
                        ConstantData::Integer { value: one },
                    ] if minus_one == &BigInt::from(-1) && one == &BigInt::from(1)
                )
            ),
            "CPython compiles boolop tuple heads before flowgraph folds them"
        );
    }

    #[test]
    fn chained_compare_jump_if_runs_cpython_check_compare_warning() {
        let message = first_exec_warning(
            "\
def f(x):
    if 1 is 1 < x:
        return x
",
        );
        assert!(
            message.contains("\"is\" with 'int' literal"),
            "CPython codegen_jump_if() checks chained comparisons before conditional lowering, got {message:?}"
        );
    }

    #[test]
    fn lambda_without_body_constants_keeps_none_like_cpython() {
        let code = compile_exec("f = lambda x: x");
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");
        let constants = lambda.constants.iter().collect::<Vec<_>>();
        assert_eq!(constants.len(), 1);

        assert!(
            matches!(constants[0], ConstantData::None),
            "CPython AddReturnAtEnd registers None for constant-free lambdas"
        );
    }

    #[test]
    fn generator_lambda_without_body_constants_omits_none_like_cpython() {
        let code = compile_exec("f = lambda x: (yield x)");
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");

        assert!(
            lambda.constants.is_empty(),
            "CPython codegen_lambda() assembles generator lambdas with addNone=0"
        );
    }

    #[test]
    fn call_function_ex_empty_args_tuple_is_folded_late_like_cpython() {
        let code = compile_exec(
            "\
def f(g, kwargs, ns):
    g(**kwargs)
    ns['T']
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let constants = f.constants.iter().collect::<Vec<_>>();
        assert_eq!(constants.len(), 3);

        assert!(
            matches!(constants[0], ConstantData::Str { value } if value.to_string() == "T")
                && matches!(constants[1], ConstantData::None)
                && matches!(constants[2], ConstantData::Tuple { elements } if elements.is_empty()),
            "CPython emits BUILD_TUPLE 0 for CALL_FUNCTION_EX args and folds it after earlier constants"
        );
    }

    #[test]
    fn large_constant_list_iterable_keeps_streaming_list_build() {
        let source = format!(
            "def f():\n    for x in [{}]:\n        pass\n",
            (0..=STACK_USE_GUIDELINE)
                .map(|i| format!("'v{i}'"))
                .collect::<Vec<_>>()
                .join(", ")
        );
        let code = compile_exec(&source);
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildList { .. })),
            "large list iterable should keep CPython streaming BUILD_LIST form, got instructions={:?}",
            f.instructions
        );
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::ListAppend { .. })),
            "large list iterable should use LIST_APPEND streaming form, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn constant_set_iterable_uses_frozenset_const() {
        let code = compile_exec(
            "\
def f():
    return [x for x in {1, 2, 3}]
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildSet { .. })),
            "constant set iterable should avoid BUILD_SET before GET_ITER"
        );
        assert!(f.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Frozenset { elements }
                if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { .. },
                        ConstantData::Integer { .. },
                        ConstantData::Integer { .. }
                    ]
                )
        )));
    }

    #[test]
    fn constant_list_membership_uses_tuple_const() {
        let code = compile_exec(
            "\
f = lambda x: x in [1, 2, 3]
",
        );
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");

        assert!(
            !lambda
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildList { .. })),
            "constant list membership should avoid BUILD_LIST before CONTAINS_OP"
        );
        assert!(lambda.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Tuple { elements }
                if matches!(
                    elements.as_slice(),
                    [
                        ConstantData::Integer { .. },
                        ConstantData::Integer { .. },
                        ConstantData::Integer { .. }
                    ]
                )
        )));
    }

    #[test]
    fn small_constant_set_membership_uses_frozenset_const() {
        let code = compile_exec(
            "\
f = lambda x: x in {0}
",
        );
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");

        assert!(
            !lambda
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildSet { .. })),
            "constant set membership should avoid BUILD_SET before CONTAINS_OP"
        );
        assert!(lambda.constants.iter().any(|constant| matches!(
            constant,
            ConstantData::Frozenset { elements }
                if matches!(elements.as_slice(), [ConstantData::Integer { value }] if *value == BigInt::from(0))
        )));
    }

    #[test]
    fn frozenset_membership_consts_deduplicate_like_cpython_constant_key() {
        let code = compile_exec(
            "\
def f(x):
    return x in {1, 2}, x in {2, 1}, x in {1, 1}
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let frozensets: Vec<_> = f
            .constants
            .iter()
            .filter_map(|constant| match constant {
                ConstantData::Frozenset { elements } => Some(elements.as_slice()),
                _ => None,
            })
            .collect();

        assert_eq!(
            frozensets.len(),
            2,
            "CPython folds equal frozensets to the same const key and removes duplicate set items"
        );
        assert!(
            frozensets.iter().any(|elements| elements.len() == 2),
            "missing shared frozenset constant for {{1, 2}} and {{2, 1}}"
        );
        assert!(
            frozensets.iter().any(|elements| elements.len() == 1),
            "missing duplicate-collapsed frozenset constant for {{1, 1}}"
        );
    }

    #[test]
    fn nonconstant_list_membership_uses_tuple() {
        let code = compile_exec(
            "\
def f(a, b, c, x):
    return x in [a, b, c]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::BuildTuple { .. },
                        Instruction::ContainsOp { .. }
                    ]
                )
            }),
            "expected BUILD_TUPLE before CONTAINS_OP for non-constant list membership, got ops={ops:?}"
        );
    }

    #[test]
    fn unary_not_membership_and_identity_invert_compare_op() {
        let code = compile_exec(
            "\
def f(a, b, d):
    x = not (a in d)
    y = not (a is b)
    return x, y
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();

        assert!(
            !ops.iter().any(|op| matches!(op, Instruction::UnaryNot)),
            "CPython folds CONTAINS_OP/IS_OP + UNARY_NOT into inverted op, got ops={ops:?}"
        );
        assert!(instructions.iter().any(|unit| {
            matches!(unit.op, Instruction::ContainsOp { invert } if invert.get(OpArg::new(unit.arg.as_u32())) == Invert::Yes)
        }));
        assert!(instructions.iter().any(|unit| {
            matches!(unit.op, Instruction::IsOp { invert } if invert.get(OpArg::new(unit.arg.as_u32())) == Invert::Yes)
        }));
    }

    #[test]
    fn starred_tuple_iterable_drops_list_to_tuple_before_get_iter() {
        let code = compile_exec(
            "\
def f(a, b, c):
    for x in *a, *b, *c:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");

        assert!(
            !has_intrinsic_1(f, IntrinsicFunction1::ListToTuple),
            "LIST_TO_TUPLE should be removed before GET_ITER in for-iterable context"
        );
        assert!(
            f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::GetIter)),
            "expected GET_ITER in for loop"
        );
    }

    #[test]
    fn comprehension_single_list_iterable_uses_tuple() {
        let code = compile_exec(
            "\
def g():
    [x for x in [(yield 1)]]
",
        );
        let g = find_code(&code, "g").expect("missing g code");
        let ops: Vec<_> = g
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [Instruction::BuildTuple { .. }, Instruction::GetIter]
                )
            }),
            "expected BUILD_TUPLE before GET_ITER for single-item list iterable in comprehension, got ops={ops:?}"
        );
    }

    #[test]
    fn comprehension_list_iterable_build_uses_iter_location_like_cpython() {
        let code = compile_exec(
            "\
async def f(i):
    return i

async def run_list():
    return [await c for c in [f(1), f(41)]]
",
        );
        let run_list = find_code(&code, "run_list").expect("missing run_list code");
        assert_eq!(
            run_list.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xdc, 0x1e, 0x1f, 0xa0, 0x01, 0x9b, 0x64, 0xa4, 0x41, 0xa0,
                0x62, 0xa3, 0x45, 0x99, 0x5d, 0xd3, 0x0b, 0x2b, 0x99, 0x5d, 0x98, 0x01, 0x8f, 0x47,
                0x8a, 0x47, 0x99, 0x5d, 0xd1, 0x0b, 0x2b, 0xd0, 0x04, 0x2b, 0x89, 0x47, 0xf9, 0xd2,
                0x0b, 0x2b, 0xf9,
            ],
            "CPython codegen_comprehension_iter() emits GET_ITER at LOC(comp->iter)"
        );
    }

    #[test]
    fn comprehension_boolop_iter_get_iter_uses_iter_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self):
    return any(not w.cancelled() for w in (self._waiters or ()))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let get_iter_positions: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::GetIter).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert!(
            get_iter_positions.contains(&(2, 44, 2, 63)),
            "CPython codegen_comprehension_iter() emits GET_ITER at LOC(comp->iter), got {get_iter_positions:?}"
        );
    }

    #[test]
    fn inlined_comprehension_backedges_use_element_location_like_cpython() {
        let code = compile_exec(
            "\
async def f(i):
    return i

async def run_list():
    return [s for c in [f(''), f('abc')] for s in await c]
",
        );
        let run_list = find_code(&code, "run_list").expect("missing run_list code");
        assert_eq!(
            run_list.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xdc, 0x18, 0x19, 0x98, 0x22, 0x9b, 0x05, 0x9c, 0x71, 0xa0,
                0x15, 0x9b, 0x78, 0xd1, 0x17, 0x28, 0xd4, 0x0b, 0x3a, 0xd1, 0x17, 0x28, 0x90, 0x21,
                0xb7, 0x27, 0xb2, 0x27, 0xa8, 0x51, 0x8a, 0x41, 0xb1, 0x27, 0x89, 0x41, 0xd1, 0x17,
                0x28, 0xd2, 0x0b, 0x3a, 0xd0, 0x04, 0x3a, 0xb1, 0x27, 0xf9, 0xd3, 0x0b, 0x3a, 0xf9,
            ],
            "CPython codegen_sync_comprehension_generator() emits comprehension backedges at elt_loc"
        );
    }

    #[test]
    fn nested_dict_comprehension_outer_backedge_uses_key_location_like_cpython() {
        let code = compile_exec(
            "\
def f(items):
    return {op: i for i, ops in items for op in ops}
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let backedge_positions: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::JumpBackward { .. }).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .collect();

        assert!(
            backedge_positions.contains(&(2, 13, 2, 18)),
            "CPython extends only the terminal dict-comprehension MAP_ADD/backedge location from key through value, got {backedge_positions:?}"
        );
        assert!(
            backedge_positions.contains(&(2, 13, 2, 15)),
            "CPython keeps outer dict-comprehension generator backedges at LOC(key), got {backedge_positions:?}"
        );
    }

    #[test]
    fn inlined_comprehension_filter_jump_uses_element_location_like_cpython() {
        let code = compile_exec(
            "\
def f(self):
    return [action for action in self._actions if action.option_strings]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let filter_jump_position = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::PopJumpIfTrue { .. }).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing optimized filter jump");
        assert_eq!(
            filter_jump_position,
            (2, 13, 2, 19),
            "CPython inlined comprehension filter jump inherits the element/backedge location after CFG cleanup"
        );
    }

    #[test]
    fn inlined_comprehension_ifexp_guard_jump_uses_body_location_like_cpython() {
        let code = compile_exec(
            "\
def f(fields):
    return [f for f in fields if (f.compare if f.hash is None else f.hash)]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let jump_forward_position = f
            .instructions
            .iter()
            .zip(&f.locations)
            .find_map(|(unit, (location, end_location))| {
                matches!(unit.op, Instruction::JumpForward { .. }).then_some((
                    location.line.get(),
                    location.character_offset.get(),
                    end_location.line.get(),
                    end_location.character_offset.get(),
                ))
            })
            .expect("missing if-expression body jump");
        assert_eq!(
            jump_forward_position,
            (2, 35, 2, 44),
            "CPython flowgraph.c::propagate_line_numbers() copies the if-expression body location onto the NO_LOCATION jump"
        );
    }

    #[test]
    fn inlined_async_comprehension_end_async_for_uses_comprehension_location_like_cpython() {
        let code = compile_exec(
            "\
async def f(it):
    for i in it:
        yield i

async def run_list():
    return [i + 1 async for i in f([10, 20])]
",
        );
        let run_list = find_code(&code, "run_list").expect("missing run_list code");
        assert_eq!(
            run_list.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xdc, 0x21, 0x22, 0xa0, 0x42, 0xa8, 0x02, 0xa0, 0x38, 0xa4,
                0x1b, 0xd7, 0x0b, 0x2d, 0xd3, 0x0b, 0x2d, 0x98, 0x41, 0x90, 0x01, 0x8f, 0x45, 0x88,
                0x45, 0xd4, 0x0b, 0x2d, 0xd0, 0x04, 0x2d, 0xf9, 0xd2, 0x0b, 0x2d, 0xf9,
            ],
            "CPython codegen_async_comprehension_generator() emits END_ASYNC_FOR at comprehension loc"
        );
    }

    #[test]
    fn async_for_anext_sequence_uses_statement_location_like_cpython() {
        let code = compile_exec(
            "\
async def f(source, buffer):
    async for i1, i2 in source():
        buffer.append(i1 + i2)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.linetable.as_ref(),
            &[
                0xe9, 0x00, 0x80, 0x00, 0xd9, 0x18, 0x1e, 0x9c, 0x08, 0xf7, 0x00, 0x01, 0x05, 0x1f,
                0xf0, 0x00, 0x01, 0x05, 0x1f, 0x89, 0x66, 0x88, 0x62, 0xd8, 0x08, 0x0e, 0x8f, 0x0d,
                0x89, 0x0d, 0x90, 0x62, 0x95, 0x67, 0xd6, 0x08, 0x1e, 0xf1, 0x03, 0x01, 0x05, 0x1f,
                0x9a, 0x08, 0xf9,
            ],
            "CPython codegen_async_for() emits GET_ANEXT/yield-from scaffolding at LOC(s)"
        );
    }

    #[test]
    fn nested_comprehension_list_iterable_uses_tuple() {
        let code = compile_exec(
            "\
def f():
    return [[y for y in [x, x + 1]] for x in [1, 3, 5]]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [Instruction::BuildTuple { .. }, Instruction::GetIter]
                )
            }),
            "expected BUILD_TUPLE before GET_ITER for nested list iterable in comprehension, got ops={ops:?}"
        );
    }

    #[test]
    fn comprehension_singleton_sub_iter_uses_assignment_idiom() {
        let code = compile_exec(
            "\
def f():
    return {j: j * j for i in range(4) for j in [i + 1]}
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let for_iter_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ForIter { .. }))
            .count();
        let has_map_add_depth_2 = f.instructions.iter().any(|unit| {
            matches!(
                unit.op,
                Instruction::MapAdd { i }
                    if i.get(OpArg::new(u32::from(u8::from(unit.arg)))) == 2
            )
        });

        assert_eq!(
            for_iter_count, 1,
            "singleton sub-iter should not emit its own FOR_ITER, got instructions={:?}",
            f.instructions
        );
        assert!(
            has_map_add_depth_2,
            "assignment-idiom dictcomp should use MAP_ADD depth 2, got instructions={:?}",
            f.instructions
        );
        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::BuildTuple { .. })),
            "singleton sub-iter should not materialize an iterator tuple, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn constant_comprehension_iterable_with_unary_int_uses_tuple_const() {
        let code = compile_exec(
            "\
l = lambda : [2 < x for x in [-1, 3, 0]]
",
        );
        let lambda = find_code(&code, "<lambda>").expect("missing lambda code");

        assert!(
            lambda.constants.iter().any(|constant| matches!(
                constant,
                ConstantData::Tuple { elements }
                    if matches!(
                        elements.as_slice(),
                        [
                            ConstantData::Integer { .. },
                            ConstantData::Integer { .. },
                            ConstantData::Integer { .. }
                        ]
                    )
            )),
            "expected folded tuple constant for comprehension iterable"
        );
    }

    #[test]
    fn module_scope_listcomp_is_inlined() {
        let code = compile_exec("values = [i for i in range(3)]\n");

        assert!(
            find_code(&code, "<listcomp>").is_none(),
            "module-scope list comprehension should be inlined"
        );
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastAndClear { .. })),
            "inlined module-scope list comprehension should use LOAD_FAST_AND_CLEAR, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn module_scope_dictcomp_is_inlined() {
        let code = compile_exec("mapping = {i: i for i in range(3)}\n");

        assert!(
            find_code(&code, "<dictcomp>").is_none(),
            "module-scope dict comprehension should be inlined"
        );
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastAndClear { .. })),
            "inlined module-scope dict comprehension should use LOAD_FAST_AND_CLEAR, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn async_dictcomp_in_async_function_is_inlined() {
        let code = compile_exec(
            "\
async def f(items):
    return {item: item async for item in items}
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            find_code(&code, "<dictcomp>").is_none(),
            "async dict comprehension should be inlined"
        );
        assert!(
            ops.iter().any(|op| matches!(op, Instruction::GetAiter)),
            "inlined async dict comprehension should keep GET_AITER in outer code, got ops={ops:?}"
        );
        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::LoadFastAndClear { .. })),
            "inlined async dict comprehension should use LOAD_FAST_AND_CLEAR, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| matches!(op, Instruction::MakeFunction)),
            "inlined async dict comprehension should not materialize MAKE_FUNCTION, got ops={ops:?}"
        );
    }

    #[test]
    fn async_inlined_comprehension_inlines_restore_return_into_end_async_for() {
        let code = compile_exec(
            "\
async def f():
    return [i + 1 async for i in g([10, 20])]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndAsyncFor,
                        Instruction::Swap { .. },
                        Instruction::StoreFast { .. },
                        Instruction::ReturnValue,
                        Instruction::Swap { .. },
                        Instruction::PopTop,
                        Instruction::Swap { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython-style restore+return inlined into END_ASYNC_FOR before cleanup, got ops={ops:?}"
        );
        assert!(
            !ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndAsyncFor,
                        Instruction::JumpForward { .. } | Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "unexpected jump from END_ASYNC_FOR to the normal restore tail, got ops={ops:?}"
        );
    }

    #[test]
    fn await_cleanup_throw_falls_through_until_cold_reorder() {
        let code = compile_exec(
            "\
async def f():
    await 1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CleanupThrow,
                        Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::CallIntrinsic1 { .. },
                    ]
                )
            }),
            "expected CPython-style cold CLEANUP_THROW jump before StopIteration handler, got ops={ops:?}"
        );
        assert!(
            !ops.windows(2).any(|window| {
                matches!(window, [Instruction::CleanupThrow, Instruction::EndSend])
            }),
            "CLEANUP_THROW should not inline the normal END_SEND return tail, got ops={ops:?}"
        );
    }

    #[test]
    fn match_async_inlined_comprehension_success_jump_layout() {
        let code = compile_exec(
            "\
async def f(name_3, name_5):
    match b'':
        case True:
            pass
        case name_5 if f'e':
            {name_3: f async for name_2 in name_5}
        case []:
            pass
    [[]]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpForward { .. },
                        Instruction::Copy { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython-style plain match success jump before async comprehension case, got ops={ops:?}"
        );
        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFast { .. },
                        Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::CallIntrinsic1 { .. },
                    ]
                )
            }),
            "CPython codegen_pop_inlined_comprehension_locals() emits JUMP_NO_INTERRUPT before the cleanup path; after flowgraph reordering it remains a backward no-interrupt jump before the StopIteration handler, got ops={ops:?}"
        );
    }

    #[test]
    fn for_loop_if_return_reorders_continue_backedge_before_exit_body() {
        let code = compile_exec(
            "\
def f(items, occurrence):
    for item in items:
        if item:
            occurrence -= 1
            if not occurrence:
                return item
    return None
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "expected CPython-style inverted return guard followed by loop backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "return guard should not fall through into the return body before the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn sync_with_after_async_for_keeps_end_async_for_line_marker() {
        let code = compile_exec(
            "\
async def f(cm, source, tgt):
    with cm:
        async for tgt[0] in source():
            pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndAsyncFor,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "expected CPython-style line-marker NOP between END_ASYNC_FOR and with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn genexpr_with_async_comprehension_element_is_async_generator() {
        let code = compile_exec(
            "\
async def f():
    gen = ([i async for i in asynciter([1, 2])] for j in [10, 20])
    return [x async for x in gen]
",
        );
        let genexpr = find_code(&code, "<genexpr>").expect("missing genexpr code");
        let units: Vec<_> = genexpr
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            units.windows(2).any(|window| {
                let [wrap, yield_value] = window else {
                    return false;
                };
                matches!(yield_value.op, Instruction::YieldValue { .. })
                    && match wrap.op {
                        Instruction::CallIntrinsic1 { func } => {
                            func.get(OpArg::new(u32::from(u8::from(wrap.arg))))
                                == bytecode::IntrinsicFunction1::AsyncGenWrap
                        }
                        _ => false,
                    }
            }),
            "expected CPython-style ASYNC_GEN_WRAP before genexpr yield, got units={units:?}"
        );
    }

    #[test]
    fn async_comprehension_propagates_coroutine_to_enclosing_genexpr_like_cpython() {
        let symbol_table = scan_program_symbol_table(
            "\
async def f():
    gen = ([i async for i in asynciter([1, 2])] for j in [10, 20])
    return [x async for x in gen]
",
        );
        let genexpr =
            find_symbol_table(&symbol_table, "<genexpr>").expect("missing genexpr symbol table");
        assert!(genexpr.is_generator, "expected genexpr symbol table");
        assert!(
            genexpr.is_coroutine,
            "CPython symtable_handle_comprehension() propagates non-generator async comprehension ste_coroutine to the enclosing genexpr"
        );
    }

    #[test]
    fn nested_module_scope_dictcomp_symbols_are_local() {
        let symbol_table = scan_program_symbol_table(
            "\
deoptmap = {
    specialized: base
    for base, family in _specializations.items()
    for specialized in family
}
",
        );

        for name in ["base", "family", "specialized"] {
            let symbol = symbol_table
                .lookup(name)
                .unwrap_or_else(|| panic!("missing module symbol {name}"));
            assert_eq!(
                symbol.scope,
                SymbolScope::Local,
                "expected module-scope inlined comprehension symbol {name} to be Local, got {symbol:?}"
            );
        }

        let comp = symbol_table
            .inlined_comprehension_blocks
            .first()
            .expect("missing comprehension symbol table");
        assert!(comp.comp_inlined, "expected comprehension to be inlined");
        for name in ["base", "family", "specialized"] {
            let symbol = comp
                .lookup(name)
                .unwrap_or_else(|| panic!("missing comprehension symbol {name}"));
            assert_eq!(
                symbol.scope,
                SymbolScope::Local,
                "expected comprehension symbol {name} to be Local, got {symbol:?}"
            );
        }
    }

    #[test]
    fn nested_module_scope_dictcomp_uses_fast_locals() {
        let code = compile_exec(
            "\
deoptmap = {
    specialized: base
    for base, family in _specializations.items()
    for specialized in family
}
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter()
                .any(|op| matches!(op, Instruction::StoreFastStoreFast { .. })),
            "expected outer target unpack to use STORE_FAST_STORE_FAST, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(
                op,
                Instruction::StoreFastLoadFast { .. }
                    | Instruction::LoadFastBorrowLoadFastBorrow { .. }
            )),
            "expected inner target/store-use path to use fast locals, got ops={ops:?}"
        );
        assert!(
            ops.iter()
                .filter(|op| matches!(op, Instruction::LoadName { .. }))
                .count()
                <= 1,
            "unexpected extra LOAD_NAME ops in nested inlined comprehension, got ops={ops:?}"
        );
        assert!(
            ops.iter()
                .filter(|op| matches!(op, Instruction::StoreName { .. }))
                .count()
                <= 1,
            "unexpected extra STORE_NAME ops in nested inlined comprehension, got ops={ops:?}"
        );
    }

    #[test]
    fn module_scope_inlined_comprehension_keeps_outer_iter_as_name_lookup() {
        let code = compile_exec(
            "\
path_separators = ['/']
_pathseps_with_colon = {f':{s}' for s in path_separators}
",
        );
        let ops: Vec<_> = code
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let load_name_path = ops
            .windows(2)
            .any(|window| matches!(window, [Instruction::LoadName { .. }, Instruction::GetIter]));
        assert!(
            load_name_path,
            "expected outer iterable to stay a NAME lookup before GET_ITER, got ops={ops:?}"
        );
        assert!(
            !ops.windows(2).any(|window| matches!(
                window,
                [
                    Instruction::LoadFast { .. } | Instruction::LoadFastCheck { .. },
                    Instruction::GetIter
                ]
            )),
            "module local outer iterable should not become a fast local, got ops={ops:?}"
        );
        assert!(
            ops.iter().any(|op| matches!(
                op,
                Instruction::StoreFastLoadFast { .. } | Instruction::StoreFast { .. }
            )),
            "comprehension target should still use fast locals, got ops={ops:?}"
        );
    }

    #[test]
    fn function_scope_inlined_comprehension_restore_keeps_swap_before_duplicate_store() {
        let code = compile_exec(
            "\
def f():
    a = [1 for a in [0]]
    return 1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| matches!(
                window,
                [
                    Instruction::PopIter,
                    Instruction::Swap { .. },
                    Instruction::StoreFast { .. },
                    Instruction::StoreFast { .. }
                ]
            )),
            "expected PopIter/SWAP 2/STORE_FAST/STORE_FAST restore tail, got ops={ops:?}"
        );
    }

    #[test]
    fn inlined_comprehension_namedexpr_target_stays_parent_fast_local() {
        let code = compile_exec(
            "\
def f(seq, emit):
    return [(x, y) for x in seq if (y := emit(x))]
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert!(f.varnames.iter().any(|name| name == "y"));
        assert!(!f.cellvars.iter().any(|name| name == "y"));
        assert!(!f.freevars.iter().any(|name| name == "y"));
        assert!(
            !f.names.iter().any(|name| name == "y"),
            "inlined comprehension namedexpr target should not use NAME ops, got names={:?}",
            f.names
        );
    }

    #[test]
    fn inlined_comprehension_namedexpr_varnames_match_cpython_order() {
        let code = compile_exec(
            "\
def f():
    def spam(a):
        return a
    input_data = [1, 2, 3]
    res = [(x, y, x / y) for x in input_data if (y := spam(x)) > 0]
    return res
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        assert_eq!(
            f.varnames.iter().map(String::as_str).collect::<Vec<_>>(),
            vec!["spam", "input_data", "x", "y", "res"]
        );
    }

    #[test]
    fn global_namedexpr_in_inlined_comprehension_saves_fast_slot() {
        let code = compile_exec(
            "\
def f(seq, value):
    global G
    [G := value for _ in seq]
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert!(f.varnames.iter().any(|name| name == "G"));
        assert!(f.instructions.iter().any(|unit| match unit.op {
            Instruction::LoadFastAndClear { var_num } => {
                let idx = var_num.get(OpArg::new(u32::from(u8::from(unit.arg))));
                f.varnames[usize::from(idx)] == "G"
            }
            _ => false,
        }));
        assert!(f.instructions.iter().any(|unit| match unit.op {
            Instruction::StoreGlobal { namei } => {
                let idx = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                f.names[usize::try_from(idx).unwrap()] == "G"
            }
            _ => false,
        }));
    }

    #[test]
    fn namedexpr_copy_uses_namedexpr_location_like_cpython() {
        let code = compile_exec(
            "\
def outer():
    a = 10
    def spam():
        nonlocal a
        (a := 20)
",
        );
        let spam = find_code(&code, "spam").expect("missing spam code");

        // CPython 3.14 NamedExpr_kind emits COPY at LOC(named expression),
        // between visiting the value and visiting the target.
        assert_eq!(
            spam.linetable.as_ref(),
            &[0xf8, 0x80, 0x00, 0xe0, 0x0e, 0x10, 0x88, 0x17, 0x8b, 0x11,]
        );
    }

    #[test]
    fn genexpr_namedexpr_target_is_cell_not_fast_local() {
        let code = compile_exec(
            "\
def f(seq):
    a = 1
    return (c := x + a for x in seq)
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert!(!f.varnames.iter().any(|name| name == "c"));
        assert_eq!(
            f.cellvars.iter().map(String::as_str).collect::<Vec<_>>(),
            ["a", "c"]
        );
    }

    #[test]
    fn public_cellvars_follow_cpython_localsplus_order() {
        let code = compile_exec(
            "\
def f():
    x = 10
    t = False
    g = ((i, j) for i in range(x) if t for j in range(x))
    [x for x in range(3)]
    return g
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert_eq!(
            f.varnames.iter().map(String::as_str).collect::<Vec<_>>(),
            ["g", "x"]
        );
        assert_eq!(
            f.cellvars.iter().map(String::as_str).collect::<Vec<_>>(),
            ["x", "t"],
            "CPython assemble.c exposes co_cellvars in localsplus order: merged local cells before non-local cells"
        );
    }

    #[test]
    fn inlined_comprehension_restore_does_not_form_store_fast_load_fast() {
        let code = compile_exec(
            "\
def f(e):
    e[1:3] = [g(i) for i in range(2)]

def g(datadir):
    files = [filename[:-4] for filename in sorted(os.listdir(datadir)) if filename.endswith('.xml')]
    input_files = [filename for filename in files if filename.startswith('in')]
    return files, input_files
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Swap { .. },
                        Instruction::StoreFast { .. },
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreSubscr,
                    ]
                )
            }),
            "expected CPython-style inlined comprehension restore before slice store, got ops={ops:?}"
        );
        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::StoreFastLoadFast { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreSubscr,
                    ]
                )
            }),
            "inlined comprehension restore should not be folded into STORE_FAST_LOAD_FAST, got ops={ops:?}"
        );

        let g = find_code(&code, "g").expect("missing g code");
        let g_ops: Vec<_> = g
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        assert!(
            g_ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::StoreFast { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython-style static swap over STORE_FAST_MAYBE_NULL restore, got ops={g_ops:?}"
        );
        assert!(
            !g_ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Swap { .. },
                        Instruction::StoreFast { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "inlined comprehension restore should statically remove SWAP before adjacent stores, got ops={g_ops:?}"
        );
    }

    #[test]
    fn single_mode_folded_multiline_constant_does_not_leave_nops() {
        let code = compile_single(
            "\
(-
 -
 -
 1)
",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Nop)),
            "expected folded single-mode multiline constant to drop NOP anchors, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn folded_multiline_tuple_constant_does_not_leave_operand_nops() {
        let code = compile_exec(
            "\
values = (
    (1 + 1j, 0 + 0j),
    (1 + 1j, 0.0),
    (1 + 1j, 0),
)
",
        );

        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Nop)),
            "expected CPython nop_out-style folded tuple operands to have no surviving NOPs, got instructions={:?}",
            code.instructions
        );
    }

    #[test]
    fn single_mode_returns_none_after_print_like_cpython() {
        let code = compile_single("1\n");
        let ops = code
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Resume { .. }))
            .collect::<Vec<_>>();

        assert!(
            !ops.iter()
                .any(|unit| matches!(unit.op, Instruction::Copy { .. })),
            "CPython codegen_stmt_expr() prints and pops interactive expressions; it does not preserve the final expression as the code object's return value, got ops={ops:?}"
        );
        let Some(load_none) = ops.iter().rev().nth(1) else {
            panic!("missing final LOAD_CONST None before RETURN_VALUE, got ops={ops:?}");
        };
        let Instruction::LoadConst { consti } = load_none.op else {
            panic!("missing final LOAD_CONST None before RETURN_VALUE, got ops={ops:?}");
        };
        let constant = &code.constants[consti.get(OpArg::new(u32::from(u8::from(load_none.arg))))];
        assert!(matches!(constant, ConstantData::None));
        assert!(matches!(
            ops.last().map(|unit| unit.op),
            Some(Instruction::ReturnValue)
        ));
    }

    #[test]
    fn folded_multiline_bytes_binop_does_not_leave_operand_nops() {
        let code = compile_exec(
            "\
def f(self, out):
    self.assertIn(
        b'gnu' + (b'/123' * 125) + b'/longlink' + (b'/123' * 125) + b'/longname',
        out)
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        assert!(
            !f.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::Nop)),
            "expected CPython nop_out-style folded operands to have no surviving NOPs, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn folded_binop_at_branch_body_start_does_not_leave_nop() {
        let code = compile_exec(
            "\
def f(sys):
    if sys.platform == 'win32':
        component = 'd' * 25
    return component
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::NotTaken,
                        Instruction::Nop,
                        Instruction::LoadConst { .. }
                    ]
                )
            }),
            "expected CPython nop_out-style folded branch body to drop operand NOP, got ops={ops:?}",
        );
    }

    #[test]
    fn folded_iterable_at_assert_target_does_not_leave_nop() {
        let code = compile_exec(
            r#"
def f(caches, non_caches):
    assert 1 / 3 <= caches / non_caches, "this test needs more caches!"
    for show_caches in (False, True):
        pass
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(2).any(|window| {
                matches!(window, [Instruction::Nop, Instruction::LoadConst { .. }])
            }),
            "expected folded for-iterable at assert target to drop operand NOP, got ops={ops:?}",
        );
    }

    #[test]
    fn multiline_unpack_target_uses_element_locations() {
        let code = compile_exec(
            "\
def f(cm):
    with cm as (_,
                filename_2):
        return filename_2
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.iter()
                .any(|op| matches!(op, Instruction::StoreFastStoreFast { .. })),
            "expected multiline target elements to keep separate STORE_FAST instructions, got ops={ops:?}",
        );
    }

    #[test]
    fn or_condition_in_jump_context_uses_shared_true_fallthrough() {
        let code = compile_exec(
            "\
def f(lines):
    for line in lines:
        if line.startswith('--') or not line.strip():
            continue
        return line
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let first_pop_jump = ops
            .iter()
            .find(|op| {
                matches!(
                    op,
                    Instruction::PopJumpIfTrue { .. } | Instruction::PopJumpIfFalse { .. }
                )
            })
            .copied()
            .expect("missing conditional jump");
        assert!(
            matches!(first_pop_jump, Instruction::PopJumpIfTrue { .. }),
            "expected first OR branch to jump on true into shared fallthrough, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_break_bool_chain_reorders_false_path_to_jump_back() {
        let code = compile_exec(
            "\
def f(filters, text, category, module, lineno, defaultaction):
    for item in filters:
        action, msg, cat, mod, ln = item
        if ((msg is None or msg.match(text)) and
            issubclass(category, cat) and
            (mod is None or mod.match(module)) and
            (ln == 0 or lineno == ln)):
            break
    else:
        action = defaultaction
    return action
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style false path to fall through into loop jump-back, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_conditional_body_keeps_duplicate_jump_back_paths() {
        let code = compile_exec(
            "\
def f(new, old):
    for replace in ['__module__', '__name__', '__qualname__', '__doc__']:
        if hasattr(old, replace):
            setattr(new, replace, getattr(old, replace))
    return new
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let jump_back_count = ops
            .iter()
            .filter(|op| {
                matches!(
                    op,
                    Instruction::JumpBackward { .. } | Instruction::JumpBackwardNoInterrupt { .. }
                )
            })
            .count();
        assert!(
            jump_back_count >= 2,
            "expected separate false-path and body jump-back blocks, got ops={ops:?}"
        );
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected false path to jump back before body, got ops={ops:?}"
        );
    }

    #[test]
    fn try_loop_inner_if_keeps_duplicate_jump_back_paths() {
        let code = compile_exec(
            "\
def f(config, logging):
    handlers = config.get('handlers', {})
    for name in handlers:
        if name not in logging._handlers:
            raise ValueError('missing')
        else:
            try:
                handler = logging._handlers[name]
                handler_config = handlers[name]
                level = handler_config.get('level', None)
                if level:
                    handler.setLevel(logging._checkLevel(level))
            except Exception as e:
                raise ValueError('bad') from e
    loggers = config.get('loggers', {})
    for name in loggers:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::EndFor,
                    ]
                )
            }),
            "expected CPython-style separate body and false-path jump-back blocks, got ops={ops:?}"
        );
    }

    #[test]
    fn try_loop_nested_bool_tail_keeps_duplicate_jump_back_paths() {
        let code = compile_exec(
            "\
def f(obj, flags, writer, value, Error):
    while obj.running:
        try:
            if value == 0:
                return
            elif obj.ready and obj.active and value == 1:
                obj.work()
                if flags.verbose and obj.chatty:
                    writer.write('trace')
            elif value == 2:
                obj.other()
            else:
                obj.default()
        except Error as e:
            obj.running = False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadConst { .. } | Instruction::LoadSmallInt { .. },
                    ]
                )
            }),
            "expected CPython-style body and both bool false-path jump-back blocks, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_continue_shares_backedge_with_fallthrough_body() {
        let code = compile_exec(
            "\
def f(names, show_empty, keywords, args_buffer, args, cls, object, level):
    for name in names:
        value = getattr(cls, name)
        if not show_empty:
            if value == []:
                field_type = cls._field_types.get(name, object)
                if getattr(field_type, '__origin__', ...) is list:
                    if not keywords:
                        args_buffer.append(repr(value))
                    continue
            if not keywords:
                args.extend(args_buffer)
                args_buffer = []
        value, simple = _format(value, level)
        if keywords:
            args.append('%s=%s' % (name, value))
        else:
            args.append(value)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache | Instruction::NotTaken))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "expected CPython-style shared continue backedge before outer condition, got ops={ops:?}"
        );
        assert!(
            !ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "unexpected duplicated continue/backedge jumps, got ops={ops:?}"
        );
    }

    #[test]
    fn line_bearing_loop_if_false_backedge_keeps_body_before_jump_back() {
        let code = compile_exec(
            "\
def f(self, replacement_pairs):
    for n, d in [(19, '%OC'), (2, '%Ow')]:
        if self.LC_alt_digits is None:
            s = str(n)
            replacement_pairs.append((s, d))
            if n < 10:
                replacement_pairs.append((s[1], d))
        elif len(self.LC_alt_digits) > n:
            replacement_pairs.append((self.LC_alt_digits[n], d))
        else:
            replacement_pairs.append((d, d))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "expected CPython-style line-bearing false target to keep body before backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "unexpected no-lineno-style inverted loop-if body, got ops={ops:?}"
        );
    }

    #[test]
    fn branch_local_implicit_continue_keeps_body_before_jump_back() {
        let code = compile_exec(
            "\
def f(items, outer, cond, sub, out):
    for x in items:
        if outer:
            if cond:
                out.append(x)
                if sub:
                    out.append(1)
                out.append(2)
        else:
            out.append(3)
    return out
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "expected branch-local implicit continue target to stay after the body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "unexpected direct-loop-body implicit continue layout for branch-local target, got ops={ops:?}"
        );
    }

    #[test]
    fn boolop_continue_deduplicates_marker_jump_back() {
        let code = compile_exec(
            "\
def f(ws, seen, more_than):
    while ws:
        w = ws.pop()
        if w in seen or w <= more_than:
            continue
        seen.add(w)
    return seen
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected adjacent equivalent continue backedges to be deduplicated, got ops={ops:?}"
        );
        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "expected CPython-style boolop continue fallthrough before body, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_elif_nested_if_false_backedge_keeps_body_before_jump_back() {
        let code = compile_exec(
            "\
def f(keys, parse_int, d, ampm, AM, PM):
    hour = minute = 0
    for group_key in keys:
        if group_key == 'I':
            hour = parse_int(d['I'])
            if ampm in ('', AM):
                if hour == 12:
                    hour = 0
            elif ampm == PM:
                if hour != 12:
                    hour += 12
        elif group_key == 'M':
            minute = parse_int(d['M'])
    return hour, minute
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                    ]
                )
            }),
            "expected CPython-style nested elif body before false backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                    ]
                )
            }),
            "unexpected inverted nested elif false path before body, got ops={ops:?}"
        );
        assert!(
            ops.windows(15).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::StoreFast { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style duplicated body/false loop exits for nested elif, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_nested_if_before_elif_keeps_body_before_false_backedge() {
        let code = compile_exec(
            "\
def f(keys, parse_int, found_dict, locale_time):
    hour = minute = 0
    for group_key in keys:
        if group_key == 'I':
            hour = parse_int(found_dict['I'])
            ampm = found_dict.get('p', '').lower()
            if ampm in ('', locale_time.am_pm[0]):
                if hour == 12:
                    hour = 0
            elif ampm == locale_time.am_pm[1]:
                if hour != 12:
                    hour += 12
        elif group_key == 'M':
            minute = parse_int(found_dict['M'])
    return hour, minute
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadSmallInt { .. },
                        Instruction::StoreFast { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style nested if body before false backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadSmallInt { .. },
                    ]
                )
            }),
            "unexpected inverted nested if body after false backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn elif_pass_before_raise_keeps_line_bearing_forward_jump() {
        let code = compile_exec(
            "\
def f(entries, path, self):
    if entries == ['.mh_sequences']:
        os.remove(os.path.join(path, '.mh_sequences'))
    elif entries == []:
        pass
    else:
        raise NotEmptyError('Folder not empty: %s' % self._path)
    os.rmdir(path)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpForward { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style pass branch forward jump before raise body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "unexpected inverted pass branch before raise body, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_multiblock_conditional_body_keeps_body_before_jump_back() {
        let code = compile_exec(
            "\
def f(random, d, f):
    for dummy in range(100):
        k = random.choice('abc')
        if random.random() < 0.2:
            if k in d:
                del d[k]
                del f[k]
        else:
            v = random.choice((1, 2))
            d[k] = v
            f[k] = v
            check(f[k], v)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrowLoadFastBorrow { .. },
                        Instruction::DeleteSubscr,
                    ]
                )
            }),
            "expected CPython-style multi-block body before false jump-back, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_not_conditional_body_threads_true_path_to_jump_back() {
        let code = compile_exec(
            "\
def f(xs):
    for x in xs:
        if not x:
            g(x)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style true path to jump back before not-body, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_not_in_conditional_body_threads_true_path_to_jump_back() {
        let code = compile_exec(
            "\
def f(native, array):
    for k in native:
        if k not in 'bBhHiIlLfd':
            del array[k]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                    ]
                )
            }),
            "expected CPython-style true path to jump back before not-in body, got ops={ops:?}"
        );
    }

    #[test]
    fn while_implicit_continue_body_after_jumpback_for_boolop_call_arg() {
        let code = compile_exec(
            "\
def f(source, state, verbose, nested):
    items = []
    itemsappend = items.append
    sourcematch = source.match
    while True:
        itemsappend(parse(source, state, verbose, nested + 1,
                          not nested and not items))
        if not sourcematch('|'):
            break
        if not nested:
            verbose = state.flags & 64
    return verbose
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style while implicit-continue jumpback before conditional body, got ops={ops:?}"
        );
    }

    #[test]
    fn multiblock_elif_continue_keeps_next_test_before_backedge() {
        let code = compile_exec(
            "\
def f(source, state, verbose, nested, subpatternappend, start, MAXGROUPS):
    sourceget = source.get
    sourcematch = source.match
    while True:
        this = source.next
        sourceget()
        if this == '(':
            if sourcematch('?'):
                char = sourceget()
                if char in '=!<':
                    dir = 1
                    if char == '<':
                        char = sourceget()
                        if char not in '=!':
                            raise source.error('unknown extension ?<' + char, len(char) + 2)
                        dir = -1
                        lookbehindgroups = state.lookbehindgroups
                        if lookbehindgroups is None:
                            state.lookbehindgroups = state.groups
                    p = parse_sub(source, state, verbose, nested + 1)
                    if dir < 0:
                        if lookbehindgroups is None:
                            state.lookbehindgroups = None
                    if not sourcematch(')'):
                        raise source.error('missing ), unterminated subpattern', source.tell() - start)
                    if char == '=':
                        subpatternappend(('ASSERT', (dir, p)))
                    elif p:
                        subpatternappend(('ASSERT_NOT', (dir, p)))
                    else:
                        subpatternappend(('FAILURE', ()))
                    continue
                elif char == '(':
                    condname = source.getuntil(')', 'group name')
                    if not (condname.isdecimal() and condname.isascii()):
                        source.checkgroupname(condname, 1)
                        condgroup = state.groupdict.get(condname)
                        if condgroup is None:
                            msg = 'unknown group name %r' % condname
                            raise source.error(msg, len(condname) + 1)
                    else:
                        condgroup = int(condname)
                        if not condgroup:
                            raise source.error('bad group number', len(condname) + 1)
                        if condgroup >= MAXGROUPS:
                            msg = 'invalid group reference %d' % condgroup
                            raise source.error(msg, len(condname) + 1)
                    state.checklookbehindgroup(condgroup, source)
                    item_yes = parse(source, state, verbose, nested + 1)
                    if source.match('|'):
                        item_no = parse(source, state, verbose, nested + 1)
                        if source.next == '|':
                            raise source.error('conditional backref with more than two branches')
                    else:
                        item_no = None
                    if not source.match(')'):
                        raise source.error('missing ), unterminated subpattern', source.tell() - start)
                    subpatternappend(('GROUPREF_EXISTS', (condgroup, item_yes, item_no)))
                    continue
                elif char == '>':
                    capture = False
        return
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style elif test between separate continue backedges, got ops={ops:?}"
        );
    }

    #[test]
    fn while_scope_exit_body_keeps_line_backedge_before_raise_body() {
        let code = compile_exec(
            "\
FLAGS = {}
TYPE_FLAGS = 0
GLOBAL_FLAGS = 0

def f(source, state, char):
    sourceget = source.get
    add_flags = 0
    del_flags = 0
    if char != '-':
        while True:
            flag = FLAGS[char]
            if source.istext:
                if char == 'L':
                    msg = 'bad inline flags'
                    raise source.error(msg)
            else:
                if char == 'u':
                    msg = 'bad inline flags'
                    raise source.error(msg)
            add_flags |= flag
            if (flag & TYPE_FLAGS) and (add_flags & TYPE_FLAGS) != flag:
                msg = 'bad inline flags'
                raise source.error(msg)
            char = sourceget()
            if char is None:
                raise source.error('missing -, : or )')
            if char in ')-:':
                break
            if char not in FLAGS:
                msg = 'unknown flag' if char.isalpha() else 'missing -, : or )'
                raise source.error(msg, len(char))
    if char == ')':
        state.flags |= add_flags
        return None
    if add_flags & GLOBAL_FLAGS:
        raise source.error('bad inline flags: cannot turn on global flag', 1)
    if char == '-':
        char = sourceget()
        if char is None:
            raise source.error('missing flag')
        if char not in FLAGS:
            msg = 'unknown flag' if char.isalpha() else 'missing flag'
            raise source.error(msg, len(char))
        while True:
            flag = FLAGS[char]
            if flag & TYPE_FLAGS:
                msg = 'bad inline flags'
                raise source.error(msg)
            del_flags |= flag
            char = sourceget()
            if char is None:
                raise source.error('missing :')
            if char == ':':
                break
            if char not in FLAGS:
                msg = 'unknown flag' if char.isalpha() else 'missing :'
                raise source.error(msg, len(char))
    return add_flags, del_flags
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let cpython_style_not_in_raise_body_count = ops
            .windows(6)
            .filter(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            })
            .count();
        assert!(
            cpython_style_not_in_raise_body_count >= 2,
            "expected both while-loop not-in checks to put the false-path backedge before the conditional-expression raise body, got ops={ops:?}"
        );
    }

    #[test]
    fn call_body_implicit_continue_keeps_cpython_normalized_forward_jump() {
        let code = compile_exec(
            "\
DIGITS = '0123456789'

def f(s, sget, lappend, addgroup, this, c):
    while True:
        if c in DIGITS:
            isoctal = False
            if s.next in DIGITS:
                this += sget()
            if not isoctal:
                addgroup(int(this[1:]), len(this) - 1)
        else:
            lappend(this)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "expected CPython-style forward jump over call body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "call body should not be moved after an implicit continue backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn empty_if_end_label_preserves_cpython_return_anchor_nop() {
        let code = compile_exec(
            "\
SRE_FLAG_LOCALE = 1
SRE_FLAG_ASCII = 2
SRE_FLAG_UNICODE = 4

def f(src, flags):
    if isinstance(src, str):
        if flags & SRE_FLAG_LOCALE:
            raise ValueError('cannot use LOCALE flag with a str pattern')
        if not flags & SRE_FLAG_ASCII:
            flags |= SRE_FLAG_UNICODE
        elif flags & SRE_FLAG_UNICODE:
            raise ValueError('ASCII and UNICODE flags are incompatible')
    else:
        if flags & SRE_FLAG_UNICODE:
            raise ValueError('cannot use UNICODE flag with a bytes pattern')
        if flags & SRE_FLAG_LOCALE and flags & SRE_FLAG_ASCII:
            raise ValueError('ASCII and LOCALE flags are incompatible')
    return flags
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::RaiseVarargs { .. },
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected CPython-style NOP return anchor after elif raise body, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_except_normal_exit_return_uses_strong_loads() {
        let code = compile_exec(
            "\
LITERAL = 1

def f(source, escape):
    try:
        c = escape[1:2]
        if c == 'N' and source.istext:
            try:
                c = ord(source.lookup())
            except (KeyError, TypeError):
                raise source.error() from None
            return LITERAL, c
    except ValueError:
        pass
    raise source.error(escape)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadFast { .. },
                        Instruction::BuildTuple { .. },
                        Instruction::ReturnValue,
                    ]
                )
            }),
            "expected CPython-style strong LOAD_FAST in nested except normal-exit return, got ops={ops:?}"
        );
    }

    #[test]
    fn targeted_nop_after_prefix_for_else_uses_strong_for_tail_loads() {
        let code = compile_exec(
            "\
LITERAL = 1
IN = 2
NEGATE = 3

def f(items):
    while True:
        prefix = None
        for item in items:
            if not item:
                break
            if prefix is None:
                prefix = item[0]
            elif item[0] != prefix:
                break
        else:
            for item in items:
                del item[0]
            continue
        break
    set = []
    for item in items:
        if len(item) != 1:
            break
        op, av = item[0]
        if op is LITERAL:
            set.append((op, av))
        elif op is IN and av[0][0] is not NEGATE:
            set.extend(av)
        else:
            break
    return set
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let get_iter_idx = ops
            .iter()
            .rposition(|op| matches!(op, Instruction::GetIter))
            .expect("missing GET_ITER");
        assert!(
            matches!(ops[get_iter_idx - 1], Instruction::LoadFast { .. }),
            "targeted NOP after prefix for/else should use strong iterable LOAD_FAST, got ops={ops:?}"
        );
        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastLoadFast { .. },
                        Instruction::BuildTuple { .. },
                    ]
                )
            }),
            "targeted NOP after prefix for/else should keep set.append tuple loads strong, got ops={ops:?}"
        );
    }

    #[test]
    fn plain_pass_before_for_tail_keeps_borrows() {
        let code = compile_exec(
            "\
def f(xs):
    pass
    for x in xs:
        pass
    return xs
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let get_iter_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::GetIter))
            .expect("missing GET_ITER");
        assert!(
            matches!(ops[get_iter_idx - 1], Instruction::LoadFastBorrow { .. }),
            "plain pass before for-tail should keep borrowed iterable load, got ops={ops:?}"
        );
    }

    #[test]
    fn targeted_nop_after_return_uses_strong_pair_call_args() {
        let code = compile_exec(
            "\
def f(x, d, count, inner, hi, w1, lo, w2):
    if x:
        return
    if 0:
        pass
    d[count] += 1
    inner(hi, w1)
    del hi
    inner(lo, w2)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::PushNull,
                        Instruction::LoadFastLoadFast { .. },
                    ]
                )
            }),
            "targeted NOP after return should keep CPython-style strong pair call args, got ops={ops:?}"
        );
        let nop_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::Nop))
            .expect("missing targeted NOP");
        assert!(
            !ops[nop_idx..].iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "targeted NOP tail should not reintroduce borrowed fast loads, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_if_pass_uses_line_bearing_jump_back_instead_of_nop() {
        let code = compile_exec(
            "\
def f(x, y):
    for i in x:
        if y:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style synthetic false-path jump-back plus body jump-back, got ops={ops:?}"
        );
        assert!(
            !ops.iter().any(|op| matches!(op, Instruction::Nop)),
            "expected pass body line to attach to loop backedge instead of leaving a NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn constant_true_while_pass_keeps_loop_header_nop() {
        let code = compile_exec(
            "\
def f():
    while 1:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style loop-header NOP before self backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_if_shared_jump_back_target_is_duplicated() {
        let code = compile_exec(
            "\
def f(s, size, encodeSetO, encodeWhiteSpace):
    inShift = True
    base64bits = 0
    out = []
    for i, ch in enumerate(s):
        if base64bits == 0:
            if i + 1 < size:
                ch2 = s[i + 1]
                if E(ch2, encodeSetO, encodeWhiteSpace):
                    if B(ch2) or ch2 == '-':
                        out.append(b'-')
                    inShift = False
            else:
                out.append(b'-')
                inShift = False
    return out
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "expected separate nested-if and outer-if jump-back tails, got ops={ops:?}"
        );
    }

    #[test]
    fn exception_cleanup_backedge_target_is_shared() {
        let code = compile_exec(
            "\
def f(enum_class, value, Flag, int_type, is_single_bit):
    try:
        try:
            enum_member = enum_class[value]
        except TypeError:
            raise KeyError
    except KeyError:
        if Flag is None or not issubclass(enum_class, Flag):
            enum_class.names.append(value)
        elif (
            Flag is not None
            and issubclass(enum_class, Flag)
            and isinstance(value, int_type)
            and is_single_bit(value)
        ):
            enum_class.names.append(value)
    enum_class.add(enum_member)
    return enum_member
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::JumpBackwardNoInterrupt { .. }
                            | Instruction::JumpBackward { .. },
                        Instruction::Reraise { .. },
                    ]
                )
            }),
            "expected CPython-style shared exception cleanup backedge before reraise, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopExcept,
                        Instruction::JumpBackwardNoInterrupt { .. }
                            | Instruction::JumpBackward { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackwardNoInterrupt { .. }
                            | Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "exception cleanup backedge should be shared, not duplicated per conditional edge, got ops={ops:?}"
        );
    }

    #[test]
    fn protected_loop_conditional_keeps_forward_body_entry() {
        let code = compile_exec(
            "\
def outer(it, C1):
    def f():
        for x in it:
            try:
                if C1:
                    yield 2
            except OSError:
                pass
    return f
",
        );
        let outer = find_code(&code, "outer").expect("missing outer code");
        let f = find_code(outer, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadSmallInt { .. },
                        Instruction::YieldValue { .. },
                        Instruction::Resume { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "expected protected conditional to keep CPython-style forward body entry, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_except_false_path_duplicates_pop_except_jump_back_tail() {
        let code = compile_exec(
            "\
def f(it, C3):
    for x in it:
        try:
            X = 3
        except OSError:
            try:
                if C3:
                    X = 4
            except OSError:
                pass
    return 42
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadSmallInt { .. },
                        Instruction::StoreFast { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style duplicated false-path exit tail, got ops={ops:?}"
        );
    }

    #[test]
    fn more_nested_except_false_paths_duplicate_all_jump_back_tails() {
        let code = compile_exec(
            "\
def f(it, C3, C4):
    for x in it:
        try:
            X = 3
        except OSError:
            try:
                if C3:
                    if C4:
                        X = 4
            except OSError:
                try:
                    if C3:
                        if C4:
                            X = 5
                except OSError:
                    pass
    return 42
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadSmallInt { .. },
                        Instruction::StoreFast { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::PopExcept,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style duplicated nested false-path exit tails, got ops={ops:?}"
        );
    }

    #[test]
    fn no_wraparound_jump_keeps_forward_hop_before_loop_backedge() {
        let code = compile_exec(
            "\
def while_not_chained(a, b, c):
    while not (a < b < c):
        pass
",
        );
        let f = find_code(&code, "while_not_chained").expect("missing while_not_chained code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpForward { .. },
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style no-wraparound forward hop before the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_while_chained_compare_break_keeps_break_jump_block() {
        let code = compile_exec(
            "\
def f(start, self, stop, size):
    while size > 0:
        while True:
            if start <= self.position < stop:
                break
            else:
                self.map_index += 1
                if self.map_index == len(self.map):
                    self.map_index = 0
        length = min(size, stop - self.position)
        size -= length
    return size
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpForward { .. },
                        Instruction::PopTop,
                        Instruction::JumpForward { .. },
                        Instruction::JumpForward { .. },
                    ]
                )
            }),
            "expected CPython-style chained-compare success hop into the break jump block, got ops={ops:?}"
        );
    }

    #[test]
    fn while_break_else_keeps_true_edge_into_forward_break_body() {
        let code = compile_exec(
            "\
def f(i):
    while i:
        i -= 1
        if i < 4:
            break
    else:
        print('x')
    print('y')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpForward { .. },
                    ]
                )
            }),
            "expected CPython-style true edge into forward break body with false path falling into the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_if_continue_reorders_false_path_to_loop_backedge() {
        let code = compile_exec(
            "\
def f(items, changes):
    for x in items:
        if not x:
            if x in changes:
                raise TypeError
            continue
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                    ]
                )
            }),
            "expected nested if/continue to keep CPython-style false-edge jump-back tails, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_assert_keeps_false_edge_into_raise_body() {
        let code = compile_exec(
            "\
def f(bytecode):
    for instr, positions in zip(bytecode, bytecode.codeobj.co_positions()):
        assert instr.positions == positions
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadCommonConstant { .. },
                        Instruction::RaiseVarargs { .. },
                    ]
                )
            }),
            "expected loop assert to keep CPython-style false-edge into the raise body, got ops={ops:?}"
        );
    }

    #[test]
    fn and_is_not_none_loop_guard_uses_direct_jump_back_false_path() {
        let code = compile_exec(
            "\
def f(code):
    last_line = -2
    for _, _, line in code.co_lines():
        if line is not None and line != last_line:
            last_line = line
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::PopJumpIfNotNone { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::CompareOp { .. },
                    ]
                )
            }),
            "expected CPython-style direct jump-back false path for 'is not None and ...', got ops={ops:?}"
        );
    }

    #[test]
    fn large_is_not_none_loop_guard_uses_direct_jump_back_false_path() {
        let code = compile_exec(
            "\
def f(cls, _FIELDS, _PARAMS):
    all_frozen_bases = None
    any_frozen_base = False
    has_dataclass_bases = False
    for b in cls.__mro__[-1:0:-1]:
        base_fields = getattr(b, _FIELDS, None)
        if base_fields is not None:
            has_dataclass_bases = True
            for field in base_fields.values():
                name = field.name
            if all_frozen_bases is None:
                all_frozen_bases = True
            current_frozen = getattr(b, _PARAMS).frozen
            all_frozen_bases = all_frozen_bases and current_frozen
            any_frozen_base = any_frozen_base or current_frozen
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::PopJumpIfNotNone { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadConst { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython-style direct jump-back false path for large 'is not None' loop body, got ops={ops:?}"
        );
    }

    #[test]
    fn continue_inside_with_keeps_line_marker_nop_before_exit_cleanup() {
        let code = compile_exec(
            "\
def f(it):
    for func in it:
        with cm():
            if cond():
                continue
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(9).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "expected CPython-style line-marker NOP before with-exit cleanup on continue, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_async_with_normal_cleanup_drops_pop_block_nop() {
        let code = compile_exec(
            "\
async def foo():
    async with CM():
        async with CM():
            raise RuntimeError
",
        );
        let f = find_code(&code, "foo").expect("missing foo code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::GetAwaitable { .. },
                    ]
                )
            }),
            "expected CPython-style async-with normal cleanup without a POP_BLOCK NOP, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::GetAwaitable { .. },
                    ]
                )
            }),
            "unexpected POP_BLOCK NOP before async-with normal cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn async_with_try_finally_before_outer_sync_with_cleanup_keeps_anchor_nop() {
        let code = compile_exec(
            "\
async def foo(self):
    with self.assertRaises(ZeroDivisionError):
        async with timeout():
            try:
                try:
                    raise ValueError
                finally:
                    await sleep(1)
            finally:
                try:
                    raise KeyError
                finally:
                    1 / 0
    after()
",
        );
        let f = find_code(&code, "foo").expect("missing foo code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "expected CPython-style async-with after-block NOP before outer sync-with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_terminal_with_keeps_outer_cleanup_target_nop() {
        let code = compile_exec(
            "\
def f():
    with a():
        with b():
            raise E()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "expected CPython-style outer with-exit target NOP after terminal nested with cleanup, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_nonterminal_with_drops_outer_cleanup_target_nop() {
        let code = compile_exec(
            "\
def f():
    with a():
        with b():
            x()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "unexpected outer with-exit target NOP for nested with with normal fallthrough, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_terminal_with_before_successor_drops_after_block_nop() {
        let code = compile_exec(
            "\
def f(a, b, c):
    with a:
        with b:
            raise c
        c()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "CPython falls through from the terminal inner-with cleanup to the following statement without an after-block NOP, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadFast { .. } | Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "unexpected inner with after-block NOP before following statement, got ops={ops:?}"
        );
    }

    #[test]
    fn try_loop_elif_places_return_before_orelse_tail() {
        let code = compile_exec(
            "\
def f(source, suggest, tb, s):
    if source is not None:
        try:
            tb = tb
        except Exception:
            suggest = False
            tb = None
        if tb is not None:
            for frame in tb:
                s += frame
        elif suggest:
            s += 'x'
    return s
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let has_direct_return = ops.windows(8).any(|window| {
            matches!(
                window,
                [
                    Instruction::EndFor,
                    Instruction::PopIter,
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::ReturnValue,
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::ToBool,
                    Instruction::PopJumpIfFalse { .. },
                    Instruction::NotTaken,
                ]
            )
        });
        let has_nop_anchored_return = ops.windows(9).any(|window| {
            matches!(
                window,
                [
                    Instruction::EndFor,
                    Instruction::PopIter,
                    Instruction::Nop,
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::ReturnValue,
                    Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    Instruction::ToBool,
                    Instruction::PopJumpIfFalse { .. },
                    Instruction::NotTaken,
                ]
            )
        });
        assert!(
            has_direct_return || has_nop_anchored_return,
            "expected CPython-style duplicated return between loop exit and elif tail, got ops={ops:?}"
        );
    }

    #[test]
    fn constant_false_while_else_deopts_post_else_borrows() {
        let code = compile_exec(
            "\
def f(self):
    x = 0
    while 0:
        x = 1
    else:
        x = 2
    self.assertEqual(x, 2)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();
        let assert_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing assertEqual call");
        let window = &ops[assert_idx.saturating_sub(1)..(assert_idx + 3).min(ops.len())];
        assert!(
            matches!(
                window,
                [
                    Instruction::LoadFast { .. },
                    Instruction::LoadAttr { .. },
                    Instruction::LoadFast { .. },
                    ..
                ]
            ),
            "expected post-else assertEqual call to use plain LOAD_FAST, got ops={window:?}"
        );
    }

    #[test]
    fn single_unpack_assignment_disables_constant_collection_folding() {
        let code = compile_exec("a, b, c = 1, 2, 3\n");

        assert!(
            !code.instructions.iter().any(|unit| {
                matches!(unit.op, Instruction::UnpackSequence { .. })
                    || matches!(unit.op, Instruction::LoadConst { .. })
                        && matches!(
                            code.constants.get(usize::from(u8::from(unit.arg))),
                            Some(ConstantData::Tuple { .. })
                        )
            }),
            "single unpack assignment should keep builder form for later lowering, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            code.instructions
                .iter()
                .filter(|unit| matches!(unit.op, Instruction::LoadSmallInt { .. }))
                .count()
                >= 3,
            "expected individual constant loads before unpack-target stores, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn four_item_unpack_assignment_folds_tuple_constant_like_cpython() {
        let code = compile_exec("a, b, c, d = 1, 2, 3, 4\n");

        assert!(
            code.instructions.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadConst { .. })
                    && matches!(
                        code.constants.get(usize::from(u8::from(unit.arg))),
                        Some(ConstantData::Tuple { elements }) if elements.len() == 4
                    )
            }),
            "four-item unpack assignment should fold BUILD_TUPLE before UNPACK_SEQUENCE like CPython, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::UnpackSequence { .. })),
            "four-item unpack assignment should keep UNPACK_SEQUENCE after tuple folding, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn chained_unpack_assignment_keeps_constant_collection_folding() {
        let code = compile_exec("(a, b) = c = d = (1, 2)\n");

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadConst { .. })),
            "chained unpack assignment should keep tuple constant, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::UnpackSequence { .. })),
            "chained unpack assignment should still unpack the copied tuple, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn constant_true_assert_skips_message_nested_scope() {
        let code = compile_exec("assert 1, (lambda x: x + 1)\n");

        assert_eq!(
            code.constants
                .iter()
                .filter(|constant| matches!(constant, ConstantData::Code { .. }))
                .count(),
            0,
            "constant-true assert should not compile the skipped message lambda"
        );
        assert!(
            !code
                .instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. })),
            "constant-true assert should be elided, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn constant_false_assert_uses_direct_raise_shape() {
        let code = compile_exec("assert 0, (lambda x: x + 1)\n");

        assert!(
            !code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::ToBool
                        | Instruction::PopJumpIfTrue { .. }
                        | Instruction::PopJumpIfFalse { .. }
                )
            }),
            "constant-false assert should use direct raise shape, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. })),
            "constant-false assert should still raise, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
        assert_eq!(
            code.constants
                .iter()
                .filter(|constant| matches!(constant, ConstantData::Code { .. }))
                .count(),
            1,
            "constant-false assert should still compile the message lambda"
        );
    }

    #[test]
    fn constant_unary_positive_and_invert_fold() {
        let code = compile_exec("x = +1\nx = ~1\n");

        assert!(
            !code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::CallIntrinsic1 { .. } | Instruction::UnaryInvert
                )
            }),
            "constant unary ops should fold away, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn bool_invert_is_not_const_folded() {
        let code = compile_exec("x = ~True\n");

        assert!(
            code.instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::UnaryInvert)),
            "~bool should remain unfurled to match CPython, got ops={:?}",
            code.instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn optimized_assert_preserves_nested_scope_order() {
        compile_exec_optimized(
            "\
class S:
    def f(self, sequence):
        _formats = [self._types_mapping[type(item)] for item in sequence]
        _list_len = len(_formats)
        assert sum(len(fmt) <= 8 for fmt in _formats) == _list_len
        _recreation_codes = [self._extract_recreation_code(item) for item in sequence]
",
        );
    }

    #[test]
    fn optimized_assert_with_nested_scope_in_first_iter() {
        // First iterator of a comprehension is evaluated in the enclosing
        // scope, so nested scopes inside it (the generator here) must also
        // be consumed when the assert is optimized away.
        compile_exec_optimized(
            "\
def f(items):
    assert [x for x in (y for y in items)]
    return [x for x in items]
",
        );
    }

    #[test]
    fn optimized_assert_with_lambda_defaults() {
        // Lambda default values are evaluated in the enclosing scope,
        // so nested scopes inside defaults must be consumed.
        compile_exec_optimized(
            "\
def f(items):
    assert (lambda x=[i for i in items]: x)()
    return [x for x in items]
",
        );
    }

    #[test]
    fn try_else_nested_scopes_keep_subtable_cursor_aligned() {
        let code = compile_exec(
            "\
try:
    import missing_mod
except ImportError:
    def fallback():
        return 0
else:
    def impl():
        return reversed('abc')
",
        );

        assert!(
            find_code(&code, "fallback").is_some(),
            "missing fallback code"
        );
        let impl_code = find_code(&code, "impl").expect("missing impl code");
        assert!(
            impl_code.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadGlobal { .. } | Instruction::LoadName { .. }
                )
            }),
            "expected impl to compile global name access, got ops={:?}",
            impl_code
                .instructions
                .iter()
                .map(|unit| unit.op)
                .collect::<Vec<_>>()
        );
    }

    #[test]
    fn nested_try_else_multi_resume_join_keeps_strong_load_fast_tail() {
        let code = compile_exec(
            "\
def f(msg):
    s = ''
    try:
        import a
    except Exception:
        suggest = False
        tb = None
    else:
        try:
            suggest = not t()
            tb = g(msg)
        except Exception:
            suggest = False
            tb = None
    if tb is not None:
        for frame in tb:
            s += frame
    elif suggest:
        s += 'y'
    return s
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let tail_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PopJumpIfNone { .. }))
            .expect("missing tail POP_JUMP_IF_NONE")
            .saturating_sub(1);
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &ops[tail_start..handler_start];

        assert!(
            !tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected nested try/except else-resume tail to keep strong LOAD_FAST ops, got tail={tail:?}"
        );

        assert!(
            tail.iter()
                .any(|op| matches!(op, Instruction::LoadFastLoadFast { .. })),
            "expected loop body to keep LOAD_FAST_LOAD_FAST in the resume tail, got tail={tail:?}"
        );
    }

    #[test]
    fn protected_conditional_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(m, class_name, category, warning_base):
    try:
        cat = getattr(m, class_name)
    except AttributeError:
        raise ValueError(category)
    if not issubclass(cat, warning_base):
        raise TypeError(category)
    return cat
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let tail_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing STORE_FAST cat");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &ops[tail_start + 1..handler_start];

        assert!(
            !tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected conditional tail to keep strong LOAD_FAST ops, got tail={tail:?}"
        );

        assert!(
            tail.iter()
                .any(|op| matches!(op, Instruction::LoadFastLoadFast { .. })),
            "expected protected tail to keep LOAD_FAST_LOAD_FAST for issubclass args, got tail={tail:?}"
        );
    }

    #[test]
    fn nonresuming_protected_conditional_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(href, parse='xml'):
    try:
        data = XINCLUDE[href]
    except KeyError:
        raise OSError('resource not found')
    if parse == 'xml':
        data = ET.XML(data)
    return data
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let tail_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::StoreFast { .. }))
            .expect("missing protected STORE_FAST data");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &ops[tail_start + 1..handler_start];

        assert!(
            !tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected non-resuming protected conditional tail to keep strong LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn optional_nonresuming_protected_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(b):
    if type(b) is not bytes:
        try:
            b = bytes(memoryview(b))
        except TypeError:
            raise TypeError(f'bad {type(b).__name__}') from None
    if b:
        sink(b)
    return len(b)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let b_index = f
            .varnames
            .iter()
            .position(|name| name.as_str() == "b")
            .expect("missing b varname");
        let store_b = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreFast { var_num } => {
                    usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg))))) == b_index
                }
                _ => false,
            })
            .expect("missing protected STORE_FAST b");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[store_b + 1..handler_start];

        assert!(
            tail.iter()
                .filter(|unit| match unit.op {
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                        usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))))
                            == b_index
                    }
                    _ => false,
                })
                .all(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })),
            "optional protected tail should keep CPython-style borrowed b loads, got tail={tail:?}"
        );
    }

    #[test]
    fn handled_except_conditional_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        if self.active:
            self.step()
        if self.waiter is not None and self.pending is None:
            self.waiter.set_result(None)
    except ConnectionResetError as exc:
        self.close(exc)
    except OSError as exc:
        self.fail(exc, 'x')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let waiter_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "waiter"
                }
                _ => false,
            })
            .expect("missing waiter LOAD_ATTR");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[waiter_idx.saturating_sub(1)..handler_start];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "handled-except conditional tail should keep borrowed loads, got tail={tail:?}"
        );
        assert!(
            !tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "handled-except conditional tail should not force strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn handled_except_else_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, fut=None):
    try:
        if self.closed:
            return
        item = self.queue.popleft()
        self.size -= len(item)
        if self.addr is not None:
            self.future = self.loop.send(self.sock, item)
        else:
            self.future = self.loop.sendto(self.sock, item, addr=item)
    except OSError as exc:
        self.protocol.error_received(exc)
    except Exception as exc:
        self.fatal(exc, 'x')
    else:
        self.future.add_done_callback(self.loop_writing)
        self.resume()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let done_callback_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "add_done_callback"
                }
                _ => false,
            })
            .expect("missing add_done_callback LOAD_ATTR");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[done_callback_idx.saturating_sub(3)..handler_start];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "handled-except else tail should keep borrowed loads, got tail={tail:?}"
        );
        assert!(
            !tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "handled-except else tail should not force strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn reraising_handler_with_handled_returns_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, fut=None):
    try:
        if fut is not None:
            fut.result()
        if self.future is not fut:
            return
        fut = self.reader.recv(self.sock, 4096)
    except CancelledError:
        return
    except (SystemExit, KeyboardInterrupt):
        raise
    except BaseException as exc:
        self.handle({'exception': exc, 'loop': self})
    else:
        self.future = fut
        fut.add_done_callback(self.loop_reading)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let recv_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "recv"
                }
                _ => false,
            })
            .expect("missing recv LOAD_ATTR");
        let done_callback_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "add_done_callback"
                }
                _ => false,
            })
            .expect("missing add_done_callback LOAD_ATTR");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail =
            &instructions[recv_idx.saturating_sub(3)..handler_start.min(done_callback_idx + 3)];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "handler chain with handled returns should keep borrowed warm/else loads, got tail={tail:?}"
        );
        assert!(
            !tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                )
            }),
            "handler chain with handled returns should not force strong warm/else loads, got tail={tail:?}"
        );
    }

    #[test]
    fn with_protected_conditional_tail_without_exception_match_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, cm, p, platform):
    with cm:
        if p.returncode != 0:
            if platform.machine() == 'x86_64':
                p.check_returncode()
            else:
                self.skipTest(f'could not compile indirect function: {p}')
        done()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        let attr_load_uses_borrow = |name: &str| {
            let attr_idx = instructions
                .iter()
                .position(|unit| match unit.op {
                    Instruction::LoadAttr { namei } => {
                        let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                        f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == name
                    }
                    _ => false,
                })
                .unwrap_or_else(|| panic!("missing {name} attr load"));
            matches!(
                instructions
                    .get(attr_idx.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            )
        };

        assert!(
            attr_load_uses_borrow("check_returncode"),
            "plain with-protected conditional tail should keep borrowed p load, got instructions={instructions:?}"
        );
        assert!(
            attr_load_uses_borrow("skipTest"),
            "plain with-protected conditional tail should keep borrowed self load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn listcomp_cleanup_predecessor_does_not_deopt_following_conditional_tail() {
        let code = compile_exec(
            "\
def f(self, compile_snippet):
    sizes = [compile_snippet(i).co_stacksize for i in range(2, 5)]
    if len(set(sizes)) != 1:
        import dis, io
        out = io.StringIO()
        dis.dis(compile_snippet(1), file=out)
        self.fail('%s\\n%s' % (sizes, out.getvalue()))
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        let has_strong_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };
        let has_borrow_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };

        for name in ["sizes", "io", "dis", "compile_snippet", "out", "self"] {
            assert!(
                has_borrow_load(name),
                "expected listcomp-following conditional tail to borrow {name}, got instructions={:?}",
                f.instructions
            );
        }
        for name in ["sizes", "io", "dis", "compile_snippet", "out", "self"] {
            assert!(
                !has_strong_load(name),
                "listcomp cleanup predecessor should not force strong LOAD_FAST for {name}, got instructions={:?}",
                f.instructions
            );
        }
    }

    #[test]
    fn handler_resume_loop_conditional_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(self):
    is_utf8 = (self.ENCODING == 'utf-8')
    encode_errors = 'surrogateescape' if is_utf8 else 'strict'
    strings = list(self.BYTES_STRINGS)
    for text in self.STRINGS:
        try:
            encoded = text.encode(self.ENCODING, encode_errors)
            if encoded not in strings:
                strings.append(encoded)
        except UnicodeEncodeError:
            encoded = None
        if is_utf8:
            encoded2 = text.encode(self.ENCODING, 'surrogatepass')
            if encoded2 != encoded:
                strings.append(encoded2)
    for encoded in strings:
        self.consume(encoded)
",
        );
        let f = find_code(&code, "f").expect("missing f code");

        let has_strong_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };
        let has_borrow_load = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };

        for name in ["is_utf8", "text", "self", "strings", "encoded2"] {
            assert!(
                has_strong_load(name),
                "expected handler-resume loop tail to use strong LOAD_FAST for {name}, got instructions={:?}",
                f.instructions
            );
        }
        assert!(
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastLoadFast { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == "encoded2"
                        && f.varnames[usize::from(right)] == "encoded"
                }
                _ => false,
            }),
            "expected encoded2/encoded comparison to use strong LOAD_FAST_LOAD_FAST, got instructions={:?}",
            f.instructions
        );
        assert!(
            !f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == "encoded2"
                        && f.varnames[usize::from(right)] == "encoded"
                }
                _ => false,
            }),
            "handler-resume loop tail should not borrow encoded2/encoded comparison, got instructions={:?}",
            f.instructions
        );
        assert!(
            has_borrow_load("strings"),
            "expected later loop/list uses outside the deopt tail to keep borrowing strings"
        );
    }

    #[test]
    fn handler_resume_while_conditional_tail_keeps_borrow_load_fast() {
        let code = compile_exec(
            "\
def f(value):
    items = []
    while value:
        try:
            token, value = parse(value)
            items.append(token)
        except Error:
            token, value = recover(value)
            items.append(token)
        if value and value[0] != ',':
            item = items[-1]
            token, value = recover(value)
            item.extend(token)
        if value and value[0] == ',':
            items.append(',')
            value = value[1:]
    return items, value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let handler_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_region = &f.instructions[..handler_start];
        let is_strong_local_load = |unit: &CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                matches!(
                    f.varnames[usize::from(var_num.get(arg))].as_str(),
                    "value" | "items" | "token" | "item"
                )
            }
            Instruction::LoadFastLoadFast { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                let left = f.varnames[usize::from(left)].as_str();
                let right = f.varnames[usize::from(right)].as_str();
                matches!(left, "value" | "items" | "token" | "item")
                    || matches!(right, "value" | "items" | "token" | "item")
            }
            _ => false,
        };

        assert!(
            !normal_region.iter().any(is_strong_local_load),
            "while-loop handler resume tail should keep CPython-style borrowed normal loads, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn multi_handler_resume_while_tail_keeps_borrow_load_fast() {
        let code = compile_exec(
            "\
def f(value):
    items = []
    while value and value[0] != ';':
        try:
            token, value = parse(value)
            items.append(token)
        except Error:
            leader = None
            if value[0] in leaders:
                leader, value = recover(value)
                if not value or value[0] in ',;':
                    items.append(leader)
                else:
                    token, value = recover_invalid(value)
                    if leader is not None:
                        token[:0] = [leader]
                    items.append(token)
            elif value[0] == ',':
                items.append(',')
            else:
                token, value = recover_invalid(value)
                if leader is not None:
                    token[:0] = [leader]
                items.append(token)
        if value and value[0] not in ',;':
            item = items[-1]
            token, value = recover_invalid(value)
            item.extend(token)
        if value and value[0] == ',':
            items.append(',')
            value = value[1:]
    return items, value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let handler_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_region = &f.instructions[..handler_start];

        assert!(
            normal_region.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected multi-handler while tail to keep borrowed normal loads, got instructions={:?}",
            f.instructions
        );
        assert!(
            !normal_region
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "multi-handler while tail should not be deoptimized to strong LOAD_FAST, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn multi_handler_resume_before_with_keeps_with_body_borrows() {
        let code = compile_exec(
            "\
def f(self, input, cm):
    try:
        self.stdin.flush()
    except BrokenPipeError:
        pass
    except ValueError:
        if not self.stdin.closed:
            raise
    if not input:
        self.stdin.close()
    with cm() as selector:
        if self.stdin and self._input:
            selector.register(self.stdin, EVENT_WRITE)
        while selector.get_map():
            ready = selector.select()
            for key in ready:
                self._fileobj2output[key].append(key)
    return self.stdin
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let handler_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &f.instructions[..handler_start];
        let self_load_is = |unit: &CodeUnit, borrowed: bool| match unit.op {
            Instruction::LoadFast { var_num } if !borrowed => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == "self"
            }
            Instruction::LoadFastBorrow { var_num } if borrowed => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == "self"
            }
            _ => false,
        };

        assert!(
            warm_path.iter().any(|unit| self_load_is(unit, true)),
            "expected multi-handler resume before with-body to keep borrowed self loads, got warm_path={warm_path:?}"
        );
        assert!(
            !warm_path.iter().any(|unit| self_load_is(unit, false)),
            "multi-handler resume must not deopt with-body self loads to strong LOAD_FAST, got warm_path={warm_path:?}"
        );
    }

    #[test]
    fn suppressing_with_and_typed_except_resume_loop_method_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(proc, text):
    try:
        with proc.stdin as pipe:
            try:
                pipe.write(text)
            except KeyboardInterrupt:
                pass
    except OSError:
        pass
    while True:
        try:
            proc.wait()
            break
        except KeyboardInterrupt:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_name = |unit: &CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        let wait_receiver_is_strong = f.instructions.windows(2).any(|window| {
            matches!(window[0].op, Instruction::LoadFast { .. })
                && load_name(&window[0]) == Some("proc")
                && matches!(window[1].op, Instruction::LoadAttr { .. })
        });
        assert!(
            wait_receiver_is_strong,
            "CPython keeps proc.wait() receiver strong after suppressing-with and typed-except loop resumes, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn handler_break_join_loop_body_and_tail_keep_strong_load_fast() {
        let code = compile_exec(
            "\
def f(function, stem):
    result = []
    state = 0
    while True:
        try:
            next = function(stem, state)
        except Exception:
            break
        if not isinstance(next, str):
            break
        result.append(next)
        state += 1
    result.sort()
    return result
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_name = |unit: &CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        let body_method_call_uses_strong_loads = instructions.windows(4).any(|window| {
            matches!(window[0].op, Instruction::LoadFast { .. })
                && load_name(window[0]) == Some("result")
                && matches!(window[1].op, Instruction::LoadAttr { .. })
                && matches!(window[2].op, Instruction::LoadFast { .. })
                && load_name(window[2]) == Some("next")
                && matches!(window[3].op, Instruction::Call { .. })
        });
        assert!(
            body_method_call_uses_strong_loads,
            "CPython keeps result.append(next) loads strong after an except-break join, got instructions={:?}",
            f.instructions
        );

        let body_update_uses_strong_load = instructions.windows(3).any(|window| {
            matches!(window[0].op, Instruction::LoadFast { .. })
                && load_name(window[0]) == Some("state")
                && matches!(window[1].op, Instruction::LoadSmallInt { .. })
                && matches!(window[2].op, Instruction::BinaryOp { .. })
        });
        assert!(
            body_update_uses_strong_load,
            "CPython keeps state += 1 load strong after an except-break join, got instructions={:?}",
            f.instructions
        );

        let tail_method_call_uses_strong_load = instructions.windows(2).any(|window| {
            matches!(window[0].op, Instruction::LoadFast { .. })
                && load_name(window[0]) == Some("result")
                && matches!(window[1].op, Instruction::LoadAttr { .. })
        });
        assert!(
            tail_method_call_uses_strong_load,
            "CPython keeps result.sort() receiver strong after an except-break join, got instructions={:?}",
            f.instructions
        );

        let return_uses_strong_load = instructions.windows(2).any(|window| {
            matches!(window[0].op, Instruction::LoadFast { .. })
                && load_name(window[0]) == Some("result")
                && matches!(window[1].op, Instruction::ReturnValue)
        });
        assert!(
            return_uses_strong_load,
            "CPython keeps post-loop result return strong after an except-break join, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn handler_resume_to_loop_header_keeps_loop_header_borrows() {
        let code = compile_exec(
            "\
def f(value, Phrase, get_word, errors, ENDS, DOT):
    phrase = Phrase()
    try:
        token, value = get_word(value)
        phrase.append(token)
    except errors.HeaderParseError:
        phrase.defects.append(errors.InvalidHeaderDefect('bad'))
    while value and value[0] not in ENDS:
        if value[0] == '.':
            phrase.append(DOT)
            phrase.defects.append(errors.ObsoleteHeaderDefect('dot'))
            value = value[1:]
        else:
            token, value = get_word(value)
            phrase.append(token)
    return phrase, value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let load_name = |unit: &CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        let loop_header_uses_borrow = instructions.windows(3).any(|window| {
            matches!(window[0].op, Instruction::LoadFastBorrow { .. })
                && load_name(window[0]) == Some("value")
                && matches!(window[1].op, Instruction::ToBool)
                && matches!(window[2].op, Instruction::PopJumpIfFalse { .. })
        });
        assert!(
            loop_header_uses_borrow,
            "CPython keeps loop-header value test borrowed after a pre-loop handler resumes to that header, got instructions={:?}",
            f.instructions
        );

        let return_pair_uses_borrow = instructions.windows(3).any(|window| {
            matches!(
                window[0].op,
                Instruction::LoadFastBorrowLoadFastBorrow { .. }
            ) && matches!(window[1].op, Instruction::BuildTuple { .. })
                && matches!(window[2].op, Instruction::ReturnValue)
        });
        assert!(
            return_pair_uses_borrow,
            "CPython keeps phrase/value return pair borrowed after a pre-loop handler resumes to the loop header, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn reraising_except_loop_break_tail_keeps_post_loop_borrows() {
        let code = compile_exec(
            "\
def f(flag=1, count=0):
    value = 2
    while value:
        count += 1
        try:
            if flag and value == 1:
                flag -= 1
                break
            value -= 1
            continue
        except:
            raise
    return count > 2 or value != 1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let return_idx = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .expect("missing return");
        let tail = &instructions[return_idx.saturating_sub(12)..return_idx];

        let load_name = |unit: &CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        for name in ["count", "value"] {
            assert!(
                tail.iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })
                        && load_name(unit) == Some(name)),
                "post-loop condition should borrow {name}, got tail={tail:?}"
            );
            assert!(
                !tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })
                        && load_name(unit) == Some(name)),
                "post-loop condition should not deopt {name} to LOAD_FAST, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn try_except_continue_keeps_try_line_nop_before_continue_jump() {
        let code = compile_exec(
            "\
def f(done=False):
    while not done:
        done = True
        try:
            continue
        except:
            done = False
    return done
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        assert!(
            instructions.windows(2).any(|window| matches!(
                window,
                [
                    CodeUnit {
                        op: Instruction::Nop,
                        ..
                    },
                    CodeUnit {
                        op: Instruction::JumpBackward { .. },
                        ..
                    }
                ]
            )),
            "try/except continue should keep CPython-style try-line NOP before continue jump, got instructions={instructions:?}"
        );
    }

    #[test]
    fn for_else_pass_keeps_line_marker_after_pop_iter() {
        let code = compile_exec(
            "\
def f():
    for item in ():
        pass
    else:
        pass
    marker = 1
    return marker
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            instructions.windows(2).any(|window| matches!(
                window,
                [
                    CodeUnit {
                        op: Instruction::PopIter,
                        ..
                    },
                    CodeUnit {
                        op: Instruction::Nop,
                        ..
                    }
                ]
            )),
            "for-else pass should keep CPython-style else-line NOP after POP_ITER, got instructions={instructions:?}"
        );
    }

    #[test]
    fn folded_if_chain_after_previous_chain_keeps_final_elif_line_marker() {
        let code = compile_exec(
            "\
def f():
    if 0: pass
    elif 0: pass
    if 0: pass
    elif 0: pass
    elif 0: pass
    elif 0: pass
    else: pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let nop_count = f
            .instructions
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::Nop))
            .count();

        assert_eq!(
            nop_count, 6,
            "folded if chains should preserve CPython-style line-marker NOPs, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn handler_resume_before_later_loop_keeps_borrowed_tail_loads() {
        let code = compile_exec(
            "\
def f(msg, category):
    s = 'x'
    if msg.line is None:
        try:
            import linecache
            line = linecache.getline(msg.filename, msg.lineno)
        except Exception:
            line = None
            linecache = None
    else:
        line = msg.line
    if line:
        line = line.strip()
        s += '  %s\\n' % line
    if msg.source is not None:
        try:
            import tracemalloc
        except Exception:
            suggest_tracemalloc = False
            tb = None
        else:
            try:
                suggest_tracemalloc = not tracemalloc.is_tracing()
                tb = tracemalloc.get_object_traceback(msg.source)
            except Exception:
                suggest_tracemalloc = False
                tb = None
        if tb is not None:
            for frame in tb:
                s += frame.filename
        elif suggest_tracemalloc:
            s += category
    return s
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let is_borrow_load = |unit: &&bytecode::CodeUnit, name: &str| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            _ => false,
        };

        assert!(
            ops.windows(5).any(|window| {
                is_borrow_load(&window[0], "line")
                    && matches!(window[1].op, Instruction::ToBool)
                    && matches!(window[2].op, Instruction::PopJumpIfFalse { .. })
                    && matches!(window[3].op, Instruction::NotTaken)
                    && is_borrow_load(&window[4], "line")
            }),
            "handler resume before a later independent loop should preserve CPython-style borrowed line loads, got instructions={:?}",
            f.instructions
        );
        assert!(
            ops.windows(2)
                .filter(|window| {
                    is_borrow_load(&window[0], "tracemalloc")
                        && matches!(window[1].op, Instruction::LoadAttr { .. })
                })
                .count()
                >= 2,
            "independent later loop should not deopt tracemalloc loads before the loop, got instructions={:?}",
            f.instructions
        );
        assert!(
            ops.windows(2).any(|window| {
                is_borrow_load(&window[0], "s") && matches!(window[1].op, Instruction::ReturnValue)
            }),
            "final return should keep CPython-style borrowed s load, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn async_early_return_send_tail_uses_strong_load_fast_after_entry() {
        let code = compile_exec(
            "\
class C:
    async def _sock_sendfile_native(self, sock, file, offset, count):
        try:
            fileno = file.fileno()
        except (AttributeError, io.UnsupportedOperation) as err:
            raise exceptions.SendfileNotAvailableError('not a regular file')
        try:
            fsize = os.fstat(fileno).st_size
        except OSError:
            raise exceptions.SendfileNotAvailableError('not a regular file')
        blocksize = count if count else fsize
        if not blocksize:
            return 0
        blocksize = min(blocksize, 0xffff_ffff)
        end_pos = min(offset + count, fsize) if count else fsize
        offset = min(offset, fsize)
        total_sent = 0
        try:
            while True:
                blocksize = min(end_pos - offset, blocksize)
                if blocksize <= 0:
                    return total_sent
                await self._proactor.sendfile(sock, file, offset, blocksize)
                offset += blocksize
                total_sent += blocksize
        finally:
            if total_sent > 0:
                file.seek(offset)
",
        );
        let f = find_code(&code, "_sock_sendfile_native").expect("missing method code");

        let names_for_unit = |unit: &bytecode::CodeUnit| -> Vec<String> {
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    vec![f.varnames[usize::from(var_num.get(arg))].to_string()]
                }
                Instruction::LoadFastLoadFast { var_nums }
                | Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let (left, right) = var_nums.get(arg).indexes();
                    vec![
                        f.varnames[usize::from(left)].to_string(),
                        f.varnames[usize::from(right)].to_string(),
                    ]
                }
                _ => Vec::new(),
            }
        };

        let borrowed_names: Vec<_> = f
            .instructions
            .iter()
            .filter_map(|unit| match unit.op {
                Instruction::LoadFastBorrow { .. }
                | Instruction::LoadFastBorrowLoadFastBorrow { .. } => Some(names_for_unit(unit)),
                _ => None,
            })
            .collect();
        assert_eq!(
            borrowed_names,
            vec![vec!["file".to_owned()]],
            "only the initial file.fileno() receiver should borrow, got instructions={:?}",
            f.instructions
        );

        let has_strong_name = |name: &str| {
            f.instructions.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                ) && names_for_unit(unit).iter().any(|loaded| loaded == name)
            })
        };

        for name in [
            "fileno",
            "count",
            "blocksize",
            "offset",
            "fsize",
            "end_pos",
            "total_sent",
            "file",
            "self",
            "sock",
        ] {
            assert!(
                has_strong_name(name),
                "async early-return send tail should use strong LOAD_FAST for {name}, got instructions={:?}",
                f.instructions
            );
        }
    }

    #[test]
    fn async_with_return_await_after_early_return_keeps_borrow_load_fast() {
        let code = compile_exec(
            "\
async def wait_for(fut, timeout):
    if timeout is not None and timeout <= 0:
        fut = ensure_future(fut)
        if fut.done():
            return fut.result()
        await cancel_and_wait(fut)
        try:
            return fut.result()
        except CancelledError as exc:
            raise TimeoutError from exc
    async with timeout_cm(timeout):
        return await fut
",
        );
        let f = find_code(&code, "wait_for").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let loaded_names = |unit: &bytecode::CodeUnit| -> Vec<String> {
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    vec![f.varnames[usize::from(var_num.get(arg))].to_string()]
                }
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let (left, right) = var_nums.get(arg).indexes();
                    vec![
                        f.varnames[usize::from(left)].to_string(),
                        f.varnames[usize::from(right)].to_string(),
                    ]
                }
                _ => Vec::new(),
            }
        };
        let borrowed_names: Vec<_> = f
            .instructions
            .iter()
            .filter_map(|unit| {
                let names = loaded_names(unit);
                (!names.is_empty()).then_some(names)
            })
            .collect();

        assert!(
            borrowed_names
                .iter()
                .flatten()
                .any(|name| name == "timeout"),
            "CPython preserves borrowed timeout loads in async-with setup, got instructions={:?}",
            f.instructions
        );
        assert!(
            ops.windows(4).any(|window| {
                matches!(window[0].op, Instruction::LoadFastBorrow { .. })
                    && loaded_names(window[0]).iter().any(|name| name == "fut")
                    && matches!(window[1].op, Instruction::LoadAttr { namei }
                        if f.names[usize::try_from(namei.get(OpArg::new(u32::from(u8::from(window[1].arg)))).name_idx()).unwrap()] == "result")
                    && matches!(window[2].op, Instruction::Call { .. })
                    && matches!(window[3].op, Instruction::ReturnValue)
            }),
            "CPython preserves borrowed fut loads for direct try-return method calls, got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn async_nested_try_finally_except_after_await_return_uses_strong_loads() {
        let code = compile_exec(
            "\
async def f(a, b, c, h):
    try:
        try:
            await sleep(1)
        finally:
            h()
    except E:
        pass
    await sleep(0)
    return a, b, c
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let return_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .expect("missing return");
        let tail = &ops[return_idx.saturating_sub(4)..return_idx];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                )
            }),
            "nested try/finally inside try/except leaves CPython's empty normal-exit block before the next await, so return loads stay strong, got tail={tail:?}",
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "nested try/finally inside try/except should not borrow final return loads, got tail={tail:?}",
        );
    }

    #[test]
    fn async_conditional_raise_finally_except_after_await_return_uses_strong_pair() {
        let code = compile_exec(
            "\
async def f(self, asyncio, sys, task, timeout_handle, sleep):
    timed_out = False
    structured_block_finished = False
    outer_code_reached = False
    try:
        try:
            await asyncio.sleep(sleep)
            structured_block_finished = True
        finally:
            timeout_handle.cancel()
            if (
                timed_out
                and task.uncancel() == 0
                and type(sys.exception()) is asyncio.CancelledError
            ):
                raise TimeoutError
    except TimeoutError:
        self.assertTrue(timed_out)
    outer_code_reached = True
    await asyncio.sleep(0)
    return timed_out, structured_block_finished, outer_code_reached
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let return_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .expect("missing return");
        let tail = &ops[return_idx.saturating_sub(5)..return_idx];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastLoadFast { .. })),
            "conditional-raise finally inside try/except should keep CPython-style strong final return pair after await, got tail={tail:?}",
        );
        assert!(
            tail.iter()
                .all(|unit| !matches!(unit.op, Instruction::LoadFastBorrowLoadFastBorrow { .. })),
            "conditional-raise finally inside try/except should not borrow final return pair after await, got tail={tail:?}",
        );
    }

    #[test]
    fn try_else_attribute_probe_end_allows_following_loads_borrow() {
        let code = compile_exec(
            "\
def f(self):
    args = (1,)
    try:
        getstate = self.__getstate__
    except AttributeError:
        dict = None
    else:
        dict = getstate()
    if dict:
        return args, dict
    return args
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let pair_arg = {
            let args = f
                .varnames
                .iter()
                .position(|name| name == "args")
                .and_then(|idx| u8::try_from(idx).ok())
                .expect("missing args local");
            let dict = f
                .varnames
                .iter()
                .position(|name| name == "dict")
                .and_then(|idx| u8::try_from(idx).ok())
                .expect("missing dict local");
            (args << 4) | dict
        };
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            ops.iter().any(|unit| matches!(
                unit.op,
                Instruction::LoadFastBorrowLoadFastBorrow { .. }
            ) && u8::from(unit.arg) == pair_arg),
            "CPython 3.14 optimize_load_fast() borrows args/dict after the try/else attribute-probe end; got ops={ops:?}",
        );
    }

    #[test]
    fn protected_import_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(s, size, pos, errors):
    message = 'x'
    look = pos
    try:
        import unicodedata
    except ImportError:
        return None
    if look < size and chr(s[look]) == '{':
        while look < size and chr(s[look]) != '}':
            look += 1
        if look > pos + 1 and look < size and chr(s[look]) == '}':
            message = 'y'
    return message
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let import_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let protected_tail = &ops[import_idx + 1..];

        assert!(
            !protected_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected protected import tail to keep strong LOAD_FAST ops, got tail={protected_tail:?}"
        );

        assert!(
            protected_tail
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastLoadFast { .. })),
            "expected protected import tail to keep LOAD_FAST_LOAD_FAST ops, got tail={protected_tail:?}"
        );
    }

    #[test]
    fn nested_protected_import_tail_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(self, mode, compresslevel):
    try:
        try:
            import zlib
        except ImportError:
            raise RuntimeError from None
        self.zlib = zlib
        self.crc = zlib.crc32(b'')
        if mode == 'r':
            self.exception = zlib.error
            self._init_read_gz()
        else:
            self._init_write_gz(compresslevel)
    except:
        self.closed = True
        raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let import_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let nested_protected_tail = &ops[import_idx + 1..handler_start];

        assert!(
            !nested_protected_tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "CPython keeps strong LOAD_FAST ops after a nested protected import tail, got tail={nested_protected_tail:?}"
        );
        assert!(
            nested_protected_tail
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastLoadFast { .. })),
            "expected nested protected import tail to keep LOAD_FAST_LOAD_FAST, got tail={nested_protected_tail:?}"
        );
    }

    #[test]
    fn unprotected_import_before_with_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, document):
    from xml.etree import ElementInclude
    document = self.xinclude_loader('C1.xml')
    with self.assertRaises(OSError) as cm:
        ElementInclude.include(document, self.xinclude_loader)
    self.assertEqual(str(cm.exception), 'resource not found')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let import_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let handler_start = ops
            .iter()
            .position(|op| matches!(op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &ops[import_idx + 1..handler_start];

        assert!(
            warm_path.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected unprotected import before with-block to keep LOAD_FAST_BORROW ops, got warm_path={warm_path:?}"
        );
        assert!(
            warm_path
                .iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrowLoadFastBorrow { .. })),
            "expected with body arguments to keep LOAD_FAST_BORROW_LOAD_FAST_BORROW, got warm_path={warm_path:?}"
        );
    }

    #[test]
    fn from_import_after_conditional_store_join_uses_strong_prefix_loads() {
        let code = compile_exec(
            "\
def f(x):
    if x is None:
        x = 'a'
    y = x.rpartition('.')[0]
    from pkgutil import get_importer
    return y
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let import_from_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ImportFrom { .. }))
            .expect("missing IMPORT_FROM");
        let rpartition_idx = ops[..import_from_idx]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "rpartition"
                }
                _ => false,
            })
            .expect("missing rpartition LOAD_ATTR");

        assert!(
            matches!(ops[rpartition_idx - 1].op, Instruction::LoadFast { .. }),
            "CPython optimize_load_fast() keeps the conditional-store join receiver strong before IMPORT_FROM, got ops={ops:?}"
        );
    }

    #[test]
    fn plain_import_after_conditional_store_join_keeps_borrow_prefix_loads() {
        let code = compile_exec(
            "\
def f(x):
    if x is None:
        x = 'a'
    y = x.rpartition('.')[0]
    import pkgutil
    return y
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let import_name_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ImportName { .. }))
            .expect("missing IMPORT_NAME");
        let rpartition_idx = ops[..import_name_idx]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "rpartition"
                }
                _ => false,
            })
            .expect("missing rpartition LOAD_ATTR");

        assert!(
            matches!(
                ops[rpartition_idx - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "plain import after conditional-store join should keep CPython-style borrowed receiver, got ops={ops:?}"
        );
    }

    #[test]
    fn unprotected_prefix_before_try_keeps_attr_subscript_borrow() {
        let code = compile_exec(
            "\
def f():
    import sys, getopt
    usage = f'usage: {sys.argv[0]}'
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'h')
    except getopt.error as msg:
        sys.stdout = sys.stderr
        print(msg)
        print(usage)
        sys.exit(2)
    return usage
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let first_argv_idx = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "argv"
                }
                _ => false,
            })
            .expect("missing argv attr load");
        let receiver = f.instructions[..first_argv_idx]
            .iter()
            .rev()
            .find(|unit| !matches!(unit.op, Instruction::Cache))
            .expect("missing argv receiver")
            .op;

        assert!(
            matches!(receiver, Instruction::LoadFastBorrow { .. }),
            "unprotected prefix before try should keep CPython-style LOAD_FAST_BORROW receiver, got {receiver:?}"
        );
    }

    #[test]
    fn terminal_except_inlined_comprehension_keeps_borrowed_warm_loads() {
        let code = compile_exec(
            r##"
def f(output):
    output = re.sub(r"\[[0-9]+ refs\]", "", output)
    try:
        result = [
            row.split("\t")
            for row in output.splitlines()
            if row and not row.startswith('#')
        ]
        result.sort(key=lambda row: int(row[0]))
        result = [row[1] for row in result]
        return "\n".join(result)
    except (IndexError, ValueError):
        raise AssertionError(
            "tracer produced unparsable output:\n{}".format(output)
        )
"##,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let handler_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &f.instructions[..handler_start];
        let load_fast_name = |unit: &bytecode::CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let borrow_name = |unit: &bytecode::CodeUnit| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        assert!(
            warm_path
                .iter()
                .filter_map(load_fast_name)
                .all(|name| name != "row" && name != "result"),
            "terminal-except inlined comprehension warm path should keep CPython-style borrowed row/result loads, got warm_path={warm_path:?}"
        );
        for name in ["row", "result"] {
            assert!(
                warm_path
                    .iter()
                    .filter_map(borrow_name)
                    .any(|var| var == name),
                "expected borrowed {name} load in terminal-except inlined comprehension warm path, got warm_path={warm_path:?}"
            );
        }
    }

    #[test]
    fn outer_guarded_protected_import_keeps_borrow_tail() {
        let code = compile_exec(
            "\
def f(sys, os, file):
    if sys.platform == 'win32':
        try:
            import nt
            if not nt._supports_virtual_terminal():
                return False
        except (ImportError, AttributeError):
            return False
    try:
        return os.isatty(file.fileno())
    except OSError:
        return hasattr(file, 'isatty') and file.isatty()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let borrows_name = |name: &str| {
            f.instructions.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
                }
                _ => false,
            })
        };

        for name in ["nt", "os", "file"] {
            assert!(
                borrows_name(name),
                "outer-guarded protected import should keep CPython-style borrow for {name}, got instructions={:?}",
                f.instructions
            );
        }
    }

    #[test]
    fn loop_or_break_continue_orders_break_before_backedge() {
        let code = compile_exec(
            "\
def f(self, quoted):
    while True:
        if self.state == 'x':
            if self.token or (self.posix and quoted):
                break
            else:
                continue
        elif self.state == 'y':
            self.consume()
    x = self.a + self.b + self.c
    return x
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let quoted_load = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == "quoted"
                }
                _ => false,
            })
            .expect("missing quoted LOAD_FAST_BORROW");
        let final_cond = ops[quoted_load + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| quoted_load + 1 + idx)
            .expect("missing final conditional jump");
        assert!(
            matches!(ops[final_cond].op, Instruction::PopJumpIfFalse { .. }),
            "expected CPython-style inverted final condition, got ops={ops:?}"
        );
        let break_jump_idx = ops[final_cond + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpForward { .. }))
            .map(|idx| final_cond + 1 + idx)
            .expect("missing break jump after condition");
        let jump_back_idx = ops[final_cond + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| final_cond + 1 + idx)
            .expect("missing continue backedge");
        assert!(
            break_jump_idx < jump_back_idx,
            "expected break jump before continue backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn backward_jump_extended_arg_accounts_for_jump_cache() {
        let mut source = String::from("def f(x, items):\n    while x:\n");
        for _ in 0..10 {
            source.push_str("        x = len(items[-1])\n");
        }
        for _ in 0..6 {
            source.push_str("        len(items)\n");
        }
        source.push_str("        continue\n");

        let code = compile_exec(&source);
        let f = find_code(&code, "f").expect("missing f code");
        assert!(
            f.instructions.windows(2).any(|window| {
                matches!(
                    (&window[0].op, &window[1].op),
                    (
                        Instruction::ExtendedArg,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. }
                    )
                )
            }),
            "CPython assemble.c resolves unconditional jumps before jump offsets, so the first offset pass must include JUMP_BACKWARD's inline cache and emit EXTENDED_ARG at this boundary; got instructions={:?}",
            f.instructions
        );
    }

    #[test]
    fn for_continue_before_return_orders_backedge_before_return_body() {
        let code = compile_exec(
            "\
def f(self):
    for version in AllowedVersions:
        if not version in self.capabilities:
            continue
        self.PROTOCOL_VERSION = version
        return
    raise self.error('x')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let contains_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ContainsOp { .. }))
            .expect("missing containment test");
        let cond_idx = ops[contains_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| contains_idx + 1 + idx)
            .expect("missing conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style condition targeting the return body, got ops={ops:?}"
        );

        let backedge_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing continue backedge");
        let store_attr_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreAttr { namei } => {
                    let namei = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(namei).unwrap()].as_str() == "PROTOCOL_VERSION"
                }
                _ => false,
            })
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing PROTOCOL_VERSION store");
        assert!(
            backedge_idx < store_attr_idx,
            "expected continue backedge before return body, got ops={ops:?}"
        );
    }

    #[test]
    fn while_conditional_return_orders_backedge_before_return_body() {
        let code = compile_exec(
            "\
def f(self, tag):
    while self._get_response():
        if self.tagged_commands[tag]:
            return tag
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let subscript_idx = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::BinaryOp { .. }))
            .expect("missing tagged_commands subscript");
        let cond_idx = ops[subscript_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| subscript_idx + 1 + idx)
            .expect("missing conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style condition targeting return body, got ops={ops:?}"
        );
        let backedge_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing loop backedge");
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing return");
        assert!(
            backedge_idx < return_idx,
            "expected loop backedge before return body, got ops={ops:?}"
        );
    }

    #[test]
    fn while_boolop_conditional_return_splits_backedges_before_return_body() {
        let code = compile_exec(
            "\
def f(flags, A, B, stop):
    while True:
        if stop:
            break
        if flags & A and flags & B:
            return None
    return flags
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(12).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::BinaryOp { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "boolop conditional return in a while tail should split CPython-style false backedges before the return body, got ops={ops:?}"
        );
    }

    #[test]
    fn for_break_to_return_orders_backedge_before_return() {
        let code = compile_exec(
            "\
def f(it):
    best = 10
    body = None
    for prio, part in it:
        if prio < best:
            best = prio
            body = part
            if prio == 0:
                break
    return body
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .filter(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .nth(1)
            .map(|(idx, _)| idx)
            .expect("missing break comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing break conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style true jump to break return path, got ops={ops:?}"
        );
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing loop backedge before break return");
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing break return path");
        assert!(
            jump_back_idx < return_idx,
            "expected loop backedge before break return block, got ops={ops:?}"
        );
    }

    #[test]
    fn for_conditional_raise_orders_backedge_before_raise() {
        let code = compile_exec(
            "\
def f(items, limit):
    found = 0
    for item in items:
        if item:
            found += 1
            if found >= limit:
                raise ValueError(found)
    return found
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .find(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .map(|(idx, _)| idx)
            .expect("missing raise comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing raise conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style true jump to raise path, got ops={ops:?}"
        );
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing loop backedge before raise");
        let raise_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing raise path");
        assert!(
            jump_back_idx < raise_idx,
            "expected loop backedge before conditional raise block, got ops={ops:?}"
        );
    }

    #[test]
    fn simple_for_conditional_raise_orders_backedge_before_raise() {
        let code = compile_exec(
            "\
def f(kw):
    for k in ('stdout', 'check'):
        if k in kw:
            raise ValueError(f'{k} argument not allowed, it will be overridden.')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style true jump to raise path after loop backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "unexpected conditional raise body before loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_nested_boolop_exit_keeps_cpython_backedge_line_order() {
        let code = compile_exec(
            "\
def f(found, value, m, done, name, renamed_variables, keep_unresolved, variables):
    for _ in [0]:
        if m is not None:
            if found:
                if '$' in value:
                    done[name] = value
                else:
                    try:
                        value = int(value)
                    except ValueError:
                        done[name] = value.strip()
                    else:
                        done[name] = value
                    variables.remove(name)
                    if name.startswith('PY_') \\
                    and name[3:] in renamed_variables:
                        name = name[3:]
                        if name not in done:
                            done[name] = value
        else:
            if keep_unresolved:
                done[name] = value
            variables.remove(name)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops_lines: Vec<_> = f
            .instructions
            .iter()
            .zip(&f.locations)
            .filter_map(|(unit, (location, _))| {
                (!matches!(unit.op, Instruction::Cache)).then_some((unit.op, location.line.get()))
            })
            .collect();

        assert!(
            ops_lines.windows(9).any(|window| {
                matches!(
                    window,
                    [
                        (Instruction::StoreSubscr, 19),
                        (Instruction::JumpBackward { .. }, 19),
                        (Instruction::JumpBackward { .. }, 18),
                        (Instruction::JumpBackward { .. }, 16),
                        (Instruction::JumpBackward { .. }, 15),
                        (Instruction::JumpBackward { .. }, 4),
                        (
                            Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                            21
                        ),
                        (Instruction::ToBool, 21),
                        (Instruction::PopJumpIfFalse { .. }, 21),
                    ]
                )
            }),
            "expected CPython-style nested boolop backedge line order before enclosing else, got ops_lines={ops_lines:?}"
        );
    }

    #[test]
    fn loop_conditional_raise_before_elif_keeps_raise_before_backedge() {
        let code = compile_exec(
            "\
def f(checks, missing, named):
    for check in checks:
        if check == 1:
            if missing:
                raise ValueError('x')
        elif check is named:
            pass
    return checks
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadGlobal { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "expected CPython-style false edge into raise body before following elif chain, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                    ]
                )
            }),
            "unexpected loop backedge before conditional raise body in if/elif chain, got ops={ops:?}"
        );
    }

    #[test]
    fn protected_for_is_none_raise_threads_backedge_before_raise() {
        let code = compile_exec(
            "\
def f(stacklevel, frame, skip_file_prefixes):
    try:
        for x in range(stacklevel - 1):
            frame = _next_external_frame(frame, skip_file_prefixes)
            if frame is None:
                raise ValueError
    except ValueError:
        frame = None
    return frame
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::PopJumpIfNone { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected protected is-None raise path to match CPython's backedge-before-raise layout, got ops={ops:?}"
        );
    }

    #[test]
    fn exception_handler_loop_conditional_raise_orders_backedge_before_raise() {
        let code = compile_exec(
            "\
def f(chunk, dec, i):
    try:
        for c in chunk:
            acc = dec[c]
    except TypeError:
        for j, c in enumerate(chunk):
            if dec[c] is None:
                raise ValueError('%d' % (i + j)) from None
        raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::BinaryOp { .. },
                        Instruction::PopJumpIfNone { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "expected exception-handler loop false path to jump back before raise body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::BinaryOp { .. },
                        Instruction::PopJumpIfNotNone { .. },
                        Instruction::NotTaken,
                        Instruction::LoadGlobal { .. },
                    ]
                )
            }),
            "unexpected exception-handler loop raise body before backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn exception_handler_loop_conditional_return_orders_backedge_before_return() {
        let code = compile_exec(
            "\
def f(cls, value):
    try:
        return cls[value]
    except TypeError:
        for name, values in cls.items():
            if value in values:
                return cls[name]
        for name, member in cls.items():
            if value == member.value:
                return cls[name]
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastLoadFast { .. }
                            | Instruction::LoadFastBorrowLoadFastBorrow { .. },
                    ]
                )
            }),
            "expected exception-handler loop false path to jump back before return body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastLoadFast { .. }
                            | Instruction::LoadFastBorrowLoadFastBorrow { .. },
                    ]
                )
            }),
            "unexpected exception-handler loop return body before backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_if_body_keeps_fallthrough_before_implicit_continue_backedge() {
        let code = compile_exec(
            "\
def f(b, curr, curr_append, decoded_append, packI, curr_clear):
    for x in b:
        if 33 <= x <= 117:
            curr_append(x)
            if len(curr) == 5:
                acc = 0
                for x in curr:
                    acc = 85 * acc + (x - 33)
                decoded_append(packI(acc))
                curr_clear()
        elif x == 122:
            decoded_append(0)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadSmallInt { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "expected CPython-style conditional body fallthrough before implicit continue backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::StoreFast { .. },
                    ]
                )
            }),
            "unexpected inverted conditional with implicit continue backedge before body, got ops={ops:?}"
        );
    }

    #[test]
    fn if_not_continue_before_conditional_listcomp_body_keeps_cpython_layout() {
        let code = compile_exec(
            "\
def f(data, use):
    for line in data:
        line = line.strip()
        if not line:
            continue
        if line.startswith('@'):
            continue
        values = [use(x) for x in line]
        use(values)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "if-not continue should keep CPython's forward true edge over the continue backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn chained_compare_continue_does_not_duplicate_cleanup_backedge() {
        let code = compile_exec(
            "\
def f(items):
    offsets = []
    ranges = [(0, 10), (20, 30)]
    for item in items:
        trans_time, offset_before, offset_after = item
        for dt_min, dt_max in ranges:
            if trans_time is not None and not (dt_min <= trans_time <= dt_max):
                continue
            if offset_before not in offsets:
                offsets.append(offset_before)
            if offset_after not in offsets:
                offsets.append(offset_after)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. }
                            | Instruction::LoadFast { .. }
                            | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::ContainsOp { .. }
                            | Instruction::LoadFastBorrow { .. }
                            | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "chained-compare continue cleanup should fall through to the following body after one backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(3).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopTop,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "chained-compare continue cleanup should not duplicate the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_loop_if_body_keeps_cpython_fallthrough_before_backedge() {
        let code = compile_exec(
            "\
def f(self, ready, selector, key, input_view, os, BrokenPipeError):
    for key, events in ready:
        if key.fileobj is self.stdin:
            chunk = input_view[self._input_offset:self._input_offset + 1]
            try:
                self._input_offset += os.write(key.fd, chunk)
            except BrokenPipeError:
                selector.unregister(key.fileobj)
                key.fileobj.close()
            else:
                if self._input_offset >= len(input_view):
                    selector.unregister(key.fileobj)
                    key.fileobj.close()
        elif key.fileobj in (self.stdout, self.stderr):
            self.read(key)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "expected CPython-style try-else if body fallthrough before loop backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "unexpected inverted try-else conditional with loop backedge before body, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_after_conditional_raise_keeps_loop_if_body_before_backedge() {
        let code = compile_exec(
            "\
def f(seq, flag, stat, OSError, pred, SpecialFileError):
    for i in seq:
        try:
            st = stat(i)
        except OSError:
            pass
        else:
            if pred(st.mode):
                raise SpecialFileError(i)
            if flag and i == 0:
                x = st.real
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::StoreFast { .. },
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "try-else tail after conditional raise should keep CPython body-before-backedge layout, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "try-else tail should not invert the inner condition before its body, got ops={ops:?}"
        );
    }

    #[test]
    fn explicit_continue_after_return_orders_return_before_backedge() {
        let code = compile_exec(
            "\
def f(j, n):
    while j < n:
        if j < 0:
            return j
        continue
    return -1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .filter(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .nth(1)
            .map(|(idx, _)| idx)
            .expect("missing inner comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfFalse { .. }),
            "expected CPython-style false jump to explicit continue, got ops={ops:?}"
        );
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing return path");
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing explicit continue backedge");
        assert!(
            return_idx < jump_back_idx,
            "expected return block before explicit continue backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn while_break_tail_does_not_duplicate_loop_false_return_epilogue() {
        let code = compile_exec(
            "\
def f(waiters):
    while waiters:
        waiter = waiters.popleft()
        if not waiter.done():
            waiter.set_result(None)
            break
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let returns = ops
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::ReturnValue))
            .count();
        assert_eq!(
            returns, 2,
            "CPython codegen_while() reuses the empty anchor block for USE_LABEL(end) when orelse is empty, so only the break fallthrough and loop-false epilogues remain, got ops={ops:?}",
        );
    }

    #[test]
    fn implicit_while_tail_return_orders_backedge_before_return() {
        let code = compile_exec(
            "\
def f(self, j, n):
    while j < n:
        name, j = self.scan(j)
        if j < 0:
            return j
    return -1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .filter(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .nth(1)
            .map(|(idx, _)| idx)
            .expect("missing inner comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style true jump to return, got ops={ops:?}"
        );
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing implicit backedge");
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing return path");
        assert!(
            jump_back_idx < return_idx,
            "expected implicit loop backedge before return block, got ops={ops:?}"
        );
    }

    #[test]
    fn branch_arm_implicit_continue_keeps_return_before_backedge() {
        let code = compile_exec(
            "\
def f(self, j, n, c):
    while j < n:
        if c == 'x':
            j = self.step(j)
            if j < 0:
                return j
        elif c == 'y':
            j = j + 1
    return -1
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .filter(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .nth(2)
            .map(|(idx, _)| idx)
            .expect("missing branch-arm return comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing branch-arm conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfFalse { .. }),
            "expected CPython-style false jump to branch-arm continuation, got ops={ops:?}"
        );
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing branch-arm return path");
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing branch-arm loop backedge");
        assert!(
            return_idx < jump_back_idx,
            "expected branch-arm return before loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_implicit_while_tail_return_orders_backedge_before_return() {
        let code = compile_exec(
            "\
def f(self, rawdata, j, match):
    while 1:
        c = rawdata[j:j + 1]
        if c in \"'\\\"\":
            m = match(rawdata, j)
            if not m:
                return -1
            j = m.end()
        else:
            name, j = self.scan(j)
            if j < 0:
                return j
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let compare_idx = ops
            .iter()
            .enumerate()
            .rfind(|(_, unit)| matches!(unit.op, Instruction::CompareOp { .. }))
            .map(|(idx, _)| idx)
            .expect("missing nested tail comparison");
        let cond_idx = ops[compare_idx + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::PopJumpIfFalse { .. } | Instruction::PopJumpIfTrue { .. }
                )
            })
            .map(|idx| compare_idx + 1 + idx)
            .expect("missing nested tail conditional jump");
        assert!(
            matches!(ops[cond_idx].op, Instruction::PopJumpIfTrue { .. }),
            "expected CPython-style true jump to nested return path, got ops={ops:?}"
        );
        let jump_back_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::JumpBackward { .. }))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing nested tail loop backedge");
        let return_idx = ops[cond_idx + 1..]
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ReturnValue))
            .map(|idx| cond_idx + 1 + idx)
            .expect("missing nested tail return path");
        assert!(
            jump_back_idx < return_idx,
            "expected nested implicit loop backedge before return block, got ops={ops:?}"
        );
    }

    #[test]
    fn join_store_global_before_import_keeps_strong_load_fast() {
        let code = compile_exec(
            "\
def f(module=None):
    global ET
    if module is None:
        module = pyET
    ET = module
    from xml.etree import ElementPath
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFast { .. },
                        Instruction::StoreGlobal { .. },
                    ]
                )
            }),
            "expected CPython-style strong LOAD_FAST before join STORE_GLOBAL followed by import, got ops={ops:?}"
        );
    }

    #[test]
    fn handler_resume_join_keeps_borrow_in_common_tail() {
        let code = compile_exec(
            "\
def f(p, errors, s, pos, look, final, escape_start, st):
    try:
        chr_codec = unicodedata.lookup('%s' % st)
    except LookupError as e:
        x = unicode_call_errorhandler(
            errors, 'unicodeescape', 'unknown Unicode character name', s, pos - 1, look + 1
        )
    else:
        x = chr_codec, look + 1
    p.append(x[0])
    pos = x[1]
    if not final:
        pos = escape_start
        return p, pos
    return unicode_call_errorhandler(
        errors, 'unicodeescape', 'unknown Unicode character name', s, pos - 1, look + 1
    )
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let append_idx = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "append"
                }
                _ => false,
            })
            .expect("missing append tail");
        let tail: Vec<_> = f.instructions[append_idx.saturating_sub(1)..]
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            matches!(
                tail.as_slice(),
                [
                    Instruction::LoadFastBorrow { .. },
                    Instruction::LoadAttr { .. },
                    Instruction::LoadFastBorrow { .. },
                    ..,
                ]
            ),
            "expected handler resume common tail to start with borrowed append receiver/arg loads, got tail={tail:?}"
        );
        assert!(
            tail.iter().any(|op| {
                matches!(
                    op,
                    Instruction::LoadFastBorrowLoadFastBorrow { .. }
                        | Instruction::LoadFastBorrow { .. }
                )
            }),
            "expected handler resume common tail to keep borrowed LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn multi_handler_guarded_resume_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(a):
    try:
        g()
    except ValueError:
        pass
    except TypeError:
        pass
    if a:
        return a.x
    return 0
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. },
                    ]
                )
            }),
            "expected guarded resume tail to keep borrowed guard/body loads, got ops={ops:?}"
        );
        assert!(
            ops.windows(2).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::LoadAttr { .. }
                    ]
                )
            }),
            "expected guarded resume tail attr access to keep borrowed receiver, got ops={ops:?}"
        );
    }

    #[test]
    fn multi_handler_method_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, xs):
    for vals, expected in xs:
        try:
            actual = g(vals)
        except OverflowError:
            self.fail(expected)
        except ValueError:
            self.fail(expected)
        self.assertEqual(actual, expected)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        let assert_equal_idx = ops
            .iter()
            .position(|op| matches!(op, Instruction::LoadAttr { .. }))
            .expect("missing assertEqual LOAD_ATTR");
        let tail = &ops[assert_equal_idx.saturating_sub(1)..];

        assert!(
            matches!(tail.first(), Some(Instruction::LoadFastBorrow { .. })),
            "expected multi-handler method-call tail receiver to keep LOAD_FAST_BORROW, got tail={tail:?}"
        );
        assert!(
            tail.iter()
                .any(|op| matches!(op, Instruction::LoadFastBorrow { .. })),
            "expected multi-handler method-call tail args to keep borrowed loads, got tail={tail:?}"
        );
    }

    #[test]
    fn named_except_cleanup_loop_header_keeps_borrow_in_for_loop() {
        let code = compile_exec(
            "\
def f(args):
    for arg in args:
        try:
            _wm._setoption(arg)
        except _wm._OptionError as msg:
            print('Invalid -W option ignored:', msg, file=sys.stderr)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let attr_idx = f
            .instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "_setoption"
                }
                _ => false,
            })
            .expect("missing _setoption attr load");
        let window: Vec<_> = f.instructions[attr_idx + 1..]
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .take(3)
            .collect();
        assert!(
            matches!(
                window.as_slice(),
                [
                    Instruction::LoadFastBorrow { .. },
                    Instruction::Call { .. },
                    Instruction::PopTop
                ]
            ),
            "expected loop body call to keep borrowed arg load after named-except cleanup, got window={window:?}"
        );
    }

    #[test]
    fn multi_named_except_loop_header_keeps_borrow_for_normal_path() {
        let code = compile_exec(
            "\
def f(self):
    for badval in ['illegal', -1, 1 << 32]:
        class A:
            def __len__(self):
                return badval
        try:
            bool(A())
        except (Exception) as e_bool:
            try:
                len(A())
            except (Exception) as e_len:
                self.assertEqual(str(e_bool), str(e_len))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(4).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadBuildClass,
                        Instruction::PushNull,
                        Instruction::LoadFastBorrow { .. },
                        Instruction::BuildTuple { .. },
                    ]
                )
            }),
            "expected class closure setup in loop header to borrow badval, got ops={ops:?}"
        );
        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrow { .. },
                        Instruction::PushNull,
                        Instruction::Call { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "expected normal bool(A()) path in loop header to borrow A, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_cleanup_simple_resume_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        1 / 0
    except Exception as e:
        tb = e.__traceback__
    self.get_disassemble_as_string(tb.tb_frame.f_code, tb.tb_lasti)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let attr_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "get_disassemble_as_string"
                }
                _ => false,
            })
            .expect("missing LOAD_ATTR for get_disassemble_as_string");
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();
        assert!(
            matches!(
                ops.get(attr_idx - 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "expected named-except resume tail to keep borrowed self load, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.get(attr_idx + 4),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "expected named-except resume tail to keep borrowed tb load, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_cleanup_conditional_raise_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self):
    try:
        output = self.trace()
        output = output.strip()
    except (A, B, C) as fnfe:
        output = str(fnfe)
    if output != 'probe: success':
        raise E('{} {}'.format(self.command[0], output))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let raise_idx = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::RaiseVarargs { .. }))
            .expect("missing conditional raise");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[..handler_start.min(raise_idx)];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "named-except cleanup conditional raise tail should keep borrowed loads, got tail={tail:?}"
        );
        assert!(
            !tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "named-except cleanup conditional raise tail should not force strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn with_suppress_named_except_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, cm, E):
    try:
        with cm:
            pass
    except E as e:
        frames = e
    self.x(frames)
    self.y(frames)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_tail_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "x"
                }
                _ => false,
            })
            .expect("missing x attr load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[first_tail_attr.saturating_sub(1)..handler_start];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected with-suppress/named-except resume tail to use strong LOAD_FAST, got tail={tail:?}"
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected with-suppress/named-except resume tail not to borrow, got tail={tail:?}"
        );
    }

    #[test]
    fn with_named_except_return_value_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, b, BlockingIOError):
    with self._write_lock:
        written = len(self._write_buf)
        if len(self._write_buf) > self.buffer_size:
            try:
                self._flush_unlocked()
            except BlockingIOError as e:
                if len(self._write_buf) > self.buffer_size:
                    overage = len(self._write_buf) - self.buffer_size
                    written -= overage
                    raise BlockingIOError(e.errno, e.strerror, written)
        return written
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let with_exit_start = instructions
            .windows(3)
            .position(|window| {
                matches!(
                    window,
                    [
                        CodeUnit {
                            op: Instruction::Swap { .. },
                            ..
                        },
                        CodeUnit {
                            op: Instruction::Swap { .. },
                            ..
                        },
                        CodeUnit {
                            op: Instruction::LoadConst { .. },
                            ..
                        },
                    ]
                )
            })
            .expect("missing with-exit cleanup");
        let return_value_load = instructions
            .get(with_exit_start.saturating_sub(1))
            .expect("missing return value load");
        let arg = OpArg::new(u32::from(u8::from(return_value_load.arg)));

        assert!(
            matches!(
                return_value_load.op,
                Instruction::LoadFastBorrow { var_num }
                    if f.varnames[usize::from(var_num.get(arg))] == "written"
            ),
            "return value loaded through with-exit cleanup should keep borrowed written, got instructions={instructions:?}"
        );
    }

    #[test]
    fn with_final_conditional_return_preserves_fallthrough_cleanup_nop() {
        let code = compile_exec(
            "\
def f(self):
    with self.lock:
        if self.raw is None or self.closed:
            return
    self.flush()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "with fallthrough cleanup should preserve the CPython POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn with_while_fallthrough_preserves_cleanup_nop() {
        let code = compile_exec(
            "\
def f(cm, source):
    with cm as out:
        s = source.read()
        while s:
            out.write(s)
            s = source.read()
    source.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "with cleanup after while fallthrough should preserve the CPython POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn with_for_fallthrough_drops_cleanup_nop() {
        let code = compile_exec(
            "\
def f(cm, xs, g):
    with cm:
        for x in xs:
            g(x)
    return None
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "with cleanup after for fallthrough should directly follow END_FOR/POP_ITER like CPython, got ops={ops:?}"
        );
        assert!(
            !ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::EndFor,
                        Instruction::PopIter,
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "with cleanup after for fallthrough should not preserve a POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn with_while_true_break_drops_cleanup_nop() {
        let code = compile_exec(
            "\
def f(cm, source):
    with cm as out:
        while True:
            data = source.read()
            if not data:
                break
            out.write(data)
    source.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "with cleanup after while True break should not preserve a POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn multi_with_while_true_try_except_drops_outer_cleanup_nop() {
        let code = compile_exec(
            "\
def f(cm1, cm2, g, E):
    with cm1, cm2:
        while True:
            try:
                g()
            except E:
                pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "outer with cleanup after an infinite inner with body should follow the inner cleanup directly like CPython, got ops={ops:?}"
        );
        assert!(
            !ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Copy { .. },
                        Instruction::PopExcept,
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "outer with cleanup after an infinite inner with body should not keep a POP_BLOCK NOP, got ops={ops:?}"
        );
    }

    #[test]
    fn with_final_assert_preserves_cleanup_nop() {
        let code = compile_exec(
            "\
def f(cm, dst):
    with cm:
        assert not dst.closed
    return dst
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .map(|unit| unit.op)
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "with cleanup after a final assert should preserve CPython's POP_BLOCK NOP anchor, got ops={ops:?}"
        );
    }

    #[test]
    fn named_except_conditional_reraise_final_store_attr_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, fd, file, closefd, owned_fd, OSError, AttributeError, errno, os, stat, _setmode):
    try:
        self._closefd = closefd
        self._stat_atopen = os.fstat(fd)
        try:
            if stat.S_ISDIR(self._stat_atopen.st_mode):
                raise IsADirectoryError(errno.EISDIR, os.strerror(errno.EISDIR), file)
        except AttributeError:
            pass
        if _setmode:
            _setmode(fd, os.O_BINARY)
        self.name = file
        if self._appending:
            try:
                os.lseek(fd, 0, SEEK_END)
            except OSError as e:
                if e.errno != errno.ESPIPE:
                    raise
    except:
        self._stat_atopen = None
        if owned_fd is not None:
            os.close(owned_fd)
        raise
    self._fd = fd
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let load_attr_name = |unit: &&bytecode::CodeUnit, expected: &str| match unit.op {
            Instruction::LoadAttr { namei } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let load_attr = namei.get(arg);
                f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == expected
            }
            _ => false,
        };
        let lseek_attr = instructions
            .iter()
            .position(|unit| load_attr_name(unit, "lseek"))
            .expect("missing lseek load");
        let store_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreAttr { namei } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.names[usize::try_from(namei.get(arg)).unwrap()].as_str() == "_fd"
                }
                _ => false,
            })
            .expect("missing _fd store");

        assert!(
            matches!(
                instructions
                    .get(lseek_attr.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "nested conditional reraise try body should keep borrowed os receiver, got instructions={instructions:?}"
        );
        assert!(
            matches!(
                instructions.get(lseek_attr + 1).map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "nested conditional reraise try body should keep borrowed fd argument, got instructions={instructions:?}"
        );
        assert!(
            matches!(
                instructions
                    .get(store_attr.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrowLoadFastBorrow { .. })
            ),
            "conditional reraise named-except final store tail should keep borrowed pair loads, got instructions={instructions:?}"
        );
    }

    #[test]
    fn with_except_else_with_resume_loop_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, cm, E):
    with cm:
        try:
            g()
        except E:
            pass
        else:
            with self.z(E):
                h()
        for _ in support.sleeping_retry(support.SHORT_TIMEOUT, 'not ready'):
            if self.x:
                break
        self.y()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let get_iter = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::GetIter))
            .expect("missing loop iterator");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[get_iter.saturating_sub(1)..handler_start];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected with except/else-with resume loop tail to use strong LOAD_FAST ops, got tail={tail:?}"
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "with except/else-with resume loop tail should not borrow LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn final_with_try_except_resume_loop_tail_uses_strong_loads() {
        let code = compile_exec(
            r#"
def f(resources, valid_zones, TZPATH, os):
    try:
        with resources.open("r") as f:
            pass
    except Exception:
        pass
    for tz_root in TZPATH:
        if not os.path.exists(tz_root):
            continue
        valid_zones.add(tz_root)
    return valid_zones
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let get_iter = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::GetIter))
            .expect("missing post-try loop iterator");
        let tail = &instructions[get_iter.saturating_sub(1)..];
        let load_fast_name = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let borrowed_name = |unit: &&bytecode::CodeUnit| match unit.op {
            Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };

        for name in ["TZPATH", "os", "tz_root", "valid_zones"] {
            assert!(
                tail.iter()
                    .filter_map(load_fast_name)
                    .any(|loaded| loaded == name),
                "expected CPython-style strong LOAD_FAST for {name} after final with/except resume, got tail={tail:?}",
            );
            assert!(
                tail.iter()
                    .filter_map(borrowed_name)
                    .all(|loaded| loaded != name),
                "final with/except resume loop tail should not borrow {name}, got tail={tail:?}",
            );
        }
    }

    #[test]
    fn finally_ending_try_except_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            r#"
def f(self, fobj, unlink, TESTFN, C):
    try:
        fobj.write(1)
    finally:
        fobj.close()
        try:
            unlink(TESTFN)
        except OSError:
            pass
    a, b = C(2), C(3)
    self.assertEqual((a, b), (1, 2))
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let assert_equal = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "assertEqual"
                }
                _ => false,
            })
            .expect("missing assertEqual load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing exception path");
        let tail = &instructions[assert_equal.saturating_sub(1)..handler_start];
        let is_strong_pair = |unit: &&bytecode::CodeUnit, left_name: &str, right_name: &str| {
            let Instruction::LoadFastLoadFast { var_nums } = unit.op else {
                return false;
            };
            let arg = OpArg::new(u32::from(u8::from(unit.arg)));
            let (left, right) = var_nums.get(arg).indexes();
            f.varnames[usize::from(left)] == left_name
                && f.varnames[usize::from(right)] == right_name
        };

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected finally/try-except resume tail to use strong LOAD_FAST ops, got tail={tail:?}"
        );
        assert!(
            tail.iter().any(|unit| is_strong_pair(unit, "a", "b")),
            "expected finally/try-except resume tuple to use strong LOAD_FAST_LOAD_FAST, got tail={tail:?}"
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "finally/try-except resume tail should not borrow LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn try_finally_bare_reraise_handler_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, os, alive_r, alive_w, address, pid):
    try:
        pid = g()
    except:
        os.close(alive_w)
        raise
    finally:
        os.close(alive_r)
    self.address = address
    self.alive_w = alive_w
    self.pid = pid
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let close_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "close"
                }
                _ => false,
            })
            .expect("missing close load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing exception path");
        let tail = &instructions[close_attr.saturating_sub(1)..handler_start];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "bare-reraise try/finally resume tail should use strong LOAD_FAST ops, got tail={tail:?}"
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "bare-reraise try/finally resume tail should not borrow LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn typed_except_return_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(resource, desired_fds, max_fds):
    try:
        import math
    except ImportError:
        return None
    fd_limit = resource.getrlimit(resource.RLIMIT_NOFILE)
    if fd_limit < desired_fds and fd_limit < max_fds:
        return desired_fds, max_fds
    return fd_limit
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let getrlimit_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "getrlimit"
                }
                _ => false,
            })
            .expect("missing getrlimit load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing exception path");
        let tail = &instructions[getrlimit_attr.saturating_sub(1)..handler_start];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "typed except-return resume tail should use strong LOAD_FAST ops, got tail={tail:?}"
        );
        assert!(
            tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "typed except-return resume tail should not borrow LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn resuming_except_before_try_preserves_next_try_entry_barrier() {
        let code = compile_exec(
            "\
def f(scan_once, s, end, _ws, _w):
    try:
        if s[end] in _ws:
            end = _w(s, end + 1).end()
    except IndexError:
        pass
    try:
        value, end = scan_once(s, end)
    except StopIteration as err:
        raise ValueError(s, err.value) from None
    return value, end
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let scan_once_load = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))].as_str() == "scan_once"
                }
                _ => false,
            })
            .expect("missing scan_once load");
        let scan_tail = &instructions[scan_once_load..scan_once_load + 4];

        assert!(
            scan_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                )
            }),
            "resuming except before another try should enter next try with strong LOAD_FAST ops, got scan_tail={scan_tail:?}"
        );
        assert!(
            scan_tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "resuming except before another try should not borrow next try entry loads, got scan_tail={scan_tail:?}"
        );
    }

    #[test]
    fn simple_except_before_try_keeps_next_try_entry_borrowed() {
        let code = compile_exec(
            "\
def f(scan_once, s, end):
    try:
        g(s, end)
    except IndexError:
        pass
    try:
        value, end = scan_once(s, end)
    except StopIteration:
        pass
    return value, end
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let scan_once_load = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))].as_str() == "scan_once"
                }
                _ => false,
            })
            .expect("missing scan_once load");
        let scan_tail = &instructions[scan_once_load..scan_once_load + 4];

        assert!(
            scan_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "simple except before another try should keep next try entry borrowed, got scan_tail={scan_tail:?}"
        );
        assert!(
            !scan_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                )
            }),
            "simple except before another try should not force strong LOAD_FAST, got scan_tail={scan_tail:?}"
        );
    }

    #[test]
    fn loop_break_except_before_try_preserves_next_try_entry_barrier() {
        let code = compile_exec(
            "\
def f(scan_once, seq1, seq2, n):
    for i in range(n):
        try:
            item1 = seq1[i]
        except (TypeError, IndexError, NotImplementedError):
            break
        try:
            item2 = seq2[i]
        except (TypeError, IndexError, NotImplementedError):
            break
    return item1, item2
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let second_subscript = instructions
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::BinaryOp { op }
                        if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                            == oparg::BinaryOperator::Subscr
                )
            })
            .expect("missing first subscript");
        let second_subscript = instructions[second_subscript + 1..]
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::BinaryOp { op }
                        if op.get(OpArg::new(u32::from(u8::from(unit.arg))))
                            == oparg::BinaryOperator::Subscr
                )
            })
            .map(|idx| idx + second_subscript + 1)
            .expect("missing second subscript");
        let scan_tail = &instructions[second_subscript.saturating_sub(2)..second_subscript];

        assert!(
            scan_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                )
            }),
            "loop break except before another try should keep next try entry strong, got scan_tail={scan_tail:?}"
        );
        assert!(
            !scan_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "loop break except before another try should not borrow next try entry loads, got scan_tail={scan_tail:?}"
        );
    }

    #[test]
    fn plain_with_then_global_loop_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, cm):
    with cm:
        self.x()
    for value in ITEMS:
        self.y(value)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let y_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "y"
                }
                _ => false,
            })
            .expect("missing y attr load");

        assert!(
            matches!(
                instructions
                    .get(y_attr.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "plain with/global-loop tail should keep CPython-style borrowed self load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn context_manager_for_join_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, factory):
    with factory() as e:
        executor = e
        self.x(e)
    for t in executor._threads:
        t.join()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let join_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "join"
                }
                _ => false,
            })
            .expect("missing join attr load");

        assert!(
            matches!(
                instructions
                    .get(join_attr.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "context-manager for-join tail should keep CPython-style borrowed t load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn with_except_resume_normal_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, cm, E):
    try:
        with self.assertRaises(E):
            with cm:
                h()
    except TimeoutError:
        self._fail_on_deadlock(cm)
    cm.shutdown(wait=True)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let shutdown_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "shutdown"
                }
                _ => false,
            })
            .expect("missing shutdown attr load");

        assert!(
            matches!(
                instructions
                    .get(shutdown_attr.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFast { .. })
            ),
            "with/except resume normal tail should keep CPython-style strong cm load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn with_except_else_attr_subscript_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, cm, E, obj):
    try:
        with cm:
            pass
    except E as exc:
        self.x(exc)
    else:
        self.fail('Expected')
    inner = obj.saved_details[1]
    self.x(inner)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let saved_details = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "saved_details"
                }
                _ => false,
            })
            .expect("missing saved_details attr load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[saved_details.saturating_sub(1)..handler_start];

        assert!(
            tail.iter().any(|unit| matches!(
                unit.op,
                Instruction::LoadFastBorrow { .. }
                    | Instruction::LoadFastBorrowLoadFastBorrow { .. }
            )),
            "expected except-else attr-subscript tail to keep borrowed LOAD_FAST ops, got tail={tail:?}"
        );
        assert!(
            tail.iter()
                .all(|unit| !matches!(unit.op, Instruction::LoadFast { .. })),
            "except-else attr-subscript tail should not be deoptimized to strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn with_suppress_attr_subscript_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, cm):
    stack = self.exit_stack()
    with self.assertRaisesRegex(TypeError, 'the context manager'):
        stack.enter_context(cm)
    stack.push(cm)
    self.assertIs(stack._exit_callbacks[-1][1], cm)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let exit_callbacks = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "_exit_callbacks"
                }
                _ => false,
            })
            .expect("missing _exit_callbacks attr load");

        assert!(
            matches!(
                instructions
                    .get(exit_callbacks.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "with-suppress attr-subscript tail should keep CPython-style borrowed stack load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn named_except_conditional_reraise_deopts_with_chain_tail() {
        let code = compile_exec(
            "\
def f(self, arc, tmp_filename, new_mode):
    try:
        os.chmod(tmp_filename, new_mode)
    except OSError as exc:
        if exc.errno == ERR:
            self.skipTest()
        else:
            raise
    with self.check_context(arc.open(), 'fully_trusted'):
        self.expect_file('a')
    with self.check_context(arc.open(), 'tar'):
        self.expect_file('b')
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_check_context = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "check_context"
                }
                _ => false,
            })
            .expect("missing check_context load");
        let first_handler = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .unwrap_or(instructions.len());
        let warm_tail = &instructions[first_check_context.saturating_sub(1)..first_handler];

        assert!(
            warm_tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected conditional named-except reraise tail to use strong LOAD_FAST ops, got tail={warm_tail:?}"
        );
        assert!(
            warm_tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "expected all warm with-chain tail loads to stay strong after named-except reraise, got tail={warm_tail:?}"
        );
    }

    #[test]
    fn terminal_bare_reraise_successor_join_keeps_final_store_borrow() {
        let code = compile_exec(
            "\
def f(self, fd, appending, errno):
    try:
        if appending:
            try:
                seek(fd)
            except OSError as e:
                if e.errno != errno:
                    raise
    except:
        self.stat = None
        raise
    self._fd = fd
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let store_fd = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreAttr { namei } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.names[usize::try_from(namei.get(arg)).unwrap()].as_str() == "_fd"
                }
                _ => false,
            })
            .expect("missing _fd STORE_ATTR");

        assert!(
            matches!(
                instructions[store_fd - 1].op,
                Instruction::LoadFastBorrowLoadFastBorrow { .. }
            ),
            "terminal bare-reraise body successor join should keep CPython-style borrowed final store pair, got instructions={instructions:?}"
        );
    }

    #[test]
    fn terminal_except_before_with_deopts_with_body_borrows() {
        let code = compile_exec(
            "\
def f(self, cm):
    try:
        g()
    except OSError:
        raise Exception('skip')
    with cm:
        self.x()
        self.y()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_tail_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "x"
                }
                _ => false,
            })
            .expect("missing x attr load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let with_tail = &instructions[first_tail_attr.saturating_sub(1)..handler_start];

        assert!(
            with_tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected terminal-except before with to use strong LOAD_FAST ops, got tail={with_tail:?}"
        );
        assert!(
            with_tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "terminal-except before with should not borrow protected with body loads, got tail={with_tail:?}"
        );
    }

    #[test]
    fn terminal_except_resume_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(re, proc, unittest):
    try:
        version = proc.communicate()
    except OSError:
        raise unittest.SkipTest('x')
    match = re.search('pat', version)
    if match is None:
        raise unittest.SkipTest(f'Unable to parse readelf version: {version}')
    return int(match.group(1)), int(match.group(2))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let search_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "search"
                }
                _ => false,
            })
            .expect("missing re.search attr load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[search_attr.saturating_sub(1)..handler_start];

        let strong_loads_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                Instruction::LoadFastLoadFast { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
                }
                _ => false,
            })
        };
        let borrows_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
                }
                _ => false,
            })
        };

        for name in ["re", "version", "match"] {
            assert!(
                strong_loads_name(name),
                "terminal-except resume tail should use strong LOAD_FAST for {name}, got tail={tail:?}"
            );
            assert!(
                !borrows_name(name),
                "terminal-except resume tail should not borrow {name}, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn terminal_except_conditional_return_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(param, value, quote):
    try:
        value.encode('ascii')
    except UnicodeEncodeError:
        return param
    if quote:
        return param
    return value
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let quote_idx = instructions[..handler_start]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == "quote"
                }
                _ => false,
            })
            .expect("missing quote guard load");
        let tail = &instructions[quote_idx..handler_start];

        let strong_loads_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };
        let borrows_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };

        for name in ["quote", "param", "value"] {
            assert!(
                strong_loads_name(name),
                "terminal-except conditional tail should use strong LOAD_FAST for {name}, got tail={tail:?}"
            );
            assert!(
                !borrows_name(name),
                "terminal-except conditional tail should not borrow {name}, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn terminal_except_successor_call_tail_uses_strong_load() {
        let code = compile_exec(
            "\
def f(curr, decoded_append, packI, curr_clear, Error):
    if len(curr) == 5:
        acc = 0
        for x in curr:
            acc = 85 * acc + (x - 33)
        try:
            decoded_append(packI(acc))
        except Error:
            raise ValueError('overflow') from None
        curr_clear()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let curr_clear_load = instructions[..handler_start]
            .iter()
            .rev()
            .find(|unit| match unit.op {
                Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == "curr_clear"
                }
                _ => false,
            })
            .expect("missing curr_clear load");

        assert!(
            matches!(curr_clear_load.op, Instruction::LoadFast { .. }),
            "terminal except successor call tail should use strong LOAD_FAST for curr_clear, got instructions={instructions:?}"
        );
    }

    #[test]
    fn loop_terminal_except_continue_if_tail_keeps_borrowed_loads() {
        let code = compile_exec(
            "\
def f(self, parser, opt, accum, rest, section, map, path, depth):
    while rest:
        rawval = rest.pop()
        try:
            if len(path) == 1:
                opt = parser.optionxform(path[0])
                v = map[opt]
            elif len(path) == 2:
                sect = path[0]
                opt = parser.optionxform(path[1])
                v = parser.get(sect, opt, raw=True)
            else:
                raise InterpolationSyntaxError(option, section, 'x')
        except (KeyError, NoSectionError, NoOptionError):
            raise InterpolationMissingOptionError(option, section, rawval, ':'.join(path)) from None
        if v is None:
            continue
        if '$' in v:
            self._interpolate_some(parser, opt, accum, v, sect, dict(parser.items(sect, raw=True)), depth + 1)
        else:
            accum.append(v)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &ops[..handler_start];
        let post_try_if = warm_path
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PopJumpIfNotNone { .. }))
            .expect("missing post-try if");
        let tail = &warm_path[post_try_if.saturating_sub(1)..];

        let mentions_name = |unit: &CodeUnit, name: &str| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            Instruction::LoadFastLoadFast { var_nums }
            | Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
            }
            _ => false,
        };
        let borrows_name = |name: &str| {
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                ) && mentions_name(unit, name)
            })
        };
        let strong_loads_name = |name: &str| {
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
                ) && mentions_name(unit, name)
            })
        };

        for name in ["v", "self", "parser", "opt", "accum", "depth"] {
            assert!(
                borrows_name(name),
                "CPython keeps loop terminal-except continue-if tail borrowed for {name}, got tail={tail:?}"
            );
            assert!(
                !strong_loads_name(name),
                "loop terminal-except continue-if tail should not deopt {name}, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn method_call_try_return_handler_keeps_following_receiver_borrowed() {
        let code = compile_exec(
            "\
def f(charset, failobj, E):
    try:
        charset.encode('us-ascii')
    except E:
        return failobj
    return charset.lower()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let lower_attr = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "lower"
                }
                _ => false,
            })
            .expect("missing lower attr");
        let receiver = &ops[lower_attr - 1];

        assert!(
            matches!(receiver.op, Instruction::LoadFastBorrow { .. }),
            "CPython codegen_try_except() does not leave a load-fast barrier after method-call try body when the handler returns, got ops={ops:?}"
        );
    }

    #[test]
    fn typed_terminal_method_call_try_deopts_successor_call_args() {
        let code = compile_exec(
            "\
def f(events, callback, args, self, sig, signal):
    try:
        signal.set_wakeup_fd(self._csock.fileno())
    except ValueError:
        raise RuntimeError('bad signal') from None
    handle = events.Handle(callback, args, self, None)
    self._signal_handlers[sig] = handle
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handle_store = ops
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::StoreFast { var_num }
                        if f.varnames[usize::from(
                            var_num.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        )] == "handle"
                )
            })
            .expect("missing handle store");
        let handle_call_window = &ops[handle_store.saturating_sub(4)..handle_store];

        assert!(
            matches!(
                handle_call_window,
                [
                    bytecode::CodeUnit {
                        op: Instruction::LoadFastLoadFast { .. },
                        ..
                    },
                    bytecode::CodeUnit {
                        op: Instruction::LoadFast { .. },
                        ..
                    },
                    bytecode::CodeUnit {
                        op: Instruction::LoadConst { .. },
                        ..
                    },
                    bytecode::CodeUnit {
                        op: Instruction::Call { .. },
                        ..
                    },
                ]
            ),
            "CPython codegen_try_except() leaves a USE_LABEL(end) continuation after the terminal typed handler; successor call args should be strong loads, got window={handle_call_window:?}; ops={ops:?}"
        );
    }

    #[test]
    fn typed_terminal_unpack_call_try_deopts_successor_call_args() {
        let code = compile_exec(
            "\
def f(self, OSError):
    try:
        request, client_address = self.get_request()
    except OSError:
        return
    if self.verify_request(request, client_address):
        self.process_request(request, client_address)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let verify_attr = ops
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.names[usize::try_from(namei.get(arg).name_idx()).unwrap()].as_str()
                        == "verify_request"
                }
                _ => false,
            })
            .expect("missing verify_request attr");
        let request_pair = &ops[verify_attr + 1];

        assert!(
            matches!(
                request_pair.op,
                Instruction::LoadFastLoadFast { var_nums }
                    if {
                        let arg = OpArg::new(u32::from(u8::from(request_pair.arg)));
                        let pair = var_nums.get(arg).as_u32();
                        f.varnames[(pair >> 4) as usize].as_str() == "request"
                            && f.varnames[(pair & 0xF) as usize].as_str() == "client_address"
                    }
            ),
            "CPython codegen_try_except() keeps successor call args strong after terminal typed unpack-call try body, got ops={ops:?}"
        );
    }

    #[test]
    fn terminal_except_following_if_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(s):
    try:
        t = s[1:]
        d = g(s)
    except ValueError:
        raise ValueError('bad') from None
    if t:
        try:
            a, b, c = h(t)
        except ValueError:
            raise ValueError('bad') from None
        else:
            if b:
                x, y, z = d
                if y <= 12 and z <= q(x, y):
                    z += 1
                d = [x, y, z]
    else:
        a = [0]
    return k(*(d + a))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail_start = ops
            .iter()
            .position(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num }
                        if f.varnames[usize::from(
                            var_num.get(OpArg::new(u32::from(u8::from(unit.arg))))
                        )] == "t"
                )
            })
            .expect("missing post-try t load");
        let tail = &ops[tail_start..handler_start];

        assert!(
            !tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "terminal except following conditional tail should use CPython-style strong LOAD_FAST ops, got tail={tail:?}"
        );
    }

    #[test]
    fn bare_except_internal_condition_keeps_try_body_borrows() {
        let code = compile_exec(
            "\
def f(buffering, raw, binary, result, BufferedReader):
    try:
        line_buffering = False
        if buffering == 1 or buffering < 0 and raw._isatty_open_only():
            buffering = -1
            line_buffering = True
        if buffering < 0:
            buffering = max(min(raw._blksize, 8192 * 1024), 8192)
        if buffering < 0:
            raise ValueError('invalid buffering size')
        if buffering == 0:
            if binary:
                return result
            raise ValueError(\"can't have unbuffered text I/O\")
        buffer = BufferedReader(raw, buffering)
        result = buffer
        if binary:
            return result
        return result
    except:
        result.close()
        raise
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &ops[..handler_start];

        let borrows_name = |name: &str| {
            warm_path.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
                }
                _ => false,
            })
        };
        let strong_loads_name = |name: &str| {
            warm_path.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                Instruction::LoadFastLoadFast { var_nums } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    let (left, right) = var_nums.get(arg).indexes();
                    f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
                }
                _ => false,
            })
        };

        for name in ["buffering", "raw", "binary", "result", "BufferedReader"] {
            assert!(
                borrows_name(name),
                "CPython keeps {name} borrowed inside the same bare-except protected region, got warm_path={warm_path:?}"
            );
            assert!(
                !strong_loads_name(name),
                "same protected-region conditional tail should not be terminal-except deoptimized for {name}, got warm_path={warm_path:?}"
            );
        }
    }

    #[test]
    fn try_except_else_terminal_handler_conditional_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, pos, whence):
    try:
        pos_index = pos.__index__
    except AttributeError:
        raise TypeError(f'{pos!r} is not an integer')
    else:
        pos = pos_index()
    if whence == 0:
        if pos < 0:
            raise ValueError(f'negative {pos!r}')
        self._pos = pos
    elif whence == 1:
        self._pos = max(0, self._pos + pos)
    return self._pos
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &ops[..handler_start];

        let op_mentions_name = |unit: &CodeUnit, name: &str| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            Instruction::LoadFastLoadFast { var_nums }
            | Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                f.varnames[usize::from(left)] == name || f.varnames[usize::from(right)] == name
            }
            _ => false,
        };
        let is_borrow_for_name = |unit: &CodeUnit, name: &str| match unit.op {
            Instruction::LoadFastBorrow { .. }
            | Instruction::LoadFastBorrowLoadFastBorrow { .. } => op_mentions_name(unit, name),
            _ => false,
        };
        let is_strong_for_name = |unit: &CodeUnit, name: &str| match unit.op {
            Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. } => {
                op_mentions_name(unit, name)
            }
            _ => false,
        };

        assert!(
            warm_path
                .iter()
                .any(|unit| is_borrow_for_name(unit, "pos_index")),
            "try-else call should remain borrowed before the terminal-handler tail, got warm_path={warm_path:?}"
        );

        let tail_start = warm_path
            .iter()
            .position(|unit| {
                is_strong_for_name(unit, "whence") || is_borrow_for_name(unit, "whence")
            })
            .expect("missing post-try conditional tail");
        let post_try_tail = &warm_path[tail_start..];
        for name in ["whence", "pos", "self"] {
            assert!(
                post_try_tail
                    .iter()
                    .any(|unit| is_strong_for_name(unit, name)),
                "terminal except conditional tail should use strong loads for {name}, got tail={post_try_tail:?}"
            );
            assert!(
                !post_try_tail
                    .iter()
                    .any(|unit| is_borrow_for_name(unit, name)),
                "terminal except conditional tail should not borrow {name}, got tail={post_try_tail:?}"
            );
        }
    }

    #[test]
    fn try_except_else_outer_join_keeps_borrowed_loads() {
        let code = compile_exec(
            "\
def f(self, pos=None):
    if self.closed:
        raise ValueError('closed')
    if pos is None:
        pos = self._pos
    else:
        try:
            pos_index = pos.__index__
        except AttributeError:
            raise TypeError(f'{pos!r} is not an integer')
        else:
            pos = pos_index()
        if pos < 0:
            raise ValueError(f'negative {pos!r}')
    del self._buffer[pos:]
    return pos
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = ops
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let warm_path = &ops[..handler_start];

        let mentions_name = |unit: &CodeUnit, name: &str| match unit.op {
            Instruction::LoadFast { var_num }
            | Instruction::LoadFastBorrow { var_num }
            | Instruction::StoreFast { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                f.varnames[usize::from(var_num.get(arg))] == name
            }
            _ => false,
        };
        let else_store = warm_path
            .iter()
            .position(|unit| {
                matches!(unit.op, Instruction::StoreFast { .. }) && mentions_name(unit, "pos")
            })
            .expect("missing try-else pos store");
        let delete_subscr = warm_path
            .iter()
            .position(|unit| matches!(unit.op, Instruction::DeleteSubscr))
            .expect("missing join delete");
        let else_tail = &warm_path[else_store + 1..delete_subscr];

        assert!(
            else_tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })
                    && mentions_name(unit, "pos")),
            "terminal try-else conditional should use strong pos loads, got tail={else_tail:?}"
        );

        let join_tail = &warm_path[delete_subscr.saturating_sub(6)..];
        for name in ["self", "pos"] {
            assert!(
                join_tail
                    .iter()
                    .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })
                        && mentions_name(unit, name)),
                "outer if/else join should keep borrowed {name} loads, got tail={join_tail:?}"
            );
        }
        assert!(
            !join_tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })
                    && (mentions_name(unit, "self") || mentions_name(unit, "pos"))),
            "outer if/else join should not inherit terminal try-else deopts, got tail={join_tail:?}"
        );
    }

    #[test]
    fn terminal_except_else_final_store_attr_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, E, Event):
    try:
        decoded = bytes(self.buf).decode(self.encoding)
    except E:
        return
    else:
        self.insert(Event('key', decoded, self.flush_buf()))
    self.keymap = self.compiled_keymap
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let store_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::StoreAttr { namei } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.names[usize::try_from(namei.get(arg)).unwrap()].as_str() == "keymap"
                }
                _ => false,
            })
            .expect("missing keymap STORE_ATTR");
        let insert_attr_idx = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "insert"
                }
                _ => false,
            })
            .expect("missing insert LOAD_ATTR");

        assert!(
            matches!(
                instructions[insert_attr_idx - 1].op,
                Instruction::LoadFastBorrow { .. }
            ),
            "terminal except should not deopt the try/else method receiver before the final tail, got instructions={instructions:?}"
        );
        assert!(
            matches!(
                (
                    instructions[store_idx - 3].op,
                    instructions[store_idx - 1].op
                ),
                (Instruction::LoadFast { .. }, Instruction::LoadFast { .. })
            ),
            "terminal except final STORE_ATTR tail should use CPython-style strong LOAD_FAST ops, got instructions={instructions:?}"
        );
    }

    #[test]
    fn except_break_try_else_loop_tail_keeps_else_borrows() {
        let code = compile_exec(
            "\
def f(self):
    self.setup()
    prompt = 'Hit Return for more, or q (and Return) to quit: '
    lineno = 0
    while 1:
        try:
            for i in range(lineno, lineno + self.MAXLINES):
                print(self.lines[i])
        except IndexError:
            break
        else:
            lineno += self.MAXLINES
            key = None
            while key is None:
                key = input(prompt)
                if key not in ('', 'q'):
                    key = None
            if key == 'q':
                break
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let borrowed_loads = instructions
            .iter()
            .filter(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            })
            .count();
        let strong_loads_in_else_tail = instructions.iter().any(|unit| {
            matches!(
                unit.op,
                Instruction::LoadFast { .. } | Instruction::LoadFastLoadFast { .. }
            )
        });

        assert!(
            borrowed_loads >= 7,
            "except-break try/else loop tail should keep CPython-style borrowed loads, got instructions={instructions:?}"
        );
        assert!(
            !strong_loads_in_else_tail,
            "except-break try/else loop tail must not be deoptimized as terminal return/raise, got instructions={instructions:?}"
        );
    }

    #[test]
    fn protected_method_call_after_terminal_except_tail_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(items, chunk, out, packI, Error):
    for i in items:
        acc = 0
        try:
            for c in chunk:
                acc = acc * 85 + c
        except TypeError:
            raise
        try:
            out.append(packI(acc))
        except Error:
            raise ValueError from None
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let append_attr = instructions[..handler_start]
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "append"
                }
                _ => false,
            })
            .expect("missing append LOAD_ATTR");
        let tail = &instructions[append_attr.saturating_sub(1)..handler_start];

        let strong_loads_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFast { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };
        let borrows_name = |name: &str| {
            tail.iter().any(|unit| match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                    f.varnames[usize::from(var_num.get(arg))] == name
                }
                _ => false,
            })
        };

        for name in ["out", "packI", "acc"] {
            assert!(
                strong_loads_name(name),
                "protected method-call after terminal except tail should use strong LOAD_FAST for {name}, got tail={tail:?}"
            );
            assert!(
                !borrows_name(name),
                "protected method-call after terminal except tail should not borrow {name}, got tail={tail:?}"
            );
        }
    }

    #[test]
    fn terminal_reraising_handler_keeps_try_body_method_borrows() {
        let code = compile_exec(
            "\
def f(self):
    try:
        self.console.prepare()
        self.arg = None
        self.finished = False
        del self.buffer[:]
        self.pos = 0
        self.dirty = True
        self.last_command = None
        self.calc_screen()
    except BaseException:
        self.restore()
        raise
    while self.scheduled_commands:
        cmd = self.scheduled_commands.pop()
        self.do_cmd((cmd, []))
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_handler = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let try_body = &instructions[..first_handler];
        let self_borrows = try_body
            .iter()
            .filter(|unit| {
                matches!(unit.op, Instruction::LoadFastBorrow { var_num }
                    if f.varnames[usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))))]
                        == "self")
            })
            .count();

        assert!(
            self_borrows >= 8,
            "terminal reraising handler should keep try-body self loads borrowed, got try_body={try_body:?}"
        );
    }

    #[test]
    fn terminal_except_loop_successor_augassign_uses_strong_load_pair() {
        let code = compile_exec(
            "\
def f(items, decoded, b32rev):
    for i in range(0, len(items), 8):
        quanta = items[i:i + 8]
        acc = 0
        try:
            for c in quanta:
                acc = (acc << 5) + b32rev[c]
        except KeyError:
            raise ValueError from None
        decoded += acc.to_bytes(5)
    return decoded
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let to_bytes_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "to_bytes"
                }
                _ => false,
            })
            .expect("missing to_bytes LOAD_ATTR");
        let pair = instructions[to_bytes_attr.saturating_sub(1)].op;

        assert!(
            matches!(pair, Instruction::LoadFastLoadFast { .. }),
            "terminal-except loop successor augassign should use strong LOAD_FAST_LOAD_FAST, got instructions={instructions:?}"
        );
    }

    #[test]
    fn terminal_except_loop_backedge_keeps_header_borrows() {
        let code = compile_exec(
            "\
def f(self, value, start=0, stop=None):
    i = start
    while stop is None or i < stop:
        try:
            v = self[i]
        except IndexError:
            break
        if v is value or v == value:
            return i
        i += 1
    raise ValueError
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            instructions.windows(7).any(|window| {
                matches!(window[0].op, Instruction::StoreFast { .. })
                    && matches!(window[1].op, Instruction::LoadFastBorrow { .. })
                    && matches!(window[2].op, Instruction::PopJumpIfNone { .. })
                    && matches!(window[3].op, Instruction::NotTaken)
                    && matches!(
                        window[4].op,
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                    )
                    && matches!(window[5].op, Instruction::CompareOp { .. })
                    && matches!(window[6].op, Instruction::PopJumpIfFalse { .. })
            }),
            "terminal-except loop backedge deopt should not cross into the loop header, got instructions={instructions:?}"
        );
    }

    #[test]
    fn one_line_protected_infinite_while_body_uses_strong_pair() {
        let code = compile_exec(
            "\
def f():
    items = range(1, 4)
    try:
        i = 0
        while 1: i = items[i]
    except IndexError:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastLoadFast { .. })),
            "one-line protected infinite while body should match CPython strong pair, got instructions={instructions:?}"
        );
        assert!(
            !instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrowLoadFastBorrow { .. })),
            "one-line protected infinite while body should not borrow the loop body pair, got instructions={instructions:?}"
        );
    }

    #[test]
    fn multiline_protected_infinite_while_body_keeps_borrow_pair() {
        let code = compile_exec(
            "\
def f(items):
    try:
        i = 0
        while 1:
            i = items[i]
    except IndexError:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrowLoadFastBorrow { .. })),
            "multiline protected infinite while body should keep CPython borrowed pair, got instructions={instructions:?}"
        );
    }

    #[test]
    fn one_line_protected_infinite_while_method_call_keeps_borrow_receiver() {
        let code = compile_exec(
            "\
def f(self):
    try:
        while 1: self.x()
    except IndexError:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();

        assert!(
            instructions
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "CPython 3.14 keeps the one-line protected bound-method receiver strong, got instructions={instructions:?}"
        );
    }

    #[test]
    fn loop_if_implicit_continue_places_body_after_jumpback() {
        let code = compile_exec(
            "\
def f(_config_vars, _INITPRE):
    for k in list(_config_vars):
        if k.startswith(_INITPRE):
            del _config_vars[k]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::DeleteSubscr,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::EndFor,
                    ]
                )
            }),
            "loop if with implicit continue should use CPython body-after-jumpback layout, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_if_call_body_implicit_continue_places_body_after_jumpback() {
        let code = compile_exec(
            "\
def f(seq, db):
    count = 0
    for c in seq:
        dec = db.value(c, -1)
        if dec != -1:
            db.check(dec, c)
            count += 1
    return count
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::Call { .. },
                    ]
                )
            }),
            "no-else loop call body should use CPython body-after-jumpback layout, got ops={ops:?}"
        );
    }

    #[test]
    fn nested_loop_if_try_body_implicit_continue_places_body_after_jumpback() {
        let code = compile_exec(
            "\
def f(seq, broken, codecs, LookupError, s, Queue, bytes):
    for encoding in seq:
        if encoding not in broken:
            q = Queue(b'')
            writer = codecs.getwriter(encoding)(q)
            encodedresult = b''
            for c in s:
                writer.write(c)
                chunk = q.read()
                encodedresult += chunk
            q = Queue(b'')
            reader = codecs.getreader(encoding)(q)
            decodedresult = ''
            for c in encodedresult:
                q.write(bytes([c]))
                decodedresult += reader.read()
        if encoding not in broken:
            try:
                encoder = codecs.getincrementalencoder(encoding)()
            except LookupError:
                pass
            else:
                encoder.encode('x')
            if encoding not in ('idna', 'mbcs'):
                try:
                    encoder = codecs.getincrementalencoder(encoding)('ignore')
                except LookupError:
                    pass
                else:
                    encodedresult = b''.join(encoder.encode(c) for c in s)
                    decoder = codecs.getincrementaldecoder(encoding)('ignore')
                    decodedresult = ''.join(decoder.decode(bytes([c])) for c in encodedresult)
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(8).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "nested final if with try body should put false backedge before body, got ops={ops:?}"
        );
        assert!(
            !ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::Nop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "nested final if with try body should not leave body before false backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_branch_raise_before_elif_keeps_body_before_backedge() {
        let code = compile_exec(
            "\
def f(checks, UNIQUE, CONTINUOUS, ValueError):
    for check in checks:
        if check is UNIQUE:
            duplicates = []
            for name in checks:
                if name:
                    duplicates.append(name)
            if duplicates:
                detail = ', '.join(str(name) for name in duplicates)
                raise ValueError('aliases: %s' % detail)
        elif check is CONTINUOUS:
            value = 1
    return value
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadConst { .. },
                        Instruction::LoadAttr { .. },
                    ]
                )
            }),
            "raise body before an elif chain should stay before the branch backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "raise body before an elif chain should not be moved after the branch backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_nested_raise_then_append_places_body_after_false_backedge() {
        let code = compile_exec(
            "\
def f(args, parameters, enforce_default_ordering, type_var_tuple_encountered, default_encountered, TypeError):
    for t in args:
        if t not in parameters:
            if enforce_default_ordering:
                if type_var_tuple_encountered and t.has_default():
                    raise TypeError('a')
                if t.has_default():
                    default_encountered = True
                elif default_encountered:
                    raise TypeError('b')
            parameters.append(t)
    return parameters
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "CPython places the nested raise/append body after the false backedge for this loop tail, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::ToBool,
                    ]
                )
            }),
            "this case should not keep the body before the false backedge; CPython emits the split backedge first, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_break_before_adjacent_break_keeps_body_before_backedge() {
        let code = compile_exec(
            "\
def f(pattern, prefix, get_prefix):
    for op, av in pattern:
        if op == 1:
            prefix.append(av)
        elif op == 2:
            prefix1, got_all = get_prefix(av)
            prefix.extend(prefix1)
            if not got_all:
                break
        else:
            break
    else:
        return prefix, True
    return prefix, False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::PopTop,
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::LoadConst { .. },
                        Instruction::BuildTuple { .. },
                    ]
                )
            }),
            "break before an adjacent break exit should stay before the loop backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::PopTop,
                    ]
                )
            }),
            "break before an adjacent break exit should not be moved after the loop backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_elif_and_pass_keeps_shared_false_backedge_after_body() {
        let code = compile_exec(
            "\
def f(methods, simple_keys, checked_keys, checked_enum, simple_enum, failed):
    for method in methods:
        if method in simple_keys and method in checked_keys:
            continue
        elif method not in simple_keys and method not in checked_keys:
            checked_method = getattr(checked_enum, method, None)
            simple_method = getattr(simple_enum, method, None)
            if hasattr(checked_method, '__func__'):
                checked_method = checked_method.__func__
                simple_method = simple_method.__func__
            if checked_method != simple_method:
                failed.append(method)
        else:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(9).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadGlobal { .. },
                        _,
                    ]
                )
            }),
            "elif-and body should stay before the shared false backedge, got ops={ops:?}"
        );
        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "elif-and shared false backedge should not be split before the body, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_nested_if_delete_slice_places_body_after_jumpback() {
        let code = compile_exec(
            "\
def f(compiler_so):
    for idx in reversed(range(len(compiler_so))):
        if compiler_so[idx] == '-arch' and compiler_so[idx + 1] == 'arm64':
            del compiler_so[idx:idx + 2]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(15).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::BinaryOp { .. },
                        Instruction::LoadConst { .. },
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                    ]
                )
            }),
            "nested loop delete-slice condition should put false jump-back before body, got ops={ops:?}"
        );
    }

    #[test]
    fn loop_if_subscr_store_delete_places_body_after_jumpback() {
        let code = compile_exec(
            "\
def f(chunks):
    for k in range(len(chunks)-1, 0, -1):
        if chunks[k-1][-1] > chunks[k][0]:
            chunks[k-1] = chunks[k-1][:-1] + chunks[k][1:]
            del chunks[k]
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::CompareOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::LoadSmallInt { .. },
                        Instruction::BinaryOp { .. },
                    ]
                )
            }),
            "loop if with subscript store/delete body should put false jump-back before body, got ops={ops:?}"
        );
    }

    #[test]
    fn final_elif_implicit_continue_places_jumpback_before_body() {
        let code = compile_exec(
            "\
def f(state, nextchar, whitespace, token, posix, quoted, debug):
    while True:
        if state is None:
            break
        elif state == ' ':
            if not nextchar:
                state = None
                break
            elif nextchar in whitespace:
                if debug >= 2:
                    print('x')
                if token or (posix and quoted):
                    break
                else:
                    continue
        elif state in ('a', 'c'):
            if not nextchar:
                state = None
                break
            elif nextchar in whitespace:
                if debug >= 2:
                    print('y')
                state = ' '
                if token or (posix and quoted):
                    break
                else:
                    continue
    return token
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "final elif with implicit continue should put false jump-back before body, got ops={ops:?}"
        );
    }

    #[test]
    fn final_attribute_elif_implicit_continue_places_jumpback_before_body() {
        let code = compile_exec(
            "\
def f(self, nextchar, quoted):
    while True:
        if self.state is None:
            break
        elif self.state in ('a', 'c'):
            if not nextchar:
                self.state = None
                break
            elif nextchar in self.whitespace:
                self.state = ' '
                if self.token or (self.posix and quoted):
                    break
                else:
                    continue
    return self.token
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(6).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadFastBorrowLoadFastBorrow { .. }
                            | Instruction::LoadFastLoadFast { .. },
                        Instruction::LoadAttr { .. },
                        Instruction::ContainsOp { .. },
                        Instruction::PopJumpIfTrue { .. },
                        Instruction::NotTaken,
                        Instruction::JumpBackward { .. }
                            | Instruction::JumpBackwardNoInterrupt { .. },
                    ]
                )
            }),
            "final attribute elif with implicit continue should put false jump-back before body, got ops={ops:?}"
        );
    }

    #[test]
    fn inner_if_implicit_continue_keeps_line_bearing_body_before_backedge() {
        let code = compile_exec(
            "\
def f(self, nextchar, quoted):
    while True:
        if self.state is None:
            break
        elif self.state in ('a', 'c'):
            if not nextchar:
                self.state = None
                break
            elif nextchar in self.whitespace:
                self.state = ' '
                if self.token or (self.posix and quoted):
                    break
                else:
                    continue
            elif nextchar in self.commenters:
                self.instream.readline()
                self.lineno += 1
                if self.posix:
                    self.state = ' '
                    if self.token or (self.posix and quoted):
                        break
                    else:
                        continue
            elif self.state == 'c':
                break
    return self.token
",
        );
        let f = find_code(&code, "f").expect("missing function code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            ops.windows(7).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::LoadAttr { .. },
                        Instruction::ToBool,
                        Instruction::PopJumpIfFalse { .. },
                        Instruction::NotTaken,
                        Instruction::LoadConst { .. },
                        Instruction::LoadFastBorrow { .. } | Instruction::LoadFast { .. },
                        Instruction::StoreAttr { .. },
                    ]
                )
            }),
            "line-bearing inner if with implicit continue should keep body before backedge, got ops={ops:?}"
        );
    }

    #[test]
    fn except_handler_with_conditional_raise_and_resume_keeps_borrow() {
        let code = compile_exec(
            "\
def f(formatstr, args, output, overflowok):
    try:
        result = formatstr % args
    except OverflowError:
        if not overflowok:
            raise
        print('overflow')
    else:
        if output and result != output:
            raise AssertionError(result, output)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let assertion_error = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadGlobal { namei } => {
                    let load_global = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_global >> 1).unwrap()].as_str() == "AssertionError"
                }
                _ => false,
            })
            .expect("missing AssertionError raise");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let tail = &instructions[..handler_start.min(assertion_error)];

        assert!(
            tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "conditional-raise handler with a resume path should keep borrowed loads, got tail={tail:?}"
        );
        assert!(
            tail.iter()
                .all(|unit| !matches!(unit.op, Instruction::LoadFast { .. })),
            "conditional-raise handler with a resume path should not force strong LOAD_FAST, got tail={tail:?}"
        );
    }

    #[test]
    fn typed_except_resume_import_warning_tail_keeps_borrows() {
        let code = compile_exec(
            r#"
def f(mod_name, error, sys, RuntimeWarning):
    pkg_name, _, _ = mod_name.rpartition(".")
    if pkg_name:
        try:
            __import__(pkg_name)
        except ImportError as e:
            if e.name is None or (e.name != pkg_name and
                    not pkg_name.startswith(e.name + ".")):
                raise
        existing = sys.modules.get(mod_name)
        if existing is not None and not hasattr(existing, "__path__"):
            from warnings import warn
            msg = "{mod_name!r} found in sys.modules after import of " \
                "package {pkg_name!r}, but prior to execution of " \
                "{mod_name!r}; this may result in unpredictable " \
                "behaviour".format(mod_name=mod_name, pkg_name=pkg_name)
            warn(RuntimeWarning(msg))
    return mod_name
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let arg = |unit: &bytecode::CodeUnit| OpArg::new(u32::from(u8::from(unit.arg)));
        let strong_names = |unit: &bytecode::CodeUnit| -> Vec<&str> {
            match unit.op {
                Instruction::LoadFast { var_num } => {
                    vec![f.varnames[usize::from(var_num.get(arg(unit)))].as_str()]
                }
                Instruction::LoadFastLoadFast { var_nums } => {
                    let (left, right) = var_nums.get(arg(unit)).indexes();
                    vec![
                        f.varnames[usize::from(left)].as_str(),
                        f.varnames[usize::from(right)].as_str(),
                    ]
                }
                _ => Vec::new(),
            }
        };
        let borrowed_names = |unit: &bytecode::CodeUnit| -> Vec<&str> {
            match unit.op {
                Instruction::LoadFastBorrow { var_num } => {
                    vec![f.varnames[usize::from(var_num.get(arg(unit)))].as_str()]
                }
                Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                    let (left, right) = var_nums.get(arg(unit)).indexes();
                    vec![
                        f.varnames[usize::from(left)].as_str(),
                        f.varnames[usize::from(right)].as_str(),
                    ]
                }
                _ => Vec::new(),
            }
        };

        let handler_start = f
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let normal_path = &f.instructions[..handler_start];
        for name in ["mod_name", "existing", "warn", "msg"] {
            assert!(
                normal_path
                    .iter()
                    .flat_map(borrowed_names)
                    .any(|borrowed| borrowed == name),
                "CPython keeps {name} borrowed after typed-except resume, got ops={:?}",
                normal_path.iter().map(|unit| unit.op).collect::<Vec<_>>()
            );
            assert!(
                !normal_path
                    .iter()
                    .flat_map(strong_names)
                    .any(|strong| strong == name),
                "typed-except resume should not force strong {name} loads, got ops={:?}",
                normal_path.iter().map(|unit| unit.op).collect::<Vec<_>>()
            );
        }
    }

    #[test]
    fn reraising_except_else_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, data, length):
    if self._paused:
        self._pending_data_length = length
        return
    if length == 0:
        self._eof_received()
        return
    if isinstance(self._protocol, protocols.BufferedProtocol):
        try:
            protocols._feed_data_to_buffered_proto(self._protocol, data)
        except (SystemExit, KeyboardInterrupt):
            raise
        except BaseException as exc:
            self._fatal_error(exc, 'x')
            return
    else:
        self._protocol.data_received(data)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let data_received_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                        == "data_received"
                }
                _ => false,
            })
            .expect("missing data_received LOAD_ATTR");
        let ops: Vec<_> = instructions.iter().map(|unit| unit.op).collect();

        assert!(
            matches!(
                ops.get(data_received_attr - 2),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "normal else tail after reraising handler should keep borrowed self load, got ops={ops:?}"
        );
        assert!(
            matches!(
                ops.get(data_received_attr + 1),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "normal else tail after reraising handler should keep borrowed data load, got ops={ops:?}"
        );
    }

    #[test]
    fn try_else_finally_with_keeps_context_manager_borrow() {
        let code = compile_exec(
            "\
def f(i):
    try:
        1 / 0
    except ZeroDivisionError:
        pass
    else:
        with i as dodgy:
            pass
    finally:
        pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_with_exit = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadSpecial { method } => {
                    method.get(OpArg::new(u32::from(u8::from(unit.arg)))) == SpecialMethod::Exit
                }
                _ => false,
            })
            .expect("missing __exit__ load");

        assert!(
            matches!(
                instructions
                    .get(first_with_exit.saturating_sub(2))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "try/except/else/finally with setup should keep CPython-style borrowed context manager load, got instructions={instructions:?}"
        );
    }

    #[test]
    fn except_star_handler_pop_block_does_not_leave_nop_before_with_exit() {
        let code = compile_exec(
            "\
def f(self):
    with self.assertRaises(TypeError):
        try:
            raise OSError('blah')
        except* ExceptionGroup as e:
            pass
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let ops: Vec<_> = f
            .instructions
            .iter()
            .map(|unit| unit.op)
            .filter(|op| !matches!(op, Instruction::Cache))
            .collect();

        assert!(
            !ops.windows(5).any(|window| {
                matches!(
                    window,
                    [
                        Instruction::Reraise { .. },
                        Instruction::Nop,
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                        Instruction::LoadConst { .. },
                    ]
                )
            }),
            "except* handler cleanup should not leave an extra NOP before with-exit None loads, got ops={ops:?}"
        );
    }

    #[test]
    fn except_star_body_to_else_jump_drops_without_line_nop() {
        let code = compile_exec(
            "\
async def f(self, cm):
    try:
        async with cm:
            pass
    except* Exception:
        pass
    else:
        self.fail()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let fail_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "fail"
                }
                _ => false,
            })
            .expect("missing self.fail load");

        assert!(
            !matches!(
                instructions
                    .get(fail_attr.saturating_sub(2))
                    .map(|unit| unit.op),
                Some(Instruction::Nop)
            ),
            "body-to-else jump should be no-location and disappear, got instructions={instructions:?}"
        );
    }

    #[test]
    fn resuming_except_before_with_keeps_with_body_borrows() {
        let code = compile_exec(
            "\
def f(self, cm):
    try:
        g()
    except OSError:
        pass
    with cm:
        self.x()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let first_tail_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "x"
                }
                _ => false,
            })
            .expect("missing x attr load");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let with_tail = &instructions[first_tail_attr.saturating_sub(1)..handler_start];

        assert!(
            with_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "resuming except before with should keep borrowed LOAD_FAST ops, got tail={with_tail:?}"
        );
    }

    #[test]
    fn nested_finally_except_resume_loop_uses_strong_loads() {
        let code = compile_exec(
            "\
def f(self, xs):
    try:
        try:
            g()
        finally:
            h()
    except OSError:
        self.skipTest('x')
    for x in xs:
        self.x(x)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let for_iter = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ForIter { .. }))
            .expect("missing FOR_ITER");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let loop_tail = &instructions[for_iter.saturating_sub(2)..handler_start];

        assert!(
            loop_tail
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected nested finally/except resume loop to use strong LOAD_FAST ops, got tail={loop_tail:?}"
        );
        assert!(
            loop_tail.iter().all(|unit| {
                !matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "nested finally/except resume loop should not borrow LOAD_FAST ops, got tail={loop_tail:?}"
        );
    }

    #[test]
    fn finally_protected_loop_without_except_resume_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self, obj, expected, buf):
    try:
        lines = obj.readlines()
    except ValueError:
        self.fail('x')
    if lines != expected:
        self.fail('bad')
    obj.close()
    obj = self.open()
    try:
        for line in obj:
            pass
        try:
            obj.readline()
            obj.readinto(buf)
        except ValueError:
            self.fail('inner')
    finally:
        obj.close()
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let get_iter = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::GetIter))
            .expect("missing GET_ITER");
        assert!(
            matches!(
                instructions
                    .get(get_iter.saturating_sub(1))
                    .map(|unit| unit.op),
                Some(Instruction::LoadFastBorrow { .. })
            ),
            "finally-protected loop without except resume should keep borrowed iterable load, got instructions={instructions:?}"
        );

        for attr_name in ["close", "open"] {
            let attr_idx = instructions[..get_iter]
                .iter()
                .rposition(|unit| match unit.op {
                    Instruction::LoadAttr { namei } => {
                        let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                        f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str()
                            == attr_name
                    }
                    _ => false,
                })
                .unwrap_or_else(|| panic!("missing {attr_name} attr load before loop"));
            assert!(
                matches!(
                    instructions
                        .get(attr_idx.saturating_sub(1))
                        .map(|unit| unit.op),
                    Some(Instruction::LoadFastBorrow { .. })
                ),
                "pre-loop {attr_name} call should keep borrowed receiver load, got instructions={instructions:?}"
            );
        }
    }

    #[test]
    fn plain_except_resume_loop_keeps_borrows() {
        let code = compile_exec(
            "\
def f(self, xs):
    try:
        g()
    except OSError:
        self.skipTest('x')
    for x in xs:
        self.x(x)
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let for_iter = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::ForIter { .. }))
            .expect("missing FOR_ITER");
        let handler_start = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::PushExcInfo))
            .expect("missing handler entry");
        let loop_tail = &instructions[for_iter.saturating_sub(2)..handler_start];

        assert!(
            loop_tail.iter().any(|unit| {
                matches!(
                    unit.op,
                    Instruction::LoadFastBorrow { .. }
                        | Instruction::LoadFastBorrowLoadFastBorrow { .. }
                )
            }),
            "plain except resume loop should keep borrowed LOAD_FAST ops, got tail={loop_tail:?}"
        );
    }

    #[test]
    fn except_pass_resume_loop_branch_keeps_borrows() {
        let code = compile_exec(
            r#"
def f(self, cls, fns):
    for name, fn in zip(self.names, fns):
        try:
            annotation_fields, return_type = self.method_annotations[name]
        except KeyError:
            pass
        else:
            annotate_fn = _make_annotate_function(cls, name, annotation_fields, return_type)
            fn.__annotate__ = annotate_fn
        if self.unconditional_adds.get(name, False):
            setattr(cls, name, fn)
        else:
            already_exists = _set_new_attribute(cls, name, fn)
            if already_exists and (msg_extra := self.overwrite_errors.get(name)):
                error_msg = (f'Cannot overwrite attribute {fn.__name__} '
                             f'in class {cls.__name__}')
                if not msg_extra is True:
                    error_msg = f'{error_msg} {msg_extra}'
                raise TypeError(error_msg)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let load_global_name = |unit: &&CodeUnit, name: &str| match unit.op {
            Instruction::LoadGlobal { namei } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let load_global = namei.get(arg) >> 1;
                f.names[usize::try_from(load_global).unwrap()].as_str() == name
            }
            _ => false,
        };
        let load_name = |unit: &&CodeUnit| match unit.op {
            Instruction::LoadFast { var_num } | Instruction::LoadFastBorrow { var_num } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                Some(f.varnames[usize::from(var_num.get(arg))].as_str())
            }
            _ => None,
        };
        let load_pair_names = |unit: &&CodeUnit| match unit.op {
            Instruction::LoadFastLoadFast { var_nums }
            | Instruction::LoadFastBorrowLoadFastBorrow { var_nums } => {
                let arg = OpArg::new(u32::from(u8::from(unit.arg)));
                let (left, right) = var_nums.get(arg).indexes();
                Some((
                    f.varnames[usize::from(left)].as_str(),
                    f.varnames[usize::from(right)].as_str(),
                ))
            }
            _ => None,
        };

        let set_new_attribute = instructions
            .iter()
            .position(|unit| load_global_name(unit, "_set_new_attribute"))
            .expect("missing _set_new_attribute call");
        let tail = &instructions[set_new_attribute..instructions.len()];
        assert!(
            tail.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadFastBorrowLoadFastBorrow { .. })
                    && load_pair_names(unit) == Some(("cls", "name"))
            }) && tail.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadFastBorrow { .. })
                    && load_name(unit) == Some("fn")
            }),
            "except-pass resume should keep CPython-style borrowed loads in loop branch, got tail={tail:?}"
        );
        assert!(
            !tail.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadFastLoadFast { .. })
                    && load_pair_names(unit) == Some(("cls", "name"))
            }) && !tail.iter().any(|unit| {
                matches!(unit.op, Instruction::LoadFast { .. })
                    && matches!(
                        load_name(unit),
                        Some("fn" | "already_exists" | "msg_extra" | "error_msg")
                    )
            }),
            "except-pass resume must not deopt the independent loop branch, got tail={tail:?}"
        );
    }

    #[test]
    fn named_except_cleanup_deopts_same_guard_fallbacks_not_outer_tail() {
        let code = compile_exec(
            r#"
def f(s, size, errors, final):
    found_invalid_escape = False
    p = []
    pos = 0
    while pos < size:
        ch = chr(s[pos])
        pos += 1
        if ch == "N":
            message = "malformed \\N character escape"
            look = pos
            try:
                import unicodedata
            except ImportError:
                message = "\\N escapes not supported (can't load unicodedata module)"
                unicode_call_errorhandler(
                    errors, "unicodeescape", message, s, pos - 1, size
                )
                continue
            if look < size and chr(s[look]) == "{":
                while look < size and chr(s[look]) != "}":
                    look += 1
                if look > pos + 1 and look < size and chr(s[look]) == "}":
                    message = "unknown Unicode character name"
                    st = s[pos + 1 : look]
                    try:
                        chr_codec = unicodedata.lookup("%s" % st)
                    except LookupError as e:
                        x = unicode_call_errorhandler(
                            errors, "unicodeescape", message, s, pos - 1, look + 1
                        )
                    else:
                        x = chr_codec, look + 1
                    p.append(x[0])
                    pos = x[1]
                else:
                    if not final:
                        pos = 0
                        break
                    x = unicode_call_errorhandler(
                        errors, "unicodeescape", message, s, pos - 1, look + 1
                    )
                    p.append(x[0])
                    pos = x[1]
            else:
                if not final:
                    pos = 0
                    break
                x = unicode_call_errorhandler(
                    errors, "unicodeescape", message, s, pos - 1, look + 1
                )
                p.append(x[0])
                pos = x[1]
        else:
            if not found_invalid_escape:
                found_invalid_escape = True
                warnings.warn(
                    "invalid escape sequence '\\%c'" % ch, DeprecationWarning, 2
                )
            p.append("\\")
            p.append(ch)
    return p, pos
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");

        let mut saw_strong_final = false;
        let mut saw_borrow_p_after_warn = false;
        let mut saw_borrow_ch_after_warn = false;
        let mut after_warn_attr = false;

        for unit in f.instructions.iter() {
            match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    let name = f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str();
                    if name == "warn" {
                        after_warn_attr = true;
                    }
                }
                Instruction::LoadFast { var_num } => {
                    let idx = usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))));
                    let name = f.varnames[idx].as_str();
                    if name == "final" {
                        saw_strong_final = true;
                    }
                }
                Instruction::LoadFastBorrow { var_num } => {
                    let idx = usize::from(var_num.get(OpArg::new(u32::from(u8::from(unit.arg)))));
                    let name = f.varnames[idx].as_str();
                    if after_warn_attr && name == "p" {
                        saw_borrow_p_after_warn = true;
                    }
                    if after_warn_attr && name == "ch" {
                        saw_borrow_ch_after_warn = true;
                    }
                }
                _ => {}
            }
        }

        assert!(
            saw_strong_final,
            "expected named-except fallback guards to deopt final to strong LOAD_FAST"
        );
        assert!(
            saw_borrow_p_after_warn && saw_borrow_ch_after_warn,
            "expected outer invalid-escape tail to keep borrowed p/ch loads"
        );
    }

    #[test]
    fn imap_idle_status_debug_tail_keeps_borrow() {
        let code = compile_exec(
            "\
def f(self, exc_type, CRLF, OSError):
    imap = self._imap
    try:
        imap.send(b'DONE' + CRLF)
        status, [msg] = imap._command_complete('IDLE', self._tag)
        if __debug__ and imap.debug >= 4:
            imap._mesg(f'idle status: {status} {msg!r}')
    except OSError:
        if not exc_type:
            raise
    return False
",
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let mesg_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "_mesg"
                }
                _ => false,
            })
            .expect("missing _mesg attr load");
        let tail = &instructions[mesg_attr.saturating_sub(1)..];

        assert!(
            tail.iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })),
            "expected idle status debug tail to keep borrowed loads, got tail={tail:?}"
        );
    }

    #[test]
    fn match_async_comprehension_iter_keeps_capture_borrow() {
        let code = compile_exec(
            r#"
async def name_4():
    match b'':
        case True:
            pass
        case name_5 if f'e':
            {name_3: name_4 async for name_2 in name_5}
        case []:
            pass
    [[]]
"#,
        );
        let name_4 = find_code(&code, "name_4").expect("missing name_4 code");
        let Some(get_aiter_pos) = name_4
            .instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::GetAiter))
        else {
            panic!("missing GET_AITER in name_4");
        };
        let prev = &name_4.instructions[get_aiter_pos - 1];
        assert!(
            matches!(
                prev.op,
                Instruction::LoadFastBorrow { var_num }
                    if name_4.varnames[usize::from(var_num.get(OpArg::new(u32::from(u8::from(prev.arg)))))] == "name_5"
            ),
            "expected async comprehension iterator capture to borrow name_5 before GET_AITER, got {prev:?}"
        );
    }

    #[test]
    fn match_fail_cleanup_label_reuse_keeps_post_match_borrow() {
        let code = compile_exec(
            r#"
def f(self):
    match 0:
        case 0:
            x = True
    self.assertIs(x, True)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let assert_is_attr = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadAttr { namei } => {
                    let load_attr = namei.get(OpArg::new(u32::from(u8::from(unit.arg))));
                    f.names[usize::try_from(load_attr.name_idx()).unwrap()].as_str() == "assertIs"
                }
                _ => false,
            })
            .expect("missing assertIs attr load");
        let receiver = &instructions[assert_is_attr - 1];
        assert!(
            matches!(
                receiver.op,
                Instruction::LoadFastBorrow { var_num }
                    if f.varnames[usize::from(var_num.get(OpArg::new(u32::from(u8::from(receiver.arg)))))] == "self"
            ),
            "CPython codegen_match_inner uses USE_LABEL(c, end), so post-match receiver should stay borrowed; got {receiver:?}"
        );
    }

    #[test]
    fn match_or_preserves_explicit_success_jumps() {
        let code = compile_exec(
            r#"
def f(w):
    match w:
        case 1 | 2 | 3:
            out = locals()
            del out["w"]
            return out
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let locals_pos = instructions
            .iter()
            .position(|unit| match unit.op {
                Instruction::LoadGlobal { namei } => {
                    let name = namei.get(OpArg::new(u32::from(u8::from(unit.arg)))) >> 1;
                    f.names[usize::try_from(name).unwrap()].as_str() == "locals"
                }
                _ => false,
            })
            .expect("missing locals load");
        let pattern_prefix = &instructions[..locals_pos];
        let false_jumps = pattern_prefix
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::PopJumpIfFalse { .. }))
            .count();
        let success_jumps = pattern_prefix
            .iter()
            .filter(|unit| matches!(unit.op, Instruction::JumpForward { .. }))
            .count();
        assert_eq!(
            false_jumps, 3,
            "CPython codegen_pattern_or() keeps each alternative as false-jump plus success jump; got prefix={pattern_prefix:?}"
        );
        assert_eq!(
            success_jumps, 3,
            "CPython codegen_pattern_or() keeps explicit success JUMPs for all alternatives; got prefix={pattern_prefix:?}"
        );
    }

    #[test]
    fn with_protected_generator_tail_after_cleanup_uses_strong_loads() {
        let code = compile_exec(
            r#"
def f(scandir, fspath, path, reversed, top, OSError, topdown=True, followlinks=False):
    stack = [fspath(top)]
    islink, join = path.islink, path.join
    while stack:
        top = stack.pop()
        dirs = []
        nondirs = []
        walk_dirs = []
        try:
            with scandir(top) as entries:
                for entry in entries:
                    try:
                        is_dir = entry.is_dir()
                    except OSError:
                        is_dir = False
                    if is_dir:
                        dirs.append(entry.name)
                    else:
                        nondirs.append(entry.name)
                    if not topdown and is_dir:
                        if followlinks:
                            walk_into = True
                        else:
                            try:
                                is_symlink = entry.is_symlink()
                            except OSError:
                                is_symlink = False
                            walk_into = not is_symlink
                        if walk_into:
                            walk_dirs.append(entry.path)
        except OSError:
            continue
        if topdown:
            yield top, dirs, nondirs
            for dirname in reversed(dirs):
                new_path = join(top, dirname)
                if not followlinks and islink(new_path):
                    continue
                stack.append(new_path)
        else:
            stack.append((top, dirs, nondirs))
            for new_path in reversed(walk_dirs):
                stack.append(new_path)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let yield_pos = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::YieldValue { .. }))
            .expect("missing YIELD_VALUE");
        assert!(
            matches!(
                instructions[yield_pos - 3].op,
                Instruction::LoadFastLoadFast { .. }
            ) && matches!(instructions[yield_pos - 2].op, Instruction::LoadFast { .. }),
            "CPython keeps the yielded tuple inputs strong after with cleanup, got {:?} {:?}",
            instructions[yield_pos - 3],
            instructions[yield_pos - 2],
        );
        assert!(
            instructions[yield_pos + 1..]
                .iter()
                .take(30)
                .any(|unit| matches!(unit.op, Instruction::LoadFast { .. })),
            "expected post-yield traversal tail to contain strong LOAD_FAST ops"
        );
    }

    #[test]
    fn yield_from_finally_cleanup_keeps_normal_path_borrows() {
        let code = compile_exec(
            r#"
def f(_fwalk, stack, isbytes, topdown, onerror, follow_symlinks, close):
    try:
        while stack:
            yield from _fwalk(stack, isbytes, topdown, onerror, follow_symlinks)
    finally:
        while stack:
            action, value = stack.pop()
            if action == 2:
                close(value)
"#,
        );
        let f = find_code(&code, "f").expect("missing f code");
        let instructions: Vec<_> = f
            .instructions
            .iter()
            .filter(|unit| !matches!(unit.op, Instruction::Cache))
            .collect();
        let send_pos = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::Send { .. }))
            .expect("missing SEND");
        assert!(
            instructions[..send_pos]
                .iter()
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })),
            "CPython keeps yield-from normal path loads borrowed, got prefix={:?}",
            &instructions[..send_pos]
        );
        let cleanup_pop = instructions
            .iter()
            .position(|unit| matches!(unit.op, Instruction::StoreFastStoreFast { .. }))
            .expect("missing finally cleanup unpack");
        assert!(
            instructions[..cleanup_pop]
                .iter()
                .rev()
                .take(12)
                .any(|unit| matches!(unit.op, Instruction::LoadFastBorrow { .. })),
            "CPython keeps normal finally cleanup loads borrowed, got cleanup prefix={:?}",
            &instructions[cleanup_pop.saturating_sub(12)..cleanup_pop]
        );
    }
}
