Skip to content

Generate an error if subclass has a different type for an attribute #970

@JukkaL

Description

@JukkaL

This code generates C compile errors:

class C:
    x: float

class D(C):
    x: int

We should reject this in mypyc, even though mypy allows this. All attribute definitions must have the same type in a class hierarchy. I think we could also reject multiple declarations of the same attribute in non-trait classes. Having a declaration both in a trait and a regular class is fine.

Here's the compiler output to make this issue more discoverable:

running build_ext
building 't' extension
gcc -pthread -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/jukka/src/mypy/mypyc/lib-rt -I/home/jukka/venv/mypy/include -I/usr/local/include/python3.11 -c build/__native.c -o build/temp.linux-x86_64-cpython-311/build/__native.o -O3 -g1 -Werror -Wno-unused-function -Wno-unused-label -Wno-unreachable-code -Wno-unused-variable -Wno-unused-command-line-argument -Wno-unknown-warning-option -Wno-unused-but-set-variable -Wno-ignored-optimization-argument -Wno-cpp
gcc -pthread -shared build/temp.linux-x86_64-cpython-311/build/__native.o -o build/lib.linux-x86_64-cpython-311/t.cpython-311-x86_64-linux-gnu.so
copying build/lib.linux-x86_64-cpython-311/t.cpython-311-x86_64-linux-gnu.so -> 
(mypy) jukka mypy $ mypyc t/t.py
running build_ext
building 't' extension
gcc -pthread -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/jukka/src/mypy/mypyc/lib-rt -I/home/jukka/venv/mypy/include -I/usr/local/include/python3.11 -c build/__native.c -o build/temp.linux-x86_64-cpython-311/build/__native.o -O3 -g1 -Werror -Wno-unused-function -Wno-unused-label -Wno-unreachable-code -Wno-unused-variable -Wno-unused-command-line-argument -Wno-unknown-warning-option -Wno-unused-but-set-variable -Wno-ignored-optimization-argument -Wno-cpp
In file included from build/__native.c:14:
build/__native.h:15:15: error: duplicate member ‘_x’
   15 |     CPyTagged _x;
      |               ^~
build/__native.c: In function ‘D_traverse’:
build/__native.c:172:33: error: passing argument 1 of ‘CPyTagged_CheckLong’ makes integer from pointer without a cast [-Werror=int-conversion]
  172 |     if (CPyTagged_CheckLong(self->_x)) {
      |                             ~~~~^~~~
      |                                 |
      |                                 PyObject * {aka struct _object *}
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:162:49: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  162 | static inline int CPyTagged_CheckLong(CPyTagged x) {
      |                                       ~~~~~~~~~~^
In file included from /usr/local/include/python3.11/Python.h:45,
                 from /home/jukka/src/mypy/mypyc/lib-rt/init.c:1,
                 from build/__native.c:1:
build/__native.c:173:45: error: passing argument 1 of ‘CPyTagged_LongAsObject’ makes integer from pointer without a cast [-Werror=int-conversion]
  173 |         Py_VISIT(CPyTagged_LongAsObject(self->_x));
      |                                         ~~~~^~~~
      |                                             |
      |                                             PyObject * {aka struct _object *}
/usr/local/include/python3.11/objimpl.h:199:13: note: in definition of macro ‘Py_VISIT’
  199 |         if (op) {                                                       \
      |             ^~
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:193:58: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  193 | static inline PyObject *CPyTagged_LongAsObject(CPyTagged x) {
      |                                                ~~~~~~~~~~^
In file included from /usr/local/include/python3.11/Python.h:38,
                 from /home/jukka/src/mypy/mypyc/lib-rt/init.c:1,
                 from build/__native.c:1:
build/__native.c:173:45: error: passing argument 1 of ‘CPyTagged_LongAsObject’ makes integer from pointer without a cast [-Werror=int-conversion]
  173 |         Py_VISIT(CPyTagged_LongAsObject(self->_x));
      |                                         ~~~~^~~~
      |                                             |
      |                                             PyObject * {aka struct _object *}
/usr/local/include/python3.11/pyport.h:24:38: note: in definition of macro ‘_Py_CAST’
   24 | #define _Py_CAST(type, expr) ((type)(expr))
      |                                      ^~~~
/usr/local/include/python3.11/objimpl.h:200:30: note: in expansion of macro ‘_PyObject_CAST’
  200 |             int vret = visit(_PyObject_CAST(op), arg);                  \
      |                              ^~~~~~~~~~~~~~
build/__native.c:173:9: note: in expansion of macro ‘Py_VISIT’
  173 |         Py_VISIT(CPyTagged_LongAsObject(self->_x));
      |         ^~~~~~~~
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:193:58: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  193 | static inline PyObject *CPyTagged_LongAsObject(CPyTagged x) {
      |                                                ~~~~~~~~~~^
build/__native.c: In function ‘D_clear’:
build/__native.c:182:33: error: passing argument 1 of ‘CPyTagged_CheckLong’ makes integer from pointer without a cast [-Werror=int-conversion]
  182 |     if (CPyTagged_CheckLong(self->_x)) {
      |                             ~~~~^~~~
      |                                 |
      |                                 PyObject * {aka struct _object *}
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:162:49: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  162 | static inline int CPyTagged_CheckLong(CPyTagged x) {
      |                                       ~~~~~~~~~~^
build/__native.c:183:27: error: initialization of ‘CPyTagged’ {aka ‘long unsigned int’} from ‘PyObject *’ {aka ‘struct _object *’} makes integer from pointer without a cast [-Werror=int-conversion]
  183 |         CPyTagged __tmp = self->_x;
      |                           ^~~~
build/__native.c:184:18: error: assignment to ‘PyObject *’ {aka ‘struct _object *’} from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion]
  184 |         self->_x = CPY_INT_TAG;
      |                  ^
build/__native.c: In function ‘D_setup’:
build/__native.c:252:14: error: assignment to ‘PyObject *’ {aka ‘struct _object *’} from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion]
  252 |     self->_x = CPY_INT_TAG;
      |              ^
In file included from /home/jukka/src/mypy/mypyc/lib-rt/pythonsupport.h:14,
                 from /home/jukka/src/mypy/mypyc/lib-rt/CPy.h:12,
                 from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
build/__native.c: In function ‘D_get_x’:
build/__native.c:267:27: error: comparison between pointer and integer [-Werror]
  267 |     if (unlikely(self->_x == CPY_INT_TAG)) {
      |                           ^~
/home/jukka/src/mypy/mypyc/lib-rt/mypyc_util.h:10:43: note: in definition of macro ‘unlikely’
   10 | #define unlikely(x)     __builtin_expect((x),0)
      |                                           ^
build/__native.c:272:26: error: passing argument 1 of ‘CPyTagged_INCREF’ makes integer from pointer without a cast [-Werror=int-conversion]
  272 |     CPyTagged_INCREF(self->_x);
      |                      ~~~~^~~~
      |                          |
      |                          PyObject * {aka struct _object *}
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:170:47: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  170 | static inline void CPyTagged_INCREF(CPyTagged x) {
      |                                     ~~~~~~~~~~^
build/__native.c:273:52: error: passing argument 1 of ‘CPyTagged_StealAsObject’ makes integer from pointer without a cast [-Werror=int-conversion]
  273 |     PyObject *retval = CPyTagged_StealAsObject(self->_x);
      |                                                ~~~~^~~~
      |                                                    |
      |                                                    PyObject * {aka struct _object *}
In file included from build/__native.c:4:
/home/jukka/src/mypy/mypyc/lib-rt/int_ops.c:96:45: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
   96 | PyObject *CPyTagged_StealAsObject(CPyTagged x) {
      |                                   ~~~~~~~~~~^
build/__native.c: In function ‘D_set_x’:
build/__native.c:285:18: error: comparison between pointer and integer [-Werror]
  285 |     if (self->_x != CPY_INT_TAG) {
      |                  ^~
build/__native.c:286:30: error: passing argument 1 of ‘CPyTagged_DECREF’ makes integer from pointer without a cast [-Werror=int-conversion]
  286 |         CPyTagged_DECREF(self->_x);
      |                          ~~~~^~~~
      |                              |
      |                              PyObject * {aka struct _object *}
In file included from /home/jukka/src/mypy/mypyc/lib-rt/init.c:2,
                 from build/__native.c:1:
/home/jukka/src/mypy/mypyc/lib-rt/CPy.h:176:47: note: expected ‘CPyTagged’ {aka ‘long unsigned int’} but argument is of type ‘PyObject *’ {aka ‘struct _object *’}
  176 | static inline void CPyTagged_DECREF(CPyTagged x) {
      |                                     ~~~~~~~~~~^
build/__native.c:295:14: error: assignment to ‘PyObject *’ {aka ‘struct _object *’} from ‘CPyTagged’ {aka ‘long unsigned int’} makes pointer from integer without a cast [-Werror=int-conversion]
  295 |     self->_x = tmp;
      |              ^
build/__native.c: At top level:
cc1: error: unrecognized command line option ‘-Wno-ignored-optimization-argument’ [-Werror]
cc1: error: unrecognized command line option ‘-Wno-unknown-warning-option’ [-Werror]
cc1: error: unrecognized command line option ‘-Wno-unused-command-line-argument’ [-Werror]
cc1: all warnings being treated as errors
error: command '/usr/bin/gcc' failed with exit code 1

Metadata

Metadata

Assignees

Labels

bugusabilityWarning/error reporting, build integration, CLI, etc.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions