Brush Up Language Features

From D Wiki
Revision as of 15:26, 14 March 2014 by 9rnsr (talk | contribs)
Jump to: navigation, search

Mangling Scheme

Consistently stop encoding return type of parent functions

Implemented: Issue 12352 - Consistently stop encoding return type of parent functions (commit)

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:

http://dlang.org/abi

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
}

IFTI

Consider narrowing conversions for literal expressions

Implemented: Issue 12290 - IFTI should consider implicit conversions of the literal arguments (commit)

void foo(E)(E[], E) {}

void main()
{
    short[] arr;
    foo(arr, 1);
    // Current:  E = common-type-of(short, int)       => no match
    // Possible: E = common-type-of(short, typeof(1)) => E = short
}

Related issue: improve common type calculation

auto a1 = true ? [1L,2] : [3,4];  // should work
auto a2 = true ? [3,4] : [1L,2];  // should work