|
| 1 | +# Source Map Return Statement Fix |
| 2 | + |
| 3 | +## Problem |
| 4 | + |
| 5 | +When hovering over variables in return statements after error propagation expansions, the LSP would map to incorrect lines (like the import closing brace) instead of the actual code. |
| 6 | + |
| 7 | +**Example**: |
| 8 | +- Dingo source line 5: `return data, nil` |
| 9 | +- Generated Go line 15: `return data, nil` |
| 10 | +- Expected: Hover on `data` at line 5 should show variable info |
| 11 | +- Actual (BEFORE fix): No mapping existed, fell back to wrong line |
| 12 | + |
| 13 | +## Root Cause |
| 14 | + |
| 15 | +The error propagation preprocessor (`pkg/preprocessor/error_prop.go`) only created mappings for: |
| 16 | +1. Lines that contained error propagation (`?` operator) |
| 17 | +2. The expanded error handling code |
| 18 | + |
| 19 | +But it did NOT create mappings for subsequent lines that were unchanged (like the return statement). |
| 20 | + |
| 21 | +This meant: |
| 22 | +- Line 4: `let data = ReadFile(path)?` → Full mappings ✅ |
| 23 | +- Line 5: `return data, nil` → NO MAPPING ❌ |
| 24 | + |
| 25 | +Without a mapping, the LSP couldn't correctly translate positions back to the original source. |
| 26 | + |
| 27 | +## Solution |
| 28 | + |
| 29 | +Added **identity mappings** for all lines that don't get transformed by the error propagation processor. |
| 30 | + |
| 31 | +### Code Changes |
| 32 | + |
| 33 | +**File**: `/Users/jack/mag/dingo/pkg/preprocessor/error_prop.go` |
| 34 | + |
| 35 | +1. **Modified `processLine()` function** (lines 263-306): |
| 36 | + - Now calls `createIdentityMapping()` for lines without `?` operator |
| 37 | + - Also creates identity mappings for ternary lines and null coalesce operators |
| 38 | + |
| 39 | +2. **Added `createIdentityMapping()` function** (lines 960-996): |
| 40 | + - Creates a 1:1 mapping for lines that pass through unchanged |
| 41 | + - Maps entire line content (excluding whitespace) |
| 42 | + - Skips empty lines and comments (no meaningful content) |
| 43 | + |
| 44 | +### How Identity Mappings Work |
| 45 | + |
| 46 | +For a line like `return data, nil` on Dingo line 5: |
| 47 | +```go |
| 48 | +{ |
| 49 | + "original_line": 5, |
| 50 | + "original_column": 2, // First non-whitespace character |
| 51 | + "generated_line": 15, // After import injection shift |
| 52 | + "generated_column": 2, // Same column (identity) |
| 53 | + "length": 16, // Length of "return data, nil" |
| 54 | + "name": "identity" |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +When LSP queries position (line=15, col=9) for `data`: |
| 59 | +1. Finds mapping for line 15 |
| 60 | +2. Calculates offset: col 9 - col 2 = offset 7 |
| 61 | +3. Maps to: original line 5, col 2 + offset 7 = col 9 |
| 62 | +4. Result: Correctly points to `data` in Dingo source |
| 63 | + |
| 64 | +## Testing |
| 65 | + |
| 66 | +### Before Fix |
| 67 | +``` |
| 68 | +Total mappings: 10 |
| 69 | +(Only error propagation mappings, no identity mappings) |
| 70 | +``` |
| 71 | + |
| 72 | +### After Fix |
| 73 | +``` |
| 74 | +Total mappings: 14 |
| 75 | +
|
| 76 | +[0] Dingo L1:C1 → Go L1:C1 (name=identity) ← package declaration |
| 77 | +[1] Dingo L3:C1 → Go L7:C1 (name=identity) ← func declaration |
| 78 | +[2-10] Dingo L4 → Go L8-14 (error propagation) ← error handling expansion |
| 79 | +[11] Dingo L5:C2 → Go L15:C2 (name=identity) ← return statement ✅ |
| 80 | +[12] Dingo L7:C1 → Go L17:C1 (name=identity) ← closing brace |
| 81 | +[13] Dingo L4 → Go L8 (unqualified import) |
| 82 | +``` |
| 83 | + |
| 84 | +### Verification |
| 85 | +```bash |
| 86 | +./bin/dingo build tests/golden/error_prop_01_simple.dingo |
| 87 | +cat tests/golden/error_prop_01_simple.go.map | python3 -c "..." |
| 88 | +# Shows 14 mappings including identity mapping for line 5 |
| 89 | +``` |
| 90 | + |
| 91 | +## Impact |
| 92 | + |
| 93 | +**Fixes**: |
| 94 | +- ✅ Hover information now works on ALL lines, not just error propagation lines |
| 95 | +- ✅ Go-to-definition works for variables used after error propagation |
| 96 | +- ✅ LSP diagnostics correctly map errors in return statements |
| 97 | + |
| 98 | +**Affects**: |
| 99 | +- All golden tests with error propagation |
| 100 | +- Any Dingo code using the `?` operator |
| 101 | +- LSP server position mapping accuracy |
| 102 | + |
| 103 | +## Related Files |
| 104 | + |
| 105 | +- `/Users/jack/mag/dingo/pkg/preprocessor/error_prop.go` - Main fix |
| 106 | +- `/Users/jack/mag/dingo/tests/golden/error_prop_01_simple.dingo` - Test file |
| 107 | +- `/Users/jack/mag/dingo/tests/golden/error_prop_01_simple.go.map` - Updated source map |
| 108 | + |
| 109 | +## Future Enhancements |
| 110 | + |
| 111 | +This same pattern should be applied to: |
| 112 | +1. Other preprocessors (enum, lambda, pattern match, etc.) |
| 113 | +2. AST transformation phase (if AST modifies line structure) |
| 114 | +3. Any code generation that shifts line numbers |
| 115 | + |
| 116 | +**Principle**: Every source line should have AT LEAST one mapping, even if it's just an identity mapping. |
0 commit comments