diff --git a/mypy/subtypes.py b/mypy/subtypes.py index b8e8d5e3b79d..5733797326e8 100644 --- a/mypy/subtypes.py +++ b/mypy/subtypes.py @@ -312,6 +312,8 @@ def _is_subtype( # ErasedType as we do for non-proper subtyping. return True + # Cases specific w.r.t. right type are easier to handle before entering the SubtypeVisitor. + # Currently, these include Union types and TypeVarType with values. if isinstance(right, UnionType) and not isinstance(left, UnionType): # Normally, when 'left' is not itself a union, the only way # 'left' can be a subtype of the union 'right' is if it is a @@ -360,6 +362,17 @@ def _is_subtype( elif is_subtype_of_item: return True # otherwise, fall through + + if isinstance(right, TypeVarType) and right.values and not isinstance(left, TypeVarType): + if proper_subtype: + if all( + is_proper_subtype(orig_left, v, subtype_context=subtype_context) + for v in right.values + ): + return True + elif all(is_subtype(orig_left, v, subtype_context=subtype_context) for v in right.values): + return True + return left.accept(SubtypeVisitor(orig_right, subtype_context, proper_subtype)) diff --git a/test-data/unit/check-typevar-values.test b/test-data/unit/check-typevar-values.test index 72bf9f7f8083..e0ebc6ddf13a 100644 --- a/test-data/unit/check-typevar-values.test +++ b/test-data/unit/check-typevar-values.test @@ -744,3 +744,17 @@ def fn(w: W) -> W: reveal_type(w) # N: Revealed type is "builtins.int" return w [builtins fixtures/isinstance.pyi] + +[case testTypeVarValuesSubtypeOfAll] +from typing import TypeVar + +class B: ... +class C(B): ... + +S = TypeVar("S", B, C) +b = B() +c = C() +def g(x: S = c): # OK + ... +def h(x: S = b): # E: Incompatible default for parameter "x" (default has type "B", parameter has type "S") + ...