|
11 | 11 |
|
12 | 12 | from mypy.nodes import ( |
13 | 13 | ARG_POS, |
| 14 | + LDEF, |
14 | 15 | CallExpr, |
15 | 16 | DictionaryComprehension, |
16 | 17 | Expression, |
|
22 | 23 | SetExpr, |
23 | 24 | TupleExpr, |
24 | 25 | TypeAlias, |
| 26 | + Var, |
25 | 27 | ) |
26 | 28 | from mypyc.ir.ops import ( |
27 | 29 | ERR_NEVER, |
@@ -490,6 +492,16 @@ def make_for_loop_generator( |
490 | 492 | for_list = ForSequence(builder, index, body_block, loop_exit, line, nested) |
491 | 493 | for_list.init(expr_reg, target_type, reverse=True) |
492 | 494 | return for_list |
| 495 | + |
| 496 | + elif ( |
| 497 | + expr.callee.fullname == "builtins.map" |
| 498 | + and len(expr.args) >= 2 |
| 499 | + and all(k == ARG_POS for k in expr.arg_kinds) |
| 500 | + ): |
| 501 | + for_map = ForMap(builder, index, body_block, loop_exit, line, nested) |
| 502 | + for_map.init(expr.args[0], expr.args[1:]) |
| 503 | + return for_map |
| 504 | + |
493 | 505 | if isinstance(expr, CallExpr) and isinstance(expr.callee, MemberExpr) and not expr.args: |
494 | 506 | # Special cases for dictionary iterator methods, like dict.items(). |
495 | 507 | rtype = builder.node_type(expr.callee.expr) |
@@ -1147,3 +1159,74 @@ def gen_step(self) -> None: |
1147 | 1159 | def gen_cleanup(self) -> None: |
1148 | 1160 | for gen in self.gens: |
1149 | 1161 | gen.gen_cleanup() |
| 1162 | + |
| 1163 | +class ForMap(ForGenerator): |
| 1164 | + """Generate optimized IR for a for loop over map(f, ...).""" |
| 1165 | + |
| 1166 | + def need_cleanup(self) -> bool: |
| 1167 | + # The wrapped for loops might need cleanup. We might generate a |
| 1168 | + # redundant cleanup block, but that's okay. |
| 1169 | + return True |
| 1170 | + |
| 1171 | + def init(self, func: Expression, exprs: list[Expression]) -> None: |
| 1172 | + self.func_expr = func |
| 1173 | + self.func = self.builder.accept(func) |
| 1174 | + self.exprs = exprs |
| 1175 | + self.cond_blocks = [BasicBlock() for _ in range(len(exprs) - 1)] + [self.body_block] |
| 1176 | + |
| 1177 | + self.gens: list[ForGenerator] = [] |
| 1178 | + for i, iterable_expr in enumerate(exprs): |
| 1179 | + argname = f"_mypyc_map_arg_{i}" |
| 1180 | + var_type = self.builder._analyze_iterable_item_type(iterable_expr) |
| 1181 | + name_expr = NameExpr(argname) |
| 1182 | + name_expr.kind = LDEF |
| 1183 | + name_expr.node = Var(argname, var_type) |
| 1184 | + self.builder.add_local_reg(name_expr.node, self.builder.node_type(iterable_expr)) |
| 1185 | + self.gens.append( |
| 1186 | + make_for_loop_generator( |
| 1187 | + self.builder, |
| 1188 | + name_expr, |
| 1189 | + iterable_expr, |
| 1190 | + #self.gens[-1].body_block if self.gens else self.body_block, |
| 1191 | + self.cond_blocks[i], |
| 1192 | + self.loop_exit, |
| 1193 | + self.line, |
| 1194 | + is_async=False, |
| 1195 | + nested=True, |
| 1196 | + ) |
| 1197 | + ) |
| 1198 | + |
| 1199 | + def gen_condition(self) -> None: |
| 1200 | + for i, gen in enumerate(self.gens): |
| 1201 | + gen.gen_condition() |
| 1202 | + if i < len(self.gens) - 1: |
| 1203 | + self.builder.activate_block(self.cond_blocks[i]) |
| 1204 | + |
| 1205 | + def begin_body(self) -> None: |
| 1206 | + builder = self.builder |
| 1207 | + line = self.line |
| 1208 | + |
| 1209 | + for gen in self.gens: |
| 1210 | + gen.begin_body() |
| 1211 | + |
| 1212 | + # This goes here to prevent a circular import |
| 1213 | + from mypyc.irbuild.expression import transform_call_expr |
| 1214 | + |
| 1215 | + call_expr = CallExpr( |
| 1216 | + self.func_expr, |
| 1217 | + #items, |
| 1218 | + [gen.index for gen in self.gens], |
| 1219 | + [ARG_POS] * len(self.gens), |
| 1220 | + [None] * len(self.gens), |
| 1221 | + ) |
| 1222 | + |
| 1223 | + result = transform_call_expr(builder, call_expr) |
| 1224 | + builder.assign(builder.get_assignment_target(self.index), result, line) |
| 1225 | + |
| 1226 | + def gen_step(self) -> None: |
| 1227 | + for gen in self.gens: |
| 1228 | + gen.gen_step() |
| 1229 | + |
| 1230 | + def gen_cleanup(self) -> None: |
| 1231 | + for gen in self.gens: |
| 1232 | + gen.gen_cleanup() |
0 commit comments