www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 17548] New: Forward reference error with scope function

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

          Issue ID: 17548
           Summary: Forward reference error with scope function parameters
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: major
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: syniurge gmail.com

//---------------------fwdref1.d--------------

// import fwdref2;

struct S1 {
    void foo(scope S2 arg) {}
    int myField;
}

enum cnst = 4321;

import fwdref2;

//---------------------fwdref2.d--------------

import fwdref1;

struct S2 {
    void bar(int arg = .fwdref1.cnst) {}
    S1 s;
}

//--------------------------------------------

$ dmd fwdref1.d
fwdref2.d(3): Error: struct fwdref2.S2 has forward references

The error disappears if "scope" is removed from fwdref1.d, or if the first dot
in ".fwdref1.cnst" i.e the module scope operator is removed.

What seems to happen:

- in TypeFunction.semantic for S1.foo, the right hand of 

    if (fparam.storageClass & STCscope && !fparam.type.hasPointers())

  gets evaluated.
- hasPointers() calls .size() on S2 which then calls .determineSize()
- S2 having _scope set, .determineSize() calls StructDeclaration.semantic() on
S2
- the default argument of S2.bar() gets semantic'd(), and DsymbolExp.resolve()
calls semantic() on the fwdref2 module
- since fwdref2.semanticRun is still at PASSinit, Module.semantic() calls
semantic() for each of its members, including S2
- S2 doesn't have _scope set anymore, scx remains null, so
StructDeclaration.semantic() ends with:

    else if (symtab && !scx)
    {
        semanticRun = PASSsemanticdone;
        return;
    }

  (while we're clearly not done, the first call is ongoing)
- back to the first semantic() call on S2, after determineFields() it then
checks that for every field with a struct type, the struct symbol is at
PASSsemanticdone. But since S1 is still at PASSsemantic, it hits:

    _scope = scx ? scx : sc.copy();
    _scope.setNoFree();
    _scope._module.addDeferredSemantic(this);
    //printf("\tdeferring %s\n", toChars());
    return;

- so now S2 has _scope set yet is at PASSsemanticdone. The deferred semantic()
call returns immediately, and then semantic2() greets S2 with our error:

    if (_scope)
    {
        error("has forward references");
        return;
    }


Sorry if this a little too detailed.

I'm not entirely sure what the proper fix is. Is Module.semantic() always
supposed to get called before any semantic-ing of its members? (this would have
prevented "." from disrupting StructDeclaration.semantic()'s assumptions)


Placing "import fwdref2;" on top also produces an error, but a different one:
"struct fwdref2.S2 no size because of forward reference".

--
Jun 24 2017