def visit(self, node, tset):
        args_set = {}
        for expr in node.args:
            args_set[expr] = self.visit(expr, tset)

        if node.obj is not None:
            expr_set = self.visit(node.obj, tset)
        else:
            expr_set = {self.current_type.name}

        types_with_method = set()
        method = None
        if node.at_type is not None:
            types_with_method.add(node.at_type)
            method = self.context.get_type(node.at_type).get_method(node.id)

        else:
            for typex in self.context.types.values():
                try:
                    method = typex.get_method(node.id)
                    if len(method.param_names) == len(node.args):
                        types_with_method.add(typex.name)
                except SemanticError:
                    continue

        if len(types_with_method) == 1:
            for arg, param in zip(node.args, method.param_names):
                method.tset.locals[param] = reduce_set(
                    method.tset.locals[param], args_set[arg])
                if isinstance(arg, VariableNode):
                    arg_locals = tset.find_set(arg.lex)
                    arg_locals[arg.lex] = reduce_set(arg_locals[arg.lex],
                                                     method.tset.locals[param])

        if isinstance(node.obj, VariableNode):
            node_id = node.obj.lex
            tset_locals = tset.find_set(node_id)

            tset_locals[node_id] = reduce_set(tset_locals[node_id],
                                              types_with_method)

        types_reduced = intersection(expr_set, types_with_method)

        if len(types_reduced) == 0:
            return {"InferenceError"}

        return_types = set()
        for item in types_reduced:
            item_type = self.context.get_type(item)
            method = item_type.get_method(node.id)
            for typex in method.tset.parent.locals[node.id]:
                return_types.add(typex)

        # ------- Despues de la entrega!!!!!!!
        if "SELF_TYPE" in return_types:
            return_types.remove("SELF_TYPE")
            return_types = union(return_types, expr_set)
        # -------------------------------
        return return_types
    def visit(self, node, tset):
        self.visit(node.left, tset)
        self.visit(node.right, tset)

        int_set = {"Int"}
        if isinstance(node.left, VariableNode):
            node_id = node.left.lex
            tset_locals = tset.find_set(node_id)
            tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set)

        if isinstance(node.right, VariableNode):
            node_id = node.right.lex
            tset_locals = tset.find_set(node_id)
            tset_locals[node_id] = reduce_set(tset_locals[node_id], int_set)

        return int_set
    def visit(self, node, tset):
        method = self.current_type.get_method(node.id)
        self.current_method = method

        current_tset = tset.children[node]
        body_set = self.visit(node.body, current_tset)
        tset.locals[node.id] = reduce_set(tset.locals[node.id], body_set)
        method.tset = current_tset
    def visit(self, node, tset):
        if node.init_exp is not None:
            init_expr_set = self.visit(node.init_exp, tset)
            tset.locals[node.id] = reduce_set(tset.locals[node.id],
                                              init_expr_set)
            return tset.locals[node.id]

        return tset.locals[node.id]
    def visit(self, node, tset):
        self.visit(node.condition, tset)

        if isinstance(node.condition, VariableNode):
            node_id = node.condition.lex
            tset_locals = tset.find_set(node_id)
            tset_locals[node_id] = reduce_set(tset_locals[node_id], {"Bool"})

        self.visit(node.body, tset)

        return {"Object"}
    def visit(self, node, tset):
        self.visit(node.if_expr, tset)
        if isinstance(node.if_expr, VariableNode):
            tset_locals = tset.find_set(node.if_expr.lex)
            tset_locals[node.if_expr.lex] = reduce_set(
                tset_locals[node.if_expr.lex], {"Bool"})
        then_expr_set = self.visit(node.then_expr, tset)
        else_expr_set = self.visit(node.else_expr, tset)

        solve = intersection(then_expr_set, else_expr_set)
        if len(solve) == 0:
            solve = union(then_expr_set, else_expr_set)

        return solve
    def visit(self, node, tset):
        if node.expr is not None:
            expr_set = self.visit(node.expr, tset)
            tset.locals[node.id] = reduce_set(tset.locals[node.id], expr_set)

        return tset.locals[node.id]
 def visit(self, node, tset):
     expr_set = self.visit(node.expr, tset)
     var_set = tset.find_set(node.id)
     var_set[node.id] = reduce_set(var_set[node.id], expr_set)
     return var_set[node.id]