www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Bug in compiler?

reply Shachar Shemesh <shachar weka.io> writes:
Please consider the following program:
import std.exception;

void main()
{
     struct A {
         int a;

          disable this(this);
          disable ref A opAssign(const ref A);

         ref A opOpAssign(string op: "~")(int data) {
             a += data;

             return this;
         }
     }

     auto a = A(2);

     a ~= 3;

     assertThrown!Exception(a ~= 3);
}

Compilation (dmd 2.066.1) fails on the assertThrown line:
Error: struct test.main.A is not copyable because it is annotated with 
 disable

What I do not understand is why A should need to be copyable. Where is 
the copy made? I'm guessing this is because of the lazy definition of 
the expression, but still I don't see any reason to create a copy.

Help?
Shachar
Dec 15 2014
parent reply ketmar via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Mon, 15 Dec 2014 16:01:35 +0200
Shachar Shemesh via Digitalmars-d <digitalmars-d puremagic.com> wrote:

 Please consider the following program:
 import std.exception;
=20
 void main()
 {
      struct A {
          int a;
=20
           disable this(this);
           disable ref A opAssign(const ref A);
=20
          ref A opOpAssign(string op: "~")(int data) {
              a +=3D data;
=20
              return this;
          }
      }
=20
      auto a =3D A(2);
=20
      a ~=3D 3;
=20
      assertThrown!Exception(a ~=3D 3);
 }
=20
 Compilation (dmd 2.066.1) fails on the assertThrown line:
 Error: struct test.main.A is not copyable because it is annotated with=20
  disable
=20
 What I do not understand is why A should need to be copyable. Where is=20
 the copy made? I'm guessing this is because of the lazy definition of=20
 the expression, but still I don't see any reason to create a copy.
yes, this is due to `lazy` in assrtThrown. what `lazy` does is actually creating a lambda. then compiler tries to deduce the type of the expression and it got `A`. so it generates the code like `A expression`. it can't see `ref` there, as `a` type is `A`, not `ref A`. you can workaround that with creating the necessary lambda manually: assertThrown!Exception((ref A aa) { aa ~=3D 3; }(a)); tl;dr: no, it's not a bug in the compiler. but the error message is misleading and you are required to understang some internals to make sense out of it.
Dec 15 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 15 December 2014 at 14:33:51 UTC, ketmar via 
Digitalmars-d wrote:
 On Mon, 15 Dec 2014 16:01:35 +0200
 Shachar Shemesh via Digitalmars-d <digitalmars-d puremagic.com> 
 wrote:

 Please consider the following program:
 import std.exception;
 
 void main()
 {
      struct A {
          int a;
 
           disable this(this);
           disable ref A opAssign(const ref A);
 
          ref A opOpAssign(string op: "~")(int data) {
              a += data;
 
              return this;
          }
      }
 
      auto a = A(2);
 
      a ~= 3;
 
      assertThrown!Exception(a ~= 3);
 }
 
 Compilation (dmd 2.066.1) fails on the assertThrown line:
 Error: struct test.main.A is not copyable because it is 
 annotated with  disable
 
 What I do not understand is why A should need to be copyable. 
 Where is the copy made? I'm guessing this is because of the 
 lazy definition of the expression, but still I don't see any 
 reason to create a copy.
yes, this is due to `lazy` in assrtThrown. what `lazy` does is actually creating a lambda. then compiler tries to deduce the type of the expression and it got `A`. so it generates the code like `A expression`. it can't see `ref` there, as `a` type is `A`, not `ref A`. you can workaround that with creating the necessary lambda manually: assertThrown!Exception((ref A aa) { aa ~= 3; }(a)); tl;dr: no, it's not a bug in the compiler. but the error message is misleading and you are required to understang some internals to make sense out of it.
Another point against storage class ref.
Dec 15 2014
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 15 December 2014 at 15:00:56 UTC, Marc Schütz wrote:
 On Monday, 15 December 2014 at 14:33:51 UTC, ketmar via 
 Digitalmars-d wrote:
 On Mon, 15 Dec 2014 16:01:35 +0200
 Shachar Shemesh via Digitalmars-d 
 <digitalmars-d puremagic.com> wrote:

 Please consider the following program:
 import std.exception;
 
 void main()
 {
     struct A {
         int a;
 
          disable this(this);
          disable ref A opAssign(const ref A);
 
         ref A opOpAssign(string op: "~")(int data) {
             a += data;
 
             return this;
         }
     }
 
     auto a = A(2);
 
     a ~= 3;
 
     assertThrown!Exception(a ~= 3);
 }
 
 Compilation (dmd 2.066.1) fails on the assertThrown line:
 Error: struct test.main.A is not copyable because it is 
 annotated with  disable
 
 What I do not understand is why A should need to be copyable. 
 Where is the copy made? I'm guessing this is because of the 
 lazy definition of the expression, but still I don't see any 
 reason to create a copy.
yes, this is due to `lazy` in assrtThrown. what `lazy` does is actually creating a lambda. then compiler tries to deduce the type of the expression and it got `A`. so it generates the code like `A expression`. it can't see `ref` there, as `a` type is `A`, not `ref A`. you can workaround that with creating the necessary lambda manually: assertThrown!Exception((ref A aa) { aa ~= 3; }(a)); tl;dr: no, it's not a bug in the compiler. but the error message is misleading and you are required to understang some internals to make sense out of it.
Another point against storage class ref.
Perhaps. I would say lazy should be clever enough to work this out.
Dec 15 2014