treeform / genny

Generate a shared library and bindings for many languages.
MIT License
224 stars 9 forks source link

Error: type mismatch: got 'seq[string]' for 'getDatas()' but expected 'SeqString = ref SeqString:ObjectType'` #36

Closed enthus1ast closed 2 years ago

enthus1ast commented 2 years ago

If seq[string] is returned by a proc, genny emits invalid code.

import genny

proc getDatas*(): seq[string] =
  result = @["a", "b", "c"]

exportSeq seq[string]:
  discard

exportProcs:
  getDatas

writeFiles("bindings", "ttt")
include bindings/internal

from generated internal.nim:

proc ttt_get_datas*(): SeqString {.raises: [], cdecl, exportc, dynlib.} =
  getDatas()

C:\Users\david\projects\gennyt\bindings\internal.nim(32, 11) Error: type mismatch: got 'seq[string]' for 'getDatas()' but expected 'SeqString = ref SeqString:ObjectType'

what works for me if i manual patch internal.nim

proc ttt_get_datas*(): SeqString {.raises: [], cdecl, exportc, dynlib.} =
  result = SeqString()
  result.s = getDatas()

Edit: Fixed import, removed nimja

guzba commented 2 years ago

Thanks for the report. I've confirmed the issue and am working on this.

treeform commented 2 years ago

Thank you for your issue! I think we have fixed it. Please pull head and try it again.

Feel free to reopen if you still have issues.

enthus1ast commented 2 years ago

yes it compiles now, thank you!

I unfortunately still cannot use it. It excepts on field access.

I compile the above testfile with:

PS C:\Users\david\projects\gennyt> nim c --app:lib -d:release --gc:orc .\ttt.nim

Then load it in ipython:

In [2]: import ttt

In [3]: d = ttt.get_datas()

In [4]: len(d)
Out[4]: 3

In [5]: print(d[0])
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
Input In [5], in <module>
----> 1 print(d[0])

File ~\projects\gennyt\bindings\ttt.py:35, in SeqString.__getitem__(self, index)
     34 def __getitem__(self, index):
---> 35     return dll.ttt_seq_string_get(self, index)

OSError: exception: access violation reading 0x0000000000000000

Nim version:

Nim Compiler Version 1.6.0 [Windows: amd64]
Compiled at 2021-10-19
Copyright (c) 2006-2021 by Andreas Rumpf

active boot switches: -d:release

Out of curiosity i also tried it with a seq[cstring], this fails in a different way:

import genny

proc getDatas*(): seq[string] =
  result = @["a", "b", "c"]

exportSeq seq[string]:
  discard

proc getDatas2*(): seq[cstring] =
  result = @["a".cstring, "b", "c"]

exportSeq seq[cstring]:
  discard

exportProcs:
  getDatas
  getDatas2

writeFiles("bindings", "ttt")
include bindings/internal

PS C:\Users\david\projects\gennyt> nim c --app:lib -d:release --gc:orc .\ttt.nim

In [1]: import ttt
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Input In [1], in <module>
----> 1 import ttt

File ~\projects\gennyt\bindings\ttt.py:124, in <module>
    121 dll.ttt_seq_cstring_len.restype = c_longlong
    123 dll.ttt_seq_cstring_get.argtypes = [SeqCstring, c_longlong]
--> 124 dll.ttt_seq_cstring_get.restype = cstring
    126 dll.ttt_seq_cstring_set.argtypes = [SeqCstring, c_longlong, cstring]
    127 dll.ttt_seq_cstring_set.restype = None

NameError: name 'cstring' is not defined
enthus1ast commented 2 years ago

if you like i can put this into a new issue.

guzba commented 2 years ago

We do not support exporting cstring directly from Nim right now. It can be added but I'm not going to right now. Looking into at the access violation.

guzba commented 2 years ago

I see the issue. Seqs were not checking to see if they needed to do type conversions for import/export of the type they hold, like procs were already in genny. Unfortunately for your testing, string is one of the few cases that need conversion so I've got that fixed now in a PR.

guzba commented 2 years ago

One small thing, I suggest using --tlsEmulation:off comple flag on Windows. It is a bad default to have that enabled and was fixed in 1.6.2 (https://nim-lang.org/blog/2021/12/17/version-162-released.html), but that regressed elsewhere.

enthus1ast commented 2 years ago

thank you @guzba this works!

There is just one little thing, if i loop through the seq, i receive a NoneType error after the last element:

C:\Users\david\projects\gennyt\bindings>ipython
Python 3.10.0 (tags/v3.10.0:b494f59, Oct  4 2021, 19:00:18) [MSC v.1929 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.0.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import ttt

In [2]: d = ttt.get_datas()

In [3]: for l in d:
   ...:     print(l)
a
b
c
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [3], in <module>
----> 1 for l in d:
      2     print(l)

File ~\projects\gennyt\bindings\ttt.py:35, in SeqString.__getitem__(self, index)
     34 def __getitem__(self, index):
---> 35     return dll.ttt_seq_string_get(self, index).decode("utf8")

AttributeError: 'NoneType' object has no attribute 'decode'

In [4]:                                                                                                                                

i think this is not such a big issue since one can use this construct:

In [15]: for idx in range(0, len(d)):
    ...:     print(d[idx])
guzba commented 2 years ago

For some reason for l in d: is reading past the end of the seq. I don't know why Python is doing that with that loop construct. Maybe there is some Python object func we need to override or something? Investigation needed.

guzba commented 2 years ago

Ok, figured out the issue. We need a custom Iterator + override __iter__ on our Seq Python classes. Working on this quick now.

enthus1ast commented 2 years ago

thank you @guzba it works fine now!