def assign(self, target: Union[Register, AssignmentTarget], rvalue_reg: Value, line: int) -> None: if isinstance(target, Register): self.add(Assign(target, rvalue_reg)) elif isinstance(target, AssignmentTargetRegister): rvalue_reg = self.coerce(rvalue_reg, target.type, line) self.add(Assign(target.register, rvalue_reg)) elif isinstance(target, AssignmentTargetAttr): if isinstance(target.obj_type, RInstance): rvalue_reg = self.coerce(rvalue_reg, target.type, line) self.add(SetAttr(target.obj, target.attr, rvalue_reg, line)) else: key = self.load_static_unicode(target.attr) boxed_reg = self.builder.box(rvalue_reg) self.add( PrimitiveOp([target.obj, key, boxed_reg], py_setattr_op, line)) elif isinstance(target, AssignmentTargetIndex): target_reg2 = self.gen_method_call(target.base, '__setitem__', [target.index, rvalue_reg], None, line) assert target_reg2 is not None, target.base.type elif isinstance(target, AssignmentTargetTuple): if isinstance(rvalue_reg.type, RTuple) and target.star_idx is None: rtypes = rvalue_reg.type.types assert len(rtypes) == len(target.items) for i in range(len(rtypes)): item_value = self.add(TupleGet(rvalue_reg, i, line)) self.assign(target.items[i], item_value, line) else: self.process_iterator_tuple_assignment(target, rvalue_reg, line) else: assert False, 'Unsupported assignment target'
def assert_emit_binary_op(self, op: str, dest: Value, left: Value, right: Value, expected: str) -> None: # TODO: merge this if op in c_binary_ops: c_ops = c_binary_ops[op] for c_desc in c_ops: if (is_subtype(left.type, c_desc.arg_types[0]) and is_subtype(right.type, c_desc.arg_types[1])): args = [left, right] if c_desc.ordering is not None: args = [args[i] for i in c_desc.ordering] self.assert_emit(CallC(c_desc.c_function_name, args, c_desc.return_type, c_desc.steals, c_desc.error_kind, 55), expected) return ops = binary_ops[op] for desc in ops: if (is_subtype(left.type, desc.arg_types[0]) and is_subtype(right.type, desc.arg_types[1])): self.assert_emit(PrimitiveOp([left, right], desc, 55), expected) break else: assert False, 'Could not find matching op'
def py_get_attr(self, obj: Value, attr: str, line: int) -> Value: """Get a Python attribute (slow). Prefer get_attr() which generates optimized code for native classes. """ key = self.load_static_unicode(attr) return self.add(PrimitiveOp([obj, key], py_getattr_op, line))
def test_new_list(self) -> None: self.assert_emit(PrimitiveOp([self.n, self.m], new_list_op, 55), """cpy_r_r0 = PyList_New(2); if (likely(cpy_r_r0 != NULL)) { PyList_SET_ITEM(cpy_r_r0, 0, cpy_r_n); PyList_SET_ITEM(cpy_r_r0, 1, cpy_r_m); } """)
def primitive_op(self, desc: OpDescription, args: List[Value], line: int) -> Value: assert desc.result_type is not None coerced = [] for i, arg in enumerate(args): formal_type = self.op_arg_type(desc, i) arg = self.coerce(arg, formal_type, line) coerced.append(arg) target = self.add(PrimitiveOp(coerced, desc, line)) return target
def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: assert expr.node, "RefExpr not resolved" fullname = expr.node.fullname if fullname in builtin_names: typ, src = builtin_names[fullname] return builder.add(LoadAddress(typ, src, expr.line)) # special cases if fullname == 'builtins.None': return builder.none() if fullname == 'builtins.True': return builder.true() if fullname == 'builtins.False': return builder.false() if fullname in name_ref_ops: # Use special access op for this particular name. desc = name_ref_ops[fullname] assert desc.result_type is not None return builder.add(PrimitiveOp([], desc, expr.line)) if isinstance(expr.node, Var) and expr.node.is_final: value = builder.emit_load_final( expr.node, fullname, expr.name, builder.is_native_ref_expr(expr), builder.types[expr], expr.line, ) if value is not None: return value if isinstance(expr.node, MypyFile) and expr.node.fullname in builder.imports: return builder.load_module(expr.node.fullname) # If the expression is locally defined, then read the result from the corresponding # assignment target and return it. Otherwise if the expression is a global, load it from # the globals dictionary. # Except for imports, that currently always happens in the global namespace. if expr.kind == LDEF and not (isinstance(expr.node, Var) and expr.node.is_suppressed_import): # Try to detect and error when we hit the irritating mypy bug # where a local variable is cast to None. (#5423) if (isinstance(expr.node, Var) and is_none_rprimitive(builder.node_type(expr)) and expr.node.is_inferred): builder.error( "Local variable '{}' has inferred type None; add an annotation" .format(expr.node.name), expr.node.line) # TODO: Behavior currently only defined for Var and FuncDef node types. return builder.read(builder.get_assignment_target(expr), expr.line) return builder.load_global(expr)
def assert_emit_binary_op(self, op: str, dest: Value, left: Value, right: Value, expected: str) -> None: ops = binary_ops[op] for desc in ops: if (is_subtype(left.type, desc.arg_types[0]) and is_subtype(right.type, desc.arg_types[1])): self.assert_emit(PrimitiveOp([left, right], desc, 55), expected) break else: assert False, 'Could not find matching op'
def transform_del_item(builder: IRBuilder, target: AssignmentTarget, line: int) -> None: if isinstance(target, AssignmentTargetIndex): builder.gen_method_call(target.base, '__delitem__', [target.index], result_type=None, line=line) elif isinstance(target, AssignmentTargetAttr): key = builder.load_static_unicode(target.attr) builder.add(PrimitiveOp([target.obj, key], py_delattr_op, line)) elif isinstance(target, AssignmentTargetRegister): # Delete a local by assigning an error value to it, which will # prompt the insertion of uninit checks. builder.add( Assign(target.register, builder.add(LoadErrorValue(target.type, undefines=True)))) elif isinstance(target, AssignmentTargetTuple): for subtarget in target.items: transform_del_item(builder, subtarget, line)
def test_load_True(self) -> None: self.assert_emit(PrimitiveOp([], true_op, 0), "cpy_r_r0 = 1;")
def test_load_None(self) -> None: self.assert_emit(PrimitiveOp([], none_object_op, 0), "cpy_r_r0 = Py_None;")
def test_new_dict(self) -> None: self.assert_emit(PrimitiveOp([], new_dict_op, 1), """cpy_r_r0 = PyDict_New();""")
def test_dict_update(self) -> None: self.assert_emit( PrimitiveOp([self.d, self.o], dict_update_op, 1), """cpy_r_r0 = CPyDict_Update(cpy_r_d, cpy_r_o) >= 0;""")
def py_get_attr(self, obj: Value, attr: str, line: int) -> Value: key = self.load_static_unicode(attr) return self.add(PrimitiveOp([obj, key], py_getattr_op, line))
def none_object(self) -> Value: """Load Python None value (type: object_rprimitive).""" return self.add(PrimitiveOp([], none_object_op, line=-1))
def load_len(self) -> Value: return self.builder.add(PrimitiveOp([self.builder.read(self.expr_target, self.line)], list_len_op, self.line))
def test_list_get_item(self) -> None: self.assert_emit(PrimitiveOp([self.m, self.k], list_get_item_op, 55), """cpy_r_r0 = CPyList_GetItem(cpy_r_m, cpy_r_k);""")
def test_list_len(self) -> None: self.assert_emit( PrimitiveOp([self.l], list_len_op, 55), """Py_ssize_t __tmp1; __tmp1 = PyList_GET_SIZE(cpy_r_l); cpy_r_r0 = CPyTagged_ShortFromSsize_t(__tmp1); """)
def test_int_neg(self) -> None: self.assert_emit(PrimitiveOp([self.m], int_neg_op, 55), "cpy_r_r0 = CPyTagged_Negate(cpy_r_m);")
def test_load_False(self) -> None: self.assert_emit(PrimitiveOp([], false_op, 0), "cpy_r_r0 = 0;")
def test_list_append(self) -> None: self.assert_emit( PrimitiveOp([self.l, self.o], list_append_op, 1), """cpy_r_r0 = PyList_Append(cpy_r_l, cpy_r_o) >= 0;""")
def none(self) -> Value: """Load unboxed None value (type: none_rprimitive).""" return self.add(PrimitiveOp([], none_op, line=-1))
def test_dict_set_item(self) -> None: self.assert_emit( PrimitiveOp([self.d, self.o, self.o2], dict_set_item_op, 1), """cpy_r_r0 = CPyDict_SetItem(cpy_r_d, cpy_r_o, cpy_r_o2) >= 0;""")
def test_list_set_item(self) -> None: self.assert_emit( PrimitiveOp([self.l, self.n, self.o], list_set_item_op, 55), """cpy_r_r0 = CPyList_SetItem(cpy_r_l, cpy_r_n, cpy_r_o);""")
def none_object(self) -> Value: return self.add(PrimitiveOp([], none_object_op, line=-1))