@@ -173,7 +173,7 @@ if hasattr(DoesNotExist, "__mro__"):
173173if not isinstance (DoesNotExist, type ):
174174 reveal_type(DoesNotExist) # revealed: Unknown & ~type
175175
176- class Foo (DoesNotExist ): ... # error: [invalid -base]
176+ class Foo (DoesNotExist ): ... # error: [unsupported -base]
177177 reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
178178```
179179
@@ -232,11 +232,15 @@ reveal_type(AA.__mro__) # revealed: tuple[<class 'AA'>, <class 'Z'>, Unknown, <
232232
233233## ` __bases__ ` includes a ` Union `
234234
235+ <!-- snapshot-diagnostics -->
236+
235237We don't support union types in a class's bases; a base must resolve to a single ` ClassType ` . If we
236238find a union type in a class's bases, we infer the class's ` __mro__ ` as being
237239` [<class>, Unknown, object] ` , the same as for MROs that cause errors at runtime.
238240
239241``` py
242+ from typing_extensions import reveal_type
243+
240244def returns_bool () -> bool :
241245 return True
242246
@@ -250,7 +254,7 @@ else:
250254
251255reveal_type(x) # revealed: <class 'A'> | <class 'B'>
252256
253- # error: 11 [invalid -base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
257+ # error: 11 [unsupported -base] "Unsupported class base with type `<class 'A'> | <class 'B'>`"
254258class Foo (x ): ...
255259
256260reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
@@ -259,8 +263,8 @@ reveal_type(Foo.__mro__) # revealed: tuple[<class 'Foo'>, Unknown, <class 'obje
259263## ` __bases__ ` is a union of a dynamic type and valid bases
260264
261265If a dynamic type such as ` Any ` or ` Unknown ` is one of the elements in the union, and all other
262- types * would be* valid class bases, we do not emit an ` invalid-base ` diagnostic and use the dynamic
263- type as a base to prevent further downstream errors.
266+ types * would be* valid class bases, we do not emit an ` invalid-base ` or ` unsupported-base `
267+ diagnostic, and we use the dynamic type as a base to prevent further downstream errors.
264268
265269``` py
266270from typing import Any
@@ -299,8 +303,8 @@ else:
299303reveal_type(x) # revealed: <class 'A'> | <class 'B'>
300304reveal_type(y) # revealed: <class 'C'> | <class 'D'>
301305
302- # error: 11 [invalid -base] "Invalid class base with type `<class 'A'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
303- # error: 14 [invalid -base] "Invalid class base with type `<class 'C'> | <class 'D'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
306+ # error: 11 [unsupported -base] "Unsupported class base with type `<class 'A'> | <class 'B'>`"
307+ # error: 14 [unsupported -base] "Unsupported class base with type `<class 'C'> | <class 'D'>`"
304308class Foo (x , y ): ...
305309
306310reveal_type(Foo.__mro__ ) # revealed: tuple[<class 'Foo'>, Unknown, <class 'object'>]
@@ -321,7 +325,7 @@ if returns_bool():
321325else :
322326 foo = object
323327
324- # error: 21 [invalid -base] "Invalid class base with type `<class 'Y'> | <class 'object'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
328+ # error: 21 [unsupported -base] "Unsupported class base with type `<class 'Y'> | <class 'object'>`"
325329class PossibleError (foo , X ): ...
326330
327331reveal_type(PossibleError.__mro__ ) # revealed: tuple[<class 'PossibleError'>, Unknown, <class 'object'>]
@@ -339,12 +343,47 @@ else:
339343# revealed: tuple[<class 'B'>, <class 'X'>, <class 'Y'>, <class 'O'>, <class 'object'>] | tuple[<class 'B'>, <class 'Y'>, <class 'X'>, <class 'O'>, <class 'object'>]
340344reveal_type(B.__mro__ )
341345
342- # error: 12 [invalid -base] "Invalid class base with type `<class 'B'> | <class 'B'>` (all bases must be a class, `Any`, `Unknown` or `Todo`) "
346+ # error: 12 [unsupported -base] "Unsupported class base with type `<class 'B'> | <class 'B'>`"
343347class Z (A , B ): ...
344348
345349reveal_type(Z.__mro__ ) # revealed: tuple[<class 'Z'>, Unknown, <class 'object'>]
346350```
347351
352+ ## ` __bases__ ` lists that include objects that are not instances of ` type `
353+
354+ <!-- snapshot-diagnostics -->
355+
356+ ``` py
357+ class Foo (2 ): ... # error: [invalid-base]
358+ ```
359+
360+ A base that is not an instance of ` type ` but does have an ` __mro_entries__ ` method will not raise an
361+ exception at runtime, so we issue ` unsupported-base ` rather than ` invalid-base ` :
362+
363+ ``` py
364+ class Foo :
365+ def __mro_entries__ (self , bases : tuple[type , ... ]) -> tuple[type , ... ]:
366+ return ()
367+
368+ class Bar (Foo ()): ... # error: [unsupported-base]
369+ ```
370+
371+ But for objects that have badly defined ` __mro_entries__ ` , ` invalid-base ` is emitted rather than
372+ ` unsupported-base ` :
373+
374+ ``` py
375+ class Bad1 :
376+ def __mro_entries__ (self , bases , extra_arg ):
377+ return ()
378+
379+ class Bad2 :
380+ def __mro_entries__ (self , bases ) -> int :
381+ return 42
382+
383+ class BadSub1 (Bad1 ()): ... # error: [invalid-base]
384+ class BadSub2 (Bad2 ()): ... # error: [invalid-base]
385+ ```
386+
348387## ` __bases__ ` lists with duplicate bases
349388
350389<!-- snapshot-diagnostics -->
0 commit comments