www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 19588] New: Invalid property opDispatch setter call inside

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

          Issue ID: 19588
           Summary: Invalid  property opDispatch setter call inside the
                    WithStatement
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: jacob.100205 gmail.com

import std.stdio;
import std.variant : Variant;

struct var {
    private Variant[string] values;

     property
    Variant opDispatch(string name)() const {
        return values[name];
    }

     property
    void opDispatch(string name, T)(T val) {
        values[name] = val;
    }
}

void main()
{
    var test;

    // Normal flow
    test.foo = "test";
    test.bar = 50;

    writeln("test.foo = ", test.foo);
    writeln("test.bar = ", test.bar);

    // Error flow
    with (test) {
        foobar = 3.14;
    }

    writeln(test.foobar);
}

The program will exit with a "Range Violation" exception. The reason is that
the compiler frontend generates a different AST when calling  property
opDispatch().

Here is how the AST looks like outside of "with":

test.opDispatch("test");
test.opDispatch(50);

And here is what happens inside the WithStatement:

with (test)
{
    (VariantN!32LU __tmpfordtor701 = ((VariantN!32LU __tmpfordtor700 =
(*__withSym).opDispatch();) , __tmpfordtor700).opAssign(3.14);) ,
__tmpfordtor701;
}

Which means that it first calls the getter, captures a reference to a variable,
and finally calls opDispatch setter on this variable.

The right behavior would be to call the setter directly like this:

with (test)
{
    var __tmp = test;
    __tmp.opDispatch(3.14);
}

Dlang online sandbox link: https://run.dlang.io/is/pwbm0d
Gist: https://gist.github.com/run-dlang/a8fbbc5dc49346b887b9aaee8758ffca

--
Jan 15