On Wed, 28 Aug 2024 at 22:11, Dennis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
On Wednesday, 28 August 2024 at 11:20:43 UTC, Manu wrote:
> At the end when everything's had a go
> (...)
> So just close out all outstanding tokens
> in the optimistic case... does that sound right?

That's what I tried to implement, with each function keeping an
array of callers of that function, so it could propagate an
attribute violation to functions that had 'outstanding tokens'
from calling that function.

But we don't have the luxury to wait, because D code may inspect
function types and demand an answer. Here's a (contrived) example:

```D
import std.traits;

@system void systemFunc();

void fun1()()
{
     alias T = typeof(fun2()); // is fun2 @safe? need an answer
for T now!

     // let's make a contradiction!
     static if (hasFunctionAttributes!(fun2!(), "@safe"))
         systemFunc();
}

void fun2()()
{
     fun1();
}

void main0() @system
{
     fun1();
}

void main() @safe
{
     fun2(); // not system!
}
```

We don't need to support such contrived examples of course, but
even for normal code, there are many places where the compiler
inspects the type of a function. Making it account everywhere for
the possibility that the function's attributes can still change,
even after semantic analysis has finished, is a complex task.

Yeah I get that... it's complex because there's not enough passes; a lot is done in one or a few passes, so there's no way to be confident that you can establish some compile-time facts before you expect they could be used...

I notice that all of your inferred functions are templates, and that reminded me a thought I had the other night... I don't see any reason non-templates couldn't be subject to attribute inferrence too; just that they shouldn't have it mangled into the name. If it carries a silent attribute that it inferred, it could be super convenient since there are so many attributes to juggle these days.
It would also mean people who didn't write code aggressively pursuing attributes may inadvertently write libraries that still CAN be used by more context sensitive users. I've noticed on my current project that I have to throw basically every library every written out the window... including druntime, etc. Heaps of druntime is compatible with my code, but because someone didn't put the attribute on it, I can't call it. It would be good if it inferred the full set of attributes silently, and then I could actually use the libs.