14 Commits
Author SHA1 Message Date
Jeong, YunWon b2c48d3ab4 Keep specialized CALL under Return/Unwind events (#8735)
* Keep specialized CALL under Return/Unwind events

Instrument only opcodes whose EVENT_FOR_OPCODE is active so
CALL_ALLOC_AND_ENTER_INIT survives Return+Unwind. LINE and
INSTRUCTION still restore every specialized opcode. FOR_ITER
RAISE/STOP_ITERATION consult the global event mask.

Assisted-by: Grok:grok-4.6

* Fix frame repr, f_lineno delete, and class cell timing

frame.__repr__ matches the C format. Deleting f_lineno raises
AttributeError. __classcell__ is filled before a custom mro()
so methods that close over __class__ can run during type creation.

Assisted-by: Grok:grok-4.6
2026-09-19 10:24:57 +09:00
Jeong, YunWon 300d8bdc02 Honor inline values, custom mro, and type lookup (#8729)
* Add inline values flags and special-method lookup

lookup_maybe_method clears AttributeError from descr_get.
slot_tp_richcompare treats a miss as NotImplemented.
hackcheck rejects object.__setattr__ on types.
Heap types with a managed dict and itemsize 0 get
INLINE_VALUES; _testinternalcapi.has_inline_values
reports the valid bit.
super is a base type; subclass __get__ binds the instance.
__classcell__/__qualname__ may share a name with a slot.
Unset member access uses the type's fully qualified name.

Assisted-by: Grok:grok-4.6

* Call custom mro and descr_get for type.__new__

type.mro() computes C3 from the current bases.
A metaclass other than type supplies the MRO via mro().
super() compares obj.__class__ to the instance type.
slot_tp_new looks up __new__ through descr_get.
is_subtype walks the stored MRO without an identity shortcut.
__slots__ names are sorted so __class__ assignment matches.

Assisted-by: Grok:grok-4.6

* Expose _testinternalcapi recursion and rare events

get_recursion_depth feeds test.support.infinite_recursion.
SPECIALIZATION_* and SHARED_KEYS_MAX_SIZE match the
adaptive counters. Rare-event hooks increment on
__class__/__bases__/function/builtins writes.

Assisted-by: Grok:grok-4.6

* Add remaining _testinternalcapi code and locale APIs

Expose get_co_localskinds, get_code_var_counts, verify_stateless_code,
code_returns_only_none, normalize_path, EncodeLocaleEx, DecodeLocaleEx,
and run_in_subinterp_with_config. Mark unimplemented compiler IR and
specialization monitoring tests as expectedFailure.

Assisted-by: Grok:grok-4.6

* Fix lint for _testinternalcapi identifiers

Add CPython identifier spellings to the cspell dictionary and apply
the rustfmt signature that CI rewrote.

Assisted-by: Grok:grok-4.6

* Expand _testinternalcapi with remaining test APIs

Add constants, compiler_cleandoc, dict_getitem_knownhash, time
helpers, interpreter/frame accessors, configs, static types, a
persistent hamt map, and GC/size counters used by the test suite.

Assisted-by: Grok:grok-4.6

* Expose compiler IR APIs in _testinternalcapi

Add InstructionSequence and compiler_codegen, optimize_cfg, and
assemble_code_object. Drop expectedFailure marks on tests that pass.

Assisted-by: Grok:grok-4.6

* Match optimize_cfg consts and addop locations

Write optimized consts back into the caller's list, mark SETUP_*
pseudo-ops as having an argument, and store addop locations in
instruction-sequence field order. Drop expectedFailure marks on
tests that pass.

Assisted-by: Grok:grok-4.6

* Fix hamt API, SETUP_* HAS_ARG, and FOR_ITER events

Honor explicit pseudo flags when generating opcode metadata so
SETUP_FINALLY/CLEANUP/WITH keep HAS_ARG after regeneration.

Complete the _testinternalcapi hamt mapping: identity on
set/delete, richcompare, weakrefs, subscript, contains, and
length-bearing iterators.

Fire RAISE/STOP_ITERATION for FOR_ITER StopIteration, and skip
both END_FOR and POP_ITER for the exhausted-branch destination.

Assisted-by: Grok:grok-4.6

* Skip FOR_ITER RAISE for sequence iterators

List/range/tuple exhaustion matches FOR_ITER_LIST/RANGE/TUPLE and
must not emit a monitoring RAISE. That event stopped pdb's
monitoring backend on for-over-list with Internal StopIteration.

Assisted-by: Grok:grok-4.6

* Fix generator FOR_ITER events and review issues

Restore settrace StopIteration for generator for-loops so
test_bdb next/return cases pass, while sequence iterators still
skip RAISE.

Honor review notes: addop oparg bounds, linetable locations,
AST instance errors, MRO subclass lock, builtin-dict notify,
direct-base layout flags, and leftover _testinternalcapi args.

Assisted-by: Grok:grok-4.6
2026-09-19 00:40:20 +09:00
Jeong, YunWon a7981dccc7 Align compiler futures, annotations, and symtable with CPython (#8550)
* Align compiler futures and annotations with CPython

Handle Barry parsing consistently across AST, type-comment, REPL, and WASM paths. Preserve deferred annotation source and scope metadata, and make _symtable conversion cached and linear-time.

Assisted-by: Codex:gpt-5.4

* Fix f-string debug ranges and update Barry/annotate test expectations

Compute the debug f-string source range from the raw leading and
trailing text instead of the comment-stripped text, so a comment inside
a multi-line replacement field no longer shifts the emitted LOAD_CONST
location.

Restrict the obsolete-operator location shift to `<>` by also requiring
a `>` at the reported offset; without it any `ExpectedExpression` that
followed a `<` (`2 <;`) was reported one column to the left.

Add `CodeFlags::FUTURE_MASK` and use it in builtins, the shell, and the
WASM VM instead of repeating the eight-flag union, and collapse the
duplicated Barry diagnostic sequences into `BarrySource::diagnostic`.

Update the `__annotate__` disassembly snapshot to LOAD_FAST_BORROW and
replace the RustPython-only `barry_as_FLUFL` co_flags assertion in
extra_tests with the CPython-matching one.

Assisted-by: Claude Code:claude-opus-5

* Restore the annotated function in __annotate__ qualnames

Signature annotation scopes are compiled in the scope enclosing the
annotated function, so the function name has to be folded back into the
qualname: `f.__annotate__`, `C.m.__annotate__`,
`outer.<locals>.inner.__annotate__`. test_type_annotations
test_annotate_qualname covers this.

test_pyrepl test_future_barry_as_flufl now passes, so drop its
expectedFailure marker.

Assisted-by: Claude Code:claude-opus-5

* Pass safepoints in the attached-thread interpreter tests

`main_and_subinterpreter_run_sections_overlap` parked its workers on a
condvar while attached, and `busy_main_interpreter_does_not_block_subinterpreter`
looped over protocol calls that never reach a safepoint. An attached
thread that never reaches a safepoint cannot be suspended, so a
concurrent process-wide stop-the-world (from the gc test running in
parallel) never completes and the already-stopped sibling interpreter
stays stopped; the second worker then waits in `wait_while_suspended`
until the 30s deadline.

Both loops now call `vm.check_signals()` each iteration, and the condvar
wait uses `wait_timeout` so the lock is released between safepoints.

Reproduced on Linux (4 CPUs): the two tests with `--test-threads=2`
failed 2/40 before and 0/40 after; the full `rustpython-vm` lib binary
failed 1/30 before and 0/30 after.

Assisted-by: Claude Code:claude-opus-5

* Report the obsolete `<>` operator from one place

`<>` was located twice: `BarrySource` recorded the token ranges it
rewrote to `!=`, and `cpython_parse_diagnostic_override` separately
peeked at the bytes around an `ExpectedExpression` location. Both
produced "invalid syntax" spanning the whole operator.

`prepare_barry_as_flufl_source` now records the operator ranges in the
non-Barry case too -- by plain text search, since nothing is rewritten
there -- so `BarrySource::invalid_legacy_operator` covers both, and the
byte-peeking helper is gone. It also defers to an unclosed bracket
earlier in the source, which the diagnostic chain it used to sit in did
for it.

A `<>` that starts a statement now spans both characters: the parser
stops at the `<` rather than one character in, which the byte peek did
not handle.

Assisted-by: Claude Code:claude-opus-5

* Drop a py object's payload before its class

`PyInner` declares `typ` before `payload`, so `drop_in_place` dropped the
class first and `PyAtomicRef::drop` left it null. A `PyWeak` payload is
still linked into the weakref list of the object it points at until its
own `Drop` unlinks it under the stripe lock, which happens after that.
`WeakRefList::add` walks the same list looking for a proxy to reuse and
reads `node.class()` off every node it passes, so it could dereference
the null class of a node on its way out.

`PyInner::dealloc` now runs the two destructors in the other order at all
three of its exit paths, with a compile-time check that no other field
has one.

Reproduced by the new test in about 0.1s, as the panic CI hit in the
c-api `weakrefobject::tests::new_proxy` run:

  panicked at crates/vm/src/object/ext.rs:312:
  unsafe precondition(s) violated: hint::unreachable_unchecked must
  never be reached

Assisted-by: Claude Code:claude-opus-5
2026-08-20 12:47:36 +09:00
Shahar Naveh a588a64572 Uncomment codegen crashing tests (#8175)
* Update `test_patma.py` to 3.14.6

* Update `test_listcomps.py`

* Align patches of `test_super.py`

* Align `test_grammar.py`

* Align patches for `test_pep646_syntax.py`
2026-06-30 23:32:30 +09:00
Shahar Naveh 5395ed1f26 Update test_super.py to 3.14.5 (#8015) 2026-06-02 09:25:40 +00:00
Jeong, YunWon bef2e41295 Bytecode parity (#7475)
* Emit TO_BOOL before conditional jumps, fix class/module prologue

- Emit TO_BOOL before POP_JUMP_IF_TRUE/FALSE in the general case
  of compile_jump_if (Compare expressions excluded since they
  already produce a bool)
- Module-level __doc__: use STORE_NAME instead of STORE_GLOBAL
- Class body __module__: use LOAD_NAME instead of LOAD_GLOBAL
- Class body: store __firstlineno__ before __doc__

* Emit MAKE_CELL and COPY_FREE_VARS before RESUME

Emit MAKE_CELL for each cell variable and COPY_FREE_VARS N for
free variables at the start of each code object, before RESUME.
These instructions are no-ops in the VM but align the bytecode
with CPython 3.14's output.

* Emit __static_attributes__ at end of class bodies

Store a tuple of attribute names (currently always empty) as
__static_attributes__ in the class namespace, matching CPython
3.14's class body epilogue. Attribute name collection from
self.xxx accesses is a follow-up task.

* Remove expectedFailure from DictProxyTests iter tests

test_iter_keys, test_iter_values, test_iter_items now pass
because class bodies emit __static_attributes__ and
__firstlineno__, matching the expected dict key set.

* Use 1-based stack indexing for LIST_EXTEND, SET_UPDATE, etc.

Switch LIST_APPEND, LIST_EXTEND, SET_ADD, SET_UPDATE, MAP_ADD
from 0-based to 1-based stack depth argument, matching CPython's
PEEK(oparg) convention. Adjust the VM to subtract 1 before
calling nth_value.

* Use plain LOAD_ATTR + PUSH_NULL for calls on imported names

When the call target is an attribute of an imported name (e.g.,
logging.getLogger()), use plain LOAD_ATTR (method_flag=0) with
a separate PUSH_NULL instead of method-mode LOAD_ATTR. This
matches CPython 3.14's behavior which avoids the method call
optimization for module attribute access.

* Duplicate return-None epilogue for fall-through blocks

When the last block in a code object is exactly LOAD_CONST None +
RETURN_VALUE (the implicit return), duplicate these instructions
into blocks that would otherwise fall through to it. This matches
CPython 3.14's behavior of giving each code path its own explicit
return instruction.

* Run cargo fmt on ir.rs

* Remove expectedFailure from test_intrinsic_1 in test_dis

* Emit TO_BOOL before conditional jumps for all expressions including Compare

* Add __classdict__ cell for classes with function definitions

Set needs_classdict=true for class scopes that contain function
definitions (def/async def), matching CPython 3.14's behavior for
PEP 649 deferred annotation support. Also restore the Compare
expression check in compile_jump_if to skip TO_BOOL for comparison
operations.

* Emit __classdictcell__ store in class body epilogue

Store the __classdict__ cell reference as __classdictcell__ in
the class namespace when the class has __classdict__ as a cell
variable. Uses LOAD_DEREF (RustPython separates cell vars from
fast locals unlike CPython's unified array).

* Always run DCE to remove dead code after terminal instructions

Run basic dead code elimination (truncating instructions after
RETURN_VALUE/RAISE/JUMP within blocks) at all optimization
levels, not just optimize > 0. CPython always removes this dead
code during assembly.

* Restrict LOAD_ATTR plain mode to module/class scope imports

Only use plain LOAD_ATTR + PUSH_NULL for imports at module or
class scope. Function-local imports use method call mode LOAD_ATTR,
matching CPython 3.14's behavior.

* Eliminate unreachable blocks after jump normalization

Split DCE into two phases: (1) within-block truncation after
terminal instructions (always runs), (2) whole-block elimination
for blocks only reachable via fall-through from terminal blocks
(runs after normalize_jumps when dead jump instructions exist).

* Fold BUILD_TUPLE 0 into LOAD_CONST empty tuple

Convert BUILD_TUPLE with size 0 to LOAD_CONST () during constant
folding, matching CPython's optimization for empty tuple literals.

* Handle __classcell__ and __classdictcell__ in type.__new__

- Remove __classcell__ from class dict after setting the cell value
- Add __classdictcell__ handling: set cell to class namespace dict,
  then remove from class dict
- Register __classdictcell__ identifier
- Use LoadClosure instead of LoadDeref for __classdictcell__ emission
- Reorder MakeFunctionFlag bits to match CPython
- Run ruff format on scripts

* Revert __classdict__ cell and __classdictcell__ changes

The __classdict__ cell addition (for classes with function defs)
and __classdictcell__ store caused cell initialization failures
in importlib. These require deeper VM changes to properly support
the cell variable lifecycle. Reverted for stability.

* Fix unreachable block elimination with fixpoint reachability

Use fixpoint iteration to properly determine block reachability:
only mark jump targets of already-reachable blocks, preventing
orphaned blocks from falsely marking their targets as reachable.
Also add a final DCE pass after assembly NOP removal to catch
dead code created by normalize_jumps.

* Check enclosing scopes for IMPORTED flag in LOAD_ATTR mode

When deciding whether to use plain LOAD_ATTR for attribute calls,
check if the name is imported in any enclosing scope (not just
the current scope). This handles the common pattern where a module
is imported at module level but used inside functions.

* Add __classdict__ cell for classes with function definitions

Set needs_classdict=true when a class scope contains function
definitions (def/async def), matching CPython 3.14 which always
creates a __classdict__ cell for PEP 649 support in such classes.

* Store __classdictcell__ in class body epilogue

Store the __classdict__ cell reference as __classdictcell__ in
the class namespace using LoadClosure (which loads the cell
object itself, not the value inside). This matches CPython 3.14's
class body epilogue.

* Fix clippy collapsible_if warnings and cargo fmt

* Revert __classdict__ and __classdictcell__ changes (cause import failures)

* Revert type.__new__ __classcell__ removal and __classdictcell__ handling

Revert the class cell cleanup changes from e6975f973 that cause
import failures when frozen module bytecode is stale. The original
behavior (not removing __classcell__ from class dict) is restored.

* Re-add __classdict__ cell and __classdictcell__ store

Restore the __classdict__ cell for classes with function
definitions and __classdictcell__ store in class body epilogue.
Previous failure was caused by stale .pyc cache files containing
bytecode from an intermediate MakeFunctionFlag reorder attempt,
not by these changes themselves.

* Reorder MakeFunctionFlag to match CPython's SET_FUNCTION_ATTRIBUTE

Reorder discriminants: Defaults=0, KwOnlyDefaults=1, Annotations=2,
Closure=3, Annotate=4, TypeParams=5. This aligns the oparg values
with CPython 3.14's convention.

Note: after this change, stale .pyc cache files must be deleted
(find . -name '*.pyc' -delete) to avoid bytecode mismatch errors.

* Use CPython-compatible power-of-two encoding for SET_FUNCTION_ATTRIBUTE

Override From/TryFrom for MakeFunctionFlag to use power-of-two
values (1,2,4,8,16,32) matching CPython's SET_FUNCTION_ATTRIBUTE
oparg encoding, instead of sequential discriminants (0,1,2,3,4,5).

* Remove expectedFailure from test_elim_jump_after_return1 and test_no_jump_over_return_out_of_finally_block

* Remove __classcell__ and __classdictcell__ from class dict in type.__new__

* Remove expectedFailure from test___classcell___expected_behaviour, cargo fmt

* Handle MakeCell and CopyFreeVars as no-ops in JIT

These prologue instructions are handled at frame creation time
by the VM. The JIT operates on already-initialized frames, so
these can be safely skipped during compilation.

* Remove expectedFailure from test_load_fast_known_simple

* Restore expectedFailure for test_load_fast_known_simple

The test expects LOAD_FAST_BORROW_LOAD_FAST_BORROW superinstruction
which RustPython does not emit yet.
2026-03-23 11:31:30 +09:00
Jeong, YunWon 0eddee500a fix fcntl, sslsocket traverse, super , excepthook (#6623)
* fix fcntl

* fix traverse

* fix super

* excepthook

* fix warn
2026-01-03 00:15:31 +09:00
Shahar Naveh be559ae453 Update support/import_helper.py from 3.13.11 (#6451)
* Update `support/import_helper.py` from 3.13.11

* Unmark passing test
2025-12-17 08:15:25 +09:00
Shahar Naveh b84f7c19ad Fix super and Update test_{descr,super}.py from 3.13.9 (#6314)
* Update `test_descr.py` from 3.13.9

* Update `test_super.py` from 3.13.9
2025-11-30 10:16:50 +09:00
Jeong, YunWon 95b8c60756 Fix __build_class__ compatibility (#6308)
* Update __build_class__

* fix test
2025-11-29 11:54:04 +09:00
YeonWoo e513bf11fe Fix metaclass check classcell (#3986) 2022-08-13 17:20:13 +09:00
Padraic Fanning ff265ea705 Clean up skip in test_super 2021-10-17 22:24:53 -04:00
eldpswp99 cd9b4946fe add TODO:RUSTPYTHON 2021-09-15 02:12:48 +09:00
eldpswp99 72be296c1d add super test by CPython 3.8 2021-09-15 02:06:23 +09:00