Repository: python/mypy

Issue:
"Source file found twice under different module names" doesn't work in some cases
I found that "Source file found twice under different module names" error doesn't happen in some cases.

## Case1: A Path in the graph is a relative path
### Files
Same as `case testDuplicateModules` in `test-data/unit/cmdline.test` ([source](https://github.com/python/mypy/blob/8219564d365ba29dda8c4383594d9db91f26feec/test-data/unit/cmdline.test#L1071-L1084)).
```
.
├── mypy.ini
└── src
    ├── a.py
    ├── foo
    │   ├── bar.py
    │   └── __init__.py
    └── __init__.py
```

### Actual behavior
```sh
$ mypy src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)

$ mypy `pwd`/src
src/foo/bar.py:1: error: Unsupported operand types for + ("int" and "str")
src/foo/bar.py:1: error: Unsupported operand types for + ("int" and "str")
Found 2 errors in 1 file (checked 4 source files)
```

### Expected behavior

```sh
$ mypy src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)

$ mypy `pwd`/src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)
```

## Case2: A Path in the graph is an absolute path
### Files
Same as `case testDuplicateModules` in `test-data/unit/cmdline.test` except `mypy.ini`.

```
.
├── mypy.ini
└── src
    ├── a.py
    ├── foo
    │   ├── bar.py
    │   └── __init__.py
    └── __init__.py
```

- mypy.ini
```
[mypy]
mypy_path = /absolute/path/to/src
```

### Actual behavior
```sh
$ mypy src
src/foo/bar.py:1: error: Unsupported operand types for + ("int" and "str")
src/foo/bar.py:1: error: Unsupported operand types for + ("int" and "str")
Found 2 errors in 1 file (checked 4 source files)

$ mypy `pwd`/src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)
```

### Expected behavior

```sh
$ mypy src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)

$ mypy `pwd`/src
src/foo/bar.py: error: Source file found twice under different module names: 'src.foo.bar' and 'foo.bar'
Found 1 error in 1 file (checked 4 source files)
```

## Versions
```sh
$ mypy --version
mypy 0.790+dev.8219564d365ba29dda8c4383594d9db91f26feec
$ python --version
Python 3.6.10
```


Discussion:

Resolving patch:
diff --git a/mypy/build.py b/mypy/build.py
--- a/mypy/build.py
+++ b/mypy/build.py
@@ -1699,6 +1699,7 @@ class State:
     order = None  # type: int  # Order in which modules were encountered
     id = None  # type: str  # Fully qualified module name
     path = None  # type: Optional[str]  # Path to module source
+    abspath = None  # type: Optional[str]  # Absolute path to module source
     xpath = None  # type: str  # Path or '<string>'
     source = None  # type: Optional[str]  # Module source code
     source_hash = None  # type: Optional[str]  # Hash calculated based on the source code
@@ -1800,6 +1801,8 @@ def __init__(self,
             if follow_imports == 'silent':
                 self.ignore_all = True
         self.path = path
+        if path:
+            self.abspath = os.path.abspath(path)
         self.xpath = path or '<string>'
         if path and source is None and self.manager.fscache.isdir(path):
             source = ''
@@ -2758,7 +2761,7 @@ def load_graph(sources: List[BuildSource], manager: BuildManager,
 
     # Note: Running this each time could be slow in the daemon. If it's a problem, we
     # can do more work to maintain this incrementally.
-    seen_files = {st.path: st for st in graph.values() if st.path}
+    seen_files = {st.abspath: st for st in graph.values() if st.path}
 
     # Collect dependencies.  We go breadth-first.
     # More nodes might get added to new as we go, but that's fine.
@@ -2805,16 +2808,18 @@ def load_graph(sources: List[BuildSource], manager: BuildManager,
                     if dep in st.dependencies_set:
                         st.suppress_dependency(dep)
                 else:
-                    if newst.path in seen_files:
-                        manager.errors.report(
-                            -1, 0,
-                            "Source file found twice under different module names: '{}' and '{}'".
-                            format(seen_files[newst.path].id, newst.id),
-                            blocker=True)
-                        manager.errors.raise_error()
-
                     if newst.path:
-                        seen_files[newst.path] = newst
+                        newst_path = os.path.abspath(newst.path)
+
+                        if newst_path in seen_files:
+                            manager.errors.report(
+                                -1, 0,
+                                "Source file found twice under different module names: "
+                                "'{}' and '{}'".format(seen_files[newst_path].id, newst.id),
+                                blocker=True)
+                            manager.errors.raise_error()
+
+                        seen_files[newst_path] = newst
 
                     assert newst.id not in graph, newst.id
                     graph[newst.id] = newst


Test patch: