{"record":{"id":"557ab8700db272eb","repo":"antlr/antlr4","slug":"insert-op-iop-within-boundaries-of-previous-r","errorCode":null,"errorMessage":"insert op ${iop} within boundaries of previous ${rop}","messagePattern":"insert op (.+?) within boundaries of previous (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"runtime/JavaScript/src/antlr4/TokenStreamRewriter.js","lineNumber":300,"sourceCode":"                    else if (prevIop instanceof InsertBeforeOp) { // combine objects\n                        // convert to strings...we're in process of toString'ing\n                        // whole token buffer so no lazy eval issue with any templates\n                        iop.text = this.catOpText(iop.text, prevIop.text);\n                        // delete redundant prior insert\n                        rewrites[prevIop.instructionIndex] = undefined;\n                    }\n                }\n            }\n            // look for replaces where iop.index is in range; error\n            let prevReplaces = this.getKindOfOps(rewrites, ReplaceOp, i);\n            for (let rop of prevReplaces) {\n                if (iop.index === rop.index) {\n                    rop.text = this.catOpText(iop.text, rop.text);\n                    rewrites[i] = undefined;\t// delete current insert\n                    continue;\n                }\n                if (iop.index >= rop.index && iop.index <= rop.lastIndex) {\n                    throw new Error(`insert op ${iop} within boundaries of previous ${rop}`);\n                }\n            }\n        }\n\n        /** @type {Map<number, RewriteOperation>} */\n        let m = new Map();\n        for (let op of rewrites) {\n            if (op == null) {\n                // ignore deleted ops\n                continue;\n            }\n            if (m.get(op.index) != null) {\n                throw new Error(\"should only be one op per index\");\n            }\n            m.set(op.index, op);\n        }\n        return m;\n    }","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/JavaScript/src/antlr4/TokenStreamRewriter.js#L282-L318","documentation":"Thrown by IntervalSet.setReadonly(false) when the set is currently read-only. Read-only status is deliberately one-way in the ANTLR runtime: it protects sets shared between threads and ATN caches, and allowing an un-flag would open a race where one consumer mutates while others read. Only transitioning false→true is legal.","triggerScenarios":"Calling setReadonly(false) on a set that already had setReadonly(true) applied, e.g. an attempt to 'unlock' a cached or ATN-owned set for modification.","commonSituations":"Code that wants to temporarily freeze and then thaw a set; sets acquired from the runtime's shared state that the application tries to make mutable again.","solutions":["Never un-flag: clone the set (new IntervalSet(set)) and mutate the clone.","Design construction so setReadonly(true) is the last step, after all mutation is done.","If you need freeze/thaw semantics, implement them in your own wrapper that swaps between mutable copies."],"exampleFix":"// before\nset.setReadonly(true);\n// ... later\nset.setReadonly(false); // IllegalStateException\n\n// after\nset.setReadonly(true);\n// ... later, work on a copy\nIntervalSet mutable = new IntervalSet(set);","handlingStrategy":"validation","validationCode":"// setReadonly is one-way; to 'unlock', copy\nIntervalSet fresh = new IntervalSet(readonlySet); // fresh is mutable\nfresh.add(newInterval);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model readonly as one-way in your own code too.","Freeze sets only at the end of their construction pipeline.","Replace 'thaw' logic with clone-and-mutate."],"tags":["antlr","java","intervaset","immutable-state","one-way-flag"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}