Repository: python/mypy

Issue:
ctypes: crash due to bad TypeInfo
* Are you reporting a bug, or opening a feature request?
```
bug - mypy INTERNAL ERROR
```
* Please insert below the code you are checking with mypy,
  or a mock-up repro if the source is private. We would appreciate
  if you try to simplify your case to a minimal repro.
```
import ctypes
buf = ctypes.create_string_buffer ( 64 )
s = buf.value.decode ( 'ascii', 'replace' )
```
* What is the actual behavior/output?
```
mypy_internal_error.py:3: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.650+dev.3ad628d797defcbd892dede48151c8e390f45258
```
* What are the versions of mypy and Python you are using?
  Do you see the same issue after installing mypy from Git master?
```
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32
mypy 0.650+dev.3ad628d797defcbd892dede48151c8e390f45258
```
* What are the mypy flags you are using? (For example --strict-optional)
```
-2 --strict --ignore-missing-imports --no-site-packages
```
* If mypy crashed with a traceback, please paste
  the full traceback below.
```
Traceback (most recent call last):
  File "C:\Python36\Scripts\mypy-script.py", line 11, in <module>
    load_entry_point('mypy==0.650+dev.3ad628d797defcbd892dede48151c8e390f45258', 'console_scripts', 'mypy')()
  File "c:\python36\lib\site-packages\mypy\__main__.py", line 7, in console_entry
    main(None)
  File "c:\python36\lib\site-packages\mypy\main.py", line 92, in main
    res = build.build(sources, options, None, flush_errors, fscache)
  File "c:\python36\lib\site-packages\mypy\build.py", line 156, in build
    result = _build(sources, options, alt_lib_path, flush_errors, fscache)
  File "c:\python36\lib\site-packages\mypy\build.py", line 206, in _build
    graph = dispatch(sources, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2230, in dispatch
    process_graph(graph, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2530, in process_graph
    process_stale_scc(graph, scc, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2653, in process_stale_scc
    graph[id].type_check_first_pass()
  File "c:\python36\lib\site-packages\mypy\build.py", line 1788, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "c:\python36\lib\site-packages\mypy\checker.py", line 282, in check_first_pass
    self.accept(d)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 848, in accept
    return visitor.visit_class_def(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1536, in visit_class_def
    self.accept(defn.defs)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 913, in accept
    return visitor.visit_block(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1688, in visit_block
    self.accept(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 611, in accept
    return visitor.visit_func_def(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 704, in visit_func_def
    self._visit_func_def(defn)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 708, in _visit_func_def
    self.check_func_item(defn, name=defn.name())
  File "c:\python36\lib\site-packages\mypy\checker.py", line 770, in check_func_item
    self.check_func_def(defn, typ, name)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 934, in check_func_def
    self.accept(item.body)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 913, in accept
    return visitor.visit_block(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1688, in visit_block
    self.accept(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1046, in accept
    return visitor.visit_return_stmt(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 2627, in visit_return_stmt
    self.check_return_stmt(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 2660, in check_return_stmt
    allow_none_return=allow_none_func_call)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1754, in accept
    return visitor.visit_tuple_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 2619, in visit_tuple_expr
    tt = self.accept(item, type_context_items[j])
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1421, in accept
    return visitor.visit_call_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 229, in visit_call_expr
    return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 271, in visit_call_expr_inner
    callee_type = self.accept(e.callee, type_context, always_allow_any=True)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1373, in accept
    return visitor.visit_member_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1687, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1698, in analyze_ordinary_member_access
    original_type = self.accept(e.expr)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1373, in accept
    return visitor.visit_member_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1687, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1702, in analyze_ordinary_member_access
    original_type=original_type, chk=self.chk)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 105, in analyze_member_access
    original_type=original_type, chk=chk)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 282, in analyze_member_var_access
    chk=chk, implicit=implicit)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 474, in analyze_var
    result = hook(AttributeContext(original_type, result, node, chk))
  File "c:\python36\lib\site-packages\mypy\plugins\ctypes.py", line 173, in array_value_callback
    types.append(ctx.api.named_generic_type('builtins.bytes', []))
  File "c:\python36\lib\site-packages\mypy\checker.py", line 3501, in named_generic_type
    info = self.lookup_typeinfo(name)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 3509, in lookup_typeinfo
    assert isinstance(node, TypeInfo)
AssertionError:
```

ctypes: crash due to bad TypeInfo
* Are you reporting a bug, or opening a feature request?
```
bug - mypy INTERNAL ERROR
```
* Please insert below the code you are checking with mypy,
  or a mock-up repro if the source is private. We would appreciate
  if you try to simplify your case to a minimal repro.
```
import ctypes
buf = ctypes.create_string_buffer ( 64 )
s = buf.value.decode ( 'ascii', 'replace' )
```
* What is the actual behavior/output?
```
mypy_internal_error.py:3: error: INTERNAL ERROR -- please report a bug at https://github.com/python/mypy/issues version: 0.650+dev.3ad628d797defcbd892dede48151c8e390f45258
```
* What are the versions of mypy and Python you are using?
  Do you see the same issue after installing mypy from Git master?
```
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Intel)] on win32
mypy 0.650+dev.3ad628d797defcbd892dede48151c8e390f45258
```
* What are the mypy flags you are using? (For example --strict-optional)
```
-2 --strict --ignore-missing-imports --no-site-packages
```
* If mypy crashed with a traceback, please paste
  the full traceback below.
```
Traceback (most recent call last):
  File "C:\Python36\Scripts\mypy-script.py", line 11, in <module>
    load_entry_point('mypy==0.650+dev.3ad628d797defcbd892dede48151c8e390f45258', 'console_scripts', 'mypy')()
  File "c:\python36\lib\site-packages\mypy\__main__.py", line 7, in console_entry
    main(None)
  File "c:\python36\lib\site-packages\mypy\main.py", line 92, in main
    res = build.build(sources, options, None, flush_errors, fscache)
  File "c:\python36\lib\site-packages\mypy\build.py", line 156, in build
    result = _build(sources, options, alt_lib_path, flush_errors, fscache)
  File "c:\python36\lib\site-packages\mypy\build.py", line 206, in _build
    graph = dispatch(sources, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2230, in dispatch
    process_graph(graph, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2530, in process_graph
    process_stale_scc(graph, scc, manager)
  File "c:\python36\lib\site-packages\mypy\build.py", line 2653, in process_stale_scc
    graph[id].type_check_first_pass()
  File "c:\python36\lib\site-packages\mypy\build.py", line 1788, in type_check_first_pass
    self.type_checker().check_first_pass()
  File "c:\python36\lib\site-packages\mypy\checker.py", line 282, in check_first_pass
    self.accept(d)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 848, in accept
    return visitor.visit_class_def(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1536, in visit_class_def
    self.accept(defn.defs)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 913, in accept
    return visitor.visit_block(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1688, in visit_block
    self.accept(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 611, in accept
    return visitor.visit_func_def(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 704, in visit_func_def
    self._visit_func_def(defn)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 708, in _visit_func_def
    self.check_func_item(defn, name=defn.name())
  File "c:\python36\lib\site-packages\mypy\checker.py", line 770, in check_func_item
    self.check_func_def(defn, typ, name)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 934, in check_func_def
    self.accept(item.body)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 913, in accept
    return visitor.visit_block(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 1688, in visit_block
    self.accept(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 393, in accept
    stmt.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1046, in accept
    return visitor.visit_return_stmt(self)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 2627, in visit_return_stmt
    self.check_return_stmt(s)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 2660, in check_return_stmt
    allow_none_return=allow_none_func_call)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1754, in accept
    return visitor.visit_tuple_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 2619, in visit_tuple_expr
    tt = self.accept(item, type_context_items[j])
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1421, in accept
    return visitor.visit_call_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 229, in visit_call_expr
    return self.visit_call_expr_inner(e, allow_none_return=allow_none_return)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 271, in visit_call_expr_inner
    callee_type = self.accept(e.callee, type_context, always_allow_any=True)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1373, in accept
    return visitor.visit_member_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1687, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1698, in analyze_ordinary_member_access
    original_type = self.accept(e.expr)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 3060, in accept
    typ = node.accept(self)
  File "c:\python36\lib\site-packages\mypy\nodes.py", line 1373, in accept
    return visitor.visit_member_expr(self)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1687, in visit_member_expr
    result = self.analyze_ordinary_member_access(e, is_lvalue)
  File "c:\python36\lib\site-packages\mypy\checkexpr.py", line 1702, in analyze_ordinary_member_access
    original_type=original_type, chk=self.chk)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 105, in analyze_member_access
    original_type=original_type, chk=chk)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 282, in analyze_member_var_access
    chk=chk, implicit=implicit)
  File "c:\python36\lib\site-packages\mypy\checkmember.py", line 474, in analyze_var
    result = hook(AttributeContext(original_type, result, node, chk))
  File "c:\python36\lib\site-packages\mypy\plugins\ctypes.py", line 173, in array_value_callback
    types.append(ctx.api.named_generic_type('builtins.bytes', []))
  File "c:\python36\lib\site-packages\mypy\checker.py", line 3501, in named_generic_type
    info = self.lookup_typeinfo(name)
  File "c:\python36\lib\site-packages\mypy\checker.py", line 3509, in lookup_typeinfo
    assert isinstance(node, TypeInfo)
AssertionError:
```



Discussion:
Presumably the bug is in the ctypes plugin, not in mypy.
cc @dgelessus who contributed the ctypes plugin.
Oh, Python 2, @dgelessus you should use `builtins.str` if it is Python 2 (`bytes` is an _alias_ to `str`, so it can't be used in `named_generic_type()`)
Presumably the bug is in the ctypes plugin, not in mypy.
cc @dgelessus who contributed the ctypes plugin.
Oh, Python 2, @dgelessus you should use `builtins.str` if it is Python 2 (`bytes` is an _alias_ to `str`, so it can't be used in `named_generic_type()`)

Resolving patch:
diff --git a/mypy/plugins/ctypes.py b/mypy/plugins/ctypes.py
--- a/mypy/plugins/ctypes.py
+++ b/mypy/plugins/ctypes.py
@@ -9,6 +9,24 @@
 from mypy.types import AnyType, CallableType, Instance, Type, TypeOfAny, UnionType, union_items
 
 
+def _get_bytes_type(api: 'mypy.plugin.CheckerPluginInterface') -> Instance:
+    """Return the type corresponding to bytes on the current Python version.
+
+    This is bytes in Python 3, and str in Python 2.
+    """
+    return api.named_generic_type(
+        'builtins.bytes' if api.options.python_version >= (3,) else 'builtins.str', [])
+
+
+def _get_text_type(api: 'mypy.plugin.CheckerPluginInterface') -> Instance:
+    """Return the type corresponding to Text on the current Python version.
+
+    This is str in Python 3, and unicode in Python 2.
+    """
+    return api.named_generic_type(
+        'builtins.str' if api.options.python_version >= (3,) else 'builtins.unicode', [])
+
+
 def _find_simplecdata_base_arg(tp: Instance, api: 'mypy.plugin.CheckerPluginInterface'
                                ) -> Optional[Type]:
     """Try to find a parametrized _SimpleCData in tp's bases and return its single type argument.
@@ -170,13 +188,9 @@ def array_value_callback(ctx: 'mypy.plugin.AttributeContext') -> Type:
             if isinstance(tp, AnyType):
                 types.append(AnyType(TypeOfAny.from_another_any, source_any=tp))
             elif isinstance(tp, Instance) and tp.type.fullname() == 'ctypes.c_char':
-                types.append(ctx.api.named_generic_type('builtins.bytes', []))
+                types.append(_get_bytes_type(ctx.api))
             elif isinstance(tp, Instance) and tp.type.fullname() == 'ctypes.c_wchar':
-                types.append(ctx.api.named_generic_type(
-                    'builtins.str'
-                    if ctx.api.options.python_version >= (3,)
-                    else 'builtins.unicode',
-                    []))
+                types.append(_get_text_type(ctx.api))
             else:
                 ctx.api.msg.fail(
                     'ctypes.Array attribute "value" is only available'
@@ -195,7 +209,7 @@ def array_raw_callback(ctx: 'mypy.plugin.AttributeContext') -> Type:
         for tp in union_items(et):
             if (isinstance(tp, AnyType)
                     or isinstance(tp, Instance) and tp.type.fullname() == 'ctypes.c_char'):
-                types.append(ctx.api.named_generic_type('builtins.bytes', []))
+                types.append(_get_bytes_type(ctx.api))
             else:
                 ctx.api.msg.fail(
                     'ctypes.Array attribute "raw" is only available'


Test patch:
diff --git a/test-data/unit/check-ctypes.test b/test-data/unit/check-ctypes.test
--- a/test-data/unit/check-ctypes.test
+++ b/test-data/unit/check-ctypes.test
@@ -80,6 +80,15 @@ reveal_type(ca.value)  # E: Revealed type is 'builtins.bytes'
 reveal_type(ca.raw)  # E: Revealed type is 'builtins.bytes'
 [builtins fixtures/floatdict.pyi]
 
+[case testCtypesCharArrayAttrsPy2]
+# flags: --py2
+import ctypes
+
+ca = (ctypes.c_char * 4)('a', 'b', 'c', '\x00')
+reveal_type(ca.value)  # E: Revealed type is 'builtins.str'
+reveal_type(ca.raw)  # E: Revealed type is 'builtins.str'
+[builtins_py2 fixtures/floatdict_python2.pyi]
+
 [case testCtypesWcharArrayAttrs]
 import ctypes
 
@@ -95,7 +104,7 @@ import ctypes
 wca = (ctypes.c_wchar * 4)(u'a', u'b', u'c', u'\x00')
 reveal_type(wca.value)  # E: Revealed type is 'builtins.unicode'
 wca.raw  # E: ctypes.Array attribute "raw" is only available with element type c_char, not "ctypes.c_wchar"
-[builtins_py2 fixtures/floatdict.pyi]
+[builtins_py2 fixtures/floatdict_python2.pyi]
 
 [case testCtypesCharUnionArrayAttrs]
 import ctypes