September 01, 2016
On Thursday, 1 September 2016 at 20:43:16 UTC, David Nadlinger wrote:
>
> See also: https://github.com/dlang/dmd/pull/692 – it's about time we finally got __ctfeWrite() merged.
>
>  — David

Oh yeah.
Let me get this into PR shape.
September 01, 2016
On 09/01/2016 11:01 PM, Rory McGuire via Digitalmars-d-announce wrote:
> I'm actually asking why we can't catch the ctfe error.

There is no CTFE error in your example. It doesn't compile in the first place, even without attempting any CTFE.

[...]
> Surely the ctfe engine could be changed to catch unsupported code
> errors. (Not invalid, just unsupported at CT).

Maybe. It isn't obvious to me that it would be a good idea, but it's not obviously terrible either.

> The ctfe engine would have to "go past" the try anyway, right? This is
> the part I don't understand. Is it because ctfe actually hasn't started
> yet and some other analysis is freaking out?

It's just a compiler error. The snippet on its own fails compilation and there is no CTFE in there. Something like `static assert(_checkCTFE());` would involve CTFE. But that's not needed to trigger the error.
September 01, 2016
On Thu, Sep 1, 2016 at 11:05 PM, David Nadlinger via Digitalmars-d-announce <digitalmars-d-announce@puremagic.com> wrote:

> On Thursday, 1 September 2016 at 21:01:46 UTC, Rory McGuire wrote:
>
>> I'm actually asking why we can't catch the ctfe error.
>>
>
> You can, by using __traits(compiles, …).
>
> Surely the ctfe engine could be changed to catch unsupported code errors.
>> (Not invalid, just unsupported at CT).
>>
>
> It already does, see above. How is this related to try/catch?
>
>  — David
>

I was hoping that the error was coming from the CTFE engine as it ran the code, but it comes up before ctfe execution I guess.

__traits(compiles, _some_function_that_calls_), thinks that the invalid code compiles even when it doesn't compile, e.g.:

template assertCTFE(bool b) {
enum assertCTFE = __traits(compiles, _checkCTFE1());
}
void _checkCTFE1() {
static if (__ctfe) { // this still stops compilation (probably because this
is checked before __traits(compiled ...) is evaluated

}
}


September 01, 2016
On Thu, Sep 1, 2016 at 11:26 PM, ag0aep6g via Digitalmars-d-announce < digitalmars-d-announce@puremagic.com> wrote:

> On 09/01/2016 11:01 PM, Rory McGuire via Digitalmars-d-announce wrote:
>
>> I'm actually asking why we can't catch the ctfe error.
>>
>
> There is no CTFE error in your example. It doesn't compile in the first place, even without attempting any CTFE.
>
> [...]
>
>> Surely the ctfe engine could be changed to catch unsupported code errors. (Not invalid, just unsupported at CT).
>>
>
> Maybe. It isn't obvious to me that it would be a good idea, but it's not obviously terrible either.
>
> The ctfe engine would have to "go past" the try anyway, right? This is
>> the part I don't understand. Is it because ctfe actually hasn't started yet and some other analysis is freaking out?
>>
>
> It's just a compiler error. The snippet on its own fails compilation and there is no CTFE in there. Something like `static assert(_checkCTFE());` would involve CTFE. But that's not needed to trigger the error.
>



Yeah, I'm using an enum to force the evaluation during CT, and its dying before CTFE from what I can tell. Here is another example:

void main() {
enum ret = ctfefunc();
mixin(ret);
}


string ctfefunc() {
static if (!assertCTFE!true) {
throw new Exception("Only during ctfe please...");
}
return `import std.stdio; writeln("ctfe generated this");`;
}

template assertCTFE(bool b) {
enum assertCTFE = __traits(compiles, _checkCTFE1());
}
void _checkCTFE1() {
static if (__ctfe) {

}
}


September 01, 2016
On Thu, Sep 01, 2016 at 08:43:16PM +0000, David Nadlinger via Digitalmars-d-announce wrote:
> On Thursday, 1 September 2016 at 19:38:13 UTC, Stefan Koch wrote:
> > I have something that will help with that a little bit. https://github.com/UplinkCoder/dmd/tree/__ctfeWriteln when you apply this patch __ctfeWriteln() will output every compiletime avilable string to the console.
> 
> More crucially, it also allows you to print runtime values during CTFE.  pragma(msg, …) suffices to print compile-time constants. Very few people seem to have the correct mental model for the the interaction between compile-time features and CTFE, hence I think using precise terminology is an important first step.
[...]

Part of the problem is that the term "compile-time" is ambiguous. In the
compilation of a D program, there are (at least) 2 distinct phases that
may be termed "compile-time": (1) expansion of templates and evaluation
of static-if, and (2) CTFE.

Phase (1) conceptually happens before the AST is finalized, and hence at this stage it makes no sense to refer to variables and such: variables don't even exist yet because the syntax tree of the program is still being manipulated.

Phase (2) happens just as the compiler is ready to emit object code: the AST has been finalized, symbols have been resolved, statements have been analysed / lowered, etc.. At this stage, static-if no longer makes any sense because the AST can no longer be manipulated at this point.

Of course, the above is a simplified picture of what actually happens. In a complex D program, you *can* have phase (2) precede phase (1), e.g., using static-if on the result of a CTFE function. The important thing to note here, though, is that the CTFE function's body must already be in phase (2), because otherwise CTFE is impossible. So another part of the code can depend on the result of the CTFE function, but the function itself is already past phase (1) and you can't change its AST anymore.  So you can have different parts of the program be in different phases, and they can have interdependencies, but the same piece of code can only progress from phase (1) to phase (2), and never the other way around.

Referring to both phases as "compile-time" is ambiguous and causes confusion to people who are not familiar with how the compilation process actually works.


T

-- 
Windows: the ultimate triumph of marketing over technology. -- Adrian von Bidder
September 01, 2016
On Thursday, 1 September 2016 at 21:48:41 UTC, Rory McGuire wrote:
> I was hoping that the error was coming from the CTFE engine as it ran the code, but it comes up before ctfe execution I guess.

As a general comment, there is no such thing as a CTFE phase. It is performed in-line with other semantic analysis as required.

> __traits(compiles, _some_function_that_calls_), thinks that the invalid code compiles even when it doesn't compile […]

No, you are missing the point. This:

---
void foo() {
  @#$!
}
---

will always cause a compiler error, regardless of whether there is a `__traits(compiles, foo())` somewhere else in the module. __traits(compiles, …) only applies to its argument and doesn't magically cause errors in code somewhere else to be ignored.

 — David
September 02, 2016
On 09/01/2016 11:51 PM, Rory McGuire via Digitalmars-d-announce wrote:
> Yeah, I'm using an enum to force the evaluation during CT,

I had missed that detail. Still, the error seems to be independent of any CTFE that's going on.

[...]
> Here is another example:
>
> void main() {
> enum ret = ctfefunc();
> mixin(ret);
> }
>
>
> string ctfefunc() {
> static if (!assertCTFE!true) {
> throw new Exception("Only during ctfe please...");
> }
> return `import std.stdio; writeln("ctfe generated this");`;
> }
>
> template assertCTFE(bool b) {
> enum assertCTFE = __traits(compiles, _checkCTFE1());
> }
> void _checkCTFE1() {
> static if (__ctfe) {
>
> }
> }

It's not clear to me what this example is supposed to show. In particular, how does it relate to catching CTFE errors?

Obviously, `static if (__ctfe)` doesn't compile right now, so _checkCTFE1 must be rejected regardless of anything else. And with _checkCTFE1, the whole program goes down.

Your code looks like it's supposed to throw an exception when ctfefunc is called during normal run-time instead of CTFE. That can be done:

----
string ctfefunc()
{
    if (!__ctfe) throw new Exception("Only during ctfe please...");
    return `import std.stdio; writeln("ctfe generated this");`;
}
----

But I feel like that's missing the point of the example.
September 05, 2016
FunctionCall support is done. (with a lot of room for improvement)
you can already return strings.
now I just have to finish string-comparison and string-concat support to make it usable.

And of course the correct translation of logical-expressions...
September 05, 2016
On Mon, Sep 5, 2016 at 1:39 PM, Stefan Koch via Digitalmars-d-announce < digitalmars-d-announce@puremagic.com> wrote:

> FunctionCall support is done. (with a lot of room for improvement)
> you can already return strings.
> now I just have to finish string-comparison and string-concat support to
> make it usable.
>
> And of course the correct translation of logical-expressions...
>


Great news! Any chance you post the commit link in your announcements? Would be really interested in being able to do a quick scan of what changed.

For that latest commit I just see the below. Is this all the changes? :)
what does it mean? (you replaced the old ctfe for functions with your new
one?)

% git show 4ba35de160cdb82bb289ad2860cf5163e1636ab5
commit 4ba35de160cdb82bb289ad2860cf5163e1636ab5
Author: Stefan Koch <Uplink.Coder@googlemail.com>
Date:   Mon Sep 5 13:35:26 2016 +0200

    hack in ability to do function calls

diff --git a/src/ctfe_bc.d b/src/ctfe_bc.d
index 2e9d0fa..a96d37c 100644
--- a/src/ctfe_bc.d
+++ b/src/ctfe_bc.d
@@ -143,6 +143,7 @@ else static if (UsePrinterBackend)
 else
 {
     import ddmd.ctfe.bc;
+import ddmd.dinterpret;

     alias BCGenT = BCGen;

@@ -2252,6 +2253,10 @@ public:
             IGaveUp = true;
             return;
         }
+        import ddmd.dinterpret;
+        ctfeInterpret(ce).accept(this);
+        return ;
+        /*
         auto fn = _sharedCtfeState.getFunctionIndex(ce.f);
         if (!fn)
         {
@@ -2296,6 +2301,8 @@ public:
                 assert(0, "Could not gen Function: " ~ ce.f.toString);
             IGaveUp = true;
         }
+        */
+
     }

     override void visit(ReturnStatement rs)




BTW: thanks for all the work!


September 05, 2016
On Monday, 5 September 2016 at 13:13:03 UTC, Rory McGuire wrote:
>
> Great news! Any chance you post the commit link in your announcements? Would be really interested in being able to do a quick scan of what changed.
At the moment writing a change-log would be tedious busywork since everything changes all the time.
> For that latest commit I just see the below. Is this all the changes? :)
> what does it mean? (you replaced the old ctfe for functions with your new
> one?)

Yes and no, I did not replace the old ctfe I merely placed myself in front of it.
Therefore I can leverage the existing mechanism for calls.
And replace a function call by the expression it yields.

For certain kind of function-calls (Those that change visible state) This is going to fail or produce incorrect code.

But I am working on it :)