D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6211 - __traits (compile) return wrong result when the bug happen
Summary: __traits (compile) return wrong result when the bug happen
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86 Windows
: P2 major
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-06-24 18:30 UTC by Lloyd Dupont
Modified: 2011-07-11 01:24 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Lloyd Dupont 2011-06-24 18:30:57 UTC
I'm using DMD2.053 on Windows7 x64

My test case:
- I have a all in one console application which output "true true"
- I have a project with the exact same code split into a static lib and an 
exe and it output "false false"

The bug is that the output is different!

=== first the all in one, outputing "true, true" =========
module main;

import std.variant;
import std.stdio;
import std.metastrings : Format;
import std.traits;

public mixin template property(T, string name)
{
    mixin(Format!("private T _%s;
                  @property public T %s() { return _%s; }
                  @property public void %s(T value) { _%s = value; }", name,
name, name, name, name));
}

interface IInter
{
}

class Foo : IInter
{
    static this()
    {
        Compiled!(Foo, "FP");
        Compiled!(Foo, "Subfoo");
    }

    @property public Foo FP() { return new Foo(); }
    @property public void FP(Foo f) { }

    mixin property!(Foo, "Subfoo");
}

int main(string[] argv)
{
    return 0;
}
void Compiled(T, string memberName)()
{
    T t;
    writeln(mixin( "__traits(compiles, t." ~memberName ~" = (" 
~typeof(__traits(getMember, T, memberName)).stringof  ~").init)" ));
}
==============================================


now the splitted program, outputting "false, false"
whereas it should output "true, true" just like above, shouldn't it!?!

===== lib.d ====
module lib;

import std.variant;
import std.stdio;
import std.metastrings : Format;
import std.traits;

public mixin template property(T, string name)
{
    mixin(Format!("private T _%s;
                  @property public T %s() { return _%s; }
                  @property public void %s(T value) { _%s = value; }", name, 
name, name, name, name));
}

interface IInter
{
}

void Compiled(T, string memberName)()
{
    T t;
    writeln(mixin( "__traits(compiles, t." ~memberName ~" = " 
~typeof(__traits(getMember, T, memberName)).stringof  ~").init" ));
}
====== main.d =====
module main;

import lib;

class Foo : IInter
{
    static this()
    {
        Compiled!(Foo, "FP");
        Compiled!(Foo, "Subfoo");
    }

    @property public Foo FP() { return new Foo(); }
    @property public void FP(Foo f) { }

    mixin property!(Foo, "Subfoo");
}

int main(string[] argv)
{
    return 0;
}
===================== buildrun.bat =========
dmd -lib -g -debug -X -of"lib1.lib" lib.d
dmd -g -debug -X main.d lib1.lib
main
====================================
Comment 1 Vladimir Panteleev 2011-06-24 18:38:13 UTC
This is not a bug. See section "Instantiation Scope" of http://www.d-programming-language.org/template.html .

> TemplateInstantances are always performed in the scope of where the 
> TemplateDeclaration is declared, with the addition of the template parameters 
> being declared as aliases for their deduced types.
Comment 2 Lloyd Dupont 2011-06-24 19:03:57 UTC
How does the template scope has anything to do with this bug?

In plain English I'm testing that the property can be set.
I.e. 
class Foo
{
 @property public Foo Subfoo() {}

 @property public Foo Subfoo2() {}
 @property public void Subfoo2(Foo f) {}
}

in the above class Subfoo can't be set, Subfoo2 can.
I'm testing it with
Foo f,
__traits(compile, f.Suboo = Foo.init)
__traits(compile, f.Suboo2 = Foo.init)

This seems to work erratically!
Comment 3 Lloyd Dupont 2011-06-24 20:24:36 UTC
Not understanding the explanation I can't claim it wrong...

Nonetheless the work around I found seems to indicate to me that the explanation was, at the very least (for what I understand) completely irrelevant.

I replaced:
writeln(mixin( "__traits(compiles, t." ~memberName ~" = ("~typeof(__traits(getMember, T, memberName)).stringof  ~").init)" ));


With:
writeln(mixin( "__traits(compiles, t." ~memberName ~" = (typeof(t."~memberName ~")).init)" ));


And it worked. Still using library and exe.
Comment 4 Vladimir Panteleev 2011-06-24 20:29:43 UTC
Sorry, it looked like you were instantiating a template in a scope where a symbol passed by name as a string didn't exist. You may want to reduce your example to the smallest amount of code which illustrates the bug for clarity.
Comment 5 Lloyd Dupont 2011-06-24 21:01:19 UTC
I found a way to reduce the sample even further.

1st no need to have 2 project (lib & exe). All in the same exe (but different module) is enough to cause the bug.

==== main.d ====
module main;

import lib;

class Foo
{
	static this()
	{
		Compiled!(Foo, "Subfoo");
	}
	
	@property public Foo Subfoo() { return null; }
	@property public void Subfoo(Foo f) { }
}

int main(string[] argv)
{
	return 0;
}
====== lib.d ======
module lib;

import std.traits;
import std.stdio;

void Compiled(T, string memberName)()
{
	T t;
	writeln(mixin( "__traits(compiles, t." ~memberName ~" = (" ~typeof(__traits(getMember, T, memberName)).stringof  ~").init)" ));
}
===============

this output "false", whereas it should output "true"

a work around (and simpler code in fact) is to use the following simpler mixin (in Compiled)
---
writeln(mixin( "__traits(compiles, t." ~memberName ~" = (typeof(t." ~memberName ~")).init)" ));
---

Yet I do think this sample highlight a compiler bug
Comment 6 Kenji Hara 2011-07-11 01:24:01 UTC
This is not bug.
In lib.d, you can't access Foo by name (without importing main).

---- lib.d ----
void Compiled(T, string memberName)()
{
    T t;      // ok
    Foo foo;  // error!
}
----