Skip to content

Commit bd1d63a

Browse files
Merge branch 'master' into patch-3
2 parents 5e09390 + db67888 commit bd1d63a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1805
-1384
lines changed

mypy/checker.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7889,6 +7889,9 @@ def has_valid_attribute(self, typ: Type, name: str) -> bool:
78897889
def get_expression_type(self, node: Expression, type_context: Type | None = None) -> Type:
78907890
return self.expr_checker.accept(node, type_context=type_context)
78917891

7892+
def is_defined_in_stub(self, typ: Instance, /) -> bool:
7893+
return self.modules[typ.type.module_name].is_stub
7894+
78927895
def check_deprecated(self, node: Node | None, context: Context) -> None:
78937896
"""Warn if deprecated and not directly imported with a `from` statement."""
78947897
if isinstance(node, Decorator):

mypy/checker_shared.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ def checking_await_set(self) -> Iterator[None]:
277277
def get_precise_awaitable_type(self, typ: Type, local_errors: ErrorWatcher) -> Type | None:
278278
raise NotImplementedError
279279

280+
@abstractmethod
281+
def is_defined_in_stub(self, typ: Instance, /) -> bool:
282+
raise NotImplementedError
283+
280284

281285
class CheckerScope:
282286
# We keep two stacks combined, to maintain the relative order

mypy/fastparse.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ def fix_function_overloads(self, stmts: list[Statement]) -> list[Statement]:
631631
ret: list[Statement] = []
632632
current_overload: list[OverloadPart] = []
633633
current_overload_name: str | None = None
634-
seen_unconditional_func_def = False
634+
last_unconditional_func_def: str | None = None
635635
last_if_stmt: IfStmt | None = None
636636
last_if_overload: Decorator | FuncDef | OverloadedFuncDef | None = None
637637
last_if_stmt_overload_name: str | None = None
@@ -641,7 +641,7 @@ def fix_function_overloads(self, stmts: list[Statement]) -> list[Statement]:
641641
if_overload_name: str | None = None
642642
if_block_with_overload: Block | None = None
643643
if_unknown_truth_value: IfStmt | None = None
644-
if isinstance(stmt, IfStmt) and seen_unconditional_func_def is False:
644+
if isinstance(stmt, IfStmt):
645645
# Check IfStmt block to determine if function overloads can be merged
646646
if_overload_name = self._check_ifstmt_for_overloads(stmt, current_overload_name)
647647
if if_overload_name is not None:
@@ -669,11 +669,18 @@ def fix_function_overloads(self, stmts: list[Statement]) -> list[Statement]:
669669
last_if_unknown_truth_value = None
670670
current_overload.append(stmt)
671671
if isinstance(stmt, FuncDef):
672-
seen_unconditional_func_def = True
672+
# This is, strictly speaking, wrong: there might be a decorated
673+
# implementation. However, it only affects the error message we show:
674+
# ideally it's "already defined", but "implementation must come last"
675+
# is also reasonable.
676+
# TODO: can we get rid of this completely and just always emit
677+
# "implementation must come last" instead?
678+
last_unconditional_func_def = stmt.name
673679
elif (
674680
current_overload_name is not None
675681
and isinstance(stmt, IfStmt)
676682
and if_overload_name == current_overload_name
683+
and last_unconditional_func_def != current_overload_name
677684
):
678685
# IfStmt only contains stmts relevant to current_overload.
679686
# Check if stmts are reachable and add them to current_overload,
@@ -729,7 +736,7 @@ def fix_function_overloads(self, stmts: list[Statement]) -> list[Statement]:
729736
# most of mypy/mypyc assumes that all the functions in an OverloadedFuncDef are
730737
# related, but multiple underscore functions next to each other aren't necessarily
731738
# related
732-
seen_unconditional_func_def = False
739+
last_unconditional_func_def = None
733740
if isinstance(stmt, Decorator) and not unnamed_function(stmt.name):
734741
current_overload = [stmt]
735742
current_overload_name = stmt.name

mypy/plugins/enums.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from typing import TypeVar, cast
1818

1919
import mypy.plugin # To avoid circular imports.
20-
from mypy.checker import TypeChecker
20+
from mypy.checker_shared import TypeCheckerSharedApi
2121
from mypy.nodes import TypeInfo, Var
2222
from mypy.subtypes import is_equivalent
2323
from mypy.typeops import fixup_partial_type, make_simplified_union
@@ -122,8 +122,8 @@ def _infer_value_type_with_auto_fallback(
122122

123123

124124
def _is_defined_in_stub(ctx: mypy.plugin.AttributeContext) -> bool:
125-
assert isinstance(ctx.api, TypeChecker)
126-
return isinstance(ctx.type, Instance) and ctx.api.modules[ctx.type.type.module_name].is_stub
125+
assert isinstance(ctx.api, TypeCheckerSharedApi)
126+
return isinstance(ctx.type, Instance) and ctx.api.is_defined_in_stub(ctx.type)
127127

128128

129129
def _implements_new(info: TypeInfo) -> bool:

mypyc/irbuild/builder.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
from mypyc.primitives.list_ops import list_get_item_unsafe_op, list_pop_last, to_list
130130
from mypyc.primitives.misc_ops import check_unpack_count_op, get_module_dict_op, import_op
131131
from mypyc.primitives.registry import CFunctionDescription, function_ops
132+
from mypyc.primitives.tuple_ops import tuple_get_item_unsafe_op
132133

133134
# These int binary operations can borrow their operands safely, since the
134135
# primitives take this into consideration.
@@ -772,10 +773,15 @@ def process_sequence_assignment(
772773
values = []
773774
for i in range(len(target.items)):
774775
item = target.items[i]
775-
index = self.builder.load_int(i)
776+
index: Value
776777
if is_list_rprimitive(rvalue.type):
778+
index = Integer(i, c_pyssize_t_rprimitive)
777779
item_value = self.primitive_op(list_get_item_unsafe_op, [rvalue, index], line)
780+
elif is_tuple_rprimitive(rvalue.type):
781+
index = Integer(i, c_pyssize_t_rprimitive)
782+
item_value = self.call_c(tuple_get_item_unsafe_op, [rvalue, index], line)
778783
else:
784+
index = self.builder.load_int(i)
779785
item_value = self.builder.gen_method_call(
780786
rvalue, "__getitem__", [index], item.type, line
781787
)

mypyc/irbuild/for_helpers.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
RTuple,
4545
RType,
4646
bool_rprimitive,
47+
c_pyssize_t_rprimitive,
4748
int_rprimitive,
4849
is_dict_rprimitive,
4950
is_fixed_width_rtype,
@@ -75,6 +76,7 @@
7576
from mypyc.primitives.misc_ops import stop_async_iteration_op
7677
from mypyc.primitives.registry import CFunctionDescription
7778
from mypyc.primitives.set_ops import set_add_op
79+
from mypyc.primitives.tuple_ops import tuple_get_item_unsafe_op
7880

7981
GenFunc = Callable[[], None]
8082

@@ -586,7 +588,9 @@ def gen_cleanup(self) -> None:
586588

587589
def load_len(self, expr: Value | AssignmentTarget) -> Value:
588590
"""A helper to get collection length, used by several subclasses."""
589-
return self.builder.builder.builtin_len(self.builder.read(expr, self.line), self.line)
591+
return self.builder.builder.builtin_len(
592+
self.builder.read(expr, self.line), self.line, use_pyssize_t=True
593+
)
590594

591595

592596
class ForIterable(ForGenerator):
@@ -766,6 +770,8 @@ def unsafe_index(builder: IRBuilder, target: Value, index: Value, line: int) ->
766770
# so we just check manually.
767771
if is_list_rprimitive(target.type):
768772
return builder.primitive_op(list_get_item_unsafe_op, [target, index], line)
773+
elif is_tuple_rprimitive(target.type):
774+
return builder.call_c(tuple_get_item_unsafe_op, [target, index], line)
769775
else:
770776
return builder.gen_method_call(target, "__getitem__", [index], None, line)
771777

@@ -784,11 +790,9 @@ def init(self, expr_reg: Value, target_type: RType, reverse: bool) -> None:
784790
# environment class.
785791
self.expr_target = builder.maybe_spill(expr_reg)
786792
if not reverse:
787-
index_reg: Value = Integer(0)
793+
index_reg: Value = Integer(0, c_pyssize_t_rprimitive)
788794
else:
789-
index_reg = builder.binary_op(
790-
self.load_len(self.expr_target), Integer(1), "-", self.line
791-
)
795+
index_reg = builder.builder.int_sub(self.load_len(self.expr_target), 1)
792796
self.index_target = builder.maybe_spill_assignable(index_reg)
793797
self.target_type = target_type
794798

@@ -838,13 +842,7 @@ def gen_step(self) -> None:
838842
builder = self.builder
839843
line = self.line
840844
step = 1 if not self.reverse else -1
841-
add = builder.int_op(
842-
short_int_rprimitive,
843-
builder.read(self.index_target, line),
844-
Integer(step),
845-
IntOp.ADD,
846-
line,
847-
)
845+
add = builder.builder.int_add(builder.read(self.index_target, line), step)
848846
builder.assign(self.index_target, add, line)
849847

850848

mypyc/irbuild/ll_builder.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,6 +2104,33 @@ def float_mod(self, lhs: Value, rhs: Value, line: int) -> Value:
21042104
def compare_floats(self, lhs: Value, rhs: Value, op: int, line: int) -> Value:
21052105
return self.add(FloatComparisonOp(lhs, rhs, op, line))
21062106

2107+
def int_add(self, lhs: Value, rhs: Value | int) -> Value:
2108+
"""Helper to add two native integers.
2109+
2110+
The result has the type of lhs.
2111+
"""
2112+
if isinstance(rhs, int):
2113+
rhs = Integer(rhs, lhs.type)
2114+
return self.int_op(lhs.type, lhs, rhs, IntOp.ADD, line=-1)
2115+
2116+
def int_sub(self, lhs: Value, rhs: Value | int) -> Value:
2117+
"""Helper to subtract a native integer from another one.
2118+
2119+
The result has the type of lhs.
2120+
"""
2121+
if isinstance(rhs, int):
2122+
rhs = Integer(rhs, lhs.type)
2123+
return self.int_op(lhs.type, lhs, rhs, IntOp.SUB, line=-1)
2124+
2125+
def int_mul(self, lhs: Value, rhs: Value | int) -> Value:
2126+
"""Helper to multiply two native integers.
2127+
2128+
The result has the type of lhs.
2129+
"""
2130+
if isinstance(rhs, int):
2131+
rhs = Integer(rhs, lhs.type)
2132+
return self.int_op(lhs.type, lhs, rhs, IntOp.MUL, line=-1)
2133+
21072134
def fixed_width_int_op(
21082135
self, type: RPrimitive, lhs: Value, rhs: Value, op: int, line: int
21092136
) -> Value:

mypyc/irbuild/specialize.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from __future__ import annotations
1616

17-
from typing import Callable, Optional
17+
from typing import Callable, Final, Optional
1818

1919
from mypy.nodes import (
2020
ARG_NAMED,
@@ -89,7 +89,7 @@
8989
dict_setdefault_spec_init_op,
9090
dict_values_op,
9191
)
92-
from mypyc.primitives.list_ops import new_list_set_item_op
92+
from mypyc.primitives.list_ops import isinstance_list, new_list_set_item_op
9393
from mypyc.primitives.str_ops import (
9494
str_encode_ascii_strict,
9595
str_encode_latin1_strict,
@@ -546,6 +546,9 @@ def gen_inner_stmts() -> None:
546546
return retval
547547

548548

549+
isinstance_primitives: Final = {"builtins.list": isinstance_list}
550+
551+
549552
@specialize_function("builtins.isinstance")
550553
def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Value | None:
551554
"""Special case for builtins.isinstance.
@@ -554,11 +557,10 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
554557
there is no need to coerce something to a new type before checking
555558
what type it is, and the coercion could lead to bugs.
556559
"""
557-
if (
558-
len(expr.args) == 2
559-
and expr.arg_kinds == [ARG_POS, ARG_POS]
560-
and isinstance(expr.args[1], (RefExpr, TupleExpr))
561-
):
560+
if not (len(expr.args) == 2 and expr.arg_kinds == [ARG_POS, ARG_POS]):
561+
return None
562+
563+
if isinstance(expr.args[1], (RefExpr, TupleExpr)):
562564
builder.types[expr.args[0]] = AnyType(TypeOfAny.from_error)
563565

564566
irs = builder.flatten_classes(expr.args[1])
@@ -569,6 +571,15 @@ def translate_isinstance(builder: IRBuilder, expr: CallExpr, callee: RefExpr) ->
569571
)
570572
obj = builder.accept(expr.args[0], can_borrow=can_borrow)
571573
return builder.builder.isinstance_helper(obj, irs, expr.line)
574+
575+
if isinstance(expr.args[1], RefExpr):
576+
node = expr.args[1].node
577+
if node:
578+
desc = isinstance_primitives.get(node.fullname)
579+
if desc:
580+
obj = builder.accept(expr.args[0])
581+
return builder.primitive_op(desc, [obj], expr.line)
582+
572583
return None
573584

574585

0 commit comments

Comments
 (0)