Bug 21614 – compiled imports: core.exception.AssertError@src/dmd/semantic3.d(812): Assertion failure

Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-02-06T10:09:27Z
Last change time
2021-04-02T05:45:31Z
Keywords
pull
Assigned to
No Owner
Creator
Iain Buclaw

Attachments

IDFilenameSummaryContent-TypeSize
1816issue21614.tar.gzreduced testcaseapplication/gzip781
1817issue21614.tar.gzreduced test without errorsapplication/gzip1047
1818issue21614.tar.gzFurther reduced test without errorsapplication/gzip384

Comments

Comment #0 by ibuclaw — 2021-02-06T10:09:27Z
Occurs when compiling with `-i` and semantic errors have occurred in non-root modules. Reduced test incoming.
Comment #1 by ibuclaw — 2021-02-06T10:15:56Z
Created attachment 1816 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 ) ---
Comment #2 by ibuclaw — 2021-02-06T10:32:29Z
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.
Comment #3 by ibuclaw — 2021-02-06T17:23:38Z
Created attachment 1817 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) { } } } ---
Comment #4 by ibuclaw — 2021-02-06T17:52:26Z
(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`.
Comment #5 by ibuclaw — 2021-02-06T18:38:24Z
(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`.
Comment #6 by ibuclaw — 2021-02-09T15:09:25Z
Created attachment 1818 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)(); } ---
Comment #7 by dlang-bot — 2021-02-09T19:17:25Z
@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
Comment #8 by dlang-bot — 2021-02-11T14:57:01Z
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
Comment #9 by dlang-bot — 2021-02-13T12:30:04Z
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
Comment #10 by dlang-bot — 2021-04-02T05:45:31Z
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