Ejemplo n.º 1
0
 def check_method_or_accessor_override_for_base(self, defn, base):
     """Check that function definition is compatible with any overridden
     definition in the specified supertype.
     """
     if base:
         if defn.name() != '__init__':
             # Check method override (create is special).
             base_method = base.get_method(defn.name())
             if base_method and base_method.info == base:
                 # There is an overridden method in the supertype.
                 
                 # Construct the type of the overriding method.
                 typ = method_type(defn)
                 # Map the overridden method type to subtype context so that
                 # it can be checked for compatibility. Note that multiple
                 # types from multiple implemented interface instances may
                 # be present.
                 original_type = map_type_from_supertype(
                     method_type(base_method), defn.info, base)
                 # Check that the types are compatible.
                 # TODO overloaded signatures
                 self.check_override(typ,
                                     original_type,
                                     defn.name(),
                                     base_method.info.name(),
                                     defn)
         
         # Also check interface implementations.
         for iface in base.interfaces:
             self.check_method_or_accessor_override_for_base(defn, iface)
         
         # We have to check that the member is compatible with all
         # supertypes due to the dynamic type. Otherwise we could first
         # override with dynamic and then with an arbitary type.
         self.check_method_or_accessor_override_for_base(defn, base.base)
Ejemplo n.º 2
0
def type_object_type(info: TypeInfo, builtin_type: Function[[str], Instance]) -> Type:
    """Return the type of a type object.

    For a generic type G with type variables T and S the type is of form

      def [T, S](...) -> G[T, S],

    where ... are argument types for the __init__ method (without the self argument).
    """
    init_method = info.get_method('__init__')
    if not init_method:
        # Must be an invalid class definition.
        return AnyType()
    else:
        # Construct callable type based on signature of __init__. Adjust
        # return type and insert type arguments.
        init_type = method_type(init_method, builtin_type('builtins.function'))
        if isinstance(init_type, Callable):
            return class_callable(init_type, info, builtin_type('builtins.type'))
        else:
            # Overloaded __init__.
            items = []  # type: List[Callable]
            for it in cast(Overloaded, init_type).items():
                items.append(class_callable(it, info, builtin_type('builtins.type')))
            return Overloaded(items)
Ejemplo n.º 3
0
def type_object_type(info: TypeInfo, type_type: Function[[], Type]) -> Type:
    """Return the type of a type object.

    For a generic type G with type variables T and S the type is of form

      def [T, S](...) -> G[T, S],

    where ... are argument types for the __init__ method.
    """
    init_method = info.get_method('__init__')
    if not init_method:
        # Must be an invalid class definition.
        return AnyType()
    else:
        # Construct callable type based on signature of __init__. Adjust
        # return type and insert type arguments.
        init_type = method_type(init_method)
        if isinstance(init_type, Callable):
            return class_callable(init_type, info)
        else:
            # Overloaded __init__.
            items = []  # type: List[Callable]
            for it in cast(Overloaded, init_type).items():
                items.append(class_callable(it, info))
            return Overloaded(items)
Ejemplo n.º 4
0
def analyse_member_var_access(name: str, itype: Instance, info: TypeInfo,
                              node: Context, is_lvalue: bool, is_super: bool,
                              msg: MessageBuilder,
                              report_type: Type = None) -> Type:
    """Analyse attribute access that does not target a method.

    This is logically part of analyse_member_access and the arguments are
    similar.
    """
    # It was not a method. Try looking up a variable.
    v = lookup_member_var_or_accessor(info, name, is_lvalue)

    vv = v
    if isinstance(vv, Decorator):
        # The associated Var node of a decorator contains the type.
        v = vv.var

    if isinstance(v, Var):
        # Found a member variable.
        var = v
        itype = map_instance_to_supertype(itype, var.info)
        if var.type:
            t = expand_type_by_instance(var.type, itype)
            if var.is_initialized_in_class and isinstance(t, FunctionLike):
                if is_lvalue:
                    if var.is_property:
                        msg.read_only_property(name, info, node)
                    else:
                        msg.cant_assign_to_method(node)

                if not var.is_staticmethod:
                    # Class-level function objects and classmethods become bound
                    # methods: the former to the instance, the latter to the
                    # class.
                    functype = cast(FunctionLike, t)
                    check_method_type(functype, itype, node, msg)
                    signature = method_type(functype)
                    if var.is_property:
                        # A property cannot have an overloaded type => the cast
                        # is fine.
                        return cast(Callable, signature).ret_type
                    else:
                        return signature
            return t
        else:
            if not var.is_ready:
                msg.cannot_determine_type(var.name(), node)
            # Implicit 'Any' type.
            return AnyType()
    elif isinstance(v, FuncDef):
        assert False, "Did not expect a function"

    # Could not find the member.
    if is_super:
        msg.undefined_in_superclass(name, node)
        return AnyType()
    else:
        return msg.has_no_attr(report_type or itype, name, node)
Ejemplo n.º 5
0
def analyse_member_var_access(name: str,
                              itype: Instance,
                              info: TypeInfo,
                              node: Context,
                              is_lvalue: bool,
                              is_super: bool,
                              msg: MessageBuilder,
                              report_type: Type = None) -> Type:
    """Analyse attribute access that does not target a method.

    This is logically part of analyse_member_access and the arguments are
    similar.
    """
    # It was not a method. Try looking up a variable.
    v = lookup_member_var_or_accessor(info, name, is_lvalue)

    vv = v
    if isinstance(vv, Decorator):
        # The associated Var node of a decorator contains the type.
        v = vv.var

    if isinstance(v, Var):
        # Found a member variable.
        var = v
        itype = map_instance_to_supertype(itype, var.info)
        if var.type:
            t = expand_type_by_instance(var.type, itype)
            if (var.is_initialized_in_class and isinstance(t, FunctionLike)
                    and not var.is_staticmethod):
                # Class-level function object becomes a bound method.
                functype = cast(FunctionLike, t)
                check_method_type(functype, itype, node, msg)
                signature = method_type(functype)
                if var.is_property:
                    if is_lvalue:
                        msg.read_only_property(name, info, node)
                    # A property cannot have an overloaded type => the cast
                    # is fine.
                    return cast(Callable, signature).ret_type
                else:
                    return signature
            return t
        else:
            if not var.is_ready:
                msg.cannot_determine_type(var.name(), node)
            # Implicit 'Any' type.
            return AnyType()
    elif isinstance(v, FuncDef):
        assert False, "Did not expect a function"

    # Could not find the member.
    if is_super:
        msg.undefined_in_superclass(name, node)
        return AnyType()
    else:
        return msg.has_no_attr(report_type or itype, name, node)
Ejemplo n.º 6
0
def analyze_var(
    name: str,
    var: Var,
    itype: Instance,
    info: TypeInfo,
    node: Context,
    is_lvalue: bool,
    msg: MessageBuilder,
    not_ready_callback: Callable[[str, Context], None],
) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return handle_partial_attribute_type(typ, is_lvalue, msg, var)
        t = expand_type_by_instance(typ, itype)
        if is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            msg.read_only_property(name, info, node)
        if var.is_initialized_in_class and isinstance(t, FunctionLike):
            if is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        msg.read_only_property(name, info, node)
                else:
                    msg.cant_assign_to_method(node)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound
                # methods: the former to the instance, the latter to the
                # class.
                functype = t
                check_method_type(functype, itype, var.is_classmethod, node, msg)
                signature = method_type(functype)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast
                    # is fine.
                    return cast(CallableType, signature).ret_type
                else:
                    return signature
        return t
    else:
        if not var.is_ready:
            not_ready_callback(var.name(), node)
        # Implicit 'Any' type.
        return AnyType()
Ejemplo n.º 7
0
def analyse_member_access(name, typ, node, is_lvalue, is_super, tuple_type, msg, override_info=None):
    """Analyse member access.

    This is a general operation that supports various different variations:
    
      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    if isinstance(typ, Instance):
        if name == "__init__" and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return Any()

        # The base object has an instance type.
        itype = typ

        info = itype.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = None
        if not is_lvalue:
            method = info.get_method(name)

        if method:
            # Found a method. The call below has a unique result for all valid
            # programs.
            itype = map_instance_to_supertype(itype, method.info)
            return expand_type_by_instance(method_type(method), itype)
        else:
            # Not a method.
            return analyse_member_var_access(name, itype, info, node, is_lvalue, is_super, msg)
    elif isinstance(typ, Any):
        # The base object has dynamic type.
        return Any()
    elif isinstance(typ, TupleType):
        # Actually look up from the tuple type.
        return analyse_member_access(name, tuple_type, node, is_lvalue, is_super, tuple_type, msg)
    elif isinstance(typ, Callable) and (typ).is_type_obj():
        # Class attribute access.
        return msg.not_implemented("class attributes", node)
    else:
        # The base object has an unsupported type.
        return msg.has_no_member(typ, name, node)
Ejemplo n.º 8
0
def analyze_var(name: str, var: Var, itype: Instance, info: TypeInfo,
                node: Context, is_lvalue: bool, msg: MessageBuilder,
                not_ready_callback: Callable[[str, Context], None]) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return handle_partial_attribute_type(typ, is_lvalue, msg, var)
        t = expand_type_by_instance(typ, itype)
        if is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            msg.read_only_property(name, info, node)
        if var.is_initialized_in_class and isinstance(t, FunctionLike):
            if is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        msg.read_only_property(name, info, node)
                else:
                    msg.cant_assign_to_method(node)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound
                # methods: the former to the instance, the latter to the
                # class.
                functype = t
                check_method_type(functype, itype, var.is_classmethod, node,
                                  msg)
                signature = method_type(functype)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast
                    # is fine.
                    return cast(CallableType, signature).ret_type
                else:
                    return signature
        return t
    else:
        if not var.is_ready:
            not_ready_callback(var.name(), node)
        # Implicit 'Any' type.
        return AnyType()
Ejemplo n.º 9
0
def analyze_var(
    name: str, var: Var, itype: Instance, info: TypeInfo, node: Context, is_lvalue: bool, msg: MessageBuilder
) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    if var.type:
        t = expand_type_by_instance(var.type, itype)
        if var.is_initialized_in_class and isinstance(t, FunctionLike):
            if is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        msg.read_only_property(name, info, node)
                else:
                    msg.cant_assign_to_method(node)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound
                # methods: the former to the instance, the latter to the
                # class.
                functype = cast(FunctionLike, t)
                check_method_type(functype, itype, node, msg)
                signature = method_type(functype)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast
                    # is fine.
                    return cast(CallableType, signature).ret_type
                else:
                    return signature
        return t
    else:
        if not var.is_ready:
            msg.cannot_determine_type(var.name(), node)
        # Implicit 'Any' type.
        return AnyType()
Ejemplo n.º 10
0
def analyze_var(name: str, var: Var, itype: Instance, info: TypeInfo,
                node: Context, is_lvalue: bool, msg: MessageBuilder) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    if var.type:
        t = expand_type_by_instance(var.type, itype)
        if var.is_initialized_in_class and isinstance(t, FunctionLike):
            if is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        msg.read_only_property(name, info, node)
                else:
                    msg.cant_assign_to_method(node)

            if not var.is_staticmethod:
                # Class-level function objects and classmethods become bound
                # methods: the former to the instance, the latter to the
                # class.
                functype = cast(FunctionLike, t)
                check_method_type(functype, itype, node, msg)
                signature = method_type(functype)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast
                    # is fine.
                    return cast(CallableType, signature).ret_type
                else:
                    return signature
        return t
    else:
        if not var.is_ready:
            msg.cannot_determine_type(var.name(), node)
        # Implicit 'Any' type.
        return AnyType()
Ejemplo n.º 11
0
def analyse_member_var_access(name, itype, info, node, is_lvalue, is_super, msg):
    """Analyse member access that does not target a method.

    This is logically part of analyse_member_access and the arguments are
    similar.
    """
    # It was not a method. Try looking up a variable.
    v = lookup_member_var_or_accessor(info, name, is_lvalue)

    if isinstance(v, Var):
        # Found a member variable.
        var = v
        itype = map_instance_to_supertype(itype, var.info)
        if var.type:
            t = expand_type_by_instance(var.type, itype)
            if var.is_initialized_in_class and isinstance(t, FunctionLike):
                # Class-level function object becomes a bound method.
                functype = t
                check_method_type(functype, itype, node, msg)
                return method_type(functype)
            return t
        else:
            if not var.is_ready:
                msg.cannot_determine_type(var.name(), node)
            # Implicit 'any' type.
            return Any()
    elif isinstance(v, FuncDef):
        # Found a getter or a setter.
        raise NotImplementedError()

    # Could not find the member.
    if is_super:
        msg.undefined_in_superclass(name, node)
        return Any()
    else:
        return msg.has_no_member(itype, name, node)
Ejemplo n.º 12
0
def analyse_member_access(name: str, typ: Type, node: Context, is_lvalue: bool,
                          is_super: bool,
                          builtin_type: Function[[str], Instance],
                          msg: MessageBuilder, override_info: TypeInfo = None,
                          report_type: Type = None) -> Type:
    """Analyse attribute access.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    report_type = report_type or typ
    if isinstance(typ, Instance):
        if name == '__init__' and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType()

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if is_lvalue:
                msg.cant_assign_to_method(node)
            typ = map_instance_to_supertype(typ, method.info)
            return expand_type_by_instance(
                method_type(method, builtin_type('builtins.function')), typ)
        else:
            # Not a method.
            return analyse_member_var_access(name, typ, info, node,
                                             is_lvalue, is_super, msg,
                                             report_type=report_type)
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType()
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [analyse_member_access(name, subtype, node, is_lvalue,
                                         is_super, builtin_type, msg)
                   for subtype in typ.items]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the fallback instance type.
        return analyse_member_access(name, typ.fallback, node, is_lvalue,
                                     is_super, builtin_type, msg)
    elif (isinstance(typ, FunctionLike) and
          cast(FunctionLike, typ).is_type_obj()):
        # Class attribute.
        # TODO super?
        sig = cast(FunctionLike, typ)
        itype = cast(Instance, sig.items()[0].ret_type)
        result = analyse_class_attribute_access(itype, name, node, is_lvalue, builtin_type, msg)
        if result:
            return result
        # Look up from the 'type' type.
        return analyse_member_access(name, sig.fallback, node, is_lvalue, is_super,
                                     builtin_type, msg, report_type=report_type)
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyse_member_access(name, typ.fallback, node, is_lvalue, is_super,
                                     builtin_type, msg, report_type=report_type)
    return msg.has_no_attr(report_type, name, node)
Ejemplo n.º 13
0
def analyse_member_access(name: str,
                          typ: Type,
                          node: Context,
                          is_lvalue: bool,
                          is_super: bool,
                          basic_types: BasicTypes,
                          msg: MessageBuilder,
                          override_info: TypeInfo = None,
                          report_type: Type = None) -> Type:
    """Analyse attribute access.

    This is a general operation that supports various different variations:

      1. lvalue or non-lvalue access (i.e. setter or getter access)
      2. supertype access (when using super(); is_super == True and
         override_info should refer to the supertype)
    """
    report_type = report_type or typ
    if isinstance(typ, Instance):
        if name == '__init__' and not is_super:
            # Accessing __init__ in statically typed code would compromise
            # type safety unless used via super().
            msg.fail(messages.CANNOT_ACCESS_INIT, node)
            return AnyType()

        # The base object has an instance type.

        info = typ.type
        if override_info:
            info = override_info

        # Look up the member. First look up the method dictionary.
        method = info.get_method(name)
        if method:
            if is_lvalue:
                msg.cant_assign_to_method(node)
            typ = map_instance_to_supertype(typ, method.info)
            return expand_type_by_instance(method_type(method), typ)
        else:
            # Not a method.
            return analyse_member_var_access(name,
                                             typ,
                                             info,
                                             node,
                                             is_lvalue,
                                             is_super,
                                             msg,
                                             report_type=report_type)
    elif isinstance(typ, AnyType):
        # The base object has dynamic type.
        return AnyType()
    elif isinstance(typ, UnionType):
        # The base object has dynamic type.
        msg.disable_type_names += 1
        results = [
            analyse_member_access(name, subtype, node, is_lvalue, is_super,
                                  basic_types, msg) for subtype in typ.items
        ]
        msg.disable_type_names -= 1
        return UnionType.make_simplified_union(results)
    elif isinstance(typ, TupleType):
        # Actually look up from the 'tuple' type.
        return analyse_member_access(name, basic_types.tuple, node, is_lvalue,
                                     is_super, basic_types, msg)
    elif (isinstance(typ, FunctionLike)
          and cast(FunctionLike, typ).is_type_obj()):
        # Class attribute.
        # TODO super?
        sig = cast(FunctionLike, typ)
        itype = cast(Instance, sig.items()[0].ret_type)
        result = analyse_class_attribute_access(itype, name, node, is_lvalue,
                                                msg)
        if result:
            return result
        # Look up from the 'type' type.
        return analyse_member_access(name,
                                     basic_types.type_type,
                                     node,
                                     is_lvalue,
                                     is_super,
                                     basic_types,
                                     msg,
                                     report_type=report_type)
    elif isinstance(typ, FunctionLike):
        # Look up from the 'function' type.
        return analyse_member_access(name,
                                     basic_types.function,
                                     node,
                                     is_lvalue,
                                     is_super,
                                     basic_types,
                                     msg,
                                     report_type=report_type)
    return msg.has_no_attr(report_type, name, node)
Ejemplo n.º 14
0
     itype = (Instance)typ
     
     info = itype.type
     if override_info:
         info = override_info
     
     # Look up the member. First look up the method dictionary.
     FuncBase method = None
     if not is_lvalue:
         method = info.get_method(name)
     
     if method:
         # Found a method. The call below has a unique result for all valid
         # programs.
         itype = map_instance_to_supertype(itype, method.info)
         return expand_type_by_instance(method_type(method), itype)
     else:
         # Not a method.
         return analyse_member_var_access(name, itype, info, node,
                                          is_lvalue, is_super, msg)
 elif isinstance(typ, Any):
     # The base object has dynamic type.
     return Any()
 elif isinstance(typ, TupleType):
     # Actually look up from the tuple type.
     return analyse_member_access(name, tuple_type, node, is_lvalue,
                                  is_super, tuple_type, msg)
 elif isinstance(typ, Callable) and ((Callable)typ).is_type_obj():
     # Class attribute access.
     return msg.not_implemented('class attributes', node)
 else: