diff --git a/mypy/constraints.py b/mypy/constraints.py index 9212964071f34..fe3edb7242eb1 100644 --- a/mypy/constraints.py +++ b/mypy/constraints.py @@ -153,7 +153,10 @@ def _infer_constraints(template: Type, actual: Type, # T :> U2", but they are not equivalent to the constraint solver, # which never introduces new Union types (it uses join() instead). if isinstance(template, TypeVarType): - return [Constraint(template.id, direction, actual)] + return [ + Constraint(template.id, direction, actual), + Constraint(template.id, SUBTYPE_OF, template.upper_bound), + ] # Now handle the case of either template or actual being a Union. # For a Union to be a subtype of another type, every item of the Union diff --git a/test-data/unit/check-generic-subtyping.test b/test-data/unit/check-generic-subtyping.test index bd1f487bc895e..eebdc4c336e5d 100644 --- a/test-data/unit/check-generic-subtyping.test +++ b/test-data/unit/check-generic-subtyping.test @@ -1033,3 +1033,18 @@ x2: X2[str, int] reveal_type(iter(x2)) # N: Revealed type is "typing.Iterator[builtins.int]" reveal_type([*x2]) # N: Revealed type is "builtins.list[builtins.int]" [builtins fixtures/dict.pyi] + + +[case testBoundTypeVarCallable] +# flags: --strict-optional +from typing import Callable, Optional, TypeVar + +class something: ... + +T = TypeVar("T", bound=something) + +def raises(opts: Optional[T]) -> T: ... +def assertRaises(cb: Callable[..., object]) -> None: ... + +assertRaises(raises) +[builtins fixtures/dict.pyi]