Skip to content

type generated by template disappears in C code. #7905

@krux02

Description

@krux02

When I generate a type in a template, everything works fine, but when I use the exact same template to generate another type and use that type, this type will disappear in the generated C code, and the generated C code will use the wrong type instead. Here is an example.

template foobar(arg: typed): untyped =
  type
    MyType = object
      member: type(arg)

  var myVar: MyType
  myVar.member = arg
  echo myVar


foobar("hello world")
foobar(123.456'f64)

This is the relevant generated C code:

// there is only one instance of MyType
struct tyObject_MyType_c8zLdw0BfP5QV35I5Dp9cLQ {
NimStringDesc* member;
};
// an instance of MyType with a member of type double does not exist.

/*...*/

// as you can see both myVar instances have the same type
tyObject_MyType_c8zLdw0BfP5QV35I5Dp9cLQ myVar_JAYCzYxe9bQSb28Ss2x9aoxg;
tyObject_MyType_c8zLdw0BfP5QV35I5Dp9cLQ myVar_JAYCzYxe9bQSb28Ss2x9aoxg_2;

/*...*/

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
	NimStringDesc* T1_;
	tyArray_nHXaesL0DJZHyVS07ARPRA T2_;
	tyArray_nHXaesL0DJZHyVS07ARPRA T3_;
nimRegisterGlobalMarker(TM_X9bGGOoNyKehOTF7f2xys3g_2);
	T1_ = (NimStringDesc*)0;
	T1_ = myVar_JAYCzYxe9bQSb28Ss2x9aoxg.member; myVar_JAYCzYxe9bQSb28Ss2x9aoxg.member = copyStringRC1(((NimStringDesc*) &TM_X9bGGOoNyKehOTF7f2xys3g_3));
	if (T1_) nimGCunrefNoCycle(T1_);
	memset((void*)T2_, 0, sizeof(tyArray_nHXaesL0DJZHyVS07ARPRA));
	T2_[0] = dollar__cL9bBANF2jNLmbCKCDXwjDQ(myVar_JAYCzYxe9bQSb28Ss2x9aoxg);
	echoBinSafe(T2_, 1);
        // here is the line that won't compile
	myVar_JAYCzYxe9bQSb28Ss2x9aoxg_2.member = 1.2345600000000000e+02;
	memset((void*)T3_, 0, sizeof(tyArray_nHXaesL0DJZHyVS07ARPRA));
	T3_[0] = dollar__cL9bBANF2jNLmbCKCDXwjDQ_2(myVar_JAYCzYxe9bQSb28Ss2x9aoxg_2);
	echoBinSafe(T3_, 1);
}

The C compiler will refuse to compile with this error message:

/tmp/nimcache/scratch.c:269:42: error: incompatible types when assigning to type 'NimStringDesc * {aka struct NimStringDesc *}' from type 'double'
  myVar_JAYCzYxe9bQSb28Ss2x9aoxg_2.member = 1.2345600000000000e+02;

Because of weak type checking in C compiling integers will silently work, so foobar(123) will compile just fine. But when the generated instance of MyType has a member of an integer type, casting pointers to it will actually work, but it will cause a segfault at runtime, when the integer is too small to hold an actual pointer value.

Interesting though, there are two different $ procedures generated for the same type. You can see them in use in the generated code as dollar__cL9bBANF2jNLmbCKCDXwjDQ and dollar__cL9bBANF2jNLmbCKCDXwjDQ_2

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions