Example #1
0
 def test_union_set_attribute(self):
     list_instance = abstract.Instance(self._vm.convert.list_type, self._vm)
     cls = abstract.InterpreterClass("obj", [], {}, None, self._vm)
     cls_instance = abstract.Instance(cls, self._vm)
     union = abstract.Union([cls_instance, list_instance], self._vm)
     node = self._vm.attribute_handler.set_attribute(
         self._vm.root_cfg_node, union, "rumpelstiltskin",
         self._vm.convert.none_type.to_variable(self._vm.root_cfg_node))
     self.assertEqual(cls_instance.members["rumpelstiltskin"].data.pop(),
                      self._vm.convert.none_type)
     self.assertIs(node, self._vm.root_cfg_node)
     error, = self._vm.errorlog.unique_sorted_errors()
     self.assertEqual(error.name, "not-writable")
Example #2
0
 def build_set(self, node, content):
   """Create a VM set from the given sequence."""
   content = list(content)  # content might be a generator
   value = abstract.Instance(self.set_type, self.vm, node)
   value.initialize_type_parameter(node, "T",
                                   self.build_content(node, content))
   return value.to_variable(node, name="set(...)")
Example #3
0
 def test_compatible_with_none(self):
   # This test is specifically for abstract.Instance, so we don't use
   # self._vm.convert.none, which is an AbstractOrConcreteValue.
   i = abstract.Instance(
       self._vm.convert.none_type, self._vm, self._node)
   self.assertIs(False, i.compatible_with(True))
   self.assertIs(True, i.compatible_with(False))
Example #4
0
 def create_kwargs(self, node):
   key_type = self.convert.primitive_class_instances[str].to_variable(node)
   value_type = self.convert.create_new_unknown(node)
   kwargs = abstract.Instance(self.convert.dict_type, self)
   kwargs.merge_instance_type_parameter(node, abstract_utils.K, key_type)
   kwargs.merge_instance_type_parameter(node, abstract_utils.V, value_type)
   return kwargs.to_variable(node)
Example #5
0
 def testAnyStrInstanceAgainstAnyStr(self):
   right = self.vm.convert.name_to_value("typing.AnyStr")
   dummy_instance = abstract.Instance(self.vm.convert.tuple_type, self.vm)
   left = abstract.TypeParameterInstance(right, dummy_instance, self.vm)
   for result in self._match_var(left, right):
     self.assertItemsEqual([(name, var.data) for name, var in result.items()],
                           [("AnyStr", [left])])
Example #6
0
 def _setup_pytdclass(self, node, cls):
     # We need to rewrite the member map of the PytdClass.
     members = dict(cls._member_map)  # pylint: disable=protected-access
     member_types = []
     for name, pytd_val in members.items():
         # Only constants need to be transformed.
         # TODO(tsudol): Ensure only valid enum members are transformed.
         if not isinstance(pytd_val, pytd.Constant):
             continue
         # Build instances directly, because you can't call instantiate() when
         # creating the class -- pytype complains about recursive types.
         member = abstract.Instance(cls, self.vm)
         member.members["name"] = self.vm.convert.constant_to_var(
             pyval=pytd.Constant(name="name", type=self._str_pytd),
             node=node)
         member.members["value"] = self.vm.convert.constant_to_var(
             pyval=pytd.Constant(name="value", type=pytd_val.type),
             node=node)
         cls._member_map[name] = member  # pylint: disable=protected-access
         cls.members[name] = member.to_variable(node)
         member_types.append(pytd_val.type)
     member_type = self.vm.convert.constant_to_value(
         pytd_utils.JoinTypes(member_types))
     cls.members["__new__"] = self._make_new(node, member_type, cls)
     cls.members["__eq__"] = EnumCmpEQ(self.vm).to_variable(node)
     return node
Example #7
0
 def build_set(self, node, content):
     """Create a VM set from the given sequence."""
     content = list(content)  # content might be a generator
     value = abstract.Instance(self.set_type, self.vm)
     value.merge_type_parameter(node, abstract.T,
                                self.build_content(content))
     return value.to_variable(node)
Example #8
0
 def test_getitem_with_instance_valself(self):
     cls = abstract.InterpreterClass("X", [], {}, None, self.vm)
     valself = abstract.Instance(cls, self.vm).to_binding(self.node)
     _, attr_var = self.attribute_handler.get_attribute(
         self.node, cls, "__getitem__", valself)
     # Since we passed in `valself` for this lookup of __getitem__ on a class,
     # it is treated as a normal lookup; X.__getitem__ does not exist.
     self.assertIsNone(attr_var)
Example #9
0
 def testToTypeWithView2(self):
   # to_type(<instance of <str or unsolvable>>, view={__class__: str})
   instance = abstract.Instance(self._vm.convert.unsolvable, self._vm)
   cls_binding = instance.cls.AddBinding(
       self._vm.convert.str_type, [], self._vm.root_cfg_node)
   view = {instance.cls: cls_binding}
   pytd_type = instance.to_type(self._vm.root_cfg_node, seen=None, view=view)
   self.assertEqual("__builtin__.str", pytd_type.name)
Example #10
0
 def build_list(self, node, content):
     """Create a VM list from the given sequence."""
     # TODO(rechen): set T to empty if there is nothing in content
     content = list(content)  # content might be a generator
     value = abstract.Instance(self.list_type, self.vm, node)
     value.initialize_type_parameter(node, abstract.T,
                                     self.build_content(node, content))
     return value.to_variable(node)
Example #11
0
 def test_compatible_with_set(self):
     i = abstract.Instance(self._vm.convert.set_type, self._vm)
     # Empty set is not compatible with True.
     self.assertFalsy(i)
     # Once a type parameter is set, list is compatible with True and False.
     i.merge_instance_type_parameter(
         self._node, abstract_utils.T,
         self._vm.convert.object_type.to_variable(self._vm.root_cfg_node))
     self.assertAmbiguous(i)
Example #12
0
 def test_call_empty_type_parameter_instance(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   t = abstract.TypeParameter(abstract_utils.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               function.Args(posargs=()))
   self.assertIs(node, self._node)
   retval, = ret.data
   self.assertIs(retval, self._vm.convert.empty)
Example #13
0
 def create_kwargs(self, node):
   key_type = self.convert.primitive_class_instances[str].to_variable(
       node, "str")
   value_type = self.convert.create_new_unknown(node, "kwargs_value")
   kwargs = abstract.Instance(self.convert.dict_type, self, node)
   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.to_variable(node, "**kwargs")
Example #14
0
 def test_instance_with_valself(self):
     instance = abstract.Instance(self.vm.convert.int_type, self.vm)
     valself = instance.to_binding(self.node)
     _, attr_var = self.attribute_handler.get_attribute(
         self.node, instance, "real", valself)
     attr_binding, = attr_var.bindings
     self.assertEqual(attr_binding.data.cls, self.vm.convert.int_type)
     # Since `valself` was passed to get_attribute, it is added to the
     # attribute's origins.
     self.assertIn(valself, _get_origins(attr_binding))
Example #15
0
 def test_instance_no_valself(self):
     instance = abstract.Instance(self.vm.convert.int_type, self.vm)
     _, attr_var = self.attribute_handler.get_attribute(
         self.node, instance, "real")
     attr_binding, = attr_var.bindings
     self.assertEqual(attr_binding.data.cls, self.vm.convert.int_type)
     # Since `valself` was not passed to get_attribute, a binding to
     # `instance` is not among the attribute's origins.
     self.assertNotIn(instance,
                      [o.data for o in _get_origins(attr_binding)])
Example #16
0
 def test_class_with_instance_valself(self):
     meta_members = {"x": self.vm.convert.none.to_variable(self.node)}
     meta = abstract.InterpreterClass("M", [], meta_members, None, self.vm)
     cls = abstract.InterpreterClass("X", [], {}, meta, self.vm)
     valself = abstract.Instance(cls, self.vm).to_binding(self.node)
     _, attr_var = self.attribute_handler.get_attribute(
         self.node, cls, "x", valself)
     # Since `valself` is an instance of X, we do not look at the metaclass, so
     # M.x is not returned.
     self.assertIsNone(attr_var)
Example #17
0
 def test_empty_type_parameter_instance(self):
   t = abstract.TypeParameter(
       abstract_utils.T, self._vm, bound=self._vm.convert.int_type)
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   node, var = self._vm.attribute_handler.get_attribute(
       self._vm.root_cfg_node, t_instance, "real")
   self.assertIs(node, self._vm.root_cfg_node)
   attr, = var.data
   self.assertIs(attr, self._vm.convert.primitive_class_instances[int])
Example #18
0
 def test_compatible_with_set(self):
     i = abstract.Instance(self._vm.convert.set_type, self._vm, self._node)
     i.init_type_parameters("T")
     # Empty list is not compatible with True.
     self.assertIs(False, i.compatible_with(True))
     self.assertIs(True, i.compatible_with(False))
     # Once a type parameter is set, list is compatible with True and False.
     i.merge_type_parameter(self._node, "T", self._vm.convert.object_type)
     self.assertIs(True, i.compatible_with(True))
     self.assertIs(True, i.compatible_with(False))
Example #19
0
 def testToTypeWithViewAndEmptyParam(self):
     instance = abstract.Instance(self._vm.convert.list_type, self._vm,
                                  self._vm.root_cfg_node)
     instance.type_parameters["T"] = self._vm.program.NewVariable()
     view = {instance.cls: instance.cls.bindings[0]}
     pytd_type = instance.to_type(self._vm.root_cfg_node,
                                  seen=None,
                                  view=view)
     self.assertEquals("__builtin__.list", pytd_type.base_type.name)
     self.assertSequenceEqual((pytd.NothingType(), ), pytd_type.parameters)
Example #20
0
 def testCallEmptyTypeParameterInstance(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   instance.initialize_type_parameter(
       self._node, abstract.T, self._vm.program.NewVariable())
   t = abstract.TypeParameter(abstract.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               abstract.FunctionArgs(posargs=()))
   self.assertIs(node, self._node)
   retval, = ret.data
   self.assertIs(retval, self._vm.convert.empty)
Example #21
0
 def testCallTypeParameterInstance(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   instance.initialize_type_parameter(
       self._node, abstract.T,
       self._vm.convert.int_type.to_variable(self._vm.root_cfg_node))
   t = abstract.TypeParameter(abstract.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               abstract.FunctionArgs(posargs=()))
   self.assertIs(node, self._node)
   retval, = ret.data
   self.assertListEqual(retval.cls.data, [self._vm.convert.int_type])
Example #22
0
 def testToTypeWithView2(self):
     # to_type(<instance of <str or unsolvable>>, view={__class__: str})
     cls = self._vm.program.NewVariable([self._vm.convert.unsolvable], [],
                                        self._vm.root_cfg_node)
     cls_binding = cls.AddBinding(self._vm.convert.str_type.data[0], [],
                                  self._vm.root_cfg_node)
     instance = abstract.Instance(cls, self._vm, self._vm.root_cfg_node)
     view = {cls: cls_binding}
     pytd_type = instance.to_type(self._vm.root_cfg_node,
                                  seen=None,
                                  view=view)
     self.assertEquals("__builtin__.str", pytd_type.name)
Example #23
0
 def test_call_type_parameter_instance(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   instance.merge_instance_type_parameter(
       self._vm.root_cfg_node, abstract_utils.T,
       self._vm.convert.int_type.to_variable(self._vm.root_cfg_node))
   t = abstract.TypeParameter(abstract_utils.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               function.Args(posargs=()))
   self.assertIs(node, self._node)
   retval, = ret.data
   self.assertEqual(retval.cls, self._vm.convert.int_type)
Example #24
0
 def testCallTypeParameterInstanceWithWrongArgs(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   instance.initialize_type_parameter(
       self._node, abstract.T,
       self._vm.convert.int_type.to_variable(self._vm.root_cfg_node))
   t = abstract.TypeParameter(abstract.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   posargs = (self._vm.convert.create_new_unsolvable(self._node),) * 3
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               abstract.FunctionArgs(posargs=posargs))
   self.assertIs(node, self._node)
   self.assertTrue(ret.bindings)
   error, = self._vm.errorlog
   self.assertEqual(error.name, "wrong-arg-count")
Example #25
0
 def test_call_type_parameter_instance_with_wrong_args(self):
   instance = abstract.Instance(self._vm.convert.list_type, self._vm)
   instance.merge_instance_type_parameter(
       self._vm.root_cfg_node, abstract_utils.T,
       self._vm.convert.int_type.to_variable(self._vm.root_cfg_node))
   t = abstract.TypeParameter(abstract_utils.T, self._vm)
   t_instance = abstract.TypeParameterInstance(t, instance, self._vm)
   posargs = (self._vm.new_unsolvable(self._node),) * 3
   node, ret = t_instance.call(self._node, t_instance.to_binding(self._node),
                               function.Args(posargs=posargs))
   self.assertIs(node, self._node)
   self.assertTrue(ret.bindings)
   error, = self._vm.errorlog
   self.assertEqual(error.name, "wrong-arg-count")
Example #26
0
 def instantiate(self, node, container=None):
     # Instantiate creates a canonical enum member. This intended for when no
     # particular enum member is needed, e.g. during analysis. Real members have
     # these fields set during class creation.
     # TODO(tsudol): Use the types of other members to set `value`.
     del container
     instance = abstract.Instance(self, self.vm)
     instance.members["name"] = self.vm.convert.build_string(node, "")
     if self.member_type:
         value = self.member_type.instantiate(node)
     else:
         # instantiate() should never be called before setup_interpreterclass sets
         # self.member_type, because pytype will complain about recursive types.
         # But there's no reason not to make sure this function is safe.
         value = self.vm.new_unsolvable(node)
     instance.members["value"] = value
     return instance.to_variable(node)
Example #27
0
 def _setup_interpreterclass(self, node, cls):
     member_types = []
     for name, value in self._get_class_locals(node, cls.name, cls.members):
         # Build instances directly, because you can't call instantiate() when
         # creating the class -- pytype complains about recursive types.
         member = abstract.Instance(cls, self.vm)
         member.members["value"] = value.orig
         member.members["name"] = self.vm.convert.build_string(node, name)
         cls.members[name] = member.to_variable(node)
         member_types.extend(value.orig.data)
     if not member_types:
         member_types.append(self.vm.convert.unsolvable)
     member_type = self.vm.convert.merge_classes(member_types)
     cls.member_type = member_type
     cls.members["__new__"] = self._make_new(node, member_type, cls)
     cls.members["__eq__"] = EnumCmpEQ(self.vm).to_variable(node)
     return node
Example #28
0
 def testToTypeWithView1(self):
     # to_type(<instance of List[int or unsolvable]>, view={T: int})
     instance = abstract.Instance(self._vm.convert.list_type, self._vm,
                                  self._vm.root_cfg_node)
     instance.type_parameters["T"] = self._vm.program.NewVariable(
         [self._vm.convert.unsolvable], [], self._vm.root_cfg_node)
     param_binding = instance.type_parameters["T"].AddBinding(
         self._vm.convert.primitive_class_instances[int], [],
         self._vm.root_cfg_node)
     view = {
         instance.cls: instance.cls.bindings[0],
         instance.type_parameters["T"]: param_binding,
         param_binding.data.cls: param_binding.data.cls.bindings[0]
     }
     pytd_type = instance.to_type(self._vm.root_cfg_node,
                                  seen=None,
                                  view=view)
     self.assertEquals("__builtin__.list", pytd_type.base_type.name)
     self.assertSetEqual({"__builtin__.int"},
                         {t.name
                          for t in pytd_type.parameters})
Example #29
0
 def test_compatible_with_non_container(self):
     # Compatible with either True or False.
     i = abstract.Instance(self._vm.convert.object_type, self._vm)
     self.assertIs(True, i.compatible_with(True))
     self.assertIs(True, i.compatible_with(False))
Example #30
0
    def _constant_to_value(self, pyval, subst, get_node):
        """Create a AtomicAbstractValue that represents a python constant.

    This supports both constant from code constant pools and PyTD constants such
    as classes. This also supports builtin python objects such as int and float.

    Args:
      pyval: The python or PyTD value to convert.
      subst: The current type parameters.
      get_node: A getter function for the current node.
    Returns:
      A Value that represents the constant, or None if we couldn't convert.
    Raises:
      NotImplementedError: If we don't know how to convert a value.
      TypeParameterError: If we can't find a substitution for a type parameter.
    """
        if pyval.__class__ is str:
            # We use a subclass of str, compat.BytesPy3, to mark Python 3
            # bytestrings, which are converted to abstract bytes instances.
            # compat.BytesType dispatches to this when appropriate.
            return abstract.AbstractOrConcreteValue(pyval, self.str_type,
                                                    self.vm)
        elif isinstance(pyval, compat.UnicodeType):
            return abstract.AbstractOrConcreteValue(pyval, self.unicode_type,
                                                    self.vm)
        elif isinstance(pyval, compat.BytesType):
            return abstract.AbstractOrConcreteValue(pyval, self.bytes_type,
                                                    self.vm)
        elif isinstance(pyval, bool):
            return self.true if pyval is True else self.false
        elif isinstance(pyval, int) and -1 <= pyval <= MAX_IMPORT_DEPTH:
            # For small integers, preserve the actual value (for things like the
            # level in IMPORT_NAME).
            return abstract.AbstractOrConcreteValue(pyval, self.int_type,
                                                    self.vm)
        elif isinstance(pyval, compat.LongType):
            # long is aliased to int
            return self.primitive_class_instances[int]
        elif pyval.__class__ in self.primitive_classes:
            return self.primitive_class_instances[pyval.__class__]
        elif isinstance(pyval, (loadmarshal.CodeType, blocks.OrderedCode)):
            return abstract.AbstractOrConcreteValue(
                pyval, self.primitive_classes[types.CodeType], self.vm)
        elif pyval is super:
            return special_builtins.Super(self.vm)
        elif pyval is object:
            return special_builtins.Object(self.vm)
        elif pyval.__class__ is type:
            try:
                return self.name_to_value(self._type_to_name(pyval), subst)
            except (KeyError, AttributeError):
                log.debug("Failed to find pytd", exc_info=True)
                raise
        elif isinstance(pyval, pytd.LateType):
            actual = self._load_late_type(pyval)
            return self._constant_to_value(actual, subst, get_node)
        elif isinstance(pyval, pytd.TypeDeclUnit):
            return self._create_module(pyval)
        elif isinstance(pyval, pytd.Module):
            mod = self.vm.loader.import_name(pyval.module_name)
            return self._create_module(mod)
        elif isinstance(pyval, pytd.Class):
            if pyval.name == "__builtin__.super":
                return self.vm.special_builtins["super"]
            elif pyval.name == "__builtin__.object":
                return self.object_type
            elif pyval.name == "types.ModuleType":
                return self.module_type
            elif pyval.name == "_importlib_modulespec.ModuleType":
                # Python 3's typeshed uses a stub file indirection to define ModuleType
                # even though it is exported via types.pyi.
                return self.module_type
            else:
                module, dot, base_name = pyval.name.rpartition(".")
                try:
                    cls = abstract.PyTDClass(base_name, pyval, self.vm)
                except mro.MROError as e:
                    self.vm.errorlog.mro_error(self.vm.frames, base_name,
                                               e.mro_seqs)
                    cls = self.unsolvable
                else:
                    if dot:
                        cls.module = module
                return cls
        elif isinstance(pyval, pytd.Function):
            signatures = [
                abstract.PyTDSignature(pyval.name, sig, self.vm)
                for sig in pyval.signatures
            ]
            type_new = self.vm.lookup_builtin("__builtin__.type").Lookup(
                "__new__")
            if pyval is type_new:
                f_cls = special_builtins.TypeNew
            else:
                f_cls = abstract.PyTDFunction
            f = f_cls(pyval.name, signatures, pyval.kind, self.vm)
            f.is_abstract = pyval.is_abstract
            return f
        elif isinstance(pyval, pytd.ClassType):
            assert pyval.cls
            return self.constant_to_value(pyval.cls, subst,
                                          self.vm.root_cfg_node)
        elif isinstance(pyval, pytd.NothingType):
            return self.empty
        elif isinstance(pyval, pytd.AnythingType):
            return self.unsolvable
        elif (isinstance(pyval, pytd.Constant)
              and isinstance(pyval.type, pytd.AnythingType)):
            # We allow "X = ... # type: Any" to declare X as a type.
            return self.unsolvable
        elif isinstance(pyval, pytd.FunctionType):
            return self.constant_to_value(pyval.function, subst,
                                          self.vm.root_cfg_node)
        elif isinstance(pyval, pytd.UnionType):
            options = [
                self.constant_to_value(t, subst, self.vm.root_cfg_node)
                for t in pyval.type_list
            ]
            if len(options) > 1:
                return abstract.Union(options, self.vm)
            else:
                return options[0]
        elif isinstance(pyval, pytd.TypeParameter):
            constraints = tuple(
                self.constant_to_value(c, {}, self.vm.root_cfg_node)
                for c in pyval.constraints)
            bound = (pyval.bound and self.constant_to_value(
                pyval.bound, {}, self.vm.root_cfg_node))
            return abstract.TypeParameter(pyval.name,
                                          self.vm,
                                          constraints=constraints,
                                          bound=bound)
        elif isinstance(pyval, abstract.AsInstance):
            cls = pyval.cls
            if isinstance(cls, pytd.LateType):
                actual = self._load_late_type(cls)
                if not isinstance(actual, pytd.ClassType):
                    return self.unsolvable
                cls = actual.cls
            if isinstance(cls, pytd.ClassType):
                cls = cls.cls
            if (isinstance(cls, pytd.GenericType)
                    and cls.base_type.name == "typing.ClassVar"):
                param, = cls.parameters
                return self.constant_to_value(abstract.AsInstance(param),
                                              subst, self.vm.root_cfg_node)
            elif isinstance(cls,
                            pytd.GenericType) or (isinstance(cls, pytd.Class)
                                                  and cls.template):
                # If we're converting a generic Class, need to create a new instance of
                # it. See test_classes.testGenericReinstantiated.
                if isinstance(cls, pytd.Class):
                    params = tuple(t.type_param.upper_value
                                   for t in cls.template)
                    cls = pytd.GenericType(base_type=pytd.ClassType(
                        cls.name, cls),
                                           parameters=params)
                if isinstance(cls.base_type, pytd.LateType):
                    actual = self._load_late_type(cls.base_type)
                    if not isinstance(actual, pytd.ClassType):
                        return self.unsolvable
                    base_cls = actual.cls
                else:
                    assert isinstance(cls.base_type, pytd.ClassType)
                    base_cls = cls.base_type.cls
                assert isinstance(base_cls, pytd.Class), base_cls
                if base_cls.name == "__builtin__.type":
                    c, = cls.parameters
                    if isinstance(c, pytd.TypeParameter):
                        if not subst or c.name not in subst:
                            raise self.TypeParameterError(c.name)
                        return self.merge_classes(get_node(),
                                                  subst[c.name].data)
                    else:
                        return self.constant_to_value(c, subst,
                                                      self.vm.root_cfg_node)
                elif isinstance(cls, pytd.TupleType):
                    content = tuple(
                        self.constant_to_var(abstract.AsInstance(p), subst,
                                             get_node())
                        for p in cls.parameters)
                    return abstract.Tuple(content, self.vm)
                elif isinstance(cls, pytd.CallableType):
                    clsval = self.constant_to_value(cls, subst,
                                                    self.vm.root_cfg_node)
                    return abstract.Instance(clsval, self.vm)
                else:
                    clsval = self.constant_to_value(base_cls, subst,
                                                    self.vm.root_cfg_node)
                    instance = abstract.Instance(clsval, self.vm)
                    num_params = len(cls.parameters)
                    assert num_params <= len(base_cls.template)
                    for i, formal in enumerate(base_cls.template):
                        if i < num_params:
                            node = get_node()
                            p = self.constant_to_var(
                                abstract.AsInstance(cls.parameters[i]), subst,
                                node)
                        else:
                            # An omitted type parameter implies `Any`.
                            node = self.vm.root_cfg_node
                            p = self.unsolvable.to_variable(node)
                        instance.merge_type_parameter(node, formal.name, p)
                    return instance
            elif isinstance(cls, pytd.Class):
                assert not cls.template
                # This key is also used in __init__
                key = (abstract.Instance, cls)
                if key not in self._convert_cache:
                    if cls.name in [
                            "__builtin__.type", "__builtin__.property"
                    ]:
                        # An instance of "type" or of an anonymous property can be anything.
                        instance = self._create_new_unknown_value("type")
                    else:
                        mycls = self.constant_to_value(cls, subst,
                                                       self.vm.root_cfg_node)
                        instance = abstract.Instance(mycls, self.vm)
                    log.info("New pytd instance for %s: %r", cls.name,
                             instance)
                    self._convert_cache[key] = instance
                return self._convert_cache[key]
            else:
                return self.constant_to_value(cls, subst,
                                              self.vm.root_cfg_node)
        elif (isinstance(pyval, pytd.GenericType)
              and pyval.base_type.name == "typing.ClassVar"):
            param, = pyval.parameters
            return self.constant_to_value(param, subst, self.vm.root_cfg_node)
        elif isinstance(pyval, pytd.GenericType):
            if isinstance(pyval.base_type, pytd.LateType):
                actual = self._load_late_type(pyval.base_type)
                if not isinstance(actual, pytd.ClassType):
                    return self.unsolvable
                base = actual.cls
            else:
                assert isinstance(pyval.base_type, pytd.ClassType)
                base = pyval.base_type.cls
            assert isinstance(base, pytd.Class), base
            base_cls = self.constant_to_value(base, subst,
                                              self.vm.root_cfg_node)
            if not isinstance(base_cls, abstract.Class):
                # base_cls can be, e.g., an unsolvable due to an mro error.
                return self.unsolvable
            if isinstance(pyval, pytd.TupleType):
                abstract_class = abstract.TupleClass
                template = list(range(len(pyval.parameters))) + [abstract.T]
                parameters = pyval.parameters + (pytd.UnionType(
                    pyval.parameters), )
            elif isinstance(pyval, pytd.CallableType):
                abstract_class = abstract.Callable
                template = list(range(len(
                    pyval.args))) + [abstract.ARGS, abstract.RET]
                parameters = pyval.args + (pytd_utils.JoinTypes(
                    pyval.args), pyval.ret)
            else:
                abstract_class = abstract.ParameterizedClass
                template = tuple(t.name for t in base.template)
                parameters = pyval.parameters
            assert (pyval.base_type.name == "typing.Generic"
                    or len(parameters) <= len(template))
            type_parameters = datatypes.LazyDict()
            for i, name in enumerate(template):
                if i < len(parameters):
                    type_parameters.add_lazy_item(name, self.constant_to_value,
                                                  parameters[i], subst,
                                                  self.vm.root_cfg_node)
                else:
                    type_parameters[name] = self.unsolvable
            return abstract_class(base_cls, type_parameters, self.vm)
        elif pyval.__class__ is tuple:  # only match raw tuple, not namedtuple/Node
            return self.tuple_to_value([
                self.constant_to_var(item, subst, self.vm.root_cfg_node)
                for i, item in enumerate(pyval)
            ])
        else:
            raise NotImplementedError("Can't convert constant %s %r" %
                                      (type(pyval), pyval))