Access protection is defined to happen after lookup and overload resolution.

Defined where in the spec?

So the correct behavior seems to match foo(int) first, then look for its access
attribute. Though I don't understand this scheme too.

Basically, all overloads of a function name are looked at, regardless of their
protection attributes, in order to pick an overload. Then the call is
validated on the protection attribute of the one that's been picked.
My guess is that the point is to protect against accidental behaviour changes
if some code is moved between modules. But maybe it's better to avoid having a
private function and a public function with the same name in the same scope.
But the current behaviour does seem to be overdoing it. If a module imports
two modules each of which defines a symbol, but in one of them it's private, an
import conflict is reported. It's been my view for a while that private
symbols should not be imported at all. Maybe the best policy is to see whether
_all_ overloads are private and, if so, the module will keep the symbol to
itself; otherwise, invoke the the current behaviour.
--
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------

My guess is that the point is to protect against accidental behaviour changes
if some code is moved between modules.

change still can happen in the module the code moved to. If there was public
foo(int), the module used to call it, then private foo(float) appears and the
module silently starts to call it.
--
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------

Access protection is defined to happen after lookup and
overload resolution.

That was Walter's comment. This exact comment made me experiment with
module-level protection attributes and led to this bug report.
Well, I think the "overload before protection" rule has its merit for classes.
Class methods *hide* methods of the same name in base classes to protect from
overload set hijacking. It probably would be confusing if hiding rules worked
differently depending on whether your function is in the same module with the
class or not.
But module members cannot hide anything. Any name collision is an error, and
any conflict resolution is explicit. Therefore I think overload resolution
should be changed for modules, too. Consider:
module a;
class A {}
void foo(A a) {}
module b;
class B {}
void foo(B b) {}
module c;
import a, b;
private alias a.foo foo;
private alias b.foo foo;
void bar() {
foo(new A);
foo(new B);
}
So far so good. But now:
module d;
import a, c;
void baz() {
foo(new A); // error ?!!
}
a.foo conflicts with c.foo ? But I don't know about c.foo. There is no
documentation for c.foo. There is no c.foo. Still, this phantom messes up
overloading.
--
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------