| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
WalkthroughBatches of nested if/if-let conditionals across the workspace were collapsed into single guarded conditionals using combined if-let/&& patterns; the workspace MSRV in Cargo.toml was bumped from 1.87.0 to 1.89.0. No public API or behavioral changes introduced. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor JS as JavaScript
participant W as wasm glue
participant VM as RustPython VM
participant IP as InnerInterperter
JS->>W: invoke wrapped function (JsValue args/kwargs)
W->>VM: stored_vm_from_wasm(wasm_id)
alt VM found
VM->>IP: interp.enter(...)
Note over IP: Args/kwargs conversion now runs inside inner VM context
IP->>IP: convert args/kwargs -> PyObjectRef
IP->>IP: call Python function
IP-->>W: return PyObjectRef / error
W->>VM: try Promise bridge (if Promise type && downcast OK)
alt Promise
W-->>JS: return Promise
else
W-->>JS: return converted result
end
else VM missing
W-->>JS: return Err(JsValue)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ Share 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type @coderabbitai help to get the list of available commands. Other keywords and placeholders
Status, Documentation and Community
|
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)derive-impl/src/compile_bytecode.rs (1)198-209: Same unwrap risk in compile_path fallback
Guard against panics; also avoid unwrap() on parent().
- let code = compile_path(&path).or_else(|e| { - if cfg!(windows) - && let Ok(real_path) = fs::read_to_string(path.canonicalize().unwrap()) - { - let joined = path.parent().unwrap().join(real_path.trim()); - if joined.exists() { - return compile_path(&joined); - } else { - return Err(e); - } - } - Err(e) - }); + let code = compile_path(&path).or_else(|e| { + if cfg!(windows) + && let Ok(canonical) = path.canonicalize() + && let Ok(real_path) = fs::read_to_string(&canonical) + && let Some(parent) = path.parent() + { + let joined = parent.join(real_path.trim()); + if joined.exists() { + return compile_path(&joined); + } else { + return Err(e); + } + } + Err(e) + });
stdlib/src/select.rs (1)📜 Review detailsvm/src/readline.rs (1)247-251: LGTM: guard-style negative-timeout check
Semantics preserved and clearer flow. Minor: consider avoiding shadowing by renaming the inner binding for readability.
- if let Some(timeout) = timeout + if let Some(t) = timeout - && timeout < 0.0 + && t < 0.0 { return Err(vm.new_value_error("timeout must be positive")); }vm/src/stdlib/itertools.rs (1)98-101: Drop the exists() check; create_dir_all is idempotent
Saves a syscall and avoids a TOCTOU check; behavior stays the same.
- if !path.exists() - && let Some(parent) = path.parent() - { - std::fs::create_dir_all(parent)?; - } + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + }stdlib/src/contextvars.rs (1)989-991: Guard against theoretical overflow when stop is None
Not introduced by this PR, but unwrap() on overflow would panic for an infinite slice after wraparound. Extremely unlikely on 64-bit, still easy to harden.
- let (next, ovf) = zelf.next.load().overflowing_add(zelf.step); - zelf.next.store(if ovf { zelf.stop.unwrap() } else { next }); + match zelf.next.load().checked_add(zelf.step) { + Some(next) => zelf.next.store(next), + None => { + if let Some(stop) = zelf.stop { + zelf.next.store(stop); + } else { + // no stop: saturate to avoid panic + zelf.next.store(usize::MAX); + } + } + }vm/src/builtins/memory.rs (1)381-385: Clarify safety for unsafe { &*cached_ptr } in let-chain
Semantics look unchanged, but please document why this unsynchronized read is acceptable (soft cache; validated by cached_id and idx guards; stale read degrades to miss).
Apply this diff to add a safety comment:
- if let Some(cached) = unsafe { &*cached_ptr } + // SAFETY: cached_ptr points into AtomicCell<Option<ContextVarCache>>. + // We only read here and validate with cached_id and idx; a stale read + // merely falls through to the map lookup/update below. + if let Some(cached) = unsafe { &*cached_ptr } && zelf.cached_id.load(Ordering::SeqCst) == ctx.get_id() && cached.idx + 1 == ctxs.len() { return Some(cached.object.clone()); }stdlib/src/unicodedata.rs (1)867-874: Outdated TODO; optionally fold the two write paths into one condition.
Both branches assign via pack_single(0, ...). You can drop the TODO and combine with matches! for clarity.
- if self.desc.ndim() == 0 { - // TODO: merge branches when we got conditional if let - if needle.is(&vm.ctx.ellipsis) { - return self.pack_single(0, value, vm); - } else if let Some(tuple) = needle.downcast_ref::<PyTuple>() - && tuple.is_empty() - { - return self.pack_single(0, value, vm); - } + if self.desc.ndim() == 0 { + if needle.is(&vm.ctx.ellipsis) + || matches!(needle.downcast_ref::<PyTuple>(), Some(t) if t.is_empty()) + { + return self.pack_single(0, value, vm); + }pylib/build.rs (1)141-146: Nit: redundant age check after extract_char
extract_char already returns Some(c) only if check_age(c) is true. You can drop the second self.check_age(c) for a tiny simplification.
Apply:
- if let Some(c) = c - && self.check_age(c) - && let Some(name) = c.to_char().and_then(unicode_names2::name) + if let Some(c) = c + && let Some(name) = c.to_char().and_then(unicode_names2::name) { return Ok(vm.ctx.new_str(name.to_string()).into()); }vm/src/stdlib/sys.rs (2)12-20: Let-chain refactor is correct; consider trimming and non-panicking path to string.
Trim possible trailing newlines from Lib’s contents, avoid panic on non-UTF-8 paths, and make changes re-run when Lib changes.
Apply:
- if cfg!(windows) - && let Ok(real_path) = std::fs::read_to_string("Lib") - { - let canonicalized_path = std::fs::canonicalize(real_path) + if cfg!(windows) + && let Ok(real_path) = std::fs::read_to_string("Lib") + { + println!("cargo:rerun-if-changed=Lib"); + let canonicalized_path = std::fs::canonicalize(real_path.trim()) .expect("failed to resolve RUSTPYTHONPATH during build time"); println!( "cargo:rustc-env=win_lib_path={}", - canonicalized_path.to_str().unwrap() + canonicalized_path.to_string_lossy() ); }vm/src/vm/vm_ops.rs (1)186-196: Minor: avoid into_os_string/into_string churn.
Use to_string_lossy() to sidestep ownership churn and Unicode fallibility.
- if let Some(exec_path) = env::args_os().next() - && let Ok(path) = which::which(exec_path) + if let Some(exec_path) = env::args_os().next() + && let Ok(path) = which::which(&exec_path) { - return ctx - .new_str( - path.into_os_string() - .into_string() - .unwrap_or_else(|p| p.to_string_lossy().into_owned()), - ) - .into(); + return ctx.new_str(path.to_string_lossy().into_owned()).into(); }
206-216: Prefer Path joining to manual “{dir}/{file}” formatting.
This is more portable (Windows path separators) and avoids intermediate Unicode checks.
- if let Ok(dir) = env::current_dir() - && let Ok(dir) = dir.into_os_string().into_string() - { - return ctx - .new_str(format!( - "{}/{}", - dir, - exec_path.strip_prefix("./").unwrap_or(&exec_path) - )) - .into(); - } + if let Ok(dir) = env::current_dir() { + let joined = dir.join(exec_path.strip_prefix("./").unwrap_or(&exec_path)); + return ctx.new_str(joined.to_string_lossy().into_owned()).into(); + }vm/src/builtins/genericalias.rs (3)302-309: slot_c resolution via chained guards is fine; consider readability
Logic matches prior nested checks and ensures slot_c differs from slot_a/slot_b. Optionally, extract the inequality checks into locals to tame line length.
- if let Some(slot_c) = class_c.slots.as_number.left_ternary_op(op_slot) - && slot_a.is_some_and(|slot_a| !std::ptr::fn_addr_eq(slot_a, slot_c)) - && slot_b.is_some_and(|slot_b| !std::ptr::fn_addr_eq(slot_b, slot_c)) + if let Some(slot_c) = class_c.slots.as_number.left_ternary_op(op_slot) + && { + let a_diff = slot_a.is_some_and(|sa| !std::ptr::fn_addr_eq(sa, slot_c)); + let b_diff = slot_b.is_some_and(|sb| !std::ptr::fn_addr_eq(sb, slot_c)); + a_diff && b_diff + } {vm/src/builtins/descriptor.rs (1)379-395: Use ctx.none() consistently in equality checks.
Elsewhere in this file you use vm.ctx.none(). For consistency (and to avoid confusion between field vs. accessor), prefer vm.ctx.none() here.
- if let Ok(sub_args) = item.get_attr(identifier!(vm, __typing_unpacked_tuple_args__), vm) - && !sub_args.is(&vm.ctx.none) + if let Ok(sub_args) = item.get_attr(identifier!(vm, __typing_unpacked_tuple_args__), vm) + && !sub_args.is(&vm.ctx.none()) && let Ok(tuple) = sub_args.try_to_ref::<PyTuple>(vm)
423-434: Same nit: prefer ctx.none() accessor for clarity.
- if let Ok(prepare) = param.get_attr(identifier!(vm, __typing_prepare_subst__), vm) - && !prepare.is(&vm.ctx.none) + if let Ok(prepare) = param.get_attr(identifier!(vm, __typing_prepare_subst__), vm) + && !prepare.is(&vm.ctx.none()) { // Call prepare(self, item) item = if item.try_to_ref::<PyTuple>(vm).is_ok() {
528-535: Simplify control flow: avoid return inside map-closure.
This is correct but a bit awkward to read. A straightforward early-return form is clearer.
- PyType::call(&zelf.origin, args, vm).map(|obj| { - if let Err(exc) = obj.set_attr(identifier!(vm, __orig_class__), zelf.to_owned(), vm) - && !exc.fast_isinstance(vm.ctx.exceptions.attribute_error) - && !exc.fast_isinstance(vm.ctx.exceptions.type_error) - { - return Err(exc); - } - Ok(obj) - })? + let obj = PyType::call(&zelf.origin, args, vm)?; + if let Err(exc) = obj.set_attr(identifier!(vm, __orig_class__), zelf.to_owned(), vm) { + if !exc.fast_isinstance(vm.ctx.exceptions.attribute_error) + && !exc.fast_isinstance(vm.ctx.exceptions.type_error) + { + return Err(exc); + } + } + Ok(obj)vm/src/vm/method.rs (1)370-376: LGTM: let-chain correctly collapses nested checks. Consider updating comment.
Behavior matches the prior logic. The nearby comment mentions only “doc”; this path now (and previously) applies to any member with a same-named class attribute. Consider adjusting the comment for accuracy.
vm/src/builtins/type.rs (2)45-52: LGTM: data-descriptor precedence kept; minor naming nit.
Shadowing cls inside the block is a bit confusing; consider owner/cls_obj to avoid shadowing the outer cls.
- let cls = cls.to_owned().into(); - return descr_get(descr, Some(obj), Some(cls), vm).map(Self::Attribute); + let cls_obj = cls.to_owned().into(); + return descr_get(descr, Some(obj), Some(cls_obj), vm).map(Self::Attribute);276-283: Prefer unsigned extraction for flags to avoid negative surprises.
Use to_u64() instead of to_i64() as u64 when reading __abc_tpflags__, so negative ints can’t wrap into huge flag bitmasks.
- let flags_val = int_obj.as_bigint().to_i64().unwrap_or(0); - let abc_flags = PyTypeFlags::from_bits_truncate(flags_val as u64); + let flags_val = int_obj.as_bigint().to_u64().unwrap_or(0); + let abc_flags = PyTypeFlags::from_bits_truncate(flags_val);Apply the same change in the bases scan block.
Also applies to: 287-294
1066-1070: Be robust to potential subclasses of function.
Using exact .class().is(function_type) is fine, but fast_isinstance would also accept function-like subclasses (if ever introduced).
- if let Some(f) = attributes.get_mut(identifier!(vm, __init_subclass__)) - && f.class().is(vm.ctx.types.function_type) + if let Some(f) = attributes.get_mut(identifier!(vm, __init_subclass__)) + && f.fast_isinstance(vm.ctx.types.function_type) { *f = PyClassMethod::from(f.clone()).into_pyobject(vm); } - if let Some(f) = attributes.get_mut(identifier!(vm, __class_getitem__)) - && f.class().is(vm.ctx.types.function_type) + if let Some(f) = attributes.get_mut(identifier!(vm, __class_getitem__)) + && f.fast_isinstance(vm.ctx.types.function_type) { *f = PyClassMethod::from(f.clone()).into_pyobject(vm); }Also applies to: 1072-1076
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration.
📥 CommitsReviewing files that changed from the base of the PR and between 0c8ae3a and fd1e7ad.
📒 Files selected for processing (48)📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style (cargo fmt to format)
Always run clippy to lint code (cargo clippy) before completing tasks. Fix any warnings or lints that are introduced by your changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust
Files:
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Do not modify the pylib/ directory directly - its contents are generated automatically
Files:
vm/src/builtins/genericalias.rs (1)stdlib/src/syslog.rs (1)vm/src/builtins/type.rs (1)
- type_params (625-625)
vm/src/builtins/function.rs (1)
- __type_params__ (944-954)
vm/src/stdlib/typing.rs (1)
- __type_params__ (570-572)
- __type_params__ (128-130)
vm/src/stdlib/sys.rs (1)vm/src/protocol/mapping.rs (1)
- argv (129-136)
vm/src/protocol/sequence.rs (1)vm/src/builtins/genericalias.rs (2)
- find_methods (98-101)
vm/src/builtins/union.rs (4)vm/src/builtins/property.rs (1)vm/src/stdlib/typevar.rs (4)
- arg (169-169)
- arg (178-178)
- __parameters__ (95-97)
- obj (156-156)
- __typing_prepare_subst__ (185-231)
- __typing_prepare_subst__ (510-518)
- __typing_prepare_subst__ (690-698)
- obj (1002-1002)
stdlib/src/unicodedata.rs (1)stdlib/src/socket.rs (1)
- name (133-148)
stdlib/src/unicodedata.rs (1)vm/src/vm/method.rs (3)
- name (133-148)
vm/src/builtins/descriptor.rs (3)vm/src/builtins/mappingproxy.rs (2)vm/src/object/core.rs (2)
- descr_get (60-90)
- descr_get (356-380)
- cls (371-371)
vm/src/builtins/dict.rs (1)
- Self (371-374)
- dict (699-701)
- dict (756-756)
vm/src/protocol/mapping.rs (1)vm/src/builtins/type.rs (6)vm/src/function/protocol.rs (2)
- find_methods (101-103)
- mapping (146-151)
- with_methods (133-135)
vm/src/builtins/descriptor.rs (5)vm/src/protocol/object.rs (2)vm/src/builtins/function.rs (5)
- qualname (240-240)
- __qualname__ (118-120)
- __qualname__ (257-267)
- class (48-50)
- class (233-235)
vm/src/builtins/builtin_func.rs (2)
- __qualname__ (549-551)
- __qualname__ (819-838)
- class (442-444)
- class (843-845)
- class (879-881)
vm/src/builtins/classmethod.rs (1)
- __qualname__ (90-110)
- __qualname__ (163-168)
vm/src/builtins/staticmethod.rs (1)
- __qualname__ (141-143)
vm/src/builtins/object.rs (1)
- __qualname__ (105-107)
- __init_subclass__ (415-415)
vm/src/builtins/descriptor.rs (3)wasm/lib/src/convert.rs (2)vm/src/types/slot.rs (1)
- descr_get (60-90)
- descr_get (356-380)
- cls (371-371)
- descr_get (901-906)
wasm/lib/src/js_module.rs (6)vm/src/vm/mod.rs (1)wasm/lib/src/vm_class.rs (1)
- args (186-186)
- args (201-201)
- args (222-222)
- new (96-99)
- new (305-341)
- new (396-400)
- stored_vm_from_wasm (99-105)
vm/src/import.rs (1)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- init_importlib_package (32-69)
vm/src/stdlib/time.rs (1)vm/src/builtins/iter.rs (1)94-101: LGTM: consolidated error mapping for negative durations
Behavior matches CPython’s message and keeps non-matching errors intact.
vm/src/stdlib/itertools.rs (1)154-160: LGTM: concise rev_length_hint guard
Equivalent logic with tighter expression; avoids double nesting.
vm/src/stdlib/io.rs (1)979-983: LGTM on the let-chain refactor
Semantics match the prior nested conditionals.
stdlib/src/syslog.rs (1)3397-3400: LGTM on chained condition
Functional parity with the previous nested if; concise and clear.
vm/src/signal.rs (1)29-38: LGTM on let-chain
Behavior preserved; early-return remains clear.
vm/src/builtins/function.rs (1)38-43: LGTM: compact trigger + handler check
Short-circuiting is correct; no behavior change.
stdlib/src/zlib.rs (2)283-288: Let-chain for kw-only defaults looks correct
Semantics and error propagation are preserved; borrow lifetimes are fine. LGTM.
vm/src/protocol/mapping.rs (1)196-201: Set-dictionary guard refactor is equivalent
The chained condition mirrors the prior nested checks (zdict present and wbits < 0). Short-circuiting/binding behavior is correct. LGTM.
576-581: Constructor path uses the same safe let-chain
Same semantics as before; only sets the dictionary when both conditions hold. LGTM.
vm/src/stdlib/warnings.rs (1)81-87: Clean let-chain in try_protocol
Combining the method presence check with the slot lookup is clear and preserves behavior; subsequent borrow_static use is safe. LGTM.
vm/src/stdlib/ast/python.rs (1)12-16: Flattened import/attr lookup is fine
The let-chain reads well; intentionally discarding call result remains unchanged. LGTM.
vm/src/object/core.rs (1)36-44: Duplicate-arg detection let-chain is correct
The combined guard matches the old logic and keeps the same error path. LGTM.
vm/src/cformat.rs (1)195-200: LGTM: let-chain preserves previous semantics under the lock
The combined guard is_generic && let Some(generic_weakref) = inner.generic_weakref is correct and avoids the extra nesting while short-circuiting as before. No ownership/aliasing issues since Option<NonNull<_>> is Copy.
vm/src/builtins/str.rs (1)198-201: LGTM: let-chain keeps single-codepoint string path intact
The combined PyStr check and exactly_one() extraction are equivalent to the nested version and return the same error on failure.
stdlib/src/socket.rs (1)327-333: LGTM: iterator advance logic unchanged with clearer guard
The else-if let-chain mirrors the prior nested condition and correctly updates position and byte offset using len_wtf8().
src/shell.rs (1)2281-2284: LGTM: IPv4 fast-path readably collapsed
Pattern + parse guard is fine and preserves prior behavior for AF_INET/AF_UNSPEC.
vm/src/builtins/property.rs (1)70-75: Use byte-based indexing for triple-quote detection
raw_location.start().to_usize() returns a byte offset; indexing source.chars() with it misaligns on multibyte UTF-8. Replace with byte-safe checks:- let mut iter = source.chars(); - if let Some(quote) = iter.nth(loc) - && iter.next() == Some(quote) - && iter.next() == Some(quote) - { - return ShellExecResult::ContinueLine; - } + let bytes = source.as_bytes(); + if let (Some(&q), Some(&q1), Some(&q2)) = ( + bytes.get(loc), + loc.checked_add(1).and_then(|i| bytes.get(i)), + loc.checked_add(2).and_then(|i| bytes.get(i)), + ) && (q == b'\'' || q == b'"') && q1 == q && q2 == q + { + return ShellExecResult::ContinueLine; + }Add a test where the quote sequence follows a non-ASCII character (e.g. “é'''”) to verify correct behavior.
vm/src/builtins/mappingproxy.rs (1)77-81: LGTM on let-chain refactors; behavior unchanged and clearer
Both the get_property_name and __isabstractmethod__ conversions are faithful and reduce nesting.
Also applies to: 252-270
vm/src/builtins/int.rs (1)65-76: LGTM: consolidated constructor guard reads well
Order-of-evaluation change is benign; exclusions for list/tuple are preserved. Unsafe borrow remains identical.
stdlib/src/math.rs (2)504-531: LGTM: let-chain preserves rounding semantics (half-even) and simplifies control flow
Tests for cases like round(15, -1) == 20, round(25, -1) == 20, and negatives should continue to pass.
vm/src/builtins/memory.rs (2)521-526: Let-chain fallback is correct and preserves semantics.
is_err() && let Some(v) = x.try_float_opt(vm) short-circuits as before; v? still surfaces the float-conversion error when present. LGTM.
533-540: Mirrors ceil() change; looks good.
Same short-circuiting and error behavior as prior nested conditionals. LGTM.
vm/src/builtins/enumerate.rs (1)333-337: Flattened downcast+released check is fine.
Behavior unchanged, now clearer. LGTM.
671-675: 0-d getitem let-chain is correct.
The empty-tuple path is neatly handled; semantics match prior code. LGTM.
vm/src/vm/context.rs (2)114-118: Guarded length-hint read is correct.
Chained pattern keeps obj.length(vm)? gated by Active status; early-return remains identical. LGTM.
vm/src/builtins/super.rs (2)390-395: Int cache lookup via let-chain: OK.
Short-circuits as before; no ownership pitfalls for i. LGTM.
401-406: BigInt cache lookup via let-chain: OK.
Same semantics with improved readability. LGTM.
jit/src/instructions.rs (2)242-246: Downcast+issubclass combined: OK.
Equivalent to prior nested checks; avoids extra nesting. LGTM.
251-256: class path guard consolidation: OK.
Order and conditions preserved; behavior unchanged. LGTM.
vm/src/builtins/object.rs (2)178-183: Let-chain preserves original jump-when-unterminated semantics — looks good
The combined if let with guards reads well and matches the prior nested checks: only jump when there is a current block, it differs from target_block, and it has no terminating inst.
211-215: Post-pass unterminated-block trap check consolidated cleanly
The let-chain correctly traps only when a current block exists and lacks a last inst. No behavior change.
vm/src/stdlib/builtins.rs (2)56-62: Cleaner guard for object.init equality
Using if let ... && to gate the “takes no arguments” TypeError keeps the logic identical and easier to read.
75-101: Abstract-method enforcement refactor is equivalent and tighter
The chained guards plus the single match on count reduce nesting while preserving error messages for 1 vs multiple abstract methods.
vm/src/exceptions.rs (2)968-979: PEP 695: namespace .type_params injection guarded succinctly
The combined checks (attr exists, is PyTuple, non-empty) before setting .type_params keep semantics intact and minimize lookups.
1001-1011: PEP 695: class __type_params__/__parameters__ setup matches prior flow
Good use of a single guard to avoid empty/invalid cases; behavior unchanged.
stdlib/src/unicodedata.rs (1)1538-1542: PyOSError.__reduce__: concise filename2 inclusion
The if let Ok(filename2) ... && !vm.is_none(...) pattern is a nice, equivalent simplification.
1661-1687: PySyntaxError.__init__: de-duplicated tuple handling
Combining the length check and tuple downcast with a single loop over known fields removes duplication; semantics are preserved.
vm/src/stdlib/sys.rs (2)124-128: lookup: chained guard is clear and equivalent
The age check combined with the character lookup is correct and keeps control flow tight.
wasm/lib/src/convert.rs (1)186-196: Let-chain for which::which lookup looks good.
Semantics preserved and clearer control flow.
871-887: Callable validation via let-chains LGTM.
Behavior matches prior nested checks; early error paths remain clear.
Also applies to: 880-887
vm/src/vm/vm_ops.rs (2)83-90: Guarded conversion for Python functions reads well.
The let-chain cleanly ensures a WASM VM id and function type before wrapping.
compiler/codegen/src/symboltable.rs (4)174-182: Let-chain for right-slot dispatch looks correct
Short-circuits on slot_b before fast_issubclass, preserves prior behavior, and keeps the slot_b = None fallback. No functional change spotted.
279-288: Ternary right-slot let-chain mirrors binary path
Same semantics as before with clearer intent; only calls slot_bb when appropriate and clears slot_b on NotImplemented. Good refactor.
compiler/codegen/src/compile.rs (5)243-249: Let-chain for class free variable flagging is correct
The guard tightens evaluation and preserves behavior of setting needs_class_closure.
252-258: Let-chain for classdict is consistent
Matches the __class__ change; semantics unchanged.
736-744: Future import detection simplified correctly
Chained conditionals accurately gate __future__ and set future_annotations only for annotations. Good.
1035-1051: Type-params disallowed-expression check via let-chain is precise
Evaluates the ban list only within TypeParams scope and reports with accurate location. Looks good.
vm/src/builtins/genericalias.rs (1)945-950: Qualname: parent-scope GlobalExplicit detection via let-chain is OK
Only inspects parent_table when present; sets force_global as before. No behavior change observed.
957-963: Qualname: mangled parent lookup let-chain is clean
Uses mangled name and GlobalExplicit check in one guard; matches prior logic.
2811-2814: Class call: keyword-args presence check simplified
The single guard for arguments existence and non-empty keywords is equivalent and clearer.
3531-3534: Mapping pattern: rest ‘_’ validation condensed
Chained guard forbids **_ succinctly; matches previous semantics.
5379-5384: ReturnConst micro-optimization via let-chain is solid
Transforms trailing LoadConst into ReturnConst in-place; minimal and efficient.
vm/src/vm/vm_new.rs (1)272-288: LGTM: let-chain refactor preserves semantics and short-circuits correctly.
vm/src/vm/method.rs (1)350-355: LGTM: chained guard preserves triple-quote detection semantics.
vm/src/vm/mod.rs (3)60-64: LGTM: object dict fast-path collapsed cleanly.
vm/src/protocol/object.rs (2)366-374: LGTM: importlib init uses let-guard; short-circuits as intended.
Note: using cfg!(feature = "rustpython-compiler") keeps the call type-checked in all builds; the function is available, so this is fine.
718-722: LGTM: capacity guard is equivalent and clearer.
833-845: LGTM: exception context wiring unchanged; ordering is clear.
vm/src/builtins/type.rs (3)223-229: Data-descriptor fast path reads clean and preserves precedence.
Early-return when both descr_get and descr_set are present matches CPython’s data-descriptor rules. Looks good.
558-562: Guarded class override check is correct.
Semantics (mask AttributeError, accept real types, avoid same-class) are preserved with reduced nesting.
324-331: Strict qualname type check reads well.
Early error on non-str values mirrors CPython behavior; no concerns.
948-951: Silent fallback to empty tuple — confirm intent.
If __type_params__ exists but isn’t a tuple, this returns (). Is this deliberate (best-effort) or should it raise to surface misuse? The setter already enforces tuples.
1372-1378: Static-type doc fast path is solid.
Combined guard avoids nesting and preserves internal-doc stripping semantics.
Sorry, something went wrong.
| authors = ["RustPython Team"] | ||
| edition = "2024" | ||
| rust-version = "1.87.0" | ||
| rust-version = "1.89.0" |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chainMSRV bump to 1.89.0: verify CI/toolchain/docs match
Looks good for enabling let-chain guards. Please ensure CI images, rust-toolchain files, and any MSRV docs are updated accordingly across the workspace.
Run to spot divergences:
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "Rust toolchain files:"
fd -HI 'rust-toolchain*' -x sh -c 'echo "==> {}"; cat "{}" 2>/dev/null || true'
echo
echo "Per-crate rust-version not using workspace or mismatched:"
rg -n --type toml -C2 '^\s*rust-version\s*=\s*"(.*?)"' | sed -n '1,200p'
echo
echo "Mentions of MSRV or minimum Rust in docs:"
fd -H -t f -a README* docs --exec rg -nC1 -i 'MSRV|Minimum Rust|rustc [0-9]+\.[0-9]+'Length of output: 918
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "Searching for MSRV mentions in README.md"
rg -nC2 'MSRV|Minimum Rust|rustc [0-9]+\.[0-9]+' README.md || true
echo
if [ -d docs ]; then
echo "Searching for MSRV mentions in docs/"
rg -nC2 'MSRV|Minimum Rust|rustc [0-9]+\.[0-9]+' docs || true
fiLength of output: 204
Pin the workspace toolchain to 1.89.0
rust-toolchain.toml still reads channel = "stable"—update it to channel = "1.89.0" (and ensure your CI images reference that exact version). No MSRV references were found in README.md or a docs/ directory.
In Cargo.toml at line 141, the workspace rust-version is pinned to "1.89.0" but rust-toolchain.toml still uses channel = "stable"; update rust-toolchain.toml to set channel = "1.89.0" so the workspace toolchain matches the pinned MSRV, and update any CI image references to use Rust 1.89.0 explicitly (replace generic "stable" tags with "1.89.0" or the appropriate image tag) to ensure consistent toolchain across local, CI, and docs.
Sorry, something went wrong.
| if cfg!(windows) | ||
| && let Ok(real_path) = fs::read_to_string(path.canonicalize().unwrap()) | ||
| { | ||
| return fs::read_dir(real_path.trim()); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Avoid panic in error-fallback path (unwrap in or_else)
path.canonicalize().unwrap() can panic while handling an error; keep this path panic-free.
- .or_else(|e| {
- if cfg!(windows)
- && let Ok(real_path) = fs::read_to_string(path.canonicalize().unwrap())
- {
- return fs::read_dir(real_path.trim());
- }
- Err(e)
- })
+ .or_else(|e| {
+ if cfg!(windows)
+ && let Ok(canonical) = path.canonicalize()
+ && let Ok(real_path) = fs::read_to_string(&canonical)
+ {
+ return fs::read_dir(real_path.trim());
+ }
+ Err(e)
+ })‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if cfg!(windows) | |
| && let Ok(real_path) = fs::read_to_string(path.canonicalize().unwrap()) | |
| { | |
| return fs::read_dir(real_path.trim()); | |
| } | |
| fs::read_dir(path).or_else(|e| { | |
| if cfg!(windows) | |
| && let Ok(canonical) = path.canonicalize() | |
| && let Ok(real_path) = fs::read_to_string(&canonical) | |
| { | |
| return fs::read_dir(real_path.trim()); | |
| } | |
| Err(e) | |
| }) |
In derive-impl/src/compile_bytecode.rs around lines 143-147, the error-fallback
path uses path.canonicalize().unwrap() which can panic; replace the unwrap with
safe error handling by first attempting canonicalize and only proceeding if it
succeeds (e.g., if let Ok(canonical) = path.canonicalize() { if let
Ok(real_path) = fs::read_to_string(&canonical) { return
fs::read_dir(real_path.trim()); } } ), so both canonicalize and read_to_string
are checked for Ok before calling read_dir, keeping the fallback panic-free.
Sorry, something went wrong.
| if matches!(af, c::AF_INET | c::AF_UNSPEC) | ||
| && !name.contains('%') | ||
| && let Ok(addr) = name.parse::<Ipv6Addr>() | ||
| { | ||
| return Ok(SocketAddr::V6(net::SocketAddrV6::new(addr, 0, 0, 0))); | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue
Bug: IPv6 branch checks the wrong address family constant
This should gate on AF_INET6 | AF_UNSPEC, not AF_INET | AF_UNSPEC. As written, it may accept IPv6 literals even when af == AF_INET, and will skip the fast path when af == AF_INET6.
Apply this fix:
- if matches!(af, c::AF_INET | c::AF_UNSPEC)
+ if matches!(af, c::AF_INET6 | c::AF_UNSPEC)
&& !name.contains('%')
&& let Ok(addr) = name.parse::<Ipv6Addr>()
{
return Ok(SocketAddr::V6(net::SocketAddrV6::new(addr, 0, 0, 0)));
}‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if matches!(af, c::AF_INET | c::AF_UNSPEC) | |
| && !name.contains('%') | |
| && let Ok(addr) = name.parse::<Ipv6Addr>() | |
| { | |
| return Ok(SocketAddr::V6(net::SocketAddrV6::new(addr, 0, 0, 0))); | |
| } | |
| if matches!(af, c::AF_INET6 | c::AF_UNSPEC) | |
| && !name.contains('%') | |
| && let Ok(addr) = name.parse::<Ipv6Addr>() | |
| { | |
| return Ok(SocketAddr::V6(net::SocketAddrV6::new(addr, 0, 0, 0))); | |
| } |
In stdlib/src/socket.rs around lines 2285 to 2290, the IPv6 fast-path incorrectly checks for c::AF_INET instead of c::AF_INET6; change the matches! predicate to match c::AF_INET6 | c::AF_UNSPEC so the branch only triggers for IPv6 or unspecified families, keeping the other guard conditions (no '%' and name.parse::<Ipv6Addr>()) unchanged.
Sorry, something went wrong.
| if !obj.fast_isinstance(vm.ctx.types.str_type) | ||
| && let Ok(elements) = vm.map_iterable_object(obj, |x| value_from_object(vm, &x)) | ||
| { | ||
| return elements; |
There was a problem hiding this comment.
⚠️ Potential issue
Bug: returning bare elements breaks the function’s return type
elements is a Vec<u8> bound from Ok(elements), but the function returns PyResult<Vec<u8>>. This should return Ok(elements); otherwise it will not compile (or would be semantically wrong if it did).
Apply this fix:
- if !obj.fast_isinstance(vm.ctx.types.str_type)
- && let Ok(elements) = vm.map_iterable_object(obj, |x| value_from_object(vm, &x))
- {
- return elements;
- }
+ if !obj.fast_isinstance(vm.ctx.types.str_type)
+ && let Ok(elements) = vm.map_iterable_object(obj, |x| value_from_object(vm, &x))
+ {
+ return Ok(elements);
+ }‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if !obj.fast_isinstance(vm.ctx.types.str_type) | |
| && let Ok(elements) = vm.map_iterable_object(obj, |x| value_from_object(vm, &x)) | |
| { | |
| return elements; | |
| if !obj.fast_isinstance(vm.ctx.types.str_type) | |
| && let Ok(elements) = vm.map_iterable_object(obj, |x| value_from_object(vm, &x)) | |
| { | |
| return Ok(elements); | |
| } |
In vm/src/byte.rs around lines 11 to 14, the match binds elements as a Vec<u8> from Ok(elements) but the function signature returns PyResult<Vec<u8>>; change the return to return Ok(elements) instead of returning bare elements so the types match and the function compiles and behaves correctly.
Sorry, something went wrong.
| if let Some(ref kwargs) = kwargs { | ||
| for pair in object_entries(kwargs) { | ||
| let (key, val) = pair?; | ||
| py_func_args | ||
| .kwargs | ||
| .insert(js_sys::JsString::from(key).into(), js_to_py(vm, val)); | ||
| } |
There was a problem hiding this comment.
⚠️ Potential issue
Likely type mismatch inserting kwargs keys (PyStrRef expected).
FuncArgs.kwargs typically uses PyStrRef keys; inserting js_sys::JsString via .into() is unlikely to compile. Convert to Rust String then intern/new_str.
Use the VM to produce a Python string key:
- py_func_args
- .kwargs
- .insert(js_sys::JsString::from(key).into(), js_to_py(vm, val));
+ let key = String::from(js_sys::JsString::from(key));
+ py_func_args
+ .kwargs
+ .insert(vm.ctx.intern_str(&key).to_owned(), js_to_py(vm, val));If kwargs expects plain String keys in this crate version, adjust accordingly, but avoid relying on Into from JsString.
📝 Committable suggestion‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if let Some(ref kwargs) = kwargs { | |
| for pair in object_entries(kwargs) { | |
| let (key, val) = pair?; | |
| py_func_args | |
| .kwargs | |
| .insert(js_sys::JsString::from(key).into(), js_to_py(vm, val)); | |
| } | |
| if let Some(ref kwargs) = kwargs { | |
| for pair in object_entries(kwargs) { | |
| let (key, val) = pair?; | |
| // Convert the JS string key into a Rust String and intern it as a PyStrRef | |
| let key = String::from(js_sys::JsString::from(key)); | |
| py_func_args | |
| .kwargs | |
| .insert(vm.ctx.intern_str(&key).to_owned(), js_to_py(vm, val)); | |
| } | |
| } |
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)wasm/lib/src/convert.rs (1)🧹 Nitpick comments (7)111-117: Kwargs key type mismatch (likely compile error) — convert keys to PyStrRef.
FuncArgs.kwargs expects PyStrRef keys. Inserting JsString via .into() won’t type-check. Use the VM to intern a Rust String into PyStrRef.
Apply:
- py_func_args - .kwargs - .insert(js_sys::JsString::from(key).into(), js_to_py(vm, val)); + let key = String::from(js_sys::JsString::from(key)); + py_func_args + .kwargs + .insert(vm.ctx.intern_str(&key).to_owned(), js_to_py(vm, val));
vm/src/readline.rs (1)📜 Review detailsvm/src/stdlib/nt.rs (1)98-102: Prefer creating the parent unconditionally; drop the exists() check.
create_dir_all is idempotent and avoids a TOCTOU + extra metadata syscall. Creating the parent regardless of file existence is simpler and equally safe.
- if !path.exists() - && let Some(parent) = path.parent() - { - std::fs::create_dir_all(parent)?; - } + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + }stdlib/src/syslog.rs (1)366-380: Avoid unwrap() at FFI boundary; map NUL conversion error to a Python exception.
WideCString::from_os_str(parent).unwrap() can panic on interior NUL. Prefer error propagation to keep VM stability consistent with surrounding conversions.
- let parent = widestring::WideCString::from_os_str(parent).unwrap(); + let parent = widestring::WideCString::from_os_str(parent) + .map_err(|e| e.to_pyexception(vm))?;stdlib/src/sqlite.rs (1)29-38: Let-chain looks good; consider robust basename extraction (handles '/' and uses last separator).
Current logic uses the first backslash and includes it in the returned slice. Prefer taking the last path separator and support both Windows and Unix separators.
- return Some( - PyStr::from(match argv.find('\\') { - Some(value) => &argv[value..], - None => argv, - }) - .into_ref(&vm.ctx), - ); + return Some( + PyStr::from(argv.rsplit(['\\', '/']).next().unwrap_or(argv)) + .into_ref(&vm.ctx), + );vm/src/vm/vm_new.rs (1)2941-2956: Avoid O(n) char traversal; use byte check for preceding space.
chars().nth(bracket_pos - 1) treats bracket_pos as a char index; it’s a byte offset from find. Checking the preceding byte is simpler and avoids extra iteration.
- let end_pos = if bracket_pos > 0 - && name_str.chars().nth(bracket_pos - 1) == Some(' ') - { + let end_pos = if bracket_pos > 0 + && name_str.as_bytes().get(bracket_pos - 1) == Some(&b' ') + { bracket_pos - 1 } else { bracket_pos };stdlib/src/contextvars.rs (1)350-355: Replace char-iterator triple-quote detection with byte-slice starts_with
raw_location.start().to_usize() yields a byte offset; slicing and calling starts_with("'''") or starts_with("\"\"\"") is more concise, avoids multiple iterator steps, and safely respects UTF-8 boundaries.- if let Some(quote) = iter.nth(loc) - && iter.next() == Some(quote) - && iter.next() == Some(quote) - { - is_incomplete = true; - } + if let Some(rest) = source.get(loc..) { + if rest.starts_with("'''") || rest.starts_with("\"\"\"") { + is_incomplete = true; + } + }wasm/lib/src/convert.rs (1)381-385: Short-circuit safe checks before unsafe deref.
Evaluate the cheap, safe ID check first, then perform the unsafe as_ptr deref to minimize time spent borrowing potentially-mutated memory.
- if let Some(cached) = unsafe { &*cached_ptr } - && zelf.cached_id.load(Ordering::SeqCst) == ctx.get_id() - && cached.idx + 1 == ctxs.len() + if zelf.cached_id.load(Ordering::SeqCst) == ctx.get_id() + && let Some(cached) = unsafe { &*cached_ptr } + && cached.idx + 1 == ctxs.len() { return Some(cached.object.clone()); }87-90: Avoid double unwrap on push_held_rc; surface errors instead of panicking.
unwrap().unwrap() can panic at conversion time. Prefer propagating to JS as an error or failing closed (e.g., returning a throwing closure). Minimal improvement is to use expect(...); better is to defer holding/upgrading into the closure and return Err on failure.
Example minimal change:
- let weak_py_obj = wasm_vm.push_held_rc(py_obj).unwrap().unwrap(); + let weak_py_obj = wasm_vm + .push_held_rc(py_obj) + .expect("failed to push held PyObject into WASM VM") + .expect("failed to obtain weak ref for held PyObject");Preferable (error-returning) approach inside the closure body:
// inside the closure, before upgrading: let weak_py_obj = match wasm_vm.push_held_rc(py_obj.clone()) { Ok(weak) => weak.map_err(|e| e)?, // JsValue error Err(py_err) => return Err(py_err_to_js_err(vm, &py_err)), };If you want, I can provide a full diff moving the hold into the closure and aligning return types.
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration.
📥 CommitsReviewing files that changed from the base of the PR and between fd1e7ad and 1546204.
📒 Files selected for processing (52)📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style (cargo fmt to format)
Always run clippy to lint code (cargo clippy) before completing tasks. Fix any warnings or lints that are introduced by your changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust
Files:
vm/src/stdlib/os.rs (1)vm/src/protocol/mapping.rs (1)
- errno_err (39-41)
vm/src/protocol/sequence.rs (1)stdlib/src/syslog.rs (1)
- find_methods (98-101)
vm/src/stdlib/sys.rs (1)wasm/lib/src/convert.rs (2)
- argv (129-136)
wasm/lib/src/js_module.rs (6)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)wasm/lib/src/vm_class.rs (1)
- args (186-186)
- args (201-201)
- args (222-222)
- new (96-99)
- new (305-341)
- new (396-400)
- stored_vm_from_wasm (99-105)
vm/src/readline.rs (1)vm/src/windows.rs (1)98-105: LGTM on the let-chain conversion.
Semantics are preserved; directory creation only happens when a parent exists, and history saving remains unchanged.
vm/src/protocol/mapping.rs (1)113-123: Let-chain refactor looks correct and preserves control flow.
Binding errno and gating with matches! is semantically equivalent to the prior nested form. No behavior change detected.
vm/src/signal.rs (1)81-87: LGTM: let-chain simplifies control flow without changing semantics.
Condition combines method lookup and capability check; returned borrow_static usage matches existing patterns.
stdlib/src/sqlite.rs (2)38-43: LGTM: chained guards are correct and short-circuit as intended.
Preserves prior behavior: index and invoke only when triggered, handler exists, and is callable.
stdlib/src/contextvars.rs (1)574-578: LGTM: progress callback let-chain is fine.
Shadowing val is clear; fall-through to -1 unchanged.
1721-1725: LGTM: close() release path is equivalent and safe.
Resets active statement when present; ownership via take() remains correct.
common/src/fileutils.rs (1)381-385: Let-chain refactor LGTM.
The conversion to an if-let chain reads correctly and preserves the early-return fast path semantics.
wasm/lib/src/convert.rs (2)84-91: Let-chain refactor looks good; adds .com to executable set (Windows-correct).
Clear, preserves behavior, and marking .com as executable is appropriate on Windows. No further action.
83-89: Guarded let-chain is fine.
Concise and equivalent to the prior nested checks.
136-140: Promise bridge let-chain LGTM.
Matches the project style used elsewhere; behavior unchanged.
Sorry, something went wrong.
| if let Some(cached) = unsafe { &*cached_ptr } | ||
| && zelf.cached_id.load(Ordering::SeqCst) == ctx.get_id() | ||
| && cached.idx + 1 == ctxs.len() | ||
| { | ||
| return Some(cached.object.clone()); |
There was a problem hiding this comment.
⚠️ Potential issue
Potential UB: dereferencing AtomicCell::as_ptr without synchronization.
Reading unsafe { &*cached_ptr } races with concurrent store/swap on cached, risking undefined behavior. This preexisted the refactor, but the let-chain keeps the hazard.
Consider replacing cached: AtomicCell<Option<ContextVarCache>> with a synchronization primitive suited for non-Copy data:
If keeping AtomicCell, you need a design that avoids borrowing through as_ptr (e.g., store Arc<ContextVarCache> and atomically swap/load the Arc).
I can open an issue and sketch a safe refactor using ArcSwapOption if you’d like.
🤖 Prompt for AI AgentsIn stdlib/src/contextvars.rs around lines 381-385 the code unsafely dereferences cached_ptr from AtomicCell::as_ptr which races with concurrent store/swap and can produce UB; fix by replacing the AtomicCell<Option<ContextVarCache>> with a synchronization primitive that supports safe non-Copy data (either RwLock<Option<ContextVarCache>> for a simple fix, or arc-swap’s ArcSwapOption<ContextVarCache> for lock-free reads). Update all reads to use a read lock or ArcSwapOption::load (and clone the Arc) instead of dereferencing raw pointers; alternatively, if you must keep AtomicCell, change it to store Arc<ContextVarCache> and atomically swap/load Arcs and never borrow through as_ptr. Ensure all unsafe derefs are removed and replace with safe load/clone or read-guard access.
Sorry, something went wrong.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)vm/src/builtins/str.rs (1)📜 Review detailscompiler/codegen/src/symboltable.rs (3)327-333: Avoid shadowing the outer value for readability.
The let-chain rebinding value shadows the earlier value: &Wtf8. Renaming the slice binding reduces cognitive load.
Apply:
- } else if let Some(value) = value.get(internal.1..) - && let Some(ch) = value.code_points().next() + } else if let Some(rest) = value.get(internal.1..) + && let Some(ch) = rest.code_points().next() { internal.0.position += 1; internal.1 += ch.len_wtf8(); return Ok(PyIterReturn::Return(ch.to_pyobject(vm))); }243-258: DRY the two free-variable checks with matches! and |=.
Avoids temporary bindings and duplication while preserving behavior.
- if let Some(class_symbol) = symbol_table.symbols.get("__class__") - && class_symbol.scope == SymbolScope::Free - { - symbol_table.needs_class_closure = true; - // Note: In CPython, the symbol is removed from the free set, - // but in RustPython we handle this differently during code generation - } + symbol_table.needs_class_closure |= matches!( + symbol_table.symbols.get("__class__"), + Some(sym) if sym.scope == SymbolScope::Free + ); - if let Some(classdict_symbol) = symbol_table.symbols.get("__classdict__") - && classdict_symbol.scope == SymbolScope::Free - { - symbol_table.needs_classdict = true; - // Note: In CPython, the symbol is removed from the free set, - // but in RustPython we handle this differently during code generation - } + symbol_table.needs_classdict |= matches!( + symbol_table.symbols.get("__classdict__"), + Some(sym) if sym.scope == SymbolScope::Free + ); + // Note: CPython removes the symbol from the free set; RustPython handles this during codegen.
736-744: Simplify future-import detection; use any() and as_str().
More idiomatic and avoids iterating after the flag is set.
- if let Stmt::ImportFrom(StmtImportFrom { module, names, .. }) = &statement - && module.as_ref().map(|id| id.as_str()) == Some("__future__") - { - for feature in names { - if &feature.name == "annotations" { - self.future_annotations = true; - } - } - } + if let Stmt::ImportFrom(StmtImportFrom { module, names, .. }) = &statement + && module.as_ref().is_some_and(|id| id.as_str() == "__future__") + && names.iter().any(|a| a.name.as_str() == "annotations") + { + self.future_annotations = true; + }
1035-1052: Prefer “assignment expression” wording for consistency with other diagnostics.
Elsewhere you use “assignment expression”; align messaging here.
- Expr::Named(_) => Some("named"), + Expr::Named(_) => Some("assignment"),
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration.
📥 CommitsReviewing files that changed from the base of the PR and between 1546204 and 5a1371d.
📒 Files selected for processing (53)📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.rs: Follow the default rustfmt code style (cargo fmt to format)
Always run clippy to lint code (cargo clippy) before completing tasks. Fix any warnings or lints that are introduced by your changes
Follow Rust best practices for error handling and memory management
Use the macro system (pyclass, pymodule, pyfunction, etc.) when implementing Python functionality in Rust
Files:
vm/src/protocol/object.rs (1)vm/src/vm/mod.rs (1)vm/src/frame.rs (1)
- s (371-371)
- spec (2236-2236)
vm/src/import.rs (1)⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- init_importlib_package (32-69)
stdlib/src/scproxy.rs (2)vm/src/cformat.rs (1)89-93: Good let-chain conversion and short-circuit ordering
Checking enabled first before attempting the host lookup is the right evaluation order. Readable and efficient.
100-102: Confirm proxy scheme for non-HTTP entries
The value uses http:// for all protocols, including "https", "ftp", and "gopher". If that mirrors CPython/_scproxy behavior, fine; otherwise consider protocol-appropriate schemes.
vm/src/vm/mod.rs (3)198-201: Let-chain refactor for %c (str case) looks correct.
Semantics match prior behavior: only a single code point passes; others fall through to the existing TypeError.
vm/src/vm/context.rs (2)366-374: Concise error-guarded init via let-chain; no behavior change.
Reads well and keeps the side effect gated behind settings and feature flag.
718-722: Capacity guard flattened; logic preserved.
Early return on pathological capacity remains intact and clearer now.
833-845: Exception context linking refactor is sound.
Cycle-avoidance loop and final set___context__ are unchanged semantically; the let-chain reduces nesting.
390-395: Let-chain refactor preserves behavior; cache hit path stays correct.
Short-circuit evaluation matches the previous nested if let semantics, and the computed index is provably non-negative within the guarded range.
401-406: Remove optional refactor suggestion
No impl From<&BigInt> for PyInt exists in the codebase, so the current clone-based fallback is necessary.
Sorry, something went wrong.
| let h = std::borrow::Cow::<str>::from(&host); | ||
| let v = if let Some(port) = proxy_dict | ||
| .find(port_key) | ||
| .and_then(|v| v.downcast::<CFNumber>()) | ||
| .and_then(|v| v.to_i32()) | ||
| { | ||
| let h = std::borrow::Cow::<str>::from(&host); | ||
| let v = if let Some(port) = proxy_dict | ||
| .find(port_key) | ||
| .and_then(|v| v.downcast::<CFNumber>()) | ||
| .and_then(|v| v.to_i32()) | ||
| { | ||
| format!("http://{h}:{port}") | ||
| } else { | ||
| format!("http://{h}") | ||
| }; | ||
| result.set_item(proto, vm.new_pyobj(v), vm)?; | ||
| } | ||
| format!("http://{h}:{port}") | ||
| } else { | ||
| format!("http://{h}") | ||
| }; | ||
| result.set_item(proto, vm.new_pyobj(v), vm)?; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
⚠️ Potential issue
Cow from CFString won’t compile; build the String explicitly
CFString doesn’t coerce to &str, so Cow::<str>::from(&host) is invalid on macOS builds. Convert to String (or format host directly) and avoid the extra Cow.
Apply:
- let h = std::borrow::Cow::<str>::from(&host);
- let v = if let Some(port) = proxy_dict
+ let host_s = host.to_string();
+ let proxy_url = if let Some(port) = proxy_dict
.find(port_key)
.and_then(|v| v.downcast::<CFNumber>())
.and_then(|v| v.to_i32())
{
- format!("http://{h}:{port}")
+ format!("http://{host_s}:{port}")
} else {
- format!("http://{h}")
+ format!("http://{host_s}")
};
- result.set_item(proto, vm.new_pyobj(v), vm)?;
+ result.set_item(proto, vm.new_pyobj(proxy_url), vm)?;‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| let h = std::borrow::Cow::<str>::from(&host); | |
| let v = if let Some(port) = proxy_dict | |
| .find(port_key) | |
| .and_then(|v| v.downcast::<CFNumber>()) | |
| .and_then(|v| v.to_i32()) | |
| { | |
| let h = std::borrow::Cow::<str>::from(&host); | |
| let v = if let Some(port) = proxy_dict | |
| .find(port_key) | |
| .and_then(|v| v.downcast::<CFNumber>()) | |
| .and_then(|v| v.to_i32()) | |
| { | |
| format!("http://{h}:{port}") | |
| } else { | |
| format!("http://{h}") | |
| }; | |
| result.set_item(proto, vm.new_pyobj(v), vm)?; | |
| } | |
| format!("http://{h}:{port}") | |
| } else { | |
| format!("http://{h}") | |
| }; | |
| result.set_item(proto, vm.new_pyobj(v), vm)?; | |
| let host_s = host.to_string(); | |
| let proxy_url = if let Some(port) = proxy_dict | |
| .find(port_key) | |
| .and_then(|v| v.downcast::<CFNumber>()) | |
| .and_then(|v| v.to_i32()) | |
| { | |
| format!("http://{host_s}:{port}") | |
| } else { | |
| format!("http://{host_s}") | |
| }; | |
| result.set_item(proto, vm.new_pyobj(proxy_url), vm)?; |
In stdlib/src/scproxy.rs around lines 94 to 104, the code uses
Cow::<str>::from(&host) where host is a CFString-derived value; CFString doesn't
coerce to &str so that conversion fails to compile. Replace the Cow usage by
constructing an owned String from host (e.g. host.to_string() or format!("{}",
host)) and use that String when formatting the URL (or interpolate host directly
into format! calls) so the code produces an owned Rust String before calling
vm.new_pyobj(v).
Sorry, something went wrong.
There was a problem hiding this comment.
lots of dedenting, great
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Raising the rust-version to 1.89 prompts clippy to start recommending replacing nested if lets with let chains. This is the result of doing exactly that and running cargo clippy --fix --workspace. It's a big diff but I think the prevented rightward creep really does aid in clarity. Reviewed well with whitespace-insensitivity turned on.
Summary by CodeRabbit
Refactor
Chores
Notes