def transform_member_expr(builder: IRBuilder, expr: MemberExpr) -> Value: # First check if this is maybe a final attribute. final = builder.get_final_ref(expr) if final is not None: fullname, final_var, native = final value = builder.emit_load_final(final_var, fullname, final_var.name, native, 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) can_borrow = builder.is_native_attr_ref(expr) obj = builder.accept(expr.expr, can_borrow=can_borrow) rtype = builder.node_type(expr) # Special case: for named tuples transform attribute access to faster index access. typ = get_proper_type(builder.types.get(expr.expr)) if isinstance(typ, TupleType) and typ.partial_fallback.type.is_named_tuple: fields = typ.partial_fallback.type.metadata['namedtuple']['fields'] if expr.name in fields: index = builder.builder.load_int(fields.index(expr.name)) return builder.gen_method_call(obj, '__getitem__', [index], rtype, expr.line) check_instance_attribute_access_through_class(builder, expr, typ) borrow = can_borrow and builder.can_borrow return builder.builder.get_attr(obj, expr.name, rtype, expr.line, borrow=borrow)
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 transform_member_expr(builder: IRBuilder, expr: MemberExpr) -> Value: # First check if this is maybe a final attribute. final = builder.get_final_ref(expr) if final is not None: fullname, final_var, native = final value = builder.emit_load_final(final_var, fullname, final_var.name, native, 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) obj = builder.accept(expr.expr) return builder.builder.get_attr(obj, expr.name, builder.node_type(expr), expr.line)
def transform_name_expr(builder: IRBuilder, expr: NameExpr) -> Value: if expr.node is None: builder.add(RaiseStandardError(RaiseStandardError.RUNTIME_ERROR, "mypyc internal error: should be unreachable", expr.line)) return builder.none() 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 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, FuncDef and MypyFile node types. if isinstance(expr.node, MypyFile): # Load reference to a module imported inside function from # the modules dictionary. It would be closer to Python # semantics to access modules imported inside functions # via local variables, but this is tricky since the mypy # AST doesn't include a Var node for the module. We # instead load the module separately on each access. mod_dict = builder.call_c(get_module_dict_op, [], expr.line) obj = builder.call_c(dict_get_item_op, [mod_dict, builder.load_str(expr.node.fullname)], expr.line) return obj else: return builder.read(builder.get_assignment_target(expr), expr.line) return builder.load_global(expr)