diff --git a/pytype/tests/test_typevar1.py b/pytype/tests/test_typevar1.py index 948439fc2..e878caa9f 100644 --- a/pytype/tests/test_typevar1.py +++ b/pytype/tests/test_typevar1.py @@ -66,6 +66,20 @@ def test_type_var_with_bounds_in_type_alias(self): """, ) + @test_utils.skipBeforePy((3, 12), "PEP 695 - 3.12 feature") + def test_type_var_with_constraints_in_type_alias(self): + ty = self.Infer(""" + type Alias[T: (int, str)] = list[T] + """) + self.assertTypesMatchPytd( + ty, + """ + from typing import TypeVar + T = TypeVar('T', int, str) + Alias = list[T] + """, + ) + @test_utils.skipBeforePy((3, 12), "PEP 695 - 3.12 feature") def test_unused_typevar_pep695_function_type_var_single(self): ty = self.Infer(""" diff --git a/pytype/vm.py b/pytype/vm.py index fe89dcb24..f376db21c 100644 --- a/pytype/vm.py +++ b/pytype/vm.py @@ -3965,7 +3965,37 @@ def byte_INTRINSIC_TYPEVAR_WITH_BOUND(self, state): return state def byte_INTRINSIC_TYPEVAR_WITH_CONSTRAINTS(self, state): - # TODO: b/350910471 - Implement to support PEP 695 + """This intrinsic is a synonym of typing.TypeVar('T', *constraint).""" + # First parameter(bound_func) is the function object that returns the type + # representation of the bound. + state, (type_var_name, constraint_func) = state.popn(2) + + type_var_name = self.ctx.convert.constant_to_var( + type_var_name.data[0].pyval, node=state.node + ) + _, constraints = function.call_function( + self.ctx, + state.node, + constraint_func, + args=function.Args( + posargs=(), + namedargs={}, + starargs=None, + starstarargs=None, + ), + ) + _, ret = function.call_function( + self.ctx, + state.node, + self._typings_type_var, + args=function.Args( + posargs=(type_var_name,), + namedargs={}, + starargs=constraints, + starstarargs=None, + ), + ) + state = state.push(ret) return state def byte_INTRINSIC_SET_FUNCTION_TYPE_PARAMS(self, state):