Open
Conversation
Implements the infrastructure for Perl 5 compatible lexical warnings: - Create WarningBitsRegistry.java: HashMap registry mapping class name to compile-time warning bits, enabling caller()[9] lookups - Enhance WarningFlags.java: - Add PERL5_OFFSETS map with Perl 5 compatible category offsets - Add userCategoryOffsets for warnings::register support - Add toWarningBitsString() for Perl 5 compatible bits format - Add isEnabledInBits() and isFatalInBits() utility methods - Add registerUserCategoryOffset() for dynamic category allocation - Enhance ScopedSymbolTable.java: - Add warningFatalStack for FATAL warnings tracking - Update enterScope()/exitScope() to handle fatal stack - Update snapShot() and copyFlagsFrom() to copy fatal stack - Add fatal warning category methods - Add getWarningBitsString() for caller()[9] support This is Phase 1 of the lexical warnings implementation as documented in dev/design/lexical-warnings.md. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add warn variants for + and - operators that check for uninitialized
values when 'use warnings "uninitialized"' is in effect.
- MathOperators.java: Added addWarn() and subtractWarn() methods
- Fixed tied scalar double-fetch issue by calling getNumber() first
then checking for scalarZero (the cached value returned for UNDEF)
- This ensures a single FETCH for tied scalars while still detecting
uninitialized values correctly
- OperatorHandler.java: Added +_warn, -_warn operator entries and
getWarn() method to get warning variant names
- EmitOperator.java: Modified emitOperator() and emitOperatorWithKey()
to select warn variants based on isWarningCategoryEnabled("uninitialized")
- EmitBinaryOperatorNode.java: Updated binary operator switch to use
warn variants for + and - when warnings are enabled
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Centralize the uninitialized value warning logic in RuntimeScalar.getNumberWarn() instead of checking for scalarZero in each operator method. Benefits: - Single place for warning logic, easier to maintain - Correctly handles tied scalars (fetch once, then check the fetched value) - Reusable by all arithmetic operators (*, /, %, etc.) - Cleaner operator implementations RuntimeScalar.java: - Added getNumberWarn(String operation) method that checks for UNDEF before converting to number, emitting warning when needed - For tied scalars, fetches first then recursively checks the fetched value MathOperators.java: - Simplified addWarn() and subtractWarn() methods to use getNumberWarn() - Removed scalarZero identity checks Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add two-variant pattern for *, /, %, **, and unary - operators. When 'use warnings "uninitialized"' is enabled, the warn variants are called, checking for undefined values via getNumberWarn(). Changes: - MathOperators.java: - Refactored multiply() to remove inline warnings (fast path) - Added multiplyWarn() using getNumberWarn() - Refactored divide() to remove inline warnings (fast path) - Added divideWarn() using getNumberWarn() - Added modulusWarn() for % operator - Refactored pow() to remove inline warnings (fast path) - Added powWarn() for ** operator - Added unaryMinusWarn() for unary - operator - OperatorHandler.java: - Added *_warn, /_warn, %_warn, **_warn, unaryMinus_warn entries The emitter (EmitBinaryOperatorNode, EmitOperator) already uses OperatorHandler.getWarn() which automatically selects the warn variant when uninitialized warnings are enabled. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Document completion of Phase 2 (Two-variant operator methods): - getNumberWarn() for centralized undef checking - Warn variants for all arithmetic operators - OperatorHandler entries for warn variants Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Implement caller()[9] support for the JVM backend by storing compile-time warning bits in generated classes and registering them with WarningBitsRegistry. Changes: - EmitterMethodCreator: Add WARNING_BITS static field and <clinit> static initializer to register bits with WarningBitsRegistry - RuntimeCode: Add extractJavaClassNames() helper to extract class names from stack trace, update callerWithSub() to look up warning bits from registry for element 9 Known limitation: Warning bits are per-class, not per-call-site. All calls from the same class share the same warning bits, but different closures correctly get their own warning bits. Refs: dev/design/lexical-warnings.md Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Implement caller()[9] support for the interpreter backend by storing compile-time warning bits in InterpretedCode and registering them with WarningBitsRegistry. Changes: - InterpretedCode: Add warningBitsString field, register with WarningBitsRegistry in constructor using identity hash code key - BytecodeCompiler: Extract warningBitsString from symbolTable and pass to InterpretedCode constructor Both JVM and interpreter backends now support caller()[9] returning the compile-time warning bits for the calling frame. Refs: dev/design/lexical-warnings.md Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Update warnings:: module functions to use caller()[9] for checking warning bits from the calling scope. This enables proper lexical warning control to work across subroutine calls. Changes to Warnings.java: - Add getWarningBitsAtLevel() helper to get warning bits from caller() - enabled() now uses caller()[9] with WarningFlags.isEnabledInBits() - warnif() checks caller()[9] and handles FATAL warnings (dies if fatal) - Add fatal_enabled() using WarningFlags.isFatalInBits() - Add enabled_at_level() for checking at specific stack levels - Add fatal_enabled_at_level() for FATAL check at specific levels - Add warnif_at_level() for warning at specific stack levels New registered methods: - warnings::enabled_at_level - warnings::fatal_enabled - warnings::fatal_enabled_at_level - warnings::warnif_at_level Refs: dev/design/lexical-warnings.md Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Phase 7 of lexical warnings: Fixed warnings::fatal_enabled() to correctly report FATAL status by: 1. SubroutineParser.java: Copy warningFatalStack and warningDisabledStack when creating filteredSnapshot for named subroutines. This was the root cause - named subs were not inheriting FATAL flags from their definition scope. 2. Warnings.java: Updated getWarningBitsAtLevel() to use level+1 to skip the Java implementation frame (Warnings.java) in the caller stack trace. 3. WarningFlags.java: Added isFatalInBits() method to check FATAL bits in a Perl 5 format warning bits string. 4. CompilerFlagNode.java: Added warningFatalFlags and warningDisabledFlags fields to track FATAL and disabled state separately from enabled state. 5. EmitCompilerFlag.java: Apply fatal and disabled flags from CompilerFlagNode. 6. EmitterMethodCreator.java: Added applyCompilerFlagNodes() to pre-apply CompilerFlagNodes so WARNING_BITS captures effective flags including FATAL. 7. BytecodeCompiler.java: Push/pop warningFatalStack and warningDisabledStack in enterScope/exitScope for interpreter. 8. StatementParser.java: Pass fatalFlags and disabledFlags to CompilerFlagNode. Test results: - warnings::fatal_enabled() now correctly returns true when 'use warnings FATAL => "all"' is in effect, including for nested subroutine calls. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add warnWithCategory() method to check if warning category is FATAL - Use caller() to look up warning bits from Perl code's scope - Convert warning to die() when category is marked FATAL - Update StringOperators to use warnWithCategory() for concat warnings Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add pushCurrent/popCurrent/getCurrent to WarningBitsRegistry for tracking current warning context during code execution - Update RuntimeCode.apply() to push/pop warning bits around code execution - Update InterpretedCode.apply() to push/pop warning bits - Modify warnWithCategory() to check both caller() and context stack This enables FATAL warnings to work correctly for: - File-scope 'use warnings FATAL => ...' - Named subroutines inheriting or setting their own warning bits - Top-level code (no named subroutine) Note: Block-scoped 'use warnings FATAL' inside a subroutine/program doesn't work due to per-class warning bits storage (not per-scope). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Document FATAL warnings implementation status - Note ThreadLocal context stack approach - Document known limitation for block-scoped FATAL warnings Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add isWarnFlagSet() helper to check $^W global variable - Update warnif() to fall back to $^W when category not enabled - Update warnIfAtLevel() with same $^W fallback logic - Update design doc with Phase 8 completion details $^W now works with warnings::warnif() when lexical warnings are not enabled for the category being checked. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Document the future approach for block-scoped use warnings / no warnings support, including implementation approaches, trade-offs, and files to modify. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add warn variants for compound assignment operators (+=, -=, *=, /=, %=) - Update EmitBinaryOperator to select warn variant when warnings enabled - Register warn variants in OperatorHandler This fixes the regression where `$x *= 1` would not warn about uninitialized values when using `-w` or `use warnings`. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ScalarSpecialVariable (used for regex captures like $1, $2) was missing getNumberWarn() override. Since the proxy type field is UNDEF, getNumberWarn() incorrectly reported uninitialized warnings for defined capture values. This fix adds getNumberWarn() override that properly delegates to getValueAsScalar().getNumberWarn(). Fixes regressions in opbasic/arith.t (183/183) and op/negate.t (48/48). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Key changes: - -w flag now sets \$^W = 1 (was incorrectly using "use warnings") - Added Warnings.shouldWarn() to check warnings at runtime - Updated getNumberWarn() to check shouldWarn() before emitting - Updated bytecode interpreter to use warn variants for *=, /=, %=, **= - Only warn-enabled operators (* / % ** << >> x &) emit warnings, while + - . | ^ do not (matching Perl behavior) This fixes op/assignwarn.t (106 -> 116) and run/switches.t (36 -> 38). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Remove default experimental warnings from ScopedSymbolTable constructor Code without explicit 'use warnings' now has empty warning bits, matching Perl behavior where default warning state is empty. - Add $BYTES = 21 to warnings.pm for proper warning bits testing This allows caller()[9] tests to compare against the expected number of warning bytes. This partially fixes op/caller.t test 27 (warnings match caller). Test 28 still fails because it requires per-call-site warning bits (Phase 9 of the lexical warnings design) - a known limitation where caller()[9] returns bits from subroutine definition site, not call site. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add WARNING_BITS to ScalarSpecialVariable with getter and setter
- Register ${^WARNING_BITS} as a special variable in GlobalContext
- Inherit warning flags from caller scope in executePerlAST
This fixes BEGIN blocks not seeing warnings from 'use warnings'
- Add setWarningBitsFromString() to parse warning bits and update
symbol table flags (reverse of toWarningBitsString)
- Add $warnings::BYTES = 21 constant for proper warning bits testing
This fixes Test::More's cmp_ok() which sets ${^WARNING_BITS} in
eval blocks to restore warning state. Without the setter, tests
would fail with "Modification of a read-only value attempted".
op/caller.t: 44/112 (was 46/112 on master, -2)
- Test 3: bit layout differs from Perl 5's exact offsets (known)
- Test 28: requires per-call-site warning bits (Phase 9)
Generated with [Devin](https://cli.devin.ai/docs)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The applyCompilerFlagNodes() function was pre-applying ALL compiler flags (including feature flags and strict options) before emitting code. This caused 'use integer' and 'use strict' to incorrectly affect code that appeared BEFORE them in the source file. The fix is to only pre-apply warning flags (needed for WARNING_BITS capture), not feature/strict flags which must be applied in order during code emission to maintain proper lexical scoping. This fixes run/fresh_perl.t test 2 which was failing because: $cusp = ~0 ^ (~0 >> 1); # Should NOT use integer semantics use integer; # Should only affect code AFTER this Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- Add qualified name aliases in PERL5_OFFSETS (e.g., io::closed -> 6) - Add missing categories: missing_import, experimental::enhanced_xx - Add placeholder categories __future_81-83 to match WARN_ALLstring - Fix experimental::signature_named_parameters offset (78 -> 79) - Update warnings.pm to declare BYTES = 21 This fixes op/caller.t test 3 (default bits on via use warnings). Test 28 still fails because it requires per-call-site warning bits (Phase 9 feature) - it now checks real values instead of passing vacuously with empty strings. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…e enabled - Sort getWarningList() for stable bit positions across runs - Enable experimental::X warning when 'use feature X' enables an experimental feature - In Perl 5, experimental warnings are ON by default unless explicitly disabled This fixes the op/decl-refs.t regression (322/408 restored from 232/408). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements Perl 5 compatible lexical warnings with zero runtime overhead when warnings are disabled.
Phase 1 (this PR): Infrastructure
WarningBitsRegistryfor class name → warning bits mappingWarningFlagswarningFatalStacktoScopedSymbolTablefor FATAL warningsgetWarningBitsString()forcaller()[9]supportwarnings.hio::closed→ offset 6)$warnings::BYTES = 21constantTest results:
${^WARNING_BITS}produces correct\x55 x 21patternRemaining phases:
add()vsaddWarn()pattern)caller()[9]warning bits implementationwarnings::Perl module functions$^Winteraction with lexical warningscaller()See
dev/design/lexical-warnings.mdfor full design document.Test plan
makepasses (all unit tests)caller()[9]per-call-site bitsGenerated with Devin