www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Help me investigate a bug to file it.

reply "monarch_dodra" <monarchdodra gmail.com> writes:
Yeah, not very exiting, but I just spent an hour tracking down 
the fix, but now I'd like to track down *what* was making it 
break (my fix was "luck"). This should help Kenji (or others) 
have an easier time fixing it :)

Also, I'm only repro'ing this on linux...

I think there are two things involved here. The first, is 
accessing members of a struct for a static if, in a global scope:

//----
import std.stdio;
import std.range;

struct S(R)
{
     R _input;
     void foo()
     {
         static assert(is(typeof(_input[size_t.max .. 
size_t.max]))); //ok
         static assert(is(typeof(_input[size_t.max .. $]))); //ok
     }
     static assert(is(typeof(_input[size_t.max .. size_t.max]))); 
//ok
     static assert(is(typeof(_input[size_t.max .. $]))); //NOPE!
}

void main()
{
     auto k = iota(0, 1).cycle();
     S!(typeof(k)) s;
}
//----

As you can see, the static if behaves differently in a function, 
or in the raw body of the struct. Is this normal? Anybody know 
what is going on exactly? I'm trying to get more context here...

-----------------------------------------------

Second, one of the things I found strange was that only *1* of 
the two assertions failed. basically, _input[0 .. 1] is fair 
game, yet, _input[0 .. $] is not? What gives? I put my nose in 
cycles's opDollar. It is written like this:

//----
         private static struct DollarToken {}
         DollarToken opDollar()
         {
             return DollarToken.init;
         }
//----
Nothing special about it. Just a function that returns an object. 
Declaring it const/nothrow/ safe *and* pure does not fix the 
problem...

*HOWEVER* declaring it as a manifest constant *does* fix the 
issue:
//----
         private static struct DollarToken {}
         enum opDollar = DollarToken.init;
//----

------------------------------------------------

I think I've run into "global static ifs using members" issues 
before, but just figured I wasn't allowed to use them. 
Apparently, to issue is more subtle than this. I have *no* idea 
how to file this, I have no idea what the rules are. Any insight?
Jul 08 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/08/13 19:54, monarch_dodra wrote:
 struct S(R)
 {
     R _input;
     void foo()
     {
         static assert(is(typeof(_input[size_t.max .. size_t.max]))); //ok
         static assert(is(typeof(_input[size_t.max .. $]))); //ok
     }
     static assert(is(typeof(_input[size_t.max .. size_t.max]))); //ok
     static assert(is(typeof(_input[size_t.max .. $]))); //NOPE!
 }
 As you can see, the static if behaves differently in a function, or in the raw
body of the struct. Is this normal? Anybody know what is going on exactly? I'm
trying to get more context here...
 
 -----------------------------------------------
 
 Second, one of the things I found strange was that only *1* of the two
assertions failed. basically, _input[0 .. 1] is fair game, yet, _input[0 .. $]
is not? What gives? I put my nose in cycles's opDollar. It is written like this:
Did you really mean size_t.*max* above? Anyway, when '$' is rewritten as 'opDollar' and that is defined as a non-static method, it would be surprising if calling the method did work w/o any context pointer...
 //----
         private static struct DollarToken {}
         DollarToken opDollar()
         {
             return DollarToken.init;
         }
 //----
 Nothing special about it. Just a function that returns an object. Declaring it
const/nothrow/ safe *and* pure does not fix the problem...
 
 *HOWEVER* declaring it as a manifest constant *does* fix the issue:
 //----
         private static struct DollarToken {}
         enum opDollar = DollarToken.init;
 //----
Does declaring the opDollar "function" as `static` fix it? artur
Jul 08 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 8 July 2013 at 18:55:30 UTC, Artur Skawina wrote:
 On 07/08/13 19:54, monarch_dodra wrote:
 struct S(R)
 {
     R _input;
     void foo()
     {
         static assert(is(typeof(_input[size_t.max .. 
 size_t.max]))); //ok
         static assert(is(typeof(_input[size_t.max .. $]))); 
 //ok
     }
     static assert(is(typeof(_input[size_t.max .. 
 size_t.max]))); //ok
     static assert(is(typeof(_input[size_t.max .. $]))); //NOPE!
 }
 As you can see, the static if behaves differently in a 
 function, or in the raw body of the struct. Is this normal? 
 Anybody know what is going on exactly? I'm trying to get more 
 context here...
 
 -----------------------------------------------
 
 Second, one of the things I found strange was that only *1* of 
 the two assertions failed. basically, _input[0 .. 1] is fair 
 game, yet, _input[0 .. $] is not? What gives? I put my nose in 
 cycles's opDollar. It is written like this:
Did you really mean size_t.*max* above?
Yeah. It's not a runtime test. In this case, I *also* need to make sure that the slie operation accepts a size_t arg. If I use size_t.min, it statically evaluates to zero, so the test becomes sens-less: saying "fun(size_t.min)" works doesn't actually guarantee you can pass a size_t: it may actually only accepts ubytes or short indexing. But I guess that is a detail in the scope of the original problem.
 Anyway, when '$' is rewritten as 'opDollar' and that is defined
 as a non-static method, it would be surprising if calling the
 method did work w/o any context pointer...
But, the "context pointer" *should* be defined as whatever the owner of the indexing/slicing object is, no? In this case, it's simply _input. It has nothing to do with the "this" pointer being available... If anything, it kind of worries me about *what* the implementation is doing with the this pointer, but I haven't been able to "trick" it into calling a wrong function.
 Does declaring the opDollar "function" as `static` fix it?

 artur
Yes. It does fix it. I think you put your finger exactly on where the issue is. I'll report it in the morning. Thank you for participating :)
Jul 08 2013
next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/08/13 23:45, monarch_dodra wrote:
 On Monday, 8 July 2013 at 18:55:30 UTC, Artur Skawina wrote:
 On 07/08/13 19:54, monarch_dodra wrote:
 struct S(R)
 {
     R _input;
     void foo()
     {
         static assert(is(typeof(_input[size_t.max .. size_t.max]))); //ok
         static assert(is(typeof(_input[size_t.max .. $]))); //ok
     }
     static assert(is(typeof(_input[size_t.max .. size_t.max]))); //ok
     static assert(is(typeof(_input[size_t.max .. $]))); //NOPE!
 }
 As you can see, the static if behaves differently in a function, or in the raw
body of the struct. Is this normal? Anybody know what is going on exactly? I'm
trying to get more context here...

 -----------------------------------------------

 Second, one of the things I found strange was that only *1* of the two
assertions failed. basically, _input[0 .. 1] is fair game, yet, _input[0 .. $]
is not? What gives? I put my nose in cycles's opDollar. It is written like this:
Did you really mean size_t.*max* above?
Yeah. It's not a runtime test. In this case, I *also* need to make sure that the slie operation accepts a size_t arg. If I use size_t.min, it statically evaluates to zero, so the test becomes sens-less: saying "fun(size_t.min)" works doesn't actually guarantee you can pass a size_t: it may actually only accepts ubytes or short indexing.
Didn't think of that; these implicit narrowing conversion can be, umm, surprising. But as long as the right overload gets picked, I guess they're safe. Thanks for the explanation.
 Anyway, when '$' is rewritten as 'opDollar' and that is defined
 as a non-static method, it would be surprising if calling the
 method did work w/o any context pointer...
But, the "context pointer" *should* be defined as whatever the owner of the indexing/slicing object is, no? In this case, it's simply _input. It has nothing to do with the "this" pointer being available... If anything, it kind of worries me about *what* the implementation is doing with the this pointer, but I haven't been able to "trick" it into calling a wrong function.
It's just like struct S { auto opDollar() { return 42; } enum a = opDollar(); } This can't work - there is no S object to call the method with. enum a = S.init.opDollar(); would work, just as making the method static.
 Does declaring the opDollar "function" as `static` fix it?
Yes. It does fix it. I think you put your finger exactly on where the issue is. I'll report it in the morning. Thank you for participating :)
Thank you for still trying to improve the std lib. I gave up on using it, other than for toy examples, long time ago. Hopefully it will be usable at some point. artur
Jul 08 2013
prev sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/09/13 00:43, Artur Skawina wrote:
 On 07/08/13 23:45, monarch_dodra wrote:
 But, the "context pointer" *should* be defined as whatever the owner of the
indexing/slicing object is, no? In this case, it's simply _input. It has
nothing to do with the "this" pointer being available...

 If anything, it kind of worries me about *what* the implementation is doing
with the this pointer, but I haven't been able to "trick" it into calling a
wrong function.
It's just like
Sorry, didn't read that code again before replying. What is indeed unintuitive is that the first typeof expression succeeds but the other one fails. But this is related to how typeof() works, apparently by design. Eg: auto f(int a) { return a; } pragma(msg, typeof(f(1))); // "int". OK. alias INT = int; pragma(msg, typeof(f(INT))); // "int". OK... //pragma(msg, typeof(f(int))); // Compile error. That plus a non-existing this._input, results in a bit (too much) magic, and the first test passes. The other one fails because of the '$' (ie opDollar() call). artur
Jul 08 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 9 July 2013 at 00:06:11 UTC, Artur Skawina wrote:
 That plus a non-existing this._input, results in a bit (too 
 much)
 magic, and the first test passes. The other one fails because of
 the '$' (ie opDollar() call).

 artur
In any case, it is now filed: http://d.puremagic.com/issues/show_bug.cgi?id=10597 I reduced it to this (imo) neat usecase: //---- struct R { void opIndex(int); int opDollar(); } R r; void foo() { static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //ok } static assert(is(typeof(r[0]))); //ok static assert(is(typeof(r[$]))); //fails (!) //---- Thanks again for the help :)
Jul 10 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/10/13 21:36, monarch_dodra wrote:
 On Tuesday, 9 July 2013 at 00:06:11 UTC, Artur Skawina wrote:
 That plus a non-existing this._input, results in a bit (too much)
 magic, and the first test passes. The other one fails because of
 the '$' (ie opDollar() call).
In any case, it is now filed: http://d.puremagic.com/issues/show_bug.cgi?id=10597 I reduced it to this (imo) neat usecase:
 struct R
 {
     void opIndex(int);
     int opDollar();
 }
 R r;
 static assert(is(typeof(r[0]))); //ok
 static assert(is(typeof(r[$]))); //fails (!)
Yeah, I can't convince myself that it's ok for the /first/ assert to pass - actually evaluating the "r[0]" expression in that same context will *fail* (because 'r' isn't known at compile time). It always possible to test with 'typeof(r.init[0])'. The fact that static assert(__traits(compiles, r[0])); succeeds, when that expression won't actually compile is also a problem. artur
Jul 10 2013