antlr/antlr4 · error · ArgumentException
insert op {iop} within boundaries of previous {rop}
Error message
insert op {iop} within boundaries of previous {rop} What it means
Thrown by TokenStreamRewriter when an insert operation's index falls strictly inside the boundaries of a previously issued replace operation (insert at exactly rop.index is legal and is prepended to the replacement text; anything between rop.index+1 and rop.lastIndex-1 is not). The rewriter cannot decide whether the inserted text belongs before, inside, or after the replacement, so it rejects the program.
Source
Thrown at runtime/CSharp/src/TokenStreamRewriter.cs:675
iop.text = CatOpText(iop.text, prevIop.text);
// delete redundant prior insert
rewrites[prevIop.instructionIndex] = null;
}
}
// look for replaces where iop.index is in range; error
IList<TokenStreamRewriter.ReplaceOp> prevReplaces = GetKindOfOps<TokenStreamRewriter.ReplaceOp>(rewrites, i_1);
foreach (TokenStreamRewriter.ReplaceOp rop in prevReplaces)
{
if (iop.index == rop.index)
{
rop.text = CatOpText(iop.text, rop.text);
rewrites[i_1] = null;
// delete current insert
continue;
}
if (iop.index >= rop.index && iop.index <= rop.lastIndex)
{
throw new ArgumentException("insert op " + iop + " within boundaries of previous " + rop);
}
}
}
// System.out.println("rewrites after="+rewrites);
IDictionary<int, TokenStreamRewriter.RewriteOperation> m = new Dictionary<int, TokenStreamRewriter.RewriteOperation>();
for (int i_2 = 0; i_2 < rewrites.Count; i_2++)
{
TokenStreamRewriter.RewriteOperation op = rewrites[i_2];
if (op == null)
{
continue;
}
// ignore deleted ops
if (m.ContainsKey(op.index))
{
throw new InvalidOperationException("should only be one op per index");
}
m[op.index] = op;View on GitHub (pinned to 7d5770395b)
Solutions
- Move the insert outside the replaced range: insert before rop.index or after rop.lastIndex instead of inside it.
- Fold the inserted text into the replacement itself: rewriter.Replace(rop.index, rop.lastIndex, insertedText + replacementText).
- If the insert index equals the replace start, rely on the supported merge by inserting exactly at rop.index (InsertBefore at the replace start is merged automatically).
- Reorder edits so replaces are issued first and then validate each insert index against the replace ranges you recorded.
Example fix
// before rewriter.Replace(2, 6, "newExpr"); rewriter.InsertAfter(4, ";"); // 4 is inside 2..6 -> throws // after rewriter.Replace(2, 6, "newExpr;"); // fold insertion into the replacement
Defensive patterns
Strategy: validation
Validate before calling
// Check an insert index is not strictly inside a previously replaced range
var replaces = new List<(int from, int to)>();
void SafeInsertBefore(TokenStreamRewriter r, int i, string text)
{
if (replaces.Any(rp => i > rp.from && i < rp.to))
throw new InvalidOperationException($"Insert at {i} falls inside replace {rp.from}..{rp.to}");
r.InsertBefore(i, text);
} Try / catch
try { rewriter.GetText(); } catch (ArgumentException ex) when (ex.Message.Contains("within boundaries")) { /* locate the insert inside a replace and fold its text into the replacement */ } Prevention
- Record replace ranges and check every insert index against them before calling InsertBefore/InsertAfter.
- Remember insert exactly at the replace start index is legal and auto-merged; only strictly-inside indexes throw.
- Fold inserted text into the replacement string when the insertion point is inside a replaced span.
When it happens
Trigger: Calling rewriter.InsertAfter(i, "x") or InsertBefore(i, "x") where a prior rewriter.Replace(i, j, text) (or delete) exists with i in (rop.index, rop.lastIndex) exclusive of the equal-index merge case. Detected during GetText() when the rewrite program is validated.
Common situations: Adding a semicolon or comma after a token that a previous edit already replaced; composing multiple independent fix-up rules (e.g. a formatter plus a refactoring) over the same token stream; off-by-one when computing the insert position relative to a replaced range.
Related errors
- replace op boundaries of {rop} overlap with previous {prevRo
- replace op boundaries of {rop} overlap with previous {prevRo
- insert op {iop} within boundaries of previous {rop}
- replace: range invalid: {from}..{to}(size={size})
- Invalid state number.
AI-assisted analysis of antlr/antlr4@7d5770395b (2026-08-14).
Data as JSON: /api/errors/4e78d0b64a15451e.
Report an issue: GitHub.