예제 #1
0
    def get_possible_types_from_node(self, node, only_definitions=True):
        """
        Find all possible types for a given node.

        Arguments
        ---------
        node : VyperNode
            The vyper AST node to find a type for.
        only_definitions: bool, optional
            If True, raises when the return value is not a type definition
            e.g a primitive, meta type, or function call

        Returns
        -------
        List
            A list of type objects
        """
        fn = self._find_fn(node)
        types_list = fn(node)
        if only_definitions:
            invalid = next(
                (i
                 for i in types_list if not isinstance(i, BaseTypeDefinition)),
                None)
            if invalid:
                if isinstance(invalid,
                              type) and types.BasePrimitive in invalid.mro():
                    raise InvalidReference(
                        f"'{invalid._id}' is a type - expected a literal or variable",
                        node)
                else:
                    raise InvalidReference("Expected a literal or variable",
                                           node)
        return types_list
예제 #2
0
파일: utils.py 프로젝트: vyperlang/vyper
    def get_possible_types_from_node(self, node, only_definitions=True):
        """
        Find all possible types for a given node.
        If the node's metadata contains type information propagated from constant folding,
        then that type is returned.

        Arguments
        ---------
        node : VyperNode
            The vyper AST node to find a type for.
        only_definitions: bool, optional
            If True, raises when the return value is not a type definition
            e.g a primitive, meta type, or function call

        Returns
        -------
        List
            A list of type objects
        """
        # Early termination if typedef is propagated in metadata
        if "type" in node._metadata:
            return [node._metadata["type"]]

        fn = self._find_fn(node)
        types_list = fn(node)
        if only_definitions:
            invalid = next(
                (i
                 for i in types_list if not isinstance(i, BaseTypeDefinition)),
                None)
            if invalid:
                if isinstance(invalid,
                              type) and types.BasePrimitive in invalid.mro():
                    raise InvalidReference(
                        f"'{invalid._id}' is a type - expected a literal or variable",
                        node)
                else:
                    raise InvalidReference("Expected a literal or variable",
                                           node)

        if all(isinstance(i, IntegerAbstractType) for i in types_list):
            # for numeric types, sort according by number of bits descending
            # we do this to ensure literals are cast with the largest possible type
            return sorted(types_list,
                          key=lambda k: (k._bits, not k._is_signed),
                          reverse=True)
        return types_list
예제 #3
0
파일: utils.py 프로젝트: saliksyed/vyper
 def types_from_Name(self, node):
     # variable name, e.g. `foo`
     name = node.id
     if name not in self.namespace and name in self.namespace["self"].members:
         raise InvalidReference(
             f"'{name}' is a storage variable, access it as self.{name}", node,
         )
     try:
         return [self.namespace[node.id]]
     except VyperException as exc:
         raise exc.with_annotation(node) from None
예제 #4
0
 def types_from_Attribute(self, node):
     # variable attribute, e.g. `foo.bar`
     var = self.get_exact_type_from_node(node.value)
     name = node.attr
     try:
         return [var.get_member(name, node)]
     except UnknownAttribute:
         if node.get("value.id") != "self":
             raise
         if name in self.namespace:
             raise InvalidReference(
                 f"'{name}' is not a storage variable, it should not be prepended with self",
                 node,
             ) from None
         raise UndeclaredDefinition(
             f"Storage variable '{name}' has not been declared",
             node) from None
예제 #5
0
파일: utils.py 프로젝트: vyperlang/vyper
    def types_from_Attribute(self, node):
        # variable attribute, e.g. `foo.bar`
        var = self.get_exact_type_from_node(node.value, only_definitions=False)
        name = node.attr
        try:
            return [var.get_member(name, node)]
        except UnknownAttribute:
            if node.get("value.id") != "self":
                raise
            if name in self.namespace:
                raise InvalidReference(
                    f"'{name}' is not a storage variable, it should not be prepended with self",
                    node,
                ) from None

            suggestions_str = get_levenshtein_error_suggestions(
                name, var.members, 0.4)
            raise UndeclaredDefinition(
                f"Storage variable '{name}' has not been declared. {suggestions_str}",
                node) from None
예제 #6
0
파일: utils.py 프로젝트: saliksyed/vyper
def validate_expected_type(node, expected_type):
    """
    Validate that the given node matches the expected type(s)

    Raises if the node does not match one of the expected types.

    Arguments
    ---------
    node : VyperNode
        Vyper ast node.
    expected_type : Tuple | BaseType
        A type object, or tuple of type objects

    Returns
    -------
    None
    """
    given_types = _ExprTypeChecker().get_possible_types_from_node(node)
    if not isinstance(expected_type, tuple):
        expected_type = (expected_type,)

    if isinstance(node, (vy_ast.List, vy_ast.Tuple)):
        # special case - for literal arrays or tuples we individually validate each item
        for expected in (i for i in expected_type if isinstance(i, ArrayDefinition)):
            if _validate_literal_array(node, expected):
                return
    else:
        for given, expected in itertools.product(given_types, expected_type):
            if expected.compare_type(given):
                return

    # validation failed, prepare a meaningful error message
    if len(expected_type) > 1:
        expected_str = f"one of {', '.join(str(i) for i in expected_type)}"
    else:
        expected_str = expected_type[0]

    if len(given_types) == 1 and getattr(given_types[0], "_is_callable", False):
        raise StructureException(
            f"{given_types[0]} cannot be referenced directly, it must be called", node
        )

    if not isinstance(node, (vy_ast.List, vy_ast.Tuple)) and node.get_descendants(
        vy_ast.Name, include_self=True
    ):
        given = given_types[0]
        if isinstance(given, type) and types.BasePrimitive in given.mro():
            raise InvalidReference(
                f"'{given._id}' is a type - expected a literal or variable", node
            )
        raise TypeMismatch(f"Given reference has type {given}, expected {expected_str}", node)
    else:
        if len(given_types) == 1:
            given_str = str(given_types[0])
        else:
            types_str = sorted(str(i) for i in given_types)
            given_str = f"{', '.join(types_str[:1])} or {types_str[-1]}"

        raise InvalidType(
            f"Expected {expected_str} but literal can only be cast as {given_str}", node
        )