[Issue 15839] this.outer is of wrong type

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Mon Mar 28 07:06:58 PDT 2016


https://issues.dlang.org/show_bug.cgi?id=15839

--- Comment #4 from Kenji Hara <k.hara.pg at gmail.com> ---
(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.

--


More information about the Digitalmars-d-bugs mailing list