Thread overview
[Issue 21614] compiled imports: core.exception.AssertError@src/dmd/semantic3.d(812): Assertion failure
Feb 06, 2021
Iain Buclaw
Feb 06, 2021
Iain Buclaw
Feb 06, 2021
Iain Buclaw
Feb 06, 2021
Iain Buclaw
Feb 06, 2021
Iain Buclaw
Feb 09, 2021
Iain Buclaw
Feb 09, 2021
Dlang Bot
Feb 11, 2021
Dlang Bot
Feb 13, 2021
Dlang Bot
Apr 02, 2021
Dlang Bot
February 06, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |ibuclaw@gdcproject.org

--- Comment #1 from Iain Buclaw <ibuclaw@gdcproject.org> ---
Created attachment 1816
  --> https://issues.dlang.org/attachment.cgi?id=1816&action=edit
reduced testcase

issue21614.d
---
module issue21614;

real logmdigammaInverse(real y)
{
    import imports.issue21614a;
    findRoot(1 , y,  2);
}
---

imports/issue21414a.d
---
module imports.issue21614a;

template AliasSeq(TList...)
{
    alias AliasSeq = TList;
}

uint formattedWrite(Writer, Char)(Writer , Char)
{
    alias spec = FormatSpec!Char();
    return 0;
}

struct FormatSpec(Char)
{
    import imports.issue21614a;
}

template ElementEncodingType(R)
{
    static if (is(R : E[], E))
        alias ElementEncodingType = E;
}

struct Appender(A)
{
    inout(ElementEncodingType!A)[] data() {
        return [];
    }
}

Appender!A appender(A)()
{
    return Appender!A();
}

immutable(Char)[] format(Char, Args)(Char[] fmt, Args)
{
    auto w = appender!(Char[]);
    formattedWrite(w, fmt);
    return w.data;
}

template Tuple(Specs)
{
    template parseSpecs(Specs)
    {
        alias parseSpecs = AliasSeq!FieldSpec;
    }

    template FieldSpec {
    }

    alias fieldSpecs = parseSpecs!Specs;

    string injectNamedFields()
    {
        foreach (i, name; fieldSpecs)
            format("%s", i);
        return "";
    }

    struct Tuple
    {
        mixin(injectNamedFields);

        this()
        {
        }
    }
}

T findRoot(T, DF, DT)(DF f, T a, T b, DT tolerance)
{
    findRoot(f, a, b, 0, 1, tolerance);
}

T findRoot(T, DF)(DF f, T a, T b)
{
    findRoot(f, a, b, false);
}

Tuple!(T) findRoot(T, R, DF, DT)(DF , T , T , R , R , DT )
---

--
February 06, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

--- Comment #2 from Iain Buclaw <ibuclaw@gdcproject.org> ---
In the unreduced test, a function that is marked `inferRetType` has a return statement, but the return type is inferred as `void` (possibly because semantic never finished for it).  Hence the assert is triggered.

--
February 06, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Attachment #1816|0                           |1
        is obsolete|                            |

--- Comment #3 from Iain Buclaw <ibuclaw@gdcproject.org> ---
Created attachment 1817
  --> https://issues.dlang.org/attachment.cgi?id=1817&action=edit
reduced test without errors

Attached reduced test that hits the assert error without any compiler errors.

issue21614.d
---
real logmdigammaInverse(real y)
{
    import imports.issue21614.numeric;
    findRoot(1, y, 2);
    return y;
}
---
imports/issue21614/numeric.d
---
module imports.issue21614.numeric;
import imports.issue21614.typecons;

T findRoot(T, DF, DT)(DF f, T a, T b, DT tolerance)
{
    immutable r = findRoot(f, a, b, a, b, tolerance);
    return r[2];
}

T findRoot(T, DF)(DF f, T a, T b)
{
    return findRoot(f, a, b, false);
}

Tuple!(T, T, R) findRoot(T, R, DF, DT)(DF, T, T, R, R, DT)
{
    return Tuple!(T, T, R)();
}
---
imports/issue21614/typecons.d
---
module imports.issue21614.typecons;
template AliasSeq(TList...)
{
    alias AliasSeq = TList;
}

template staticMap(alias F, T...)
{
    static if (T.length == 1)
        alias staticMap = AliasSeq!(F!T);
    else
        alias staticMap = AliasSeq!(staticMap!(F, T[0]), staticMap!(F, T[$/2 ..
$]));
}
uint formattedWrite(Writer, Char)(Writer , Char)
{
    auto spec = FormatSpec!Char();
    return 0;
}

struct FormatSpec(Char)
{
    import imports.issue21614.typecons;
}
template ElementEncodingType(R)
{
    static if (is(R : E[], E))
        alias ElementEncodingType = E;
}

struct Appender(A)
{
    inout(ElementEncodingType!A)[] data()
    {
        return [];
    }
}

Appender!A appender(A)()
{
    return Appender!A();
}
immutable(Char)[] format(Char, Args...)(Char[] fmt)
{
    auto w = appender!(Char[]);
    formattedWrite(w, fmt);
    return w.data;
}
template Tuple(Specs...)
{
    template parseSpecs(Specs...)
    {
        static if (Specs.length == 0)
            alias parseSpecs = AliasSeq!();
        static if (is(Specs[0]))
            alias parseSpecs = AliasSeq!(FieldSpec!(Specs[0]),
parseSpecs!(Specs[1 .. $]));
    }

    template FieldSpec(T, string s = "")
    {
        alias Type = T;
        alias name = s;
    }

    alias fieldSpecs = parseSpecs!Specs;

    alias extractType(alias spec) = spec.Type;
    alias extractName(alias spec) = spec.name;

    string injectNamedFields()
    {
        string decl;
        foreach (i; staticMap!(extractName, fieldSpecs))
            format(i);
        return decl;
    }

    struct Tuple
    {
        alias Types = staticMap!(extractType, fieldSpecs);
        Types expand;
        mixin(injectNamedFields);

        alias expand this;
        this(Types)
        {
        }
    }
}
---

--
February 06, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

--- Comment #4 from Iain Buclaw <ibuclaw@gdcproject.org> ---
(In reply to Iain Buclaw from comment #2)
> In the unreduced test, a function that is marked `inferRetType` has a return statement, but the return type is inferred as `void` (possibly because semantic never finished for it).  Hence the assert is triggered.
This assumption was wrong.  What really happens is that there's a constructor marked as `inferRetType`.  It's body is empty so it is inferred `void`.  Then an automatic `return this` statement is appended to the body (because it isCtorDeclaration), and an assert is triggered because the return type is `void`.

--
February 06, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

--- Comment #5 from Iain Buclaw <ibuclaw@gdcproject.org> ---
(In reply to Iain Buclaw from comment #4)
> (In reply to Iain Buclaw from comment #2)
> > In the unreduced test, a function that is marked `inferRetType` has a return statement, but the return type is inferred as `void` (possibly because semantic never finished for it).  Hence the assert is triggered.
> This assumption was wrong.  What really happens is that there's a constructor marked as `inferRetType`.  It's body is empty so it is inferred `void`.  Then an automatic `return this` statement is appended to the body (because it isCtorDeclaration), and an assert is triggered because the return type is `void`.
And to add insult to injury, because of a self-reference (the import statement that leads back to current module), during the semantic1 pass of `struct Tuple`, the semantic1 pass of the constructor is skipped, jumping straight to `semantic2`.

--
February 09, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Attachment #1817|0                           |1
        is obsolete|                            |

--- Comment #6 from Iain Buclaw <ibuclaw@gdcproject.org> ---
Created attachment 1818
  --> https://issues.dlang.org/attachment.cgi?id=1818&action=edit
Further reduced test without errors

Reduced the test down even further.  Now it is just two modules ~25 sloc.

issue21614.d
---
void logmdigammaInverse(real y)
{
    import imports.issue21614a;
    findRoot(y);
}
---
imports/issue21614a.d
---
module imports.issue21614a;

struct FormatSpec(Char)
{
    import imports.issue21614a;
}

template Tuple(Specs...)
{
    struct Tuple
    {
        alias spec = FormatSpec!char();
        this(Specs)
        {
        }
    }
}

auto findRoot(T)(T)
{
    return Tuple!(T)();
}
---

--
February 09, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull

--- Comment #7 from Dlang Bot <dlang-bot@dlang.rocks> ---
@ibuclaw created dlang/dmd pull request #12191 "fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion failure" fixing this issue:

- fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion failure

  Template instances may import modules that have not finished semantic1,
  and in the case of cyclic imports, semantic2 could be ran on a function
  symbol before semantic1 has begun, which can lead to inferred functions
  given the wrong return type.

https://github.com/dlang/dmd/pull/12191

--
February 11, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

Dlang Bot <dlang-bot@dlang.rocks> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--- Comment #8 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #12191 "fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion failure" was merged into stable:

- 7637e61675b2249d640c44ffc792fff4d1fecb69 by Iain Buclaw:
  fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion failure

  Template instances may import modules that have not finished semantic1,
  and in the case of cyclic imports, semantic2 could be ran on a function
  symbol before semantic1 has begun, which can lead to auto functions
  given the wrong return type.

https://github.com/dlang/dmd/pull/12191

--
February 13, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

--- Comment #9 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #12195 "Merge stable" was merged into master:

- 599c1b32a92d6d7606b3ec475d2229cde2d4a412 by Iain Buclaw:
  fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion failure

  Template instances may import modules that have not finished semantic1,
  and in the case of cyclic imports, semantic2 could be ran on a function
  symbol before semantic1 has begun, which can lead to auto functions
  given the wrong return type.

https://github.com/dlang/dmd/pull/12195

--
April 02, 2021
https://issues.dlang.org/show_bug.cgi?id=21614

--- Comment #10 from Dlang Bot <dlang-bot@dlang.rocks> ---
dlang/dmd pull request #12339 "[dmd-cxx] Backport fixes and trivial features from upstream dmd" was merged into dmd-cxx:

- 6692347215181ee125177cf23ff71e766cd1f5ef by Iain Buclaw:
  [dmd-cxx] fix Issue 21614 - AssertError@src/dmd/semantic3.d(812): Assertion
failure

https://github.com/dlang/dmd/pull/12339

--