(builder: IRBuilder, stmt: AssignmentStmt)
| 207 | |
| 208 | |
| 209 | def transform_assignment_stmt(builder: IRBuilder, stmt: AssignmentStmt) -> None: |
| 210 | lvalues = stmt.lvalues |
| 211 | assert lvalues |
| 212 | builder.disallow_class_assignments(lvalues, stmt.line) |
| 213 | check_unsupported_cls_assignment(builder, stmt) |
| 214 | first_lvalue = lvalues[0] |
| 215 | if stmt.type and isinstance(stmt.rvalue, TempNode): |
| 216 | # This is actually a variable annotation without initializer. Don't generate |
| 217 | # an assignment but we need to call get_assignment_target since it adds a |
| 218 | # name binding as a side effect. |
| 219 | builder.get_assignment_target(first_lvalue, stmt.line) |
| 220 | return |
| 221 | |
| 222 | # Special case multiple assignments like 'x, y = e1, e2'. |
| 223 | if ( |
| 224 | isinstance(first_lvalue, (TupleExpr, ListExpr)) |
| 225 | and isinstance(stmt.rvalue, (TupleExpr, ListExpr)) |
| 226 | and len(first_lvalue.items) == len(stmt.rvalue.items) |
| 227 | and all(is_simple_lvalue(item) for item in first_lvalue.items) |
| 228 | and len(lvalues) == 1 |
| 229 | ): |
| 230 | temps = [] |
| 231 | for right in stmt.rvalue.items: |
| 232 | rvalue_reg = builder.accept(right) |
| 233 | temp = Register(rvalue_reg.type) |
| 234 | builder.assign(temp, rvalue_reg, stmt.line) |
| 235 | temps.append(temp) |
| 236 | for left, temp in zip(first_lvalue.items, temps): |
| 237 | assignment_target = builder.get_assignment_target(left) |
| 238 | builder.assign(assignment_target, temp, stmt.line) |
| 239 | builder.flush_keep_alives(stmt.line) |
| 240 | return |
| 241 | |
| 242 | line = stmt.rvalue.line |
| 243 | rvalue_reg = builder.accept(stmt.rvalue) |
| 244 | |
| 245 | if builder.non_function_scope() and stmt.is_final_def: |
| 246 | builder.init_final_static(first_lvalue, rvalue_reg) |
| 247 | |
| 248 | # Special-case multiple assignments like 'x, y = expr' to reduce refcount ops. |
| 249 | if ( |
| 250 | isinstance(first_lvalue, (TupleExpr, ListExpr)) |
| 251 | and isinstance(rvalue_reg.type, RTuple) |
| 252 | and len(rvalue_reg.type.types) == len(first_lvalue.items) |
| 253 | and len(lvalues) == 1 |
| 254 | and all(is_simple_lvalue(item) for item in first_lvalue.items) |
| 255 | and any(t.is_refcounted for t in rvalue_reg.type.types) |
| 256 | ): |
| 257 | n = len(first_lvalue.items) |
| 258 | borrows = [builder.add(TupleGet(rvalue_reg, i, borrow=True)) for i in range(n)] |
| 259 | builder.builder.keep_alive([rvalue_reg], line, steal=True) |
| 260 | for lvalue_item, rvalue_item in zip(first_lvalue.items, borrows): |
| 261 | rvalue_item = builder.add(Unborrow(rvalue_item)) |
| 262 | builder.assign(builder.get_assignment_target(lvalue_item), rvalue_item, line) |
| 263 | builder.flush_keep_alives(line) |
| 264 | return |
| 265 | |
| 266 | for lvalue in lvalues: |
no test coverage detected
searching dependent graphs…