[Issue 15839] this.outer is of wrong type

2016-03-31 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #7 from Jacob Carlborg  ---
I tried modifying my code to explicitly pass in the outer this reference. That
works until you have nested anonymous classes. For example:

interface A {}
interface B {}

class Foo
{
void foo()
{
auto a = new class(this) A {
Foo outer;
this(Foo outer)
{
this.outer = outer;
this.outer.bar();

auto b = new class(this) B {
A outer;
this(A outer)
{
this.outer = outer;
this.outer.outer.bar(); // line 20
}
};
}
};
}

void bar() {}
}

The above will of course fail to compile since there's no "bar" in "A":

main.d(20): Error: no property 'outer' for type 'main.A'

Any suggestions?

--


[Issue 15839] this.outer is of wrong type

2016-03-29 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

Martin Nowak  changed:

   What|Removed |Added

 CC||c...@dawg.eu

--- Comment #6 from Martin Nowak  ---
(In reply to Kenji Hara from comment #4)
> Note that, compiler cannot determine whether the start() makes a closure
> environment or not at the place where 'this.outer' is used. Because of that,
> the .outer property should have void* type, to be consistent with the
> lexical scope nesting.

But this.outer always refers to the enclosing function even if no closure is
required, right? A this.outer that is typed as void* and either refers to an
enclosing function or an enclosing class would be highly confusing.

--


[Issue 15839] this.outer is of wrong type

2016-03-28 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #5 from Jacob Carlborg  ---
(In reply to Kenji Hara from comment #4)

> However... of course it's not stable. And as far as I know, there's no way
> to know the number of chains up to reach wanting enclosing scope.

So the best approach would be to pass in the outer reference to the constructor
when creating the anonymous class and use that instead of "this.outer"?

--


[Issue 15839] this.outer is of wrong type

2016-03-28 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #4 from Kenji Hara  ---
(In reply to Jacob Carlborg from comment #3)
> So it's not representing the this reference of the outer class anymore?

Until 2.070, the builtin .outer property sometimes returned correct class
reference, sometimes invalid one. Test following code with 2.070 or earlier.

import core.stdc.stdio : printf;

interface Runnable {}

class GC
{
this(AnimatedProgress ap)
{
printf("GC.ctor, ap = %p\n", ap);
}
}

class AnimatedProgress
{
void start()
{
printf("start, this = %p\n", this);

version(ng) int a;

auto r = new class Runnable {
void run()
{
printf("run, this.outer = %p\n", this.outer);

GC gc = new GC(this.outer);

version(ng) int b = a;
}
};
r.run();
}
}

void main()
{
auto ap = new AnimatedProgress();
printf("main, ap = %p\n", ap);
ap.start();
}

Without -version=ng, the class reference (instance address) are same, so the
code would work as the author's expected. But with -version=ng, the start()
member function will become a closure, and this.outer will suddenly return a
pointer to the closure environment - of course it's invalid as a class
reference.

Note that, compiler cannot determine whether the start() makes a closure
environment or not at the place where 'this.outer' is used. Because of that,
the .outer property should have void* type, to be consistent with the lexical
scope nesting.

> Is
> it possible to get that behavior somehow?
> 
> This is a huge regression for DWT.

Theoretically the chain of 'outer' can reach to AnimatedProgress class
instance.

Actually in my example code, following code can work in run() function with
-version=ng case.

version(ng) printf("run, *cast(void**)this.outer = %p\n",
*cast(void**)this.outer);
//GC gc = new GC(this.outer);
GC gc = new GC(cast(AnimatedProgress)*cast(void**)this.outer);

However... of course it's not stable. And as far as I know, there's no way to
know the number of chains up to reach wanting enclosing scope.

--


[Issue 15839] this.outer is of wrong type

2016-03-27 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #3 from Jacob Carlborg  ---
(In reply to Kenji Hara from comment #1)

> > The property .outer used in a nested class gives the this pointer to its 
> > enclosing class. If the enclosing context is not a class, the .outer will 
> > give the pointer to it as a void* type.
> 
> It means `this.outer` in `run()` member function should represent the frame
> of 'start' function. Actually the generated code is following the spec, but
> front-end had incorrectly typed 'this.outer' like an AnimatedProgress class.

So it's not representing the this reference of the outer class anymore? Is it
possible to get that behavior somehow?

This is a huge regression for DWT.

--


[Issue 15839] this.outer is of wrong type

2016-03-27 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

Jack Stouffer  changed:

   What|Removed |Added

 CC||j...@jackstouffer.com

--- Comment #2 from Jack Stouffer  ---
If this is the result of a breaking change, then it should be in the changelog.

--


[Issue 15839] this.outer is of wrong type

2016-03-27 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #1 from Kenji Hara  ---
This is an intentional bugfix introduced by fixing issue 14442.

Note that there was accepts-invalid bug. The spec page
http://dlang.org/spec/class said:

> The property .outer used in a nested class gives the this pointer to its 
> enclosing class. If the enclosing context is not a class, the .outer will 
> give the pointer to it as a void* type.

It means `this.outer` in `run()` member function should represent the frame of
'start' function. Actually the generated code is following the spec, but
front-end had incorrectly typed 'this.outer' like an AnimatedProgress class.

--