D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 2484 - Templated classes have no moduleinfo
Summary: Templated classes have no moduleinfo
Status: REOPENED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 major
Assignee: No Owner
URL:
Keywords: patch, wrong-code
Depends on: 4116
Blocks:
  Show dependency treegraph
 
Reported: 2008-12-02 07:56 UTC by Simen Kjaeraas
Modified: 2024-12-13 17:49 UTC (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Simen Kjaeraas 2008-12-02 07:56:10 UTC
import std.stdio;
class c() {}
void main() {
	auto a = new c!();
	auto t = Object.factory(a.classinfo.name);
}

Here, Object.factory return null, because c!() has no information in ModuleInfo.
Comment 1 Neia Neutuladh 2009-02-15 10:07:45 UTC
This is actually an interesting situation.

Most nested types should be fine. Templates are difficult. The ClassInfo is generated at each instantiation, and the linker takes care of duplicates. But the compiler can't. So the ClassInfo would have to appear in multiple ModuleInfos. This isn't a very good situation, and besides, the name of the variable is localClasses -- the template isn't necessarily instantiated in the same module in which it is defined. And you can't patch up the object file for that module to include the generated ClassInfo for the instantiation.

You could have each module have a list of templated classes instantiated in that module. That seems a bit ugly. You could have that list stored privately and patch up ModuleInfo.localClasses at runtime, but that could be expensive.
Comment 2 Justin 2009-07-01 10:56:19 UTC
Following Chris Wright's suggestion, I can confirm that this works (dmd.1.045):

import std.stdio,
	std.moduleinit;

void main() {
	
	auto foo = new Container!(int)();
	foo.thingy = 3;
	assert(foo.thingy == 3);
	writefln("foo Classinfo.name : ", foo.classinfo.name);
	
	// Patch ModuleInfo
	foreach (mod; ModuleInfo.modules)
	{
		if (mod.name == "factory")
		{
			mod.localClasses ~= [foo.classinfo];
			break;
		}
	}
	
	auto bar = Object.factory(foo.classinfo.name);
	assert(bar !is null);
	writefln("bar Classinfo.name : ", bar.classinfo.name);
}
class Container(T) { T thingy; }
Comment 3 Justin 2009-07-01 11:31:25 UTC
Ok, with a bit of work, I thing I've improved on this technique a bit.
Here's factory.d:

module factory;

import std.stdio;
import container;

void main() {	
	auto foo = new Container!(int)();
	foo.thingy = 3;
	assert(foo.thingy == 3);
	writefln("foo Classinfo.name : ", foo.classinfo.name);
	
	auto bar = Object.factory(foo.classinfo.name);
	assert(bar !is null);
	writefln("bar Classinfo.name : ", bar.classinfo.name);
}

And container.d uses a template to insert the patching work:
module container;

import std.moduleinit;

const char[] CURRENT_MODULE = "container";

class Container(T) { 
	T thingy; 

	mixin registerTemplatedClass;
}

public template registerTemplatedClass() {
	static this() {
		// Patch ModuleInfo
		foreach (mod; ModuleInfo.modules)
		{
			if (mod.name == CURRENT_MODULE)
			{
				mod.localClasses ~= [this.classinfo];
				break;
			}
		}
	}
}

This could be improved if there's a way of getting the current module; I couldn't find anything, so I created the constant CURRENT_MODULE which will have to be placed in each module which uses the template.

Output is the expected:
foo Classinfo.name : container.Container!(int).Container
bar Classinfo.name : container.Container!(int).Container
Comment 4 nfxjfg 2010-04-23 16:23:51 UTC
This has absolutely nothing to do with templates. It's because dmd does a very crappy job when finding classes of a module and adding them into ModuleInfo.localClasses. For example, this doesn't work either:

struct X {
    class Y {
    }
}

assert(!!Object.factory(X.Y.classinfo.name));

At least that's what I suspect. ModuleInfo.localClasses recently got commented out in D2 (thanks a lot Walter), so I don't really feel like continuing finding out what goes wrong.
Comment 5 Robert Clipsham 2010-04-24 04:50:38 UTC
It seems the system for doing this has been replaced in D2, it uses a property rather than a variable: http://dsource.org/projects/druntime/browser/trunk/src/object_.d#L1495, it should still function the same way though.
Comment 6 nfxjfg 2010-04-24 06:41:02 UTC
But it's not user accessible: http://dsource.org/projects/druntime/browser/trunk/import/object.di#L226
Well, maybe this is just a temporary regression.
Comment 7 Robert Clipsham 2010-04-24 07:30:03 UTC
Reported as bug #4116.
Comment 8 nfxjfg 2010-04-24 08:24:31 UTC
Here's a partial patch against dmd 1.057:

diff --git a/dsymbol.c b/dsymbol.c
index 7614e13..5fca88e 100644
--- a/dsymbol.c
+++ b/dsymbol.c
@@ -715,6 +715,20 @@ ScopeDsymbol::ScopeDsymbol(Identifier *id)
     prots = NULL;
 }
 
+void ScopeDsymbol::addLocalClass(ClassDeclarations * aclasses) {
+    //????????????????????????
+    if (!members)
+        return;
+
+    //printf("members->dim = %d\n", members->dim);
+    for (int i = 0; i < members->dim; i++)
+    {   Dsymbol *member = (Dsymbol *)members->data[i];
+
+        //printf("\tmember '%s'\n", member->toChars());
+        member->addLocalClass(aclasses);
+    }
+}
+
 Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
 {
     //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
diff --git a/dsymbol.h b/dsymbol.h
index e566515..49f8750 100644
--- a/dsymbol.h
+++ b/dsymbol.h
@@ -270,6 +270,8 @@ struct ScopeDsymbol : Dsymbol
     static Dsymbol *getNth(Array *members, size_t nth, size_t *pn = NULL);
 
     ScopeDsymbol *isScopeDsymbol() { return this; }
+
+    void addLocalClass(ClassDeclarations *);
 };
 
 // With statement scope
diff --git a/template.h b/template.h
index 90b5161..ecbd04e 100644
--- a/template.h
+++ b/template.h
@@ -87,6 +87,9 @@ struct TemplateDeclaration : ScopeDsymbol
     int isOverloadable();
 
     void makeParamNamesVisibleInConstraint(Scope *paramscope);
+
+    // don't add uninstantiated template classes
+    void addLocalClass(ClassDeclarations *) {}
 };
 
 struct TemplateParameter
diff --git a/toobj.c b/toobj.c
index e2d2403..1431e0e 100644
--- a/toobj.c
+++ b/toobj.c
@@ -92,13 +92,7 @@ void Module::genmoduleinfo()
 
     ClassDeclarations aclasses;
 
-    //printf("members->dim = %d\n", members->dim);
-    for (int i = 0; i < members->dim; i++)
-    {  Dsymbol *member = (Dsymbol *)members->data[i];
-
-       //printf("\tmember '%s'\n", member->toChars());
-       member->addLocalClass(&aclasses);
-    }
+    addLocalClass(&aclasses);
 
     // importedModules[]
     int aimports_dim = aimports.dim;


Here's a test case:

import tango.io.Stdout;

class This {}

struct X {
    class Foo {
    }
}

class C(T) { }

void main() {
    class Goo { } //not detected
    auto z = new Goo();
    C!(int) x = new C!(int);
    ClassInfo cobj = Object.classinfo;
    foreach (ModuleInfo m; ModuleInfo) {
        foreach (ClassInfo ci; m.localClasses) {
            if (ci is This.classinfo) {
                foreach (c; m.localClasses)
                    Stdout.formatln("{}", c.name);
        }
    }
}

It prints:
d.This
d.X.Foo
d.C!(int).C

As can be seen, class Goo is still missing. It seems the patch doesn't search through functions. Maybe there are other cases where it still fails.
Comment 9 Vladimir Panteleev 2017-07-02 16:32:23 UTC
I believe we are moving away from Object.factory, so I doubt anything major will change here.

Today, D's introspection capabilities allow building reflection information at compile-time and using it at run-time, thus allowing users to build their own Object.factory equivalents with the capabilities they need.
Comment 10 Jean-Louis Leroy 2017-09-25 14:02:37 UTC
Re-opened because this makes problem makes my openmethods library unusable for templatized classes.
Comment 11 Jean-Louis Leroy 2017-09-25 14:42:48 UTC
See discussion here: http://forum.dlang.org/post/oyluuzzooythxhvuuhri@forum.dlang.org
Comment 12 dlangBugzillaToGithub 2024-12-13 17:49:04 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/17809

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB