Ejemplo n.º 1
0
def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint],
                      strict: bool =True) -> List[Optional[Type]]:
    """Solve type constraints.

    Return the best type(s) for type variables; each type can be None if the value of the variable
    could not be solved.

    If a variable has no constraints, if strict=True then arbitrarily
    pick NoneTyp as the value of the type variable.  If strict=False,
    pick AnyType.
    """
    # Collect a list of constraints for each type variable.
    cmap = defaultdict(list)  # type: Dict[TypeVarId, List[Constraint]]
    for con in constraints:
        cmap[con.type_var].append(con)

    res = []  # type: List[Optional[Type]]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Optional[Type]
        top = None  # type: Optional[Type]
        candidate = None  # type: Optional[Type]

        # Process each constraint separately, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the constraint
        # targets do not have constraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target)

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            res.append(AnyType())
            continue
        elif bottom is None:
            if top:
                candidate = top
            else:
                # No constraints for type variable -- 'UninhabitedType' is the most specific type.
                if strict:
                    candidate = UninhabitedType()
                else:
                    candidate = AnyType()
        elif top is None:
            candidate = bottom
        elif is_subtype(bottom, top):
            candidate = bottom
        else:
            candidate = None
        res.append(candidate)

    return res
Ejemplo n.º 2
0
def solve_constraints(vars, constraints, basic):
    """Solve type constraints.

    Return lower bound for each type variable or None if the variable could
    not be solved.
    """
    # Collect a list of constraints for each type variable.
    cmap = {}
    for con in constraints:
        a = cmap.get(con.type_var, [])
        a.append(con)
        cmap[con.type_var] = a
    
    res = []

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None
        top = None
        
        # Process each contraint separely, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the contraint
        # targets do not have contraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target, basic)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target, basic)
        
        if top is None:
            if isinstance(bottom, Void):
                top = Void()
            else:
                top = basic.object
        
        if bottom is None:
            if isinstance(top, Void):
                bottom = Void()
            else:
                bottom = NoneTyp()
        
        if isinstance(top, Any) or isinstance(bottom, Any):
            top = Any()
            bottom = Any()
        
        # Pick the most specific type if it satisfies the constraints.
        if (not top or not bottom or is_subtype(bottom, top)) and (
                not isinstance(top, ErrorType) and
                not isinstance(bottom, ErrorType)):
            res.append(bottom)
        else:
            res.append(None)
    
    return res
Ejemplo n.º 3
0
 def assert_simple_meet(self, s: Type, t: Type, meet: Type) -> None:
     result = meet_types(s, t)
     actual = str(result)
     expected = str(meet)
     assert_equal(actual, expected,
                  'meet({}, {}) == {{}} ({{}} expected)'.format(s, t))
     assert is_subtype(result, s), '{} not subtype of {}'.format(result, s)
     assert is_subtype(result, t), '{} not subtype of {}'.format(result, t)
Ejemplo n.º 4
0
def solve_constraints(vars: List[int], constraints: List[Constraint],
                      basic: BasicTypes) -> List[Type]:
    """Solve type constraints.

    Return the best type(s) for type variables; each type can be None if the value of the variable
    could not be solved. If a variable has no constraints, arbitrarily pick NoneTyp as the value of
    the type variable.
    """
    # Collect a list of constraints for each type variable.
    cmap = Dict[int, List[Constraint]]()
    for con in constraints:
        a = cmap.get(con.type_var, [])
        a.append(con)
        cmap[con.type_var] = a

    res = []  # type: List[Type]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Type
        top = None  # type: Type

        # Process each contraint separely, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the constraint
        # targets do not have constraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target, basic)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target, basic)

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            res.append(AnyType())
            continue
        elif bottom is None:
            if top:
                candidate = top
            else:
                # No constraints for type variable -- type 'None' is the most specific type.
                candidate = NoneTyp()
        elif top is None:
            candidate = bottom
        elif is_subtype(bottom, top):
            candidate = bottom
        else:
            candidate = None
        if isinstance(candidate, ErrorType):
            res.append(None)
        else:
            res.append(candidate)

    return res
Ejemplo n.º 5
0
Archivo: join.py Proyecto: alanhdu/mypy
    def join_instances(self, t: Instance, s: Instance) -> ProperType:
        if (t, s) in self.seen_instances or (s, t) in self.seen_instances:
            return object_from_instance(t)

        self.seen_instances.append((t, s))
        """Calculate the join of two instance types."""
        if t.type == s.type:
            # Simplest case: join two types with the same base type (but
            # potentially different arguments).

            # Combine type arguments.
            args: List[Type] = []
            # N.B: We use zip instead of indexing because the lengths might have
            # mismatches during daemon reprocessing.
            for ta, sa, type_var in zip(t.args, s.args, t.type.defn.type_vars):
                ta_proper = get_proper_type(ta)
                sa_proper = get_proper_type(sa)
                new_type: Optional[Type] = None
                if isinstance(ta_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, ta_proper)
                elif isinstance(sa_proper, AnyType):
                    new_type = AnyType(TypeOfAny.from_another_any, sa_proper)
                elif type_var.variance == COVARIANT:
                    new_type = join_types(ta, sa, self)
                    if len(type_var.values
                           ) != 0 and new_type not in type_var.values:
                        self.seen_instances.pop()
                        return object_from_instance(t)
                    if not is_subtype(new_type, type_var.upper_bound):
                        self.seen_instances.pop()
                        return object_from_instance(t)
                elif type_var.variance == CONTRAVARIANT:
                    new_type = meet.meet_types(ta, sa)
                    if len(type_var.values
                           ) != 0 and new_type not in type_var.values:
                        self.seen_instances.pop()
                        return object_from_instance(t)
                    # No need to check subtype, as ta and sa already have to be subtypes of
                    # upper_bound
                elif type_var.variance == INVARIANT:
                    new_type = join_types(ta, sa)
                    if not is_equivalent(ta, sa):
                        self.seen_instances.pop()
                        return object_from_instance(t)
                assert new_type is not None
                args.append(new_type)
            result: ProperType = Instance(t.type, args)
        elif t.type.bases and is_subtype_ignoring_tvars(t, s):
            result = self.join_instances_via_supertype(t, s)
        else:
            # Now t is not a subtype of s, and t != s. Now s could be a subtype
            # of t; alternatively, we need to find a common supertype. This works
            # in of the both cases.
            result = self.join_instances_via_supertype(s, t)

        self.seen_instances.pop()
        return result
Ejemplo n.º 6
0
 def assert_simple_meet(self, s: Type, t: Type, meet: Type) -> None:
     result = meet_types(s, t)
     actual = str(result)
     expected = str(meet)
     assert_equal(actual, expected,
                  'meet({}, {}) == {{}} ({{}} expected)'.format(s, t))
     assert_true(is_subtype(result, s),
                 '{} not subtype of {}'.format(result, s))
     assert_true(is_subtype(result, t),
                 '{} not subtype of {}'.format(result, t))
Ejemplo n.º 7
0
 def assert_simple_meet(self, s, t, meet):
     result = meet_types(s, t)
     actual = str(result)
     expected = str(meet)
     assert_equal(actual, expected,
                  'meet({}, {}) == {{}} ({{}} expected)'.format(s, t))
     if not isinstance(s, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(result, s),
                     '{} not subtype of {}'.format(result, s))
     if not isinstance(t, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(result, t),
                     '{} not subtype of {}'.format(result, t))
Ejemplo n.º 8
0
 def assert_simple_meet(self, s, t, meet):
     result = meet_types(s, t)
     actual = str(result)
     expected = str(meet)
     assert_equal(actual, expected,
                  'meet({}, {}) == {{}} ({{}} expected)'.format(s, t))
     if not isinstance(s, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(result, s),
                     '{} not subtype of {}'.format(result, s))
     if not isinstance(t, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(result, t),
                     '{} not subtype of {}'.format(result, t))
Ejemplo n.º 9
0
def analyze_instance_member_access(name: str, typ: Instance, mx: MemberContext,
                                   override_info: Optional[TypeInfo]) -> Type:
    if name == '__init__' and not mx.is_super:
        # Accessing __init__ in statically typed code would compromise
        # type safety unless used via super().
        mx.msg.fail(message_registry.CANNOT_ACCESS_INIT, mx.context)
        return AnyType(TypeOfAny.from_error)

    # The base object has an instance type.

    info = typ.type
    if override_info:
        info = override_info

    if (state.find_occurrences and info.name == state.find_occurrences[0]
            and name == state.find_occurrences[1]):
        mx.msg.note("Occurrence of '{}.{}'".format(*state.find_occurrences),
                    mx.context)

    # Look up the member. First look up the method dictionary.
    method = info.get_method(name)
    if method:
        if method.is_property:
            assert isinstance(method, OverloadedFuncDef)
            first_item = cast(Decorator, method.items[0])
            return analyze_var(name, first_item.var, typ, info, mx)
        if mx.is_lvalue:
            mx.msg.cant_assign_to_method(mx.context)
        signature = function_type(method, mx.builtin_type('builtins.function'))
        signature = freshen_function_type_vars(signature)
        if name == '__new__':
            # __new__ is special and behaves like a static method -- don't strip
            # the first argument.
            pass
        else:
            if isinstance(signature, FunctionLike) and name != '__call__':
                # TODO: use proper treatment of special methods on unions instead
                #       of this hack here and below (i.e. mx.self_type).
                dispatched_type = meet.meet_types(mx.original_type, typ)
                signature = check_self_arg(signature, dispatched_type,
                                           method.is_class, mx.context, name,
                                           mx.msg)
            signature = bind_self(signature,
                                  mx.self_type,
                                  is_classmethod=method.is_class)
        typ = map_instance_to_supertype(typ, method.info)
        member_type = expand_type_by_instance(signature, typ)
        freeze_type_vars(member_type)
        return member_type
    else:
        # Not a method.
        return analyze_member_var_access(name, typ, info, mx)
Ejemplo n.º 10
0
def join_similar_callables(t: CallableType, s: CallableType) -> CallableType:
    from mypy.meet import meet_types
    arg_types = []  # type: List[Type]
    for i in range(len(t.arg_types)):
        arg_types.append(meet_types(t.arg_types[i], s.arg_types[i]))
    # TODO in combine_similar_callables also applies here (names and kinds)
    # The fallback type can be either 'function' or 'type'. The result should have 'type' as
    # fallback only if both operands have it as 'type'.
    if t.fallback.type.fullname() != 'builtins.type':
        fallback = t.fallback
    else:
        fallback = s.fallback
    return t.copy_modified(arg_types=arg_types,
                           ret_type=join_types(t.ret_type, s.ret_type),
                           fallback=fallback,
                           name=None)
Ejemplo n.º 11
0
def join_similar_callables(t: CallableType, s: CallableType) -> CallableType:
    from mypy.meet import meet_types
    arg_types = []  # type: List[Type]
    for i in range(len(t.arg_types)):
        arg_types.append(meet_types(t.arg_types[i], s.arg_types[i]))
    # TODO in combine_similar_callables also applies here (names and kinds)
    # The fallback type can be either 'function' or 'type'. The result should have 'type' as
    # fallback only if both operands have it as 'type'.
    if t.fallback.type.fullname() != 'builtins.type':
        fallback = t.fallback
    else:
        fallback = s.fallback
    return t.copy_modified(arg_types=arg_types,
                           ret_type=join_types(t.ret_type, s.ret_type),
                           fallback=fallback,
                           name=None)
Ejemplo n.º 12
0
def analyze_var(name: str,
                var: Var,
                itype: Instance,
                info: TypeInfo,
                mx: MemberContext,
                *,
                implicit: bool = False) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.

    itype is the class object in which var is defined
    original_type is the type of E in the expression E.var
    if implicit is True, the original Var was created as an assignment to self
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var,
                                                  mx.context)
        t = expand_type_by_instance(typ, itype)
        if mx.is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            mx.msg.read_only_property(name, itype.type, mx.context)
        if mx.is_lvalue and var.is_classvar:
            mx.msg.cant_assign_to_classvar(name, mx.context)
        result = t
        if var.is_initialized_in_class and isinstance(
                t, FunctionLike) and not t.is_type_obj():
            if mx.is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        mx.msg.read_only_property(name, itype.type, mx.context)
                else:
                    mx.msg.cant_assign_to_method(mx.context)

            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
                # Use meet to narrow original_type to the dispatched type.
                # For example, assume
                # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
                # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
                # * x: Union[A1, B1]
                # In `x.f`, when checking `x` against A1 we assume x is compatible with A
                # and similarly for B1 when checking agains B
                dispatched_type = meet.meet_types(mx.original_type, itype)
                check_self_arg(functype, dispatched_type, var.is_classmethod,
                               mx.context, name, mx.msg)
                signature = bind_self(functype, mx.original_type,
                                      var.is_classmethod)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast is fine.
                    assert isinstance(signature, CallableType)
                    result = signature.ret_type
                else:
                    result = signature
    else:
        if not var.is_ready:
            mx.not_ready_callback(var.name(), mx.context)
        # Implicit 'Any' type.
        result = AnyType(TypeOfAny.special_form)
    fullname = '{}.{}'.format(var.info.fullname(), name)
    hook = mx.chk.plugin.get_attribute_hook(fullname)
    if result and not mx.is_lvalue and not implicit:
        result = analyze_descriptor_access(mx.original_type,
                                           result,
                                           mx.builtin_type,
                                           mx.msg,
                                           mx.context,
                                           chk=mx.chk)
    if hook:
        result = hook(
            AttributeContext(mx.original_type, result, mx.context, mx.chk))
    return result
Ejemplo n.º 13
0
def solve_constraints(vars: List[TypeVarId], constraints: List[Constraint],
                      strict: bool =True) -> List[Optional[Type]]:
    """Solve type constraints.

    Return the best type(s) for type variables; each type can be None if the value of the variable
    could not be solved.

    If a variable has no constraints, if strict=True then arbitrarily
    pick NoneTyp as the value of the type variable.  If strict=False,
    pick AnyType.
    """
    # Collect a list of constraints for each type variable.
    cmap = defaultdict(list)  # type: Dict[TypeVarId, List[Constraint]]
    for con in constraints:
        cmap[con.type_var].append(con)

    res = []  # type: List[Optional[Type]]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Optional[Type]
        top = None  # type: Optional[Type]
        candidate = None  # type: Optional[Type]

        # Process each constraint separately, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the constraint
        # targets do not have constraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target)

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            source_any = top if isinstance(top, AnyType) else bottom
            assert isinstance(source_any, AnyType)
            res.append(AnyType(TypeOfAny.from_another_any, source_any=source_any))
            continue
        elif bottom is None:
            if top:
                candidate = top
            else:
                # No constraints for type variable -- 'UninhabitedType' is the most specific type.
                if strict:
                    candidate = UninhabitedType()
                    candidate.ambiguous = True
                else:
                    candidate = AnyType(TypeOfAny.special_form)
        elif top is None:
            candidate = bottom
        elif is_subtype(bottom, top):
            candidate = bottom
        else:
            candidate = None
        res.append(candidate)

    return res
Ejemplo n.º 14
0
def analyze_var(name: str,
                var: Var,
                itype: Instance,
                info: TypeInfo,
                mx: MemberContext, *,
                implicit: bool = False) -> Type:
    """Analyze access to an attribute via a Var node.

    This is conceptually part of analyze_member_access and the arguments are similar.

    itype is the class object in which var is defined
    original_type is the type of E in the expression E.var
    if implicit is True, the original Var was created as an assignment to self
    """
    # Found a member variable.
    itype = map_instance_to_supertype(itype, var.info)
    typ = var.type
    if typ:
        if isinstance(typ, PartialType):
            return mx.chk.handle_partial_var_type(typ, mx.is_lvalue, var, mx.context)
        t = expand_type_by_instance(typ, itype)
        if mx.is_lvalue and var.is_property and not var.is_settable_property:
            # TODO allow setting attributes in subclass (although it is probably an error)
            mx.msg.read_only_property(name, itype.type, mx.context)
        if mx.is_lvalue and var.is_classvar:
            mx.msg.cant_assign_to_classvar(name, mx.context)
        result = t
        if var.is_initialized_in_class and isinstance(t, FunctionLike) and not t.is_type_obj():
            if mx.is_lvalue:
                if var.is_property:
                    if not var.is_settable_property:
                        mx.msg.read_only_property(name, itype.type, mx.context)
                else:
                    mx.msg.cant_assign_to_method(mx.context)

            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
                # Use meet to narrow original_type to the dispatched type.
                # For example, assume
                # * A.f: Callable[[A1], None] where A1 <: A (maybe A1 == A)
                # * B.f: Callable[[B1], None] where B1 <: B (maybe B1 == B)
                # * x: Union[A1, B1]
                # In `x.f`, when checking `x` against A1 we assume x is compatible with A
                # and similarly for B1 when checking agains B
                dispatched_type = meet.meet_types(mx.original_type, itype)
                check_self_arg(functype, dispatched_type, var.is_classmethod, mx.context, name,
                               mx.msg)
                signature = bind_self(functype, mx.original_type, var.is_classmethod)
                if var.is_property:
                    # A property cannot have an overloaded type => the cast is fine.
                    assert isinstance(signature, CallableType)
                    result = signature.ret_type
                else:
                    result = signature
    else:
        if not var.is_ready:
            mx.not_ready_callback(var.name(), mx.context)
        # Implicit 'Any' type.
        result = AnyType(TypeOfAny.special_form)
    fullname = '{}.{}'.format(var.info.fullname(), name)
    hook = mx.chk.plugin.get_attribute_hook(fullname)
    if result and not mx.is_lvalue and not implicit:
        result = analyze_descriptor_access(mx.original_type, result, mx.builtin_type,
                                           mx.msg, mx.context, chk=mx.chk)
    if hook:
        result = hook(AttributeContext(mx.original_type, result, mx.context, mx.chk))
    return result
Ejemplo n.º 15
0
 Type top = None
 
 # Process each contraint separely, and calculate the lower and upper
 # bounds based on constraints. Note that we assume that the contraint
 # targets do not have contraint references.
 for c in cmap.get(tvar, []):
     if c.op == SUPERTYPE_OF:
         if bottom is None:
             bottom = c.target
         else:
             bottom = join_types(bottom, c.target, basic)
     else:
         if top is None:
             top = c.target
         else:
             top = meet_types(top, c.target, basic)
 
 if top is None:
     if isinstance(bottom, Void):
         top = Void()
     else:
         top = basic.object
 
 if bottom is None:
     if isinstance(top, Void):
         bottom = Void()
     else:
         bottom = NoneTyp()
 
 if isinstance(top, Any) or isinstance(bottom, Any):
     top = Any()
Ejemplo n.º 16
0
Archivo: solve.py Proyecto: silky/mypy
def solve_constraints(vars: List[int], constraints: List[Constraint],
                      basic: BasicTypes) -> List[Type]:
    """Solve type constraints.

    Return lower bound for each type variable or None if the variable could
    not be solved.
    """
    # Collect a list of constraints for each type variable.
    cmap = Dict[int, List[Constraint]]()
    for con in constraints:
        a = cmap.get(con.type_var, [])
        a.append(con)
        cmap[con.type_var] = a

    res = []  # type: List[Type]

    # Solve each type variable separately.
    for tvar in vars:
        bottom = None  # type: Type
        top = None  # type: Type

        # Process each contraint separely, and calculate the lower and upper
        # bounds based on constraints. Note that we assume that the contraint
        # targets do not have contraint references.
        for c in cmap.get(tvar, []):
            if c.op == SUPERTYPE_OF:
                if bottom is None:
                    bottom = c.target
                else:
                    bottom = join_types(bottom, c.target, basic)
            else:
                if top is None:
                    top = c.target
                else:
                    top = meet_types(top, c.target, basic)

        if top is None:
            if isinstance(bottom, Void):
                top = Void()
            else:
                top = basic.object

        if bottom is None:
            if isinstance(top, Void):
                bottom = Void()
            else:
                bottom = NoneTyp()

        if isinstance(top, AnyType) or isinstance(bottom, AnyType):
            top = AnyType()
            bottom = AnyType()

        # Pick the most specific type if it satisfies the constraints.
        if (not top or not bottom or is_subtype(
                bottom, top)) and (not isinstance(top, ErrorType)
                                   and not isinstance(bottom, ErrorType)):
            res.append(bottom)
        else:
            res.append(None)

    return res