Alternatively post an example with Nim core types that exhibits the same issue.
Ok I figured it out, not sure if bug or user error:
proc BufferData in File A which imports opengl, which defines GLenum, used by BufferData
File B calls BufferData, but does not import opengl, and I get an error about the type defined in opengl.
If I add the opengl import to File B, it works. This occurs whether or not BufferData is marked with {.inline.}
Bug? Bad error message? I suppose BufferData is being brought into the scope of File B when it is instantiated?
I will put together a minimal example of this now that I know what is going on.
Ok here we go, takes 3 files to repro:
types.nim:
type Foo* = distinct int
lib.nim:
import types
proc Bar*[T](input:T) =
let x = 5.Foo
echo $x.int
echo input
bug.nim:
import lib
proc bug() =
Bar("HEllo World")
bug()
I think that's just normal Nim behavior, right?
If module A imports module B, and module B imports module C, then module A won't automatically see everything that B imported that was able to let B compile?
You could probably solve the probly by either:
It's probably also possible for tne Nim compiler to automatically do some kind of export/import so that bug.nim can - while importing lib.nim, also "see" the required types from "types.nim"; at least to the extent so that bug.nim could typecheck correctly.
@wizzardx is correct, this is normal Nim behaviour.
Nim generic proc is instantiated at callsite. The above example, Bar is instantiated at bug.nim not at lib.nim, and at that time, the scope where the Bar is instantiated have no information about Foo symbol.
Actually I think there is a difference between how types and procs are treated, I don't know if this is intentional.
This compiles:
types.nim
type Foo* = distinct int
proc toFoo*(x: int): Foo =
Foo(x)
lib.nim
import types
proc Bar*[T](input:T) =
let x = 5.toFoo
echo $x.int
echo input
bug.nim
import lib
proc bug() =
Bar("HEllo World")
bug()
I checked things a bit.
I think it's an artifact of Nim code compiling each .nim file into a separate standalone .c file. After that point the regular C toolchain takes over.
c gets compiled to .o, and then .o files get linked into the final binary.
At the .o level, there's some symbols exported; mainly for things like global variables, or for (non-generic) functions. But nothing like C types, let alone things like generics (or Nim macros, templates, and other metaprogramming). The .o files are already 99% machine code by that point.
In the working version, the .o file for types.nim has got an exported link symbol for "toFoo" that takes an int and returns an int.
In the not-working symbol, there's no link symbols that could be exported from types.nim, in the final types.o file.
The C and linker compilation semantics probably gets reflected in how Nim does parsing of things like generics, to be able to compile the .nim files separately to C, and then link them together again to get to the final binary.
I think it's something like that, anyhow.
Probably the compiler could be updated so that it's a bit smarter and doesn't need to follow the .so link rules so directly (eg, everything gets compiled into one single C file each time, or directly to a binary like some other langs, so no separate link stage is really needed where important details like types or generics need to be dropped half-way through the compile process). But I think that would also mean slower compile times.
Or at least, I think that's probably a fundamental underlying model.
There's a lot of higher level clever things that Nim does before getting to separate C files, I think separate .c units is just an optimisation not a restriction, but that it did to some extent shape how the Nim compiler logic worked during development.
Nim probably just needs to be taught to be able to treat "let x = 5.Foo" and "let x = 5.toFoo" the same way, rather the base case of how separate C compilation works. In which case, types.o in the not-working version still wouldn't export any (proc) symbols, but lib.c would know that it was dealing with an int.
I think it might be something like a small bug or limit on the type inference, where technically it could infer something, but it's not yet able to.
Well, basically I think it's something like there's no huge formally unifying theory behind how the entire Nim lang semantics should work for a given lang ver (eg, something like a lang report spec made by committee); but rather it's something that's defined by what the most recent compiler supports, as well as Araqs insights over time.