diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 2c807806efe9..8b44c8dc6322 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -128,6 +128,13 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile): FileIndex = var dummy: bool result = fileInfoIdx(conf, filename, dummy) +proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile; isKnownFile: var bool): FileIndex = + fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), isKnownFile) + +proc fileInfoIdx*(conf: ConfigRef; filename: RelativeFile): FileIndex = + var dummy: bool + fileInfoIdx(conf, AbsoluteFile expandFilename(filename.string), dummy) + proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo = result.fileIndex = fileInfoIdx if line < int high(uint16): diff --git a/compiler/vm.nim b/compiler/vm.nim index 53a16bcb0f2a..61261c44c3db 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1934,14 +1934,24 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of 1: # getLine regs[ra].node = newIntNode(nkIntLit, n.info.line.int) of 2: # getColumn - regs[ra].node = newIntNode(nkIntLit, n.info.col) + regs[ra].node = newIntNode(nkIntLit, n.info.col.int) else: internalAssert c.config, false regs[ra].node.info = n.info regs[ra].node.typ = n.typ - of opcNSetLineInfo: + of opcNCopyLineInfo: decodeB(rkNode) regs[ra].node.info = regs[rb].node.info + of opcNSetLineInfoLine: + decodeB(rkNode) + regs[ra].node.info.line = regs[rb].intVal.uint16 + of opcNSetLineInfoColumn: + decodeB(rkNode) + regs[ra].node.info.col = regs[rb].intVal.int16 + of opcNSetLineInfoFile: + decodeB(rkNode) + regs[ra].node.info.fileIndex = + fileInfoIdx(c.config, RelativeFile regs[rb].node.strVal) of opcEqIdent: decodeBC(rkInt) # aliases for shorter and easier to understand code below diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 54876f37da4a..114a49557157 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -141,7 +141,8 @@ type opcNError, opcNWarning, opcNHint, - opcNGetLineInfo, opcNSetLineInfo, + opcNGetLineInfo, opcNCopyLineInfo, opcNSetLineInfoLine, + opcNSetLineInfoColumn, opcNSetLineInfoFile opcEqIdent, opcStrToIdent, opcGetImpl, diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 1fdfea7c411f..6a2ab1d11a07 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1335,7 +1335,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) = of "copyLineInfo": internalAssert c.config, n.len == 3 unused(c, n, dest) - genBinaryStmt(c, n, opcNSetLineInfo) + genBinaryStmt(c, n, opcNCopyLineInfo) + of "setLine": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoLine) + of "setColumn": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoColumn) + of "setFile": + internalAssert c.config, n.len == 3 + unused(c, n, dest) + genBinaryStmt(c, n, opcNSetLineInfoFile) else: internalAssert c.config, false of mNHint: unused(c, n, dest) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 18a70f20cb35..138ec47a0d8e 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -533,6 +533,22 @@ proc getFile(arg: NimNode): string {.magic: "NLineInfo", noSideEffect.} proc copyLineInfo*(arg: NimNode, info: NimNode) {.magic: "NLineInfo", noSideEffect.} ## Copy lineinfo from `info`. +proc setLine(arg: NimNode, line: uint16) {.magic: "NLineInfo", noSideEffect.} +proc setColumn(arg: NimNode, column: int16) {.magic: "NLineInfo", noSideEffect.} +proc setFile(arg: NimNode, file: string) {.magic: "NLineInfo", noSideEffect.} + +proc setLineInfo*(arg: NimNode, file: string, line: int, column: int) = + ## Sets the line info on the NimNode. The file needs to exists, but can be a + ## relative path. If you want to attach line info to a block using `quote` + ## you'll need to add the line information after the quote block. + arg.setFile(file) + arg.setLine(line.uint16) + arg.setColumn(column.int16) + +proc setLineInfo*(arg: NimNode, lineInfo: LineInfo) = + ## See `setLineInfo proc<#setLineInfo,NimNode,string,int,int>`_ + setLineInfo(arg, lineInfo.filename, lineInfo.line, lineInfo.column) + proc lineInfoObj*(n: NimNode): LineInfo = ## Returns `LineInfo` of `n`, using absolute path for `filename`. result = LineInfo(filename: n.getFile, line: n.getLine, column: n.getColumn) diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim index d702db56a819..08be4602c653 100644 --- a/tests/macros/tmacros_various.nim +++ b/tests/macros/tmacros_various.nim @@ -91,7 +91,7 @@ block tlexerex: -block tlineinfo: +block tcopylineinfo: # issue #5617, feature request type Test = object @@ -103,6 +103,27 @@ block tlineinfo: var z = mixer(Test) doAssert z +block tsetgetlineinfo: + # issue #21098, feature request + type Test = object + + macro mixer1(n: typed): untyped = + let x = newIdentNode("echo") + var lineInfo = n.lineInfoObj + x.setLineInfo lineInfo + result = newLit(x.lineInfo == n.lineInfo) + + macro mixer2(n: typed): untyped = + let x = newIdentNode("echo") + var lineInfo = n.lineInfoObj + lineInfo.line += 1 + x.setLineInfo lineInfo + result = newLit(x.lineInfo != n.lineInfo) + + doAssert mixer1(Test) + + doAssert mixer2(Test) + block tdebugstmt: