Exemple #1
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
Exemple #2
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
Exemple #3
0
 def test_mixed_truth_restricted_type(self) -> None:
     # join_types against differently restricted truthiness types drops restrictions.
     true_any = true_only(AnyType(TypeOfAny.special_form))
     false_o = false_only(self.fx.o)
     j = join_types(true_any, false_o)
     assert_true(j.can_be_true)
     assert_true(j.can_be_false)
Exemple #4
0
 def test_mixed_truth_restricted_type(self) -> None:
     # join_types against differently restricted truthiness types drops restrictions.
     true_any = true_only(AnyType(TypeOfAny.special_form))
     false_o = false_only(self.fx.o)
     j = join_types(true_any, false_o)
     assert_true(j.can_be_true)
     assert_true(j.can_be_false)
Exemple #5
0
 def assert_simple_join(self, s: Type, t: Type, join: Type) -> None:
     result = join_types(s, t)
     actual = str(result)
     expected = str(join)
     assert_equal(actual, expected,
                  'join({}, {}) == {{}} ({{}} expected)'.format(s, t))
     assert is_subtype(s, result), '{} not subtype of {}'.format(s, result)
     assert is_subtype(t, result), '{} not subtype of {}'.format(t, result)
Exemple #6
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
Exemple #7
0
 def test_simple_type_objects(self):
     t1 = self.type_callable(self.fx.a, self.fx.a)
     t2 = self.type_callable(self.fx.b, self.fx.b)
     
     self.assert_join(t1, t1, t1)
     assert_true(join_types(t1, t1, self.fx.basic).is_type_obj())
     
     self.assert_join(t1, t2, self.fx.std_type)
     self.assert_join(t1, self.fx.std_type, self.fx.std_type)
     self.assert_join(self.fx.std_type, self.fx.std_type, self.fx.std_type)
Exemple #8
0
 def assert_simple_join(self, s: Type, t: Type, join: Type) -> None:
     result = join_types(s, t)
     actual = str(result)
     expected = str(join)
     assert_equal(actual, expected,
                  'join({}, {}) == {{}} ({{}} expected)'.format(s, t))
     assert_true(is_subtype(s, result),
                 '{} not subtype of {}'.format(s, result))
     assert_true(is_subtype(t, result),
                 '{} not subtype of {}'.format(t, result))
Exemple #9
0
    def test_simple_type_objects(self):
        t1 = self.type_callable(self.fx.a, self.fx.a)
        t2 = self.type_callable(self.fx.b, self.fx.b)

        self.assert_join(t1, t1, t1)
        assert_true(join_types(t1, t1).is_type_obj())

        self.assert_join(t1, t2, self.fx.type_type)
        self.assert_join(t1, self.fx.type_type, self.fx.type_type)
        self.assert_join(self.fx.type_type, self.fx.type_type,
                         self.fx.type_type)
Exemple #10
0
 def assert_simple_join(self, s, t, join):
     result = join_types(s, t)
     actual = str(result)
     expected = str(join)
     assert_equal(actual, expected,
                  'join({}, {}) == {{}} ({{}} expected)'.format(s, t))
     if not isinstance(s, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(s, result),
                     '{} not subtype of {}'.format(s, result))
     if not isinstance(t, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(t, result),
                     '{} not subtype of {}'.format(t, result))
Exemple #11
0
 def assert_simple_join(self, s, t, join):
     result = join_types(s, t)
     actual = str(result)
     expected = str(join)
     assert_equal(actual, expected,
                  'join({}, {}) == {{}} ({{}} expected)'.format(s, t))
     if not isinstance(s, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(s, result),
                     '{} not subtype of {}'.format(s, result))
     if not isinstance(t, ErrorType) and not isinstance(result, ErrorType):
         assert_true(is_subtype(t, result),
                     '{} not subtype of {}'.format(t, result))
Exemple #12
0
    def test_simple_type_objects(self) -> None:
        t1 = self.type_callable(self.fx.a, self.fx.a)
        t2 = self.type_callable(self.fx.b, self.fx.b)

        self.assert_join(t1, t1, t1)
        j = join_types(t1, t1)
        assert isinstance(j, CallableType)
        assert_true(j.is_type_obj())

        self.assert_join(t1, t2, self.fx.type_type)
        self.assert_join(t1, self.fx.type_type, self.fx.type_type)
        self.assert_join(self.fx.type_type, self.fx.type_type,
                         self.fx.type_type)
Exemple #13
0
    def test_simple_type_objects(self) -> None:
        t1 = self.type_callable(self.fx.a, self.fx.a)
        t2 = self.type_callable(self.fx.b, self.fx.b)

        self.assert_join(t1, t1, t1)
        j = join_types(t1, t1)
        assert isinstance(j, CallableType)
        assert_true(j.is_type_obj())

        self.assert_join(t1, t2, self.fx.type_type)
        self.assert_join(t1, self.fx.type_type, self.fx.type_type)
        self.assert_join(self.fx.type_type, self.fx.type_type,
                         self.fx.type_type)
Exemple #14
0
    def visit_or_pattern(self, o: OrPattern) -> PatternType:
        current_type = self.type_context[-1]

        #
        # Check all the subpatterns
        #
        pattern_types = []
        for pattern in o.patterns:
            pattern_type = self.accept(pattern, current_type)
            pattern_types.append(pattern_type)
            current_type = pattern_type.rest_type

        #
        # Collect the final type
        #
        types = []
        for pattern_type in pattern_types:
            if not is_uninhabited(pattern_type.type):
                types.append(pattern_type.type)

        #
        # Check the capture types
        #
        capture_types: Dict[Var, List[Tuple[Expression,
                                            Type]]] = defaultdict(list)
        # Collect captures from the first subpattern
        for expr, typ in pattern_types[0].captures.items():
            node = get_var(expr)
            capture_types[node].append((expr, typ))

        # Check if other subpatterns capture the same names
        for i, pattern_type in enumerate(pattern_types[1:]):
            vars = {get_var(expr) for expr, _ in pattern_type.captures.items()}
            if capture_types.keys() != vars:
                self.msg.fail(message_registry.OR_PATTERN_ALTERNATIVE_NAMES,
                              o.patterns[i])
            for expr, typ in pattern_type.captures.items():
                node = get_var(expr)
                capture_types[node].append((expr, typ))

        captures: Dict[Expression, Type] = {}
        for var, capture_list in capture_types.items():
            typ = UninhabitedType()
            for _, other in capture_list:
                typ = join_types(typ, other)

            captures[capture_list[0][0]] = typ

        union_type = make_simplified_union(types)
        return PatternType(union_type, current_type, captures)
Exemple #15
0
def meet_similar_callables(t: CallableType, s: CallableType) -> CallableType:
    from mypy.join import join_types
    arg_types = []  # type: List[Type]
    for i in range(len(t.arg_types)):
        arg_types.append(join_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 'function' as
    # fallback only if both operands have it as 'function'.
    if t.fallback.type.fullname() != 'builtins.function':
        fallback = t.fallback
    else:
        fallback = s.fallback
    return t.copy_modified(arg_types=arg_types,
                           ret_type=meet_types(t.ret_type, s.ret_type),
                           fallback=fallback,
                           name=None)
Exemple #16
0
def meet_similar_callables(t: CallableType, s: CallableType) -> CallableType:
    from mypy.join import join_types
    arg_types = []  # type: List[Type]
    for i in range(len(t.arg_types)):
        arg_types.append(join_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 'function' as
    # fallback only if both operands have it as 'function'.
    if t.fallback.type.fullname() != 'builtins.function':
        fallback = t.fallback
    else:
        fallback = s.fallback
    return t.copy_modified(arg_types=arg_types,
                           ret_type=meet_types(t.ret_type, s.ret_type),
                           fallback=fallback,
                           name=None)
Exemple #17
0
    def _analyze_iterable_item_type(self, expr: Expression) -> Type:
        """Return the item type given by 'expr' in an iterable context."""
        # This logic is copied from mypy's TypeChecker.analyze_iterable_item_type.
        iterable = get_proper_type(self.types[expr])
        echk = self.graph[self.module_name].type_checker().expr_checker
        iterator = echk.check_method_call_by_name('__iter__', iterable, [], [], expr)[0]

        from mypy.join import join_types
        if isinstance(iterable, TupleType):
            joined = UninhabitedType()  # type: Type
            for item in iterable.items:
                joined = join_types(joined, item)
            return joined
        else:
            # Non-tuple iterable.
            return echk.check_method_call_by_name('__next__', iterator, [], [], expr)[0]
Exemple #18
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
Exemple #19
0
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
Exemple #20
0
    Type[] res = []

    # Solve each type variable separately.
    for tvar in vars:
        Type bottom = None
        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()
Exemple #21
0
    def visit_class_pattern(self, o: ClassPattern) -> PatternType:
        current_type = get_proper_type(self.type_context[-1])

        #
        # Check class type
        #
        type_info = o.class_ref.node
        assert type_info is not None
        if isinstance(type_info, TypeAlias) and not type_info.no_args:
            self.msg.fail(message_registry.CLASS_PATTERN_GENERIC_TYPE_ALIAS, o)
            return self.early_non_match()
        if isinstance(type_info, TypeInfo):
            any_type = AnyType(TypeOfAny.implementation_artifact)
            typ: Type = Instance(type_info,
                                 [any_type] * len(type_info.defn.type_vars))
        elif isinstance(type_info, TypeAlias):
            typ = type_info.target
        else:
            if isinstance(type_info, Var):
                name = str(type_info.type)
            else:
                name = type_info.name
            self.msg.fail(
                message_registry.CLASS_PATTERN_TYPE_REQUIRED.format(name),
                o.class_ref)
            return self.early_non_match()

        new_type, rest_type = self.chk.conditional_types_with_intersection(
            current_type, [get_type_range(typ)], o, default=current_type)
        if is_uninhabited(new_type):
            return self.early_non_match()
        # TODO: Do I need this?
        narrowed_type = narrow_declared_type(current_type, new_type)

        #
        # Convert positional to keyword patterns
        #
        keyword_pairs: List[Tuple[Optional[str], Pattern]] = []
        match_arg_set: Set[str] = set()

        captures: Dict[Expression, Type] = {}

        if len(o.positionals) != 0:
            if self.should_self_match(typ):
                if len(o.positionals) > 1:
                    self.msg.fail(
                        message_registry.
                        CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o)
                pattern_type = self.accept(o.positionals[0], narrowed_type)
                if not is_uninhabited(pattern_type.type):
                    return PatternType(
                        pattern_type.type,
                        join_types(rest_type, pattern_type.rest_type),
                        pattern_type.captures)
                captures = pattern_type.captures
            else:
                local_errors = self.msg.clean_copy()
                match_args_type = analyze_member_access("__match_args__",
                                                        typ,
                                                        o,
                                                        False,
                                                        False,
                                                        False,
                                                        local_errors,
                                                        original_type=typ,
                                                        chk=self.chk)

                if local_errors.is_errors():
                    self.msg.fail(
                        message_registry.MISSING_MATCH_ARGS.format(typ), o)
                    return self.early_non_match()

                proper_match_args_type = get_proper_type(match_args_type)
                if isinstance(proper_match_args_type, TupleType):
                    match_arg_names = get_match_arg_names(
                        proper_match_args_type)

                    if len(o.positionals) > len(match_arg_names):
                        self.msg.fail(
                            message_registry.
                            CLASS_PATTERN_TOO_MANY_POSITIONAL_ARGS, o)
                        return self.early_non_match()
                else:
                    match_arg_names = [None] * len(o.positionals)

                for arg_name, pos in zip(match_arg_names, o.positionals):
                    keyword_pairs.append((arg_name, pos))
                    if arg_name is not None:
                        match_arg_set.add(arg_name)

        #
        # Check for duplicate patterns
        #
        keyword_arg_set = set()
        has_duplicates = False
        for key, value in zip(o.keyword_keys, o.keyword_values):
            keyword_pairs.append((key, value))
            if key in match_arg_set:
                self.msg.fail(
                    message_registry.CLASS_PATTERN_KEYWORD_MATCHES_POSITIONAL.
                    format(key), value)
                has_duplicates = True
            elif key in keyword_arg_set:
                self.msg.fail(
                    message_registry.CLASS_PATTERN_DUPLICATE_KEYWORD_PATTERN.
                    format(key), value)
                has_duplicates = True
            keyword_arg_set.add(key)

        if has_duplicates:
            return self.early_non_match()

        #
        # Check keyword patterns
        #
        can_match = True
        for keyword, pattern in keyword_pairs:
            key_type: Optional[Type] = None
            local_errors = self.msg.clean_copy()
            if keyword is not None:
                key_type = analyze_member_access(keyword,
                                                 narrowed_type,
                                                 pattern,
                                                 False,
                                                 False,
                                                 False,
                                                 local_errors,
                                                 original_type=new_type,
                                                 chk=self.chk)
            else:
                key_type = AnyType(TypeOfAny.from_error)
            if local_errors.is_errors() or key_type is None:
                key_type = AnyType(TypeOfAny.from_error)
                self.msg.fail(
                    message_registry.CLASS_PATTERN_UNKNOWN_KEYWORD.format(
                        typ, keyword), value)

            inner_type, inner_rest_type, inner_captures = self.accept(
                pattern, key_type)
            if is_uninhabited(inner_type):
                can_match = False
            else:
                self.update_type_map(captures, inner_captures)
                if not is_uninhabited(inner_rest_type):
                    rest_type = current_type

        if not can_match:
            new_type = UninhabitedType()
        return PatternType(new_type, rest_type, captures)
Exemple #22
0
    def visit_sequence_pattern(self, o: SequencePattern) -> PatternType:
        #
        # check for existence of a starred pattern
        #
        current_type = get_proper_type(self.type_context[-1])
        if not self.can_match_sequence(current_type):
            return self.early_non_match()
        star_positions = [
            i for i, p in enumerate(o.patterns)
            if isinstance(p, StarredPattern)
        ]
        star_position: Optional[int] = None
        if len(star_positions) == 1:
            star_position = star_positions[0]
        elif len(star_positions) >= 2:
            assert False, "Parser should prevent multiple starred patterns"
        required_patterns = len(o.patterns)
        if star_position is not None:
            required_patterns -= 1

        #
        # get inner types of original type
        #
        if isinstance(current_type, TupleType):
            inner_types = current_type.items
            size_diff = len(inner_types) - required_patterns
            if size_diff < 0:
                return self.early_non_match()
            elif size_diff > 0 and star_position is None:
                return self.early_non_match()
        else:
            inner_type = self.get_sequence_type(current_type)
            if inner_type is None:
                inner_type = self.chk.named_type("builtins.object")
            inner_types = [inner_type] * len(o.patterns)

        #
        # match inner patterns
        #
        contracted_new_inner_types: List[Type] = []
        contracted_rest_inner_types: List[Type] = []
        captures: Dict[Expression, Type] = {}

        contracted_inner_types = self.contract_starred_pattern_types(
            inner_types, star_position, required_patterns)
        can_match = True
        for p, t in zip(o.patterns, contracted_inner_types):
            pattern_type = self.accept(p, t)
            typ, rest, type_map = pattern_type
            if is_uninhabited(typ):
                can_match = False
            else:
                contracted_new_inner_types.append(typ)
                contracted_rest_inner_types.append(rest)
            self.update_type_map(captures, type_map)
        new_inner_types = self.expand_starred_pattern_types(
            contracted_new_inner_types, star_position, len(inner_types))

        #
        # Calculate new type
        #
        new_type: Type
        rest_type: Type = current_type
        if not can_match:
            new_type = UninhabitedType()
        elif isinstance(current_type, TupleType):
            narrowed_inner_types = []
            inner_rest_types = []
            for inner_type, new_inner_type in zip(inner_types,
                                                  new_inner_types):
                narrowed_inner_type, inner_rest_type = \
                    self.chk.conditional_types_with_intersection(
                        new_inner_type,
                        [get_type_range(inner_type)],
                        o,
                        default=new_inner_type
                    )
                narrowed_inner_types.append(narrowed_inner_type)
                inner_rest_types.append(inner_rest_type)
            if all(not is_uninhabited(typ) for typ in narrowed_inner_types):
                new_type = TupleType(narrowed_inner_types,
                                     current_type.partial_fallback)
            else:
                new_type = UninhabitedType()

            if all(is_uninhabited(typ) for typ in inner_rest_types):
                # All subpatterns always match, so we can apply negative narrowing
                new_type, rest_type = self.chk.conditional_types_with_intersection(
                    current_type, [get_type_range(new_type)],
                    o,
                    default=current_type)
        else:
            new_inner_type = UninhabitedType()
            for typ in new_inner_types:
                new_inner_type = join_types(new_inner_type, typ)
            new_type = self.construct_sequence_child(current_type,
                                                     new_inner_type)
            if not is_subtype(new_type, current_type):
                new_type = current_type
        return PatternType(new_type, rest_type, captures)