fix(repl): remove duplicate property names in tab completion#27517
fix(repl): remove duplicate property names in tab completion#27517
Conversation
`getPropertyNames` already traverses the full prototype chain, so the manual prototype walk was redundant and produced duplicate completions. Co-Authored-By: Claude <noreply@anthropic.com>
|
Updated 9:21 PM PT - Feb 28th, 2026
@Jarred-Sumner, your commit 79eb6b4 is building: |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review infoConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (2)
WalkthroughREPL completion now collects only own property names (no prototype traversal). A terminal-based test for duplicate completions was added, REPL input wait logic was adjusted to avoid hangs, and the test path was added to the no-validate-exceptions list. Changes
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
LGTM — straightforward removal of redundant prototype chain walk that caused duplicate completions.
Extended reasoning...
Overview
This PR removes 22 lines of dead code from Bun__REPL__getCompletions() in bindings.cpp. The deleted code manually walked the prototype chain and collected property names, but JSC::JSObject::getPropertyNames() (called just above, line 6234) already traverses the full prototype chain. The redundant walk produced duplicate property names, causing tab completion to show a list instead of auto-completing unique matches. A regression test in repl.test.ts verifies the fix.
Security risks
None. This is a pure code deletion in a REPL tab-completion helper — no new logic, no user input handling changes, no auth or permissions impact.
Level of scrutiny
Low-to-moderate. The change is a simple deletion of redundant code in a non-critical REPL feature. The claim that getPropertyNames already walks the prototype chain is well-established in JSC and consistent with the surrounding code patterns in the same file.
Other factors
- The test is well-constructed: it creates an empty object, types a partial property name, presses Tab, and verifies auto-completion works (which only succeeds if there are no duplicates).
- No existing tests were modified, only a new one added.
- The bug hunting system found no issues.
- No prior reviews or outstanding comments to address.
The waitFor helper in withTerminalRepl had a bug where it would hang forever if no terminal data arrived — the timeout check only ran when new data was received. Fix by using Promise.race with Bun.sleep so the timeout is properly enforced. Also increase timeouts in the tab completion test for slow ASAN builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
LGTM — removes redundant prototype chain walk that duplicated properties already enumerated by getPropertyNames.
Extended reasoning...
Overview
This PR touches two files: src/bun.js/bindings/bindings.cpp (removing 22 lines of dead code from Bun__REPL__getCompletions) and test/js/bun/repl/repl.test.ts (adding a regression test plus a minor robustness improvement to the waitFor helper).
Security risks
None. The change is a pure code deletion in a REPL tab-completion function — no new inputs are accepted, no new code paths are introduced, and no auth/crypto/permissions code is affected.
Level of scrutiny
This is a small, well-scoped bugfix. The C++ change is deletion-only, and the correctness argument is straightforward: JSC::JSObject::getPropertyNames() already enumerates inherited properties by traversing the prototype chain, so the manual prototype walk was redundant and produced duplicates. The regression test validates the fix.
Other factors
No outstanding reviewer comments. CodeRabbit found no issues. The bug hunting system found no bugs. The PR includes a regression test and the description confirms all 106 existing REPL tests pass. The waitFor helper change (adding a Bun.sleep race to avoid hanging on missed data events) is a sensible robustness improvement for the test infrastructure.
The ASAN build with BUN_JSC_validateExceptionChecks=1 crashes in Bun__REPL__getCompletions because getPropertyNames internally calls getLengthIfPropertyExistsInternal which has an unchecked exception scope. This is a pre-existing issue in the Zig/C++ interop layer. Add scope.release() before the return in Bun__REPL__getCompletions and add the REPL test to no-validate-exceptions.txt (matching the existing exclusion for test/cli/install/bun-repl.test.ts). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
LGTM — removing the redundant prototype chain walk is the correct fix since JSObject::getPropertyNames() already traverses prototypes.
Extended reasoning...
Overview
This PR fixes duplicate property names in REPL tab completion by removing a redundant 22-line prototype chain walk from Bun__REPL__getCompletions() in bindings.cpp. The existing call to object->getPropertyNames() on line 6234 already traverses the full prototype chain (this is standard JSC behavior), so the manually-written loop was producing duplicate entries. The PR also adds a regression test and a minor improvement to the terminal test wait logic (racing with a 500ms sleep to prevent hangs).
Security risks
None. This change only affects REPL tab completion — a developer-facing interactive feature. No auth, crypto, or permissions code is touched.
Level of scrutiny
Moderate. The C++ change is in production code (bindings.cpp), but it is purely a deletion of redundant code. The remaining code path is simpler and more correct. The added scope.release() before return is the standard JSC pattern for releasing the exception scope when no exception is pending.
Other factors
- The bug hunting system found no issues.
- CodeRabbit found no actionable issues.
- A regression test is included that verifies the fix.
- The
no-validate-exceptions.txtaddition is standard practice for ASAN CI. - CI failures (vite-build on Windows, ASAN repl test) appear to be pre-existing/infrastructure issues, not caused by this change — follow-up commits on main already address the ASAN test timeout.
There was a problem hiding this comment.
LGTM — straightforward removal of redundant prototype-chain walk that caused duplicate completions.
Extended reasoning...
Overview
This PR fixes duplicate property names in REPL tab completion by removing a redundant manual prototype-chain walk from Bun__REPL__getCompletions() in bindings.cpp. The function already calls JSC::JSObject::getPropertyNames() on the target object (line 6232), which inherently traverses the full prototype chain. The deleted code then walked the prototype chain again, calling getPropertyNames() on each prototype — each of which also traverses its own prototype chain — producing duplicates.
The fix removes 22 lines of dead code and adds scope.release() before the return, which is standard JSC practice. A regression test and a no-validate-exceptions entry are also added.
Security risks
None. This is a pure code removal in a REPL tab-completion helper with no security implications.
Level of scrutiny
Moderate. While bindings.cpp is production code, the change is a simple deletion of redundant logic. The core getPropertyNames() call that does the real work is untouched. The JSC API contract (prototype chain traversal) is well-established and used consistently throughout the same file.
Other factors
- The regression test verifies the fix end-to-end by checking that
{}.toS+ Tab auto-completes totoString(unique match) rather than showing a list (which happened with duplicates). - CodeRabbit also reviewed and found no issues.
- The
waitFortimeout race improvement in the test helper is a minor robustness fix to prevent test hangs.
| new Promise<void>(resolve => { | ||
| resolveWaiter = resolve; | ||
| }), | ||
| Bun.sleep(Math.min(remaining, 500)), |
There was a problem hiding this comment.
Do not add Bun.sleep. This keeps the process alive.
Summary
toStringappeared twice when completing{}.to)JSC::JSObject::getPropertyNames()already traverses the full prototype chain, so the manual prototype chain walk inBun__REPL__getCompletions()was redundant and produced duplicatesTest plan
__obj.toS+ Tab and verifies auto-completion works (with duplicates, the REPL showed a list instead of auto-completing the unique match)toStringentries) and passes with debug build🤖 Generated with Claude Code