예제 #1
0
 def test_call_with_kwonly_args(self):
   f = self._make_func(
       param_names=("test",),
       kwonly_params=("a", "b"),
       annotations={
           "test": self._vm.convert.str_type,
           "a": self._vm.convert.str_type,
           "b": self._vm.convert.str_type
       }
   )
   kwargs = abstract.Dict(self._vm)
   kwargs.update(
       self._vm.root_node, {
           "a": self._vm.convert.build_string(self._vm.root_node, "2"),
           "b": self._vm.convert.build_string(self._vm.root_node, "3")
       })
   kwargs = kwargs.to_variable(self._vm.root_node)
   args = function.Args(
       posargs=(self._vm.convert.build_string(self._vm.root_node, "1"),),
       namedargs=abstract.Dict(self._vm),
       starstarargs=kwargs)
   f.call(self._vm.root_node, f, args)
   kwargs = abstract.Dict(self._vm)
   kwargs.update(self._vm.root_node,
                 {"b": self._vm.convert.build_string(self._vm.root_node, "3")})
   kwargs = kwargs.to_variable(self._vm.root_node)
   args = function.Args(
       posargs=(self._vm.convert.build_string(self._vm.root_node, "1"),
                self._vm.convert.build_int(self._vm.root_node)),
       namedargs=abstract.Dict(self._vm),
       starstarargs=kwargs)
   self.assertRaises(function.MissingParameter, f.call, self._vm.root_node, f,
                     args)
예제 #2
0
 def test_call_with_all_args(self):
   f = self._make_func(
       param_names=("a", "b", "c"),
       varargs_name="arg",
       kwargs_name="kwarg",
       defaults=(self._vm.convert.build_int(self._vm.root_cfg_node),),
       annotations={
           "a": self._vm.convert.str_type,
           "b": self._vm.convert.int_type,
           "c": self._vm.convert.int_type,
           "arg": self._vm.convert.primitive_classes[float],
           "kwarg": self._vm.convert.primitive_classes[bool]
       }
   )
   posargs = (self._vm.convert.build_string(self._vm.root_cfg_node, "1"),
              self._vm.convert.build_int(self._vm.root_cfg_node))
   float_inst = self._vm.convert.primitive_class_instances[float]
   stararg = abstract.Tuple((float_inst.to_variable(self._vm.root_cfg_node),),
                            self._vm).to_variable(self._vm.root_cfg_node)
   namedargs = abstract.Dict(self._vm)
   kwarg = abstract.Dict(self._vm)
   kwarg.update(self._vm.root_cfg_node,
                {"x": self._vm.convert.build_bool(self._vm.root_cfg_node),
                 "y": self._vm.convert.build_bool(self._vm.root_cfg_node)})
   kwarg = kwarg.to_variable(self._vm.root_cfg_node)
   args = function.Args(posargs, namedargs, stararg, kwarg)
   f.call(self._vm.root_cfg_node, f, args)
예제 #3
0
 def test_call_with_bad_kwargs(self):
   f = self._make_func(
       kwargs_name="kwarg",
       annotations={"kwarg": self._vm.convert.str_type})
   kwargs = abstract.Dict(self._vm)
   kwargs.update(self._vm.root_cfg_node,
                 {"_1": self._vm.convert.build_int(self._vm.root_cfg_node)})
   kwargs = kwargs.to_variable(self._vm.root_cfg_node)
   args = function.Args(
       posargs=(),
       namedargs=abstract.Dict(self._vm),
       starstarargs=kwargs
   )
   self.assertRaises(function.WrongArgTypes, f.call,
                     self._vm.root_cfg_node, f, args)
예제 #4
0
 def call(self, node, func, args):
     args = args.simplify(node)
     self.match_args(node, args, match_all_views=True)
     # As long as the types match we do not really care about the actual
     # class name. But, if we have a string literal value as the name arg,
     # we will use it.
     name_arg = args.namedargs.get(self._name_arg_name) or args.posargs[0]
     try:
         _ = abstract_utils.get_atomic_python_constant(name_arg, str)
     except abstract_utils.ConversionError:
         name_arg = self.vm.convert.constant_to_var(
             "_NewType_Internal_Class_Name_%d_" %
             self.internal_name_counter)
     type_arg = args.namedargs.get(self._type_arg_name) or args.posargs[1]
     try:
         type_value = abstract_utils.get_atomic_value(type_arg)
     except abstract_utils.ConversionError:
         # We need the type arg to be an atomic value. If not, we just
         # silently return unsolvable.
         return node, self.vm.new_unsolvable(node)
     value_arg_name = "val"
     constructor = overlay_utils.make_method(
         self.vm,
         node,
         name="__init__",
         params=[Param(value_arg_name, type_value)])
     members = abstract.Dict(self.vm)
     members.set_str_item(node, "__init__", constructor)
     return self.vm.make_class(node, name_arg, (type_arg, ),
                               members.to_variable(node), None)
예제 #5
0
 def test_compatible_with__after_unambiguous_update(self):
     unambiguous_dict = abstract.Dict(self._vm)
     unambiguous_dict.set_str_item(self._node, "a",
                                   self._vm.new_unsolvable(self._node))
     self._d.update(self._node, unambiguous_dict)
     self.assertIs(True, compare.compatible_with(self._d, True))
     self.assertIs(False, compare.compatible_with(self._d, False))
예제 #6
0
 def test_compatible_with__after_ambiguous_update(self):
     ambiguous_dict = abstract.Dict(self._vm)
     ambiguous_dict.merge_instance_type_parameter(
         self._node, abstract_utils.K, self._vm.new_unsolvable(self._node))
     ambiguous_dict.could_contain_anything = True
     self._d.update(self._node, ambiguous_dict)
     self.assertAmbiguous(self._d)
예제 #7
0
 def call(self, node, func, args):
   args = args.simplify(node)
   self._match_args(node, args, match_all_views=True)
   # As long as the types match we do not really care about the actual
   # class name. But, if we have a string literal value as the name arg,
   # we will use it.
   name_arg = args.namedargs.get(self._name_arg_name) or args.posargs[0]
   try:
     _ = abstract.get_atomic_python_constant(name_arg, str)
   except abstract.ConversionError:
     name_arg = self.vm.convert.constant_to_var(
         "_NewType_Internal_Class_Name_%d_" % self.internal_name_counter)
   type_arg = args.namedargs.get(self._type_arg_name) or args.posargs[1]
   try:
     type_value = abstract.get_atomic_value(type_arg)
   except abstract.ConversionError:
     # We need the type arg to be an atomic value. If not, we just
     # silently return unsolvable.
     return node, self.vm.convert.create_new_unsolvable(node)
   value_arg_name = "val"
   constructor = abstract.SimpleFunction(
       name="__init__",
       param_names=("self", value_arg_name),
       varargs_name=None,
       kwonly_params=(),
       kwargs_name=None,
       defaults={},
       annotations={value_arg_name: type_value},
       late_annotations={},
       vm=self.vm,
   ).to_variable(node)
   members = abstract.Dict(self.vm)
   members.set_str_item(node, "__init__", constructor)
   return node, self.vm.make_class(node, name_arg, (type_arg,),
                                   members.to_variable(node), None)
예제 #8
0
 def init_subclass(self, node, cls):
   # Subclasses of Module call self.setup() when creating instances.
   cls.additional_init_methods.append("setup")
   dc = ModuleDataclass.make(self.vm)
   cls_var = cls.to_variable(node)
   args = function.Args(posargs=(cls_var,), namedargs=abstract.Dict(self.vm))
   node, _ = dc.call(node, None, args)
   return node
예제 #9
0
 def test_call_with_kwargs(self):
   f = self._make_func(
       kwargs_name="kwarg",
       annotations={"kwarg": self._vm.convert.str_type})
   kwargs = abstract.Dict(self._vm)
   kwargs.update(
       self._vm.root_node, {
           "_1": self._vm.convert.build_string(self._vm.root_node, "1"),
           "_2": self._vm.convert.build_string(self._vm.root_node, "2")
       })
   kwargs = kwargs.to_variable(self._vm.root_node)
   args = function.Args(
       posargs=(),
       namedargs=abstract.Dict(self._vm),
       starstarargs=kwargs
   )
   f.call(self._vm.root_node, f, args)
예제 #10
0
 def test_compatible_with__after_ambiguous_update(self):
     ambiguous_dict = abstract.Dict(self._vm)
     ambiguous_dict.merge_type_parameter(
         self._node, abstract.K,
         self._vm.convert.create_new_unsolvable(self._node))
     ambiguous_dict.could_contain_anything = True
     self._d.update(self._node, ambiguous_dict)
     self.assertIs(True, self._d.compatible_with(True))
     self.assertIs(True, self._d.compatible_with(False))
예제 #11
0
파일: infer.py 프로젝트: yang/pytype-hack
 def create_kwargs(self, node):
   key_type = self.primitive_class_instances[str].to_variable(node, "str")
   value_type = self.create_new_unknown(node, "kwargs_value")
   kwargs = abstract.Dict("kwargs", self)
   kwargs.overwrite_type_parameter(
       node, abstract.Dict.KEY_TYPE_PARAM, key_type)
   kwargs.overwrite_type_parameter(
       node, abstract.Dict.VALUE_TYPE_PARAM, value_type)
   return kwargs
예제 #12
0
 def test_compatible_with__after_empty_update(self):
     empty_dict = abstract.Dict(self._vm)
     self._d.update(self._node, empty_dict)
     self.assertIs(False, self._d.compatible_with(True))
     self.assertIs(True, self._d.compatible_with(False))
예제 #13
0
 def build_map(self, node):
     """Create an empty VM dict."""
     return abstract.Dict(self.vm).to_variable(node)
예제 #14
0
 def setUp(self):
     super(DictTest, self).setUp()
     self._d = abstract.Dict(self._vm)
     self._var = self._program.NewVariable()
     self._var.AddBinding(abstract.Unknown(self._vm), [], self._node)
예제 #15
0
 def setUp(self):
   super(DictTest, self).setUp()
   self._d = abstract.Dict("test_dict", self._vm, self._node)
   self._var = self._program.NewVariable("test_var")
   self._var.AddBinding(abstract.Unknown(self._vm))
예제 #16
0
 def test_compatible_with__after_unambiguous_update(self):
     unambiguous_dict = abstract.Dict(self._vm)
     unambiguous_dict.set_str_item(self._node, "a",
                                   self._vm.new_unsolvable(self._node))
     self._d.update(self._node, unambiguous_dict)
     self.assertTruthy(self._d)
예제 #17
0
 def test_compatible_with__after_empty_update(self):
     empty_dict = abstract.Dict(self._vm)
     self._d.update(self._node, empty_dict)
     self.assertFalsy(self._d)
예제 #18
0
    def call(self, node, func, args, alias_map=None):
        """Implements the behavior of the enum functional API."""
        # Because of how this is called, we supply our own "self" argument.
        # See class_mixin.Class._call_new_and_init.
        args = args.simplify(node, self.vm)
        args = args.replace(posargs=(self.vm.new_unsolvable(node), ) +
                            args.posargs)
        self.load_lazy_attribute("__new__")
        new = abstract_utils.get_atomic_value(self.members["__new__"])
        # Note that super().call or _call_new_and_init won't work here, because
        # they don't raise FailedFunctionCall.
        new.match_args(node, args, alias_map)
        # There should only be 1 signature for Enum.__new__.
        assert len(
            new.signatures) == 1, "Expected only 1 Enum.__new__ signature."
        sig = new.signatures[0].signature
        argmap = {name: var for name, var, _ in sig.iter_args(args)}

        cls_name_var = argmap["value"]
        try:
            names = abstract_utils.get_atomic_python_constant(argmap["names"])
        except abstract_utils.ConversionError as e:
            log.info(
                "Failed to unwrap values in enum functional interface:\n%s", e)
            return node, self.vm.new_unsolvable(node)

        if isinstance(names, str):
            names = names.replace(",", " ").split()
            fields = {name: self.vm.convert.build_int(node) for name in names}
        elif isinstance(names, dict):
            # Dict keys are strings, not strings in variables. The values are
            # variables, they don't need to be changed.
            fields = names
        else:
            # List of names, or list of (name, value) pairs.
            try:
                possible_pairs = [
                    abstract_utils.get_atomic_python_constant(p) for p in names
                ]
            except abstract_utils.ConversionError as e:
                log.debug("Failed to unwrap possible enum field pairs:\n  %s",
                          e)
                return node, self.vm.new_unsolvable(node)
            if not possible_pairs:
                fields = {}
            elif isinstance(possible_pairs[0], str):
                fields = {
                    name: self.vm.convert.build_int(node)
                    for name in possible_pairs
                }
            else:
                # List of (name_var, value_var) pairs.
                # The earlier get_atomic_python_constant call only unwrapped the tuple,
                # so the values in the tuple still need to be unwrapped.
                try:
                    fields = {
                        abstract_utils.get_atomic_python_constant(name): value
                        for name, value in possible_pairs
                    }
                except abstract_utils.ConversionError as e:
                    log.debug("Failed to unwrap field names for enum:\n  %s",
                              e)
                    return node, self.vm.new_unsolvable(node)

        cls_dict = abstract.Dict(self.vm)
        cls_dict.update(node, fields)

        metaclass = self.vm.loaded_overlays["enum"].members["EnumMeta"]

        return self.vm.make_class(node=node,
                                  name_var=cls_name_var,
                                  bases=[self.to_variable(node)],
                                  class_dict_var=cls_dict.to_variable(node),
                                  cls_var=metaclass,
                                  class_type=EnumInstance)
예제 #19
0
    def _build_namedtuple(self, name, field_names, field_types, late_annots,
                          node):
        # Build an InterpreterClass representing the namedtuple.
        if field_types:
            # TODO(mdemello): Fix this to support late types.
            field_types_union = abstract.Union(field_types, self.vm)
        else:
            field_types_union = self.vm.convert.none_type

        members = {
            n: t.instantiate(node)
            for n, t in moves.zip(field_names, field_types)
        }

        # collections.namedtuple has: __dict__, __slots__ and _fields.
        # typing.NamedTuple adds: _field_types, __annotations__ and _field_defaults.
        # __slots__ and _fields are tuples containing the names of the fields.
        slots = tuple(
            self.vm.convert.build_string(node, f) for f in field_names)
        members["__slots__"] = abstract.Tuple(slots, self.vm).to_variable(node)
        members["_fields"] = abstract.Tuple(slots, self.vm).to_variable(node)
        # __dict__ and _field_defaults are both collections.OrderedDicts that map
        # field names (strings) to objects of the field types.
        ordered_dict_cls = self.vm.convert.name_to_value(
            "collections.OrderedDict", ast=self.collections_ast)

        # In Python 2, keys can be `str` or `unicode`; support both.
        # In Python 3, `str_type` and `unicode_type` are the same.
        field_keys_union = abstract.Union(
            [self.vm.convert.str_type, self.vm.convert.unicode_type], self.vm)

        # Normally, we would use abstract_utils.K and abstract_utils.V, but
        # collections.pyi doesn't conform to that standard.
        field_dict_cls = abstract.ParameterizedClass(ordered_dict_cls, {
            "K": field_keys_union,
            "V": field_types_union
        }, self.vm)
        members["__dict__"] = field_dict_cls.instantiate(node)
        members["_field_defaults"] = field_dict_cls.instantiate(node)
        # _field_types and __annotations__ are both collections.OrderedDicts
        # that map field names (strings) to the types of the fields.
        field_types_cls = abstract.ParameterizedClass(
            ordered_dict_cls, {
                "K": field_keys_union,
                "V": self.vm.convert.type_type
            }, self.vm)
        members["_field_types"] = field_types_cls.instantiate(node)
        members["__annotations__"] = field_types_cls.instantiate(node)

        # __new__
        # We set the bound on this TypeParameter later. This gives __new__ the
        # signature: def __new__(cls: Type[_Tname], ...) -> _Tname, i.e. the same
        # signature that visitor.CreateTypeParametersForSignatures would create.
        # This allows subclasses of the NamedTuple to get the correct type from
        # their constructors.
        cls_type_param = abstract.TypeParameter(
            visitors.CreateTypeParametersForSignatures.PREFIX + name,
            self.vm,
            bound=None)
        cls_type = abstract.ParameterizedClass(
            self.vm.convert.type_type, {abstract_utils.T: cls_type_param},
            self.vm)
        # Use late annotations as field types if they exist.
        params = [
            Param(n, late_annots.get(n, t))
            for n, t in moves.zip(field_names, field_types)
        ]
        members["__new__"] = overlay_utils.make_method(
            self.vm,
            node,
            name="__new__",
            self_param=Param("cls", cls_type),
            params=params,
            return_type=cls_type_param,
        )

        # __init__
        members["__init__"] = overlay_utils.make_method(self.vm,
                                                        node,
                                                        name="__init__",
                                                        varargs=Param("args"),
                                                        kwargs=Param("kwargs"))

        # _make
        # _make is a classmethod, so it needs to be wrapped by
        # specialibuiltins.ClassMethodInstance.
        # Like __new__, it uses the _Tname TypeVar.
        sized_cls = self.vm.convert.name_to_value("typing.Sized")
        iterable_type = abstract.ParameterizedClass(
            self.vm.convert.name_to_value("typing.Iterable"),
            {abstract_utils.T: field_types_union}, self.vm)
        cls_type = abstract.ParameterizedClass(
            self.vm.convert.type_type, {abstract_utils.T: cls_type_param},
            self.vm)
        len_type = abstract.CallableClass(
            self.vm.convert.name_to_value("typing.Callable"), {
                0: sized_cls,
                abstract_utils.ARGS: sized_cls,
                abstract_utils.RET: self.vm.convert.int_type
            }, self.vm)
        params = [
            Param("iterable", iterable_type),
            Param("new").unsolvable(self.vm, node),
            Param("len", len_type).unsolvable(self.vm, node)
        ]
        make = overlay_utils.make_method(self.vm,
                                         node,
                                         name="_make",
                                         params=params,
                                         self_param=Param("cls", cls_type),
                                         return_type=cls_type_param)
        make_args = function.Args(posargs=(make, ))
        _, members["_make"] = self.vm.special_builtins["classmethod"].call(
            node, None, make_args)

        # _replace
        # Like __new__, it uses the _Tname TypeVar. We have to annotate the `self`
        # param to make sure the TypeVar is substituted correctly.
        members["_replace"] = overlay_utils.make_method(
            self.vm,
            node,
            name="_replace",
            self_param=Param("self", cls_type_param),
            return_type=cls_type_param,
            kwargs=Param("kwds", field_types_union))

        # __getnewargs__
        getnewargs_tuple_params = dict(
            tuple(enumerate(field_types)) +
            ((abstract_utils.T, field_types_union), ))
        getnewargs_tuple = abstract.TupleClass(self.vm.convert.tuple_type,
                                               getnewargs_tuple_params,
                                               self.vm)
        members["__getnewargs__"] = overlay_utils.make_method(
            self.vm, node, name="__getnewargs__", return_type=getnewargs_tuple)

        # __getstate__
        members["__getstate__"] = overlay_utils.make_method(
            self.vm, node, name="__getstate__")

        # _asdict
        members["_asdict"] = overlay_utils.make_method(
            self.vm, node, name="_asdict", return_type=field_dict_cls)

        # Finally, make the class.
        cls_dict = abstract.Dict(self.vm)
        cls_dict.update(node, members)
        if name.__class__ is compat.UnicodeType:
            # Unicode values should be ASCII.
            name = compat.native_str(name.encode("ascii"))

        node, cls_var = self.vm.make_class(
            node=node,
            name_var=self.vm.convert.build_string(node, name),
            bases=[self.vm.convert.tuple_type.to_variable(node)],
            class_dict_var=cls_dict.to_variable(node),
            cls_var=None)
        cls = cls_var.data[0]

        # Now that the class has been made, we can complete the TypeParameter used
        # by __new__, _make and _replace.
        cls_type_param.bound = cls

        # Add late annotations to the new class
        if late_annots:
            cls.late_annotations = late_annots
            self.vm.classes_with_late_annotations.append(cls)

        return node, cls_var
예제 #20
0
 def new_dict(self, **kwargs):
     """Create a Dict from keywords mapping names to Variable objects."""
     d = abstract.Dict(self._vm)
     for name, var in kwargs.items():
         d.set_str_item(self._node, name, var)
     return d
예제 #21
0
    def _build_namedtuple(self, name, field_names, field_types, node):
        # Build an InterpreterClass representing the namedtuple.
        if field_types:
            field_types_union = abstract.Union(field_types, self.vm)
        else:
            field_types_union = self.vm.convert.none_type

        members = {
            n: t.instantiate(node)
            for n, t in moves.zip(field_names, field_types)
        }
        # collections.namedtuple has: __dict__, __slots__ and _fields.
        # typing.NamedTuple adds: _field_types, __annotations__ and _field_defaults.
        # __slots__ and _fields are tuples containing the names of the fields.
        slots = tuple(
            self.vm.convert.build_string(node, f) for f in field_names)
        members["__slots__"] = abstract.Tuple(slots, self.vm).to_variable(node)
        members["_fields"] = abstract.Tuple(slots, self.vm).to_variable(node)
        # __dict__ and _field_defaults are both collections.OrderedDicts that map
        # field names (strings) to objects of the field types.
        ordered_dict_cls = self.vm.convert.name_to_value(
            "collections.OrderedDict", ast=self.collections_ast)

        # In Python 2, keys can be `str` or `unicode`; support both.
        # In Python 3, `str_type` and `unicode_type` are the same.
        field_keys_union = abstract.Union(
            [self.vm.convert.str_type, self.vm.convert.unicode_type], self.vm)

        # Normally, we would use abstract_utils.K and abstract_utils.V, but
        # collections.pyi doesn't conform to that standard.
        field_dict_cls = abstract.ParameterizedClass(ordered_dict_cls, {
            "K": field_keys_union,
            "V": field_types_union
        }, self.vm)
        members["__dict__"] = field_dict_cls.instantiate(node)
        members["_field_defaults"] = field_dict_cls.instantiate(node)
        # _field_types and __annotations__ are both collections.OrderedDicts
        # that map field names (strings) to the types of the fields.
        field_types_cls = abstract.ParameterizedClass(
            ordered_dict_cls, {
                "K": field_keys_union,
                "V": self.vm.convert.type_type
            }, self.vm)
        members["_field_types"] = field_types_cls.instantiate(node)
        members["__annotations__"] = field_types_cls.instantiate(node)
        # __new__
        new_annots = {}
        new_lates = {}
        for (n, t) in moves.zip(field_names, field_types):
            # We don't support late annotations yet, but once we do, they'll show up
            # as LateAnnotation objects to be stored in new_lates.
            new_annots[n] = t
        # We set the bound on this TypeParameter later. This gives __new__ the
        # signature: def __new__(cls: Type[_Tname], ...) -> _Tname, i.e. the same
        # signature that visitor.CreateTypeParametersForSignatures would create.
        # This allows subclasses of the NamedTuple to get the correct type from
        # their constructors.
        cls_type_param = abstract.TypeParameter(
            visitors.CreateTypeParametersForSignatures.PREFIX + name,
            self.vm,
            bound=None)
        new_annots["cls"] = abstract.ParameterizedClass(
            self.vm.convert.type_type, {abstract_utils.T: cls_type_param},
            self.vm)
        new_annots["return"] = cls_type_param
        members["__new__"] = abstract.SimpleFunction(
            name="__new__",
            param_names=("cls", ) + tuple(field_names),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name=None,
            defaults={},
            annotations=new_annots,
            late_annotations=new_lates,
            vm=self.vm).to_variable(node)
        # __init__
        members["__init__"] = abstract.SimpleFunction(
            name="__init__",
            param_names=("self", ),
            varargs_name="args",
            kwonly_params=(),
            kwargs_name="kwargs",
            defaults={},
            annotations={},
            late_annotations={},
            vm=self.vm).to_variable(node)
        # _make
        # _make is a classmethod, so it needs to be wrapped by
        # specialibuiltins.ClassMethodInstance.
        # Like __new__, it uses the _Tname TypeVar.
        sized_cls = self.vm.convert.name_to_value("typing.Sized")
        iterable_type = abstract.ParameterizedClass(
            self.vm.convert.name_to_value("typing.Iterable"),
            {abstract_utils.T: field_types_union}, self.vm)
        make = abstract.SimpleFunction(
            name="_make",
            param_names=("cls", "iterable", "new", "len"),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name=None,
            defaults={
                "new": self.vm.convert.unsolvable.to_variable(node),
                "len": self.vm.convert.unsolvable.to_variable(node)
            },
            annotations={
                "cls":
                abstract.ParameterizedClass(self.vm.convert.type_type,
                                            {abstract_utils.T: cls_type_param},
                                            self.vm),
                "iterable":
                iterable_type,
                "new":
                self.vm.convert.unsolvable,
                "len":
                abstract.Callable(
                    self.vm.convert.name_to_value("typing.Callable"), {
                        0: sized_cls,
                        abstract_utils.ARGS: sized_cls,
                        abstract_utils.RET: self.vm.convert.int_type
                    }, self.vm),
                "return":
                cls_type_param
            },
            late_annotations={},
            vm=self.vm).to_variable(node)
        make_args = function.Args(posargs=(make, ))
        _, members["_make"] = self.vm.special_builtins["classmethod"].call(
            node, None, make_args)
        # _replace
        # Like __new__, it uses the _Tname TypeVar. We have to annotate the `self`
        # param to make sure the TypeVar is substituted correctly.
        members["_replace"] = abstract.SimpleFunction(
            name="_replace",
            param_names=("self", ),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name="kwds",
            defaults={},
            annotations={
                "self": cls_type_param,
                "kwds": field_types_union,
                "return": cls_type_param
            },
            late_annotations={},
            vm=self.vm).to_variable(node)
        # __getnewargs__
        getnewargs_tuple_params = dict(
            tuple(enumerate(field_types)) +
            ((abstract_utils.T, field_types_union), ))
        getnewargs_tuple = abstract.TupleClass(self.vm.convert.tuple_type,
                                               getnewargs_tuple_params,
                                               self.vm)
        members["__getnewargs__"] = abstract.SimpleFunction(
            name="__getnewargs__",
            param_names=("self", ),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name=None,
            defaults={},
            annotations={
                "return": getnewargs_tuple
            },
            late_annotations={},
            vm=self.vm).to_variable(node)
        # __getstate__
        members["__getstate__"] = abstract.SimpleFunction(
            name="__getstate__",
            param_names=("self", ),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name=None,
            defaults={},
            annotations={},
            late_annotations={},
            vm=self.vm).to_variable(node)
        # _asdict
        members["_asdict"] = abstract.SimpleFunction(
            name="_asdict",
            param_names=("self", ),
            varargs_name=None,
            kwonly_params=(),
            kwargs_name=None,
            defaults={},
            annotations={
                "return": field_dict_cls
            },
            late_annotations={},
            vm=self.vm).to_variable(node)
        # Finally, make the class.
        abs_membs = abstract.Dict(self.vm)
        abs_membs.update(node, members)
        cls_var = self.vm.make_class(
            node=node,
            name_var=self.vm.convert.build_string(node, name),
            bases=[self.vm.convert.tuple_type.to_variable(node)],
            class_dict_var=abs_membs.to_variable(node),
            cls_var=None)
        # Now that the class has been made, we can complete the TypeParameter used
        # by __new__, _make and _replace.
        cls_type_param.bound = cls_var.data[0]
        return cls_var