February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #11 from Andrei Alexandrescu <andrei@erdani.com> ---
(In reply to Jonathan Marler from comment #10)
> > I think at the least we can do a vastly better job at issuing error messages.
> 
> I'm limiting focus to this issue alone. Do you have an idea on a way to improve the error message for this case?
> 
> CURRENT BEHAVIOR
> ----------------------------
> dmd -c foo.d bar.d
> Error: module baz from file bar.d must be imported with 'import baz;'
> 
> PROPOSED BEHAVIOR
> ----------------------------
> dmd -c foo.d bar.d
> Error: module baz from file bar.d must be imported with 'import baz;' or
> must be compiled separately

To make clear what the use case is, I'll paste the files again:

foo.d:
----
import bar;
----

bar.d:
----
module baz; /* not bar */
----

In this case, attempting to compile them together would be mistaken. I suggest:

Error: file bar.d masquerades as module `baz`, so it must be compiled separately or imported with `import baz;`

This way we clarify where the discrepancy is and even mildly disapprove of it. It's also clear that if no mismatch, this problem would disappear.

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #12 from Andrei Alexandrescu <andrei@erdani.com> ---
Also enclosing the file name in double quotes might be nice.

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #13 from Timothee Cour <timothee.cour2@gmail.com> ---
I don't see what's controversial about the fact that this is broken and breaks the module system.

Hopefully this other example will convince you, where all I do is change the order of imports and goes from CT error to compiling.


./main.d
pragma(msg, __FILE__," ",__MODULE__);
import foo.bar;
import foo.bar2;

version(A){
import foo.bar4;
import foo.bar3;
}
else version(B){
import foo.bar3;
import foo.bar4;
}


void main(){}
./foo/bar2.d
module foo.bar2;
pragma(msg, __FILE__," ",__MODULE__);
./foo/bar4.d
module foo.bar4;
pragma(msg, __FILE__," ",__MODULE__);

import asdf.wrong;

./foo/bar.d
pragma(msg, __FILE__," ",__MODULE__);
./foo/bar3.d
module asdf.wrong;
pragma(msg, __FILE__," ",__MODULE__);

./asdf/wrong.d
pragma(msg, __FILE__," ",__MODULE__);

```
dmd -version=A -run main.d
main.d(7): Error: module `asdf.wrong` from file foo/bar3.d conflicts with
another module wrong from file asdf/wrong.d

dmd -version=B -run main.d
main.d main
foo/bar.d bar
foo/bar2.d foo.bar2
foo/bar3.d asdf.wrong
foo/bar4.d foo.bar4
```


This causes many other weirdnesses:
* seperate compilation vs all-at-once compilation is broken
* this makes `./foo/bar.d` and `foo/bar.d` appear as different paths:

```
dmd foo/bar.d -run main.d
main.d(2): Error: module `bar` from file foo/bar.d must be imported with
'import bar;'
dmd ./foo/bar.d -run main.d
main.d(2): Error: module `bar` from file foo/bar.d conflicts with another
module bar from file ./foo/bar.d
```

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

ag0aep6g@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|INVALID                     |---

--- Comment #14 from ag0aep6g@gmail.com ---
Reopening. INVALID is not an acceptable resolution for this.

Per the spec, a module must be imported by its module name [1]. And the module name is set by the module declaration, if there is one [2]. Importing a module by its file name is not in the spec. Of course, I may be missing how the spec allows DMD's current behavior. If so, someone please point it out.

If I'm not missing anything in the spec, this issue (like all compiler bugs) can be resolved by changing the compiler to match the spec, or by changing the spec to match the compiler. It could also be closed as WONTFIX, I guess. But that would be disappointing. DMD and the spec should agree on the rules.


[1] https://dlang.org/spec/module.html#import-declaration [2] https://dlang.org/spec/module.html#module_declaration

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #15 from Timothee Cour <timothee.cour2@gmail.com> ---
the example I just posted breaks this spec:

> The order in which ImportDeclarations occur has no significance.

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #16 from Andrei Alexandrescu <andrei@erdani.com> ---
The example in which the order of imports makes or breaks the build is compelling. Even better would be a bug whereby the project builds both ways but does different things. That would be the smoking gun.

OK to leave this open. At the minimum we must fix the order dependency and make the spec clearer. Thanks!

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #17 from Jonathan Marler <johnnymarler@gmail.com> ---
I was able to reproduce Timothee's example.  The error only occurs if the modules are specified in a particular order.

I also tested this using PR (https://github.com/dlang/dmd/pull/7878#issuecomment-365364824) and confirmed that it will assert an error in both cases regardless of the order the imports appear in.

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #18 from Timothee Cour <timothee.cour2@gmail.com> ---
> Even better would be a bug whereby the project builds both ways but does different things. That would be the smoking gun.

could shorten but this shows it:

./asdf/wrong.d
pragma(msg, __FILE__," ",__MODULE__);

extern(C) int baz(){
  return 42;
}
./main.d
static if(__traits(compiles, {import foo.bar6;})) {
  import foo.bar6;
}

extern(C) int baz();
void main(){
  import std.stdio;
  writeln("baz:", baz);
}
./foo/bar6.d
module foo.bar6;

version(A){
import foo.bar4;
import foo.bar3;
}
else version(B){
import foo.bar3;
import foo.bar4;
}
./foo/bar2.d
module foo.bar2;
pragma(msg, __FILE__," ",__MODULE__);
./foo/bar5.d
module foo.bar5;
pragma(msg, __FILE__," ",__MODULE__);
import asdf.wrong;
./foo/bar4.d
module foo.bar4;
pragma(msg, __FILE__," ",__MODULE__);
import asdf.wrong;
./foo/bar.d
pragma(msg, __FILE__," ",__MODULE__);
./foo/bar3.d
module asdf.wrong;
pragma(msg, __FILE__," ",__MODULE__);

extern(C) int baz(){
  return 41;
}



dmd -i -version=A -run main.d
foo/bar4.d foo.bar4
asdf/wrong.d wrong
baz:42
dmd -i -version=B -run main.d
foo/bar3.d asdf.wrong
foo/bar4.d foo.bar4
baz:41

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #19 from ag0aep6g@gmail.com ---
(In reply to Andrei Alexandrescu from comment #16)
> The example in which the order of imports makes or breaks the build is compelling. Even better would be a bug whereby the project builds both ways but does different things. That would be the smoking gun.

My take on it:

foo.d:
----
version (A)
{
    static import baz;
    static import bar;
}
version (B)
{
    static import bar;
    static import baz;
}
void main()
{
    import std.stdio;
    writeln(bar.thing);
    writeln(baz.thing);
}
----

bar.d:
----
module baz;
enum thing = "this is baz from bar.d";
----

baz.d:
----
module bar;
enum thing = "this is bar from baz.d";
----

`dmd foo.d -version=A && ./foo`:
----
this is bar from baz.d
this is bar from baz.d
----

`dmd foo.d -version=B && ./foo`:
----
this is baz from bar.d
this is baz from bar.d
----

--
February 13, 2018
https://issues.dlang.org/show_bug.cgi?id=15086

--- Comment #20 from Jonathan Marler <johnnymarler@gmail.com> ---
Confirmed ag0aep6g's example.  Also confirmed the proposed PR treats the example as an error.

version=A

foo.d(3): Deprecation: module `bar` from file baz.d must be imported with
'import bar;'

version=B

foo.d(8): Deprecation: module `baz` from file bar.d must be imported with
'import baz;'

--