Brush Up Language Features
Contents
Mangling Scheme
Consistently stop encoding return type of parent functions
Currently, for function local symbols, the return types of their parent functions are normally mangled into the name.
module test; int foo() { void bar() { struct S {} pragma(msg, S.mangleof); // S 4test 3fooFZi 3barMFZv 1S // | | // int of foo | // void of bar } return 0; }
But, for voldemort types, we already has an exception of the rule.
module test; auto foo() { auto bar() { struct S {} pragma(msg, S.mangleof); // S 4test 3fooFZ 3barMFZ 1S // | | // no return type for foo | // no return type for bar return S(); } return 0; }
The change was introduced to fix Issue 8847. https://d.puremagic.com/issues/show_bug.cgi?id=8847
In D, functions cannot be overloaded based on the return types.
void foo() {} int foo() {} // wrong overloading of foo
So the return type mangling is essentially redundant.
module test; void foo() { struct S {} pragma(msg, "1: ", S.mangleof); } void foo(int) { struct S {} pragma(msg, "2: ", S.mangleof); }
Current result;
1: S4test3fooFZv1S 2: S4test3fooFiZv1S
Modified result:
1: S4test3fooFZ1S 2: S4test3fooFiZ1S // --> The two local symbols S still have unique mangled names.
Do not mangle context-ness of parent lambdas
Lambdas are the only one element of D language which have context-inference.
void main() { int x; auto fp = (){ return 1; }; auto dg = (){ return x; }; static assert(!is(typeof(fp) == delegate)); static assert( is(typeof(dg) == delegate)); }
But the context-ness is normally mangled into the name:
MangledName: _D QualifiedName Type _D QualifiedName M Type
And has an undeterministic case for lambda local symbols:
module test; void main() { int x; auto y = (){ // __lambda1 struct S {} pragma(msg, S.mangleof); // S 4test 4mainFZv 9__lambda1MFZ 1S // or: S 4test 4mainFZv 9__lambda1FZ 1S ? // | // the context-ness of __lambda1 is not yet determined. version(A) return 1; else return x; }; }
To avoid the ambiguity, I think we should add a special mangling rule for lambdas:
module test; void main() { int x; auto y = (){ // __lambda1 struct S {} pragma(msg, S.mangleof); // S 4test 4mainFZv 9__lambda1 1S // | // stop mangling of the context, parameters, and return type version(A) return 1; else return x; }; }
Today, most of lambdas have unique names in the defined scope.
void main() { pragma(msg, __traits(identifier, {})); // __lambda1 pragma(msg, __traits(identifier, {})); // __lambda2 // in 'main' function, unique numbers are distributed. }
The proposed rule will work relying on the lambdas unique names.
Nested Symbols
Static alias parameter
void foo(alias sym)() { ... } void main() { static int x; int y; static class C { int z; } pragma(msg, typeof(&foo!x)); // the instantiated function will be global function pragma(msg, typeof(&foo!y)); // the instantiated function will be a local function of 'main' pragma(msg, typeof(&foo!(C.z))); // the instantiated function will be a member function of 'C' }
The behavior is necessary if foo will access to sym in runtime.
But, if sym is only needed for the compile-time calculation, foo!y
and foo!(C.z)
will cause need 'this' for ...
error in some cases.
Issue 11946 - "need 'this' to access member" when passing field to template parameter https://d.puremagic.com/issues/show_bug.cgi?id=11946
However, I think that inferring context-ness in general case is mostly impossible. A particular problem against the context inference is the deterministic mangling scheme for the local symbols of the inferred function. (Related: "Do not mangle context-ness of parent lambdas")
A small idea to avoid problems is:
void bar(static alias sym)() { ... } void main() { static int x; int y; static class C { int z; } pragma(msg, typeof(&bar!x)); // the instantiated function will be global function pragma(msg, typeof(&bar!y)); // the instantiated function will be global function pragma(msg, typeof(&bar!(C.z))); // the instantiated function will be global function // In all cases, bar will ignore the context of the symbol that passed to sym }