Repository: python/mypy

Issue:
super(self.__class__, self) causes INTERNAL ERROR (AssertionError: unreachable)
This is a bug.
<br>**Reproducer**
```python
import types
from typing import TypeVar

class Foo:
    def f(self):
        print('Foo')

class Bar(Foo):
    def f(self):
        print('Bar')

T = TypeVar('T')

def my_f(self: T) -> None:
    super(self.__class__, self).f()
    print('monkeypatch')

bar = Bar()
bar.f = types.MethodType(my_f, bar)
bar.f()
```
This code may not be perfect, but it is accepted by the python interpreter.
<br>**Actual Behavior**
```
repr.py:15: error: INTERNAL ERROR -- Please try using mypy master on Github:
https://mypy.rtfd.io/en/latest/common_issues.html#using-a-development-mypy-build
If this issue continues with mypy master, please report a bug at https://github.com/python/mypy/issues
version: 0.770+dev.150d4921e702512e8afa0fc9cc22e71e720c3069
repr.py:15: : note: please use --show-traceback to print a traceback when reporting a bug
```
<br>**Expected Behavior**
mypy does not crash.
<br>**Versions**
mypy: Reproducible on 0.761 release and git master (commit 150d492)
python: 3.8.1
<br>**Flags Used**
No flags are necessary.
<br>**Traceback**
```
Traceback (most recent call last):
  File "/usr/bin/mypy", line 11, in <module>
    load_entry_point('mypy==0.770+dev.150d4921e702512e8afa0fc9cc22e71e720c3069', 'console_scripts', 'mypy')()
  File "/usr/lib/python3.8/site-packages/mypy/__main__.py", line 8, in console_entry
    main(None, sys.stdout, sys.stderr)
  File "/usr/lib/python3.8/site-packages/mypy/main.py", line 89, in main
    res = build.build(sources, options, None, flush_errors, fscache, stdout, stderr)
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 165, in build
    result = _build(
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 234, in _build
    graph = dispatch(sources, manager, stdout)
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 2631, in dispatch
    process_graph(graph, manager)
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 2938, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 3037, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/usr/lib/python3.8/site-packages/mypy/build.py", line 2130, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 293, in check_first_pass
    self.accept(d)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 400, in accept
    stmt.accept(self)
  File "/usr/lib/python3.8/site-packages/mypy/nodes.py", line 676, in accept
    return visitor.visit_func_def(self)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 725, in visit_func_def
    self._visit_func_def(defn)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 729, in _visit_func_def
    self.check_func_item(defn, name=defn.name)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 791, in check_func_item
    self.check_func_def(defn, typ, name)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 974, in check_func_def
    self.accept(item.body)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 400, in accept
    stmt.accept(self)
  File "/usr/lib/python3.8/site-packages/mypy/nodes.py", line 1004, in accept
    return visitor.visit_block(self)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 1969, in visit_block
    self.accept(s)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 400, in accept
    stmt.accept(self)
  File "/usr/lib/python3.8/site-packages/mypy/nodes.py", line 1019, in accept
    return visitor.visit_expression_stmt(self)
  File "/usr/lib/python3.8/site-packages/mypy/checker.py", line 3089, in visit_expression_stmt
    self.expr_checker.accept(s.expr, allow_none_return=True, always_allow_any=True)
  File "/usr/lib/python3.8/site-packages/mypy/checkexpr.py", line 3745, in accept
    typ = self.visit_call_expr(node, allow_none_return=True)
  File "/usr/lib/python3.8/site-packages/mypy/checkexpr.py", line 263, in visit_call_expr
    return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
  File "/usr/lib/python3.8/site-packages/mypy/checkexpr.py", line 312, in visit_call_expr_inner
    callee_type = get_proper_type(self.accept(e.callee, type_context, always_allow_any=True))
  File "/usr/lib/python3.8/site-packages/mypy/checkexpr.py", line 3749, in accept
    typ = node.accept(self)
  File "/usr/lib/python3.8/site-packages/mypy/nodes.py", line 1834, in accept
    return visitor.visit_super_expr(self)
  File "/usr/lib/python3.8/site-packages/mypy/checkexpr.py", line 3474, in visit_super_expr
    assert False, 'unreachable'
AssertionError: unreachable
```


Discussion:
I was able to reproduce the crash. Fixing the crash shouldn't be hard. It would be okay to generate an error for `super()` outside a method, if supporting this idiom would be difficult -- it's better than crashing, and the error can be ignored.
> I was able to reproduce the crash. Fixing the crash shouldn't be hard. It would be okay to generate an error for `super()` outside a method, if supporting this idiom would be difficult -- it's better than crashing, and the error can be ignored.

I am unable to reproduce the crash. I am running the program on VS code, Python 3.8.

@Arshaan-256 what version of mypy are you using, and how are you running it? I can repro it here: https://mypy-play.net/?mypy=0.761&python=3.8&gist=967f4c6130eef4725d313bffeba50430
@JukkaL @ethanhs  I managed to reproduce the crash. I have been studying the visit_super_expr() function in checkexpr.py. Can you point me to some resource which could help me tackle the bug? I think the condition at line number 3456 at https://github.com/Arshaan-256/mypy/blob/master/mypy/checkexpr.py failed to evaluate to true, causing the return statement to be skipped and hence the error.
hi @JukkaL  can i work on it over

@mridullpandey Great! If you have questions, feel free to ask here.
@mridullpandey please report back, if you are out of time I can be of help as well.
Since there hasn't been any updates in a while, this issue is up for grabs.
Hi, @JukkaL Picking up the issue.
Hi @madhavkhosla! If this is open can I pick it up?
@owaiskazi19 Please go ahead, as there hasn't been an update for a while.
Thanks @JukkaL. I have reproduced the issue already. I just want to know how should I test a program with the updated mypy local code? 
You can use `pytest` for this. Here you find the testing documentation https://github.com/python/mypy/blob/master/test-data/unit/README.md
- Install with 'python3 -m pip install -U -r test-requirements.txt' as mentioned there
- Refer here if you have in-depth questions about the unit tests syntax, it's a bit funky
- Take other _.test_ files as examples if you need more info quickly.

You'll probably need to add a test to the file [check-expressions.test](https://github.com/python/mypy/blob/master/test-data/unit/check-expressions.test) if that is the file where your contributions fall into. This data-driven test is registered at [testcheck.py line 70](https://github.com/python/mypy/blob/7802f37b9c5aa7da9355095e9425a82c59a83825/mypy/test/testcheck.py#L70) and parsed in the class TypeCheckSuite when `run_case` is called. Now, when you call the pytest command it will discover this TypeCheckSuite automatically.

For any test you add to the data file like `check-expressions.test` (or whatever file is more applicable to your changes), use the following command locally to trigger pytest to scan for that test (so you dont have to run the whole bunch):
> python -m pytest -k testNoneAsRvalue ./mypy

- First flag `-k` is your filter, which I chose one of the testCases in the file `check-expressions.test` at random. Replace with your new test case's name.
- The second argument is the path, I run the test one folder above my mypy repo clone.

@owaiskazi19 good luck!
Thanks @davidzwa for the detailed explanation. I am looking into https://github.com/python/mypy/blob/master/mypy/checkexpr.py#L3422 . I am just trying to figure out what @JukkaL's comment says. The new check was added in https://github.com/python/mypy/pull/7232. It will be great if you can help me out on that.
Also, before running the test cases I just want to run the locally modified code of visit_super_expr() for the above mentioned Reproducer file. How should I proceed for that?
Because running `mypy PROGRAM.py` will run the installed module of `mypy` and not the development build of `mypy`.
#### Python Path
Ah, on the latter question, I (personally) have fixed a way to avoid running my installed mypy by adding a `.env` file:
> PYTHONPATH= ...absolute_path_here\mypy
#### VS Code
I use VS Code and it picks up this PYTHONPATH. As you see, you can trick python into looking into a different folder for finding a library/module. This is an environment variable you can also change before calling `import mypy`. It might be a bit tricky, so you'll have to try.

My advice to explore and learn is to set the right _debug break-points_. These are really nice to explore the internal modules of mypy.

#### Example
My project mate and me pushed to the following repository ([test - main.py module](https://github.com/akerami/my_py_test/blob/master/main.py)) for testing direct API calls (not tests, as they are directly callable with `pytest`). Maybe you can find something to help yourself there. VS Code `.vscode/launch.json` :

```
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Module",
            "type": "python",
            "request": "launch",
            "module": "main",
            "console": "internalConsole",
            "cwd": "${workspaceFolder}/"
        }
    ]
}
```

#### Your challenge
I'm not too involved in your issue's background, I thought I could help in setting up as it can be a waste of time to figure out. Now, others can help you further on the technical details of this issue! 

Resolving patch:
diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py
--- a/mypy/checkexpr.py
+++ b/mypy/checkexpr.py
@@ -3464,6 +3464,10 @@ def visit_super_expr(self, e: SuperExpr) -> Type:
             self.chk.fail(message_registry.SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1, e)
             return AnyType(TypeOfAny.from_error)
 
+        if len(mro) == index + 1:
+            self.chk.fail(message_registry.TARGET_CLASS_HAS_NO_BASE_CLASS, e)
+            return AnyType(TypeOfAny.from_error)
+
         for base in mro[index+1:]:
             if e.name in base.names or base == mro[-1]:
                 if e.info and e.info.fallback_to_any and base == mro[-1]:
diff --git a/mypy/message_registry.py b/mypy/message_registry.py
--- a/mypy/message_registry.py
+++ b/mypy/message_registry.py
@@ -109,6 +109,7 @@
 SUPER_POSITIONAL_ARGS_REQUIRED = '"super" only accepts positional arguments'  # type: Final
 SUPER_ARG_2_NOT_INSTANCE_OF_ARG_1 = \
     'Argument 2 for "super" not an instance of argument 1'  # type: Final
+TARGET_CLASS_HAS_NO_BASE_CLASS = 'Target class has no base class'  # type: Final
 SUPER_OUTSIDE_OF_METHOD_NOT_SUPPORTED = \
     'super() outside of a method is not supported'  # type: Final
 SUPER_ENCLOSING_POSITIONAL_ARGS_REQUIRED = \


Test patch:
diff --git a/test-data/unit/check-super.test b/test-data/unit/check-super.test
--- a/test-data/unit/check-super.test
+++ b/test-data/unit/check-super.test
@@ -280,6 +280,20 @@ class B(A):
 class C:
     a = super().whatever  # E: super() outside of a method is not supported
 
+[case testSuperWithObjectClassAsFirstArgument]
+class A:
+    def f(self) -> None:
+        super(object, self).f()  # E: Target class has no base class
+
+[case testSuperWithTypeVarAsFirstArgument]
+from typing import TypeVar
+
+T = TypeVar('T')
+
+def f(obj: T) -> None:
+    super(obj.__class__, obj).f()  # E: Target class has no base class
+[builtins fixtures/__new__.pyi]
+
 [case testSuperWithSingleArgument]
 class B:
     def f(self) -> None: pass