March 26
https://issues.dlang.org/show_bug.cgi?id=24451

          Issue ID: 24451
           Summary: Private imports can create conflicts with public
                    imports when using selective imports
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: issues.dlang@jmdavisProg.com

Okay. This is a bit weird, but if we have

--- foo/bar.d ---
module foo.bar;

bool empty(T)(T[] arr)
{
    return arr.length == 0;
}
---

--- foo/package.d ---
module foo;

import baz;

public import foo.bar;
---

--- baz.d ---
module baz;

bool empty(T)(T[] arr)
{
    return arr.length == 0;
}
---

--- q.d ---
import foo : empty;

void main()
{
    int[] arr;
    auto result = arr.empty;
}
---

This results in
---
q.d(6): Error: `empty` matches conflicting symbols:
foo/bar.d(3):        function `foo.bar.empty!int.empty`
baz.d(3):        function `baz.empty!int.empty
---

If the import in q.d is changed to

import foo;

then the problem goes away. So, something about how the selective import works makes it so that the symbols from the private import are in the overload set.

I don't know how likely it is for this situation to come up in practice is, but the way that I ran into it was by trying to add the range API functions for arrays to object.d to see what would happen. Unsurprisingly, there were a bunch of symbol conflicts, but surprisingly, I couldn't fix the symbol conflicts with selective imports from std.range, e.g.

import std.range : empty;

didn't fix anything. On the other hand, selective imports from std.range.primitives _did_ resolve the conflicts, e.g.

import std.range.primitives : empty;

So, something about the public import was screwing up the selective import, and the test case here is what I came up with. With empty being in object.d, it's implicitly imported just like happens in the example here with baz being explicitly imported.

In any case, I don't know how likely it is that this problem would come up normally, but it _will_ affect any conflicts with symbols that we add to object.d in the future, and it affects any symbols that are in there now. It's just that it would only come up when public imports are involved, and they're less common, though it will definitely cause problems if we ever add the current range API functions to object.d.

--