Skip to content

Commit 9b5f28f

Browse files
Merge branch 'master' into truedictprimitive
2 parents a51a3c1 + 27b9ba0 commit 9b5f28f

File tree

8 files changed

+878
-73
lines changed

8 files changed

+878
-73
lines changed

mypyc/ir/rtypes.py

Lines changed: 45 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ def may_be_immortal(self) -> bool:
192192
def serialize(self) -> str:
193193
return "void"
194194

195-
def __eq__(self, other: object) -> bool:
195+
def __eq__(self, other: object) -> TypeGuard[RVoid]:
196196
return isinstance(other, RVoid)
197197

198198
def __hash__(self) -> int:
@@ -279,7 +279,7 @@ def serialize(self) -> str:
279279
def __repr__(self) -> str:
280280
return "<RPrimitive %s>" % self.name
281281

282-
def __eq__(self, other: object) -> bool:
282+
def __eq__(self, other: object) -> TypeGuard[RPrimitive]:
283283
return isinstance(other, RPrimitive) and other.name == self.name
284284

285285
def __hash__(self) -> int:
@@ -520,15 +520,15 @@ def __hash__(self) -> int:
520520
range_rprimitive: Final = RPrimitive("builtins.range", is_unboxed=False, is_refcounted=True)
521521

522522

523-
def is_tagged(rtype: RType) -> bool:
523+
def is_tagged(rtype: RType) -> TypeGuard[RPrimitive]:
524524
return rtype is int_rprimitive or rtype is short_int_rprimitive
525525

526526

527-
def is_int_rprimitive(rtype: RType) -> bool:
527+
def is_int_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
528528
return rtype is int_rprimitive
529529

530530

531-
def is_short_int_rprimitive(rtype: RType) -> bool:
531+
def is_short_int_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
532532
return rtype is short_int_rprimitive
533533

534534

@@ -542,7 +542,7 @@ def is_int32_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
542542
)
543543

544544

545-
def is_int64_rprimitive(rtype: RType) -> bool:
545+
def is_int64_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
546546
return rtype is int64_rprimitive or (
547547
rtype is c_pyssize_t_rprimitive and rtype._ctype == "int64_t"
548548
)
@@ -561,88 +561,100 @@ def is_uint8_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
561561
return rtype is uint8_rprimitive
562562

563563

564-
def is_uint32_rprimitive(rtype: RType) -> bool:
564+
def is_uint32_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
565565
return rtype is uint32_rprimitive
566566

567567

568-
def is_uint64_rprimitive(rtype: RType) -> bool:
568+
def is_uint64_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
569569
return rtype is uint64_rprimitive
570570

571571

572-
def is_c_py_ssize_t_rprimitive(rtype: RType) -> bool:
572+
def is_c_py_ssize_t_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
573573
return rtype is c_pyssize_t_rprimitive
574574

575575

576-
def is_pointer_rprimitive(rtype: RType) -> bool:
576+
def is_pointer_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
577577
return rtype is pointer_rprimitive
578578

579579

580-
def is_float_rprimitive(rtype: RType) -> bool:
580+
def is_float_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
581581
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.float"
582582

583583

584-
def is_bool_rprimitive(rtype: RType) -> bool:
584+
def is_bool_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
585585
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.bool"
586586

587587

588-
def is_bit_rprimitive(rtype: RType) -> bool:
588+
def is_bit_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
589589
return isinstance(rtype, RPrimitive) and rtype.name == "bit"
590590

591591

592-
def is_bool_or_bit_rprimitive(rtype: RType) -> bool:
592+
def is_bool_or_bit_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
593593
return is_bool_rprimitive(rtype) or is_bit_rprimitive(rtype)
594594

595595

596-
def is_object_rprimitive(rtype: RType) -> bool:
596+
def is_object_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
597597
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.object"
598598

599599

600-
def is_none_rprimitive(rtype: RType) -> bool:
600+
def is_none_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
601601
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.None"
602602

603603

604-
def is_list_rprimitive(rtype: RType) -> bool:
604+
def is_list_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
605605
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.list"
606606

607607

608-
def is_dict_rprimitive(rtype: RType) -> bool:
608+
def is_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
609609
return isinstance(rtype, RPrimitive) and rtype.name in (
610610
"builtins.dict",
611611
"builtins.dict[exact]",
612612
)
613613

614614

615-
def is_exact_dict_rprimitive(rtype: RType) -> bool:
615+
def is_exact_dict_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
616616
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.dict[exact]"
617617

618618

619-
def is_set_rprimitive(rtype: RType) -> bool:
619+
def is_set_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
620620
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.set"
621621

622622

623-
def is_frozenset_rprimitive(rtype: RType) -> bool:
623+
def is_frozenset_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
624624
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.frozenset"
625625

626626

627-
def is_str_rprimitive(rtype: RType) -> bool:
627+
def is_str_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
628628
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.str"
629629

630630

631-
def is_bytes_rprimitive(rtype: RType) -> bool:
631+
def is_bytes_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
632632
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.bytes"
633633

634634

635-
def is_tuple_rprimitive(rtype: RType) -> bool:
635+
def is_tuple_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
636636
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.tuple"
637637

638638

639-
def is_range_rprimitive(rtype: RType) -> bool:
639+
def is_range_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
640640
return isinstance(rtype, RPrimitive) and rtype.name == "builtins.range"
641641

642642

643-
def is_sequence_rprimitive(rtype: RType) -> bool:
643+
def is_sequence_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
644644
return isinstance(rtype, RPrimitive) and (
645-
is_list_rprimitive(rtype) or is_tuple_rprimitive(rtype) or is_str_rprimitive(rtype)
645+
is_list_rprimitive(rtype)
646+
or is_tuple_rprimitive(rtype)
647+
or is_str_rprimitive(rtype)
648+
or is_bytes_rprimitive(rtype)
649+
)
650+
651+
652+
def is_immutable_rprimitive(rtype: RType) -> TypeGuard[RPrimitive]:
653+
return (
654+
is_str_rprimitive(rtype)
655+
or is_bytes_rprimitive(rtype)
656+
or is_tuple_rprimitive(rtype)
657+
or is_frozenset_rprimitive(rtype)
646658
)
647659

648660

@@ -731,7 +743,7 @@ def __str__(self) -> str:
731743
def __repr__(self) -> str:
732744
return "<RTuple %s>" % ", ".join(repr(typ) for typ in self.types)
733745

734-
def __eq__(self, other: object) -> bool:
746+
def __eq__(self, other: object) -> TypeGuard[RTuple]:
735747
return isinstance(other, RTuple) and self.types == other.types
736748

737749
def __hash__(self) -> int:
@@ -864,7 +876,7 @@ def __repr__(self) -> str:
864876
", ".join(name + ":" + repr(typ) for name, typ in zip(self.names, self.types)),
865877
)
866878

867-
def __eq__(self, other: object) -> bool:
879+
def __eq__(self, other: object) -> TypeGuard[RStruct]:
868880
return (
869881
isinstance(other, RStruct)
870882
and self.name == other.name
@@ -934,7 +946,7 @@ def attr_type(self, name: str) -> RType:
934946
def __repr__(self) -> str:
935947
return "<RInstance %s>" % self.name
936948

937-
def __eq__(self, other: object) -> bool:
949+
def __eq__(self, other: object) -> TypeGuard[RInstance]:
938950
return isinstance(other, RInstance) and other.name == self.name
939951

940952
def __hash__(self) -> int:
@@ -988,7 +1000,7 @@ def __str__(self) -> str:
9881000
return "union[%s]" % ", ".join(str(item) for item in self.items)
9891001

9901002
# We compare based on the set because order in a union doesn't matter
991-
def __eq__(self, other: object) -> bool:
1003+
def __eq__(self, other: object) -> TypeGuard[RUnion]:
9921004
return isinstance(other, RUnion) and self.items_set == other.items_set
9931005

9941006
def __hash__(self) -> int:
@@ -1030,7 +1042,7 @@ def optional_value_type(rtype: RType) -> RType | None:
10301042
return None
10311043

10321044

1033-
def is_optional_type(rtype: RType) -> bool:
1045+
def is_optional_type(rtype: RType) -> TypeGuard[RUnion]:
10341046
"""Is rtype an optional type with exactly two union items?"""
10351047
return optional_value_type(rtype) is not None
10361048

@@ -1062,7 +1074,7 @@ def __str__(self) -> str:
10621074
def __repr__(self) -> str:
10631075
return f"<RArray {self.item_type!r}[{self.length}]>"
10641076

1065-
def __eq__(self, other: object) -> bool:
1077+
def __eq__(self, other: object) -> TypeGuard[RArray]:
10661078
return (
10671079
isinstance(other, RArray)
10681080
and self.item_type == other.item_type

mypyc/irbuild/builder.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
RType,
9292
RUnion,
9393
bitmap_rprimitive,
94+
bytes_rprimitive,
9495
c_pyssize_t_rprimitive,
9596
exact_dict_rprimitive,
9697
int_rprimitive,
@@ -964,8 +965,12 @@ def get_sequence_type_from_type(self, target_type: Type) -> RType:
964965
elif isinstance(target_type, Instance):
965966
if target_type.type.fullname == "builtins.str":
966967
return str_rprimitive
967-
else:
968+
elif target_type.type.fullname == "builtins.bytes":
969+
return bytes_rprimitive
970+
try:
968971
return self.type_to_rtype(target_type.args[0])
972+
except IndexError:
973+
raise ValueError(f"{target_type!r} is not a valid sequence.") from None
969974
# This elif-blocks are needed for iterating over classes derived from NamedTuple.
970975
elif isinstance(target_type, TypeVarLikeType):
971976
return self.get_sequence_type_from_type(target_type.upper_bound)

mypyc/irbuild/for_helpers.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
is_dict_rprimitive,
5050
is_exact_dict_rprimitive,
5151
is_fixed_width_rtype,
52+
is_immutable_rprimitive,
5253
is_list_rprimitive,
5354
is_sequence_rprimitive,
5455
is_short_int_rprimitive,
@@ -211,9 +212,9 @@ def sequence_from_generator_preallocate_helper(
211212
there is no condition list in the generator and only one original sequence with
212213
one index is allowed.
213214
214-
e.g. (1) tuple(f(x) for x in a_list/a_tuple)
215-
(2) list(f(x) for x in a_list/a_tuple)
216-
(3) [f(x) for x in a_list/a_tuple]
215+
e.g. (1) tuple(f(x) for x in a_list/a_tuple/a_str/a_bytes)
216+
(2) list(f(x) for x in a_list/a_tuple/a_str/a_bytes)
217+
(3) [f(x) for x in a_list/a_tuple/a_str/a_bytes]
217218
RTuple as an original sequence is not supported yet.
218219
219220
Args:
@@ -230,7 +231,7 @@ def sequence_from_generator_preallocate_helper(
230231
"""
231232
if len(gen.sequences) == 1 and len(gen.indices) == 1 and len(gen.condlists[0]) == 0:
232233
rtype = builder.node_type(gen.sequences[0])
233-
if is_list_rprimitive(rtype) or is_tuple_rprimitive(rtype) or is_str_rprimitive(rtype):
234+
if is_sequence_rprimitive(rtype):
234235
sequence = builder.accept(gen.sequences[0])
235236
length = builder.builder.builtin_len(sequence, gen.line, use_pyssize_t=True)
236237
target_op = empty_op_llbuilder(length, gen.line)
@@ -802,17 +803,31 @@ class ForSequence(ForGenerator):
802803
Supports iterating in both forward and reverse.
803804
"""
804805

806+
length_reg: Value | AssignmentTarget | None
807+
805808
def init(self, expr_reg: Value, target_type: RType, reverse: bool) -> None:
809+
assert is_sequence_rprimitive(expr_reg.type), expr_reg
806810
builder = self.builder
807811
self.reverse = reverse
808812
# Define target to contain the expression, along with the index that will be used
809813
# for the for-loop. If we are inside of a generator function, spill these into the
810814
# environment class.
811815
self.expr_target = builder.maybe_spill(expr_reg)
816+
if is_immutable_rprimitive(expr_reg.type):
817+
# If the expression is an immutable type, we can load the length just once.
818+
self.length_reg = builder.maybe_spill(self.load_len(self.expr_target))
819+
else:
820+
# Otherwise, even if the length is known, we must recalculate the length
821+
# at every iteration for compatibility with python semantics.
822+
self.length_reg = None
812823
if not reverse:
813824
index_reg: Value = Integer(0, c_pyssize_t_rprimitive)
814825
else:
815-
index_reg = builder.builder.int_sub(self.load_len(self.expr_target), 1)
826+
if self.length_reg is not None:
827+
len_val = builder.read(self.length_reg)
828+
else:
829+
len_val = self.load_len(self.expr_target)
830+
index_reg = builder.builder.int_sub(len_val, 1)
816831
self.index_target = builder.maybe_spill_assignable(index_reg)
817832
self.target_type = target_type
818833

@@ -831,9 +846,13 @@ def gen_condition(self) -> None:
831846
second_check = BasicBlock()
832847
builder.add_bool_branch(comparison, second_check, self.loop_exit)
833848
builder.activate_block(second_check)
834-
# For compatibility with python semantics we recalculate the length
835-
# at every iteration.
836-
len_reg = self.load_len(self.expr_target)
849+
if self.length_reg is None:
850+
# For compatibility with python semantics we recalculate the length
851+
# at every iteration.
852+
len_reg = self.load_len(self.expr_target)
853+
else:
854+
# (unless input is immutable type).
855+
len_reg = builder.read(self.length_reg, line)
837856
comparison = builder.binary_op(builder.read(self.index_target, line), len_reg, "<", line)
838857
builder.add_bool_branch(comparison, self.body_block, self.loop_exit)
839858

mypyc/irbuild/specialize.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def translate_tuple_from_generator_call(
304304
"""Special case for simplest tuple creation from a generator.
305305
306306
For example:
307-
tuple(f(x) for x in some_list/some_tuple/some_str)
307+
tuple(f(x) for x in some_list/some_tuple/some_str/some_bytes)
308308
'translate_safe_generator_call()' would take care of other cases
309309
if this fails.
310310
"""

mypyc/test-data/fixtures/ir.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ def __getitem__(self, i: int) -> int: ...
172172
def __getitem__(self, i: slice) -> bytes: ...
173173
def join(self, x: Iterable[object]) -> bytes: ...
174174
def decode(self, x: str=..., y: str=...) -> str: ...
175+
def __iter__(self) -> Iterator[int]: ...
175176

176177
class bytearray:
177178
@overload

mypyc/test-data/irbuild-generics.test

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -716,18 +716,18 @@ L0:
716716
r0 = __mypyc_self__.__mypyc_env__
717717
r1 = var_object_size args
718718
r2 = PyList_New(r1)
719-
r3 = 0
719+
r3 = var_object_size args
720+
r4 = 0
720721
L1:
721-
r4 = var_object_size args
722-
r5 = r3 < r4 :: signed
722+
r5 = r4 < r3 :: signed
723723
if r5 goto L2 else goto L4 :: bool
724724
L2:
725-
r6 = CPySequenceTuple_GetItemUnsafe(args, r3)
725+
r6 = CPySequenceTuple_GetItemUnsafe(args, r4)
726726
x = r6
727-
CPyList_SetItemUnsafe(r2, r3, x)
727+
CPyList_SetItemUnsafe(r2, r4, x)
728728
L3:
729-
r7 = r3 + 1
730-
r3 = r7
729+
r7 = r4 + 1
730+
r4 = r7
731731
goto L1
732732
L4:
733733
can_listcomp = r2

0 commit comments

Comments
 (0)