Implement Static Single Assignment (SSA) DIP
https://github.com/WalterBright/documents/blob/master/final.md
Thanks for your pull request, @WalterBright!
Bugzilla references
Your PR doesn't reference any Bugzilla issue.
If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
Testing this PR locally
If you don't have a local development environment setup, you can use Digger to test this PR:
dub run digger -- build "master + dmd#22171"
Given that this is running up against existing test cases (failing), it'll need to go behind a preview switch until it's ready & approved.
Ran into an unexpected problem. Using __traits(getLinkage, F) to transfer final to a delegate causes problems.
I think I can fix it. Tomorrow!
void main()
{
final int[2] a;
a[0]++; // no error
final S s;
s.i++; // no error
}
struct S
{
int i;
}
The DIP says:
final applied to a declaration of a variable of struct type means the non-static fields of the struct are implicitly final, and cannot be modified after initialization.
It doesn't mention static arrays, but as they are values, the elements should be final IMO.
@ntrel you're right
Casting a pointer to final should probably be allowed in @system code. It currently errors:
final int i = 3;
int* pm = cast(int*) &i; // Error: cannot implicitly convert final `& i` to `int*`
As final is local to a function, and does not leak out of it, being able to override it in a function is not needed (one can simply delete the final in that function). It is not so simple with const, which is why that can be overridden in a @system function.
As final is local to a function
final can apply to a module scope variable too, and the user of that variable may not have write access to the module where it's defined. I suppose use const tempPtr = &finalVar; then cast away const (e.g. to pass to a non-const function parameter that a particular call doesn't write to).
@ntrel yes you can do that in @system code. But you're no worse off if you didn't add the final.
How does final interact with other types and storage classes?
Structs, arrays, noreturn, ref, etc.
How does final interact with other types and storage classes?
All in the same way. Any final variable declaration prevents modification of the contents of the variable.
- structs: protects the fields
- classes: protects the reference to the class
- static arrays: protects the array contents
- dynamic arrays: protects the pointer/length
- ref: protects the reference already,
finalis redundant here - out: same as ref
- delegate: protects the function pointer and context pointer
out: same as ref
I'm amending that to 'final' being applied to an out parameter should be an error.
The behavior of all these cases is based on the idea that a final object should not be subject to modification after initialization.
ref: protects the reference already, final is redundant here
When I tried this a few days ago, the final actually applied to the pointed-to data, and I think that is more useful. See https://forum.dlang.org/post/[email protected].
@ntrel thanks I will look into that.
As explained in the ng, I've put this on hold for the time being.