Skip to content

Crash in union with a forward reference to a bad type. #4543

Closed
@ilevkivskyi

Description

@ilevkivskyi

This code causes a crash:

Alias = Union[Bad, C, D]

Bad = object()

class C:
    pass
class D:
    pass

option: Alias
if isinstance(option, C):
    pass

Here is a traceback:

tmp.py:3: error: Invalid type "tmp.Bad"
tmp.py:13: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.570-dev-d2c04190b8d407476c535f30d07a9f6712e7b12a-dirty
Traceback (most recent call last):
  File "/Users/ilevkivskyi/mypy/bin/mypy", line 11, in <module>
    load_entry_point('mypy===0.570-dev-d2c04190b8d407476c535f30d07a9f6712e7b12a-dirty', 'console_scripts', 'mypy')()
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/__main__.py", line 7, in console_entry
    main(None)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/main.py", line 80, in main
    type_check_only(sources, bin_dir, options, flush_errors)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/main.py", line 129, in type_check_only
    flush_errors=flush_errors)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 172, in build
    result = _build(sources, options, alt_lib_path, bin_dir, saved_cache, flush_errors)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 258, in _build
    graph = dispatch(sources, manager)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 2048, in dispatch
    process_graph(graph, manager)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 2349, in process_graph
    process_stale_scc(graph, scc, manager)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 2525, in process_stale_scc
    graph[id].type_check_first_pass()
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/build.py", line 1923, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/checker.py", line 228, in check_first_pass
    self.accept(d)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/checker.py", line 323, in accept
    stmt.accept(self)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/nodes.py", line 928, in accept
    return visitor.visit_if_stmt(self)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/checker.py", line 2232, in visit_if_stmt
    if_map, else_map = self.find_isinstance_check(e)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/checker.py", line 2835, in find_isinstance_check
    return conditional_type_map(expr, vartype, type)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/checker.py", line 3191, in conditional_type_map
    remaining_type = restrict_subtype_away(current_type, proposed_precise_type)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/subtypes.py", line 817, in restrict_subtype_away
    new_items = [item for item in t.relevant_items()
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/subtypes.py", line 818, in <listcomp>
    if (not (is_proper_subtype(erase_type(item), erased_s) or
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/erasetype.py", line 25, in erase_type
    return typ.accept(EraseTypeVisitor())
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/types.py", line 194, in accept
    return visitor.visit_unbound_type(self)
  File "/Users/ilevkivskyi/mypy/lib/python3.6/site-packages/mypy/erasetype.py", line 31, in visit_unbound_type
    assert False, 'Not supported'
AssertionError: Not supported

It looks like the problem is that clearly erroneous types are not wrapped in ForwardRef and are not post-processed in third pass. There are two options that I see now for UnboundTypes (maybe there are other):

  • Expect them in type checker and amend the corresponding visitors
  • Replace them with Any after giving an Invalid type error (maybe with better error message, but we already have an issue for this.)

I would prefer the second option, since this seems simpler and would probably minimize the amount of not useful errors (because of the initially invalid type).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions