forked from nim-lang/Nim
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
make
var
/pointer types not match if base type has to be converted
split again from nim-lang#24038, fixes status-im/nimbus-eth2#6554 (comment)
- Loading branch information
Showing
5 changed files
with
244 additions
and
4 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
discard """ | ||
errormsg: "for a 'var' type a variable needs to be passed; but 'uint16(x)' is immutable" | ||
errormsg: "type mismatch: got <uint8>" | ||
""" | ||
|
||
proc toUInt16(x: var uint16) = | ||
discard | ||
|
||
var x = uint8(1) | ||
toUInt16 x | ||
toUInt16 x |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
discard """ | ||
action: reject | ||
nimout: ''' | ||
but expression 'int(a)' is immutable, not 'var' | ||
''' | ||
""" | ||
|
||
proc `++`(n: var int) = | ||
n += 1 | ||
|
||
var a: int32 = 15 | ||
|
||
++int(a) #[tt.Error | ||
^ type mismatch: got <int>]# | ||
|
||
echo a |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
proc `++`(n: var int) = | ||
n += 1 | ||
|
||
var a: int32 = 15 | ||
|
||
++a #[tt.Error | ||
^ type mismatch: got <int32>]# | ||
|
||
echo a |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
# https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102 | ||
# failed with "for a 'var' type a variable needs to be passed; but 'uint64(result)' is immutable" | ||
|
||
import | ||
std/[typetraits, macros] | ||
|
||
type | ||
DefaultFlavor = object | ||
|
||
template serializationFormatImpl(Name: untyped) {.dirty.} = | ||
type Name = object | ||
|
||
template serializationFormat(Name: untyped) = | ||
serializationFormatImpl(Name) | ||
|
||
template setReader(Format, FormatReader: distinct type) = | ||
when arity(FormatReader) > 1: | ||
template Reader(T: type Format, F: distinct type = DefaultFlavor): type = FormatReader[F] | ||
else: | ||
template ReaderType(T: type Format): type = FormatReader | ||
template Reader(T: type Format): type = FormatReader | ||
|
||
template useDefaultReaderIn(T: untyped, Flavor: type) = | ||
mixin Reader | ||
|
||
template readValue(r: var Reader(Flavor), value: var T) = | ||
mixin readRecordValue | ||
readRecordValue(r, value) | ||
|
||
from stew/shims/macros import field, isTuple, recordFields, skipPragma | ||
|
||
type | ||
FieldTag[RecordType: object; fieldName: static string] = distinct void | ||
|
||
func declval*(T: type): T {.compileTime.} = | ||
default(ptr T)[] | ||
|
||
macro enumAllSerializedFieldsImpl(T: type, body: untyped): untyped = | ||
var typeAst = getType(T)[1] | ||
var typeImpl: NimNode | ||
let isSymbol = not typeAst.isTuple | ||
|
||
if not isSymbol: | ||
typeImpl = typeAst | ||
else: | ||
typeImpl = getImpl(typeAst) | ||
result = newStmtList() | ||
|
||
var i = 0 | ||
for field in recordFields(typeImpl): | ||
let | ||
fieldIdent = field.name | ||
realFieldName = newLit($fieldIdent.skipPragma) | ||
fieldName = realFieldName | ||
fieldIndex = newLit(i) | ||
|
||
let fieldNameDefs = | ||
if isSymbol: | ||
quote: | ||
const fieldName {.inject, used.} = `fieldName` | ||
const realFieldName {.inject, used.} = `realFieldName` | ||
else: | ||
quote: | ||
const fieldName {.inject, used.} = $`fieldIndex` | ||
const realFieldName {.inject, used.} = $`fieldIndex` | ||
|
||
let field = | ||
if isSymbol: | ||
quote do: declval(`T`).`fieldIdent` | ||
else: | ||
quote do: declval(`T`)[`fieldIndex`] | ||
|
||
result.add quote do: | ||
block: | ||
`fieldNameDefs` | ||
|
||
template FieldType: untyped {.inject, used.} = typeof(`field`) | ||
|
||
`body` | ||
|
||
# echo repr(result) | ||
|
||
template enumAllSerializedFields(T: type, body): untyped = | ||
enumAllSerializedFieldsImpl(T, body) | ||
|
||
type | ||
FieldReader[RecordType, Reader] = tuple[ | ||
fieldName: string, | ||
reader: proc (rec: var RecordType, reader: var Reader) | ||
{.gcsafe, nimcall.} | ||
] | ||
|
||
proc totalSerializedFieldsImpl(T: type): int = | ||
mixin enumAllSerializedFields | ||
enumAllSerializedFields(T): inc result | ||
|
||
template totalSerializedFields(T: type): int = | ||
(static(totalSerializedFieldsImpl(T))) | ||
|
||
template GetFieldType(FT: type FieldTag): type = | ||
typeof field(declval(FT.RecordType), FT.fieldName) | ||
|
||
proc makeFieldReadersTable(RecordType, ReaderType: distinct type, | ||
numFields: static[int]): | ||
array[numFields, FieldReader[RecordType, ReaderType]] = | ||
mixin enumAllSerializedFields, handleReadException | ||
var idx = 0 | ||
|
||
enumAllSerializedFields(RecordType): | ||
proc readField(obj: var RecordType, reader: var ReaderType) | ||
{.gcsafe, nimcall.} = | ||
|
||
mixin readValue | ||
|
||
type F = FieldTag[RecordType, realFieldName] | ||
field(obj, realFieldName) = reader.readValue(GetFieldType(F)) | ||
|
||
result[idx] = (fieldName, readField) | ||
inc idx | ||
|
||
proc fieldReadersTable(RecordType, ReaderType: distinct type): auto = | ||
mixin readValue | ||
type T = RecordType | ||
const numFields = totalSerializedFields(T) | ||
var tbl {.threadvar.}: ref array[numFields, FieldReader[RecordType, ReaderType]] | ||
if tbl == nil: | ||
tbl = new typeof(tbl) | ||
tbl[] = makeFieldReadersTable(RecordType, ReaderType, numFields) | ||
return addr(tbl[]) | ||
|
||
proc readValue(reader: var auto, T: type): T = | ||
mixin readValue | ||
reader.readValue(result) | ||
|
||
template decode(Format: distinct type, | ||
input: string, | ||
RecordType: distinct type): auto = | ||
mixin Reader | ||
block: # https://github.com/nim-lang/Nim/issues/22874 | ||
var reader: Reader(Format) | ||
reader.readValue(RecordType) | ||
|
||
template readValue(Format: type, | ||
ValueType: type): untyped = | ||
mixin Reader, init, readValue | ||
var reader: Reader(Format) | ||
readValue reader, ValueType | ||
|
||
template parseArrayImpl(numElem: untyped, | ||
actionValue: untyped) = | ||
actionValue | ||
|
||
serializationFormat Json | ||
template createJsonFlavor(FlavorName: untyped, | ||
skipNullFields = false) {.dirty.} = | ||
type FlavorName = object | ||
|
||
template Reader(T: type FlavorName): type = Reader(Json, FlavorName) | ||
type | ||
JsonReader[Flavor = DefaultFlavor] = object | ||
|
||
Json.setReader JsonReader | ||
|
||
template parseArray(r: var JsonReader; body: untyped) = | ||
parseArrayImpl(idx): body | ||
|
||
template parseArray(r: var JsonReader; idx: untyped; body: untyped) = | ||
parseArrayImpl(idx): body | ||
|
||
proc readRecordValue[T](r: var JsonReader, value: var T) = | ||
type | ||
ReaderType {.used.} = type r | ||
T = type value | ||
|
||
discard T.fieldReadersTable(ReaderType) | ||
|
||
proc readValue[T](r: var JsonReader, value: var T) = | ||
mixin readValue | ||
|
||
when value is seq: | ||
r.parseArray: | ||
readValue(r, value[0]) | ||
|
||
elif value is object: | ||
readRecordValue(r, value) | ||
|
||
type | ||
RemoteSignerInfo = object | ||
id: uint32 | ||
RemoteKeystore = object | ||
|
||
proc readValue(reader: var JsonReader, value: var RemoteKeystore) = | ||
discard reader.readValue(seq[RemoteSignerInfo]) | ||
|
||
createJsonFlavor RestJson | ||
useDefaultReaderIn(RemoteSignerInfo, RestJson) | ||
proc readValue(reader: var JsonReader[RestJson], value: var uint64) = | ||
discard reader.readValue(string) | ||
|
||
discard Json.decode("", RemoteKeystore) | ||
block: # https://github.com/nim-lang/Nim/issues/22874 | ||
var reader: Reader(RestJson) | ||
discard reader.readValue(RemoteSignerInfo) |