def visit(self, node, scope):
        if node.obj == None:
            obj_type = self.current_type
        elif isinstance(node.obj, tuple):
            self.visit(node.obj[0], scope)
            child_type = self.update_type(node.obj[0].inferenced_type)
            try:
                obj_type = self.context.get_type(node.obj[1],
                                                 selftype=False,
                                                 autotype=False)
                if isinstance(child_type, AutoType):
                    child_type.set_upper_limmit([obj_type])
            except SemanticError:
                obj_type = ErrorType()
        else:
            self.visit(node.obj, scope)
            obj_type = self.update_type(node.obj.inferenced_type)

        methods = None
        try:
            methods = [(obj_type, obj_type.get_method(node.id))]
        except SemanticError as err:
            if isinstance(obj_type, AutoType):
                result = self.context.get_method_by_name(
                    node.id, len(node.args))
                types = [typex for _, typex in result]
                obj_type.set_upper_limmit(types)
                if len(obj_type.upper_limmit):
                    methods = [(t, t.get_method(node.id))
                               for t in obj_type.upper_limmit]
            else:
                self.AddError(err)

        node.inferenced_obj_type = obj_type
        if methods:
            type_set = set()
            heads = []
            for typex, method in methods:
                ret_type = method.return_type
                ret_type = typex if isinstance(ret_type,
                                               SelfType) else ret_type
                heads, type_set = smart_add(type_set, heads, ret_type)
                if len(node.args) == len(method.param_types):
                    for i in range(len(node.args)):
                        arg, param_type = node.args[i], method.param_types[i]
                        self.visit(arg, scope)
                        arg_type = self.update_type(arg.inferenced_type)
                        arg_type = conforms(arg_type, param_type)
                        if isinstance(param_type, AutoType):
                            param_type = conforms(param_type, arg_type)
                            method.param_types[i] = param_type
                        self.update_graph(arg_type, param_type)
                        arg.inferenced_type = arg_type
            node.inferenced_type = AutoType(node.id, heads, type_set)
        else:
            node.inferenced_type = ErrorType()
Пример #2
0
    def visit(self, node, scope):
        if isinstance(node.inferenced_type, ErrorType):
            return

        if node.obj == None:
            obj_type = self.current_type
        elif isinstance(node.obj, tuple):
            self.visit(node.obj[0], scope)
            child_type = self.update_type(node.obj[0].inferenced_type)
            try:
                obj_type = self.context.get_type(node.obj[1],
                                                 selftype=False,
                                                 autotype=False)
                if isinstance(child_type, AutoType):
                    child_type.set_upper_limmit([obj_type])
            except SemanticError:
                obj_type = ErrorType()
        else:
            self.visit(node.obj, scope)
            obj_type = self.update_type(node.obj.inferenced_type)

        method = None
        try:
            method = obj_type.get_method(node.id)
        except SemanticError:
            if isinstance(obj_type, AutoType):
                result = self.context.get_method_by_name(
                    node.id, len(node.args))
                valid = []
                for meth, typex in result:
                    if typex in obj_type.type_set:
                        valid.append((meth, typex))

                if len(valid) > 1:
                    error = f"Method \"{node.id}\" found in {len(valid)} unrelated types:\n"
                    error += "   -Found in: "
                    error += ", ".join(typex.name for _, typex in valid)
                    self.AddError(error)
                    obj_type = ErrorType()
                elif len(valid) == 0:
                    self.AddError(
                        f"There is no method called {node.id} which takes {len(node.args)} paramters."
                    )
                    obj_type == ErrorType()
                else:
                    method, types = valid[0]
                    obj_type.set_upper_limmit([types])
        node.inferenced_obj_type = self.compare_types(node.inferenced_obj_type,
                                                      obj_type)
        if method:
            type_set = set()
            heads = []
            ret_type = self.update_type(method.return_type)
            heads, type_set = smart_add(type_set, heads, ret_type)
            if len(node.args) == len(method.param_types):
                for i in range(len(node.args)):
                    arg, param_type = node.args[i], method.param_types[i]
                    arg_infer = arg.inferenced_type
                    self.visit(arg, scope)
                    arg_type = self.update_type(arg.inferenced_type)
                    arg_type = conforms(arg_type, param_type)
                    if isinstance(param_type, AutoType):
                        param_type = conforms(param_type, arg_type)
                        method.param_types[i] = self.compare_types(
                            method.param_types[i], param_type)
                    arg.inferenced_type = self.compare_types(
                        arg_infer, arg_type)

            inferred = node.inferenced_type
            if isinstance(ret_type, AutoType) and is_subset(
                    inferred, ret_type):
                method.return_type.set_upper_limmit(heads)
                node.inferenced_type = self.compare_types(
                    inferred, method.return_type)
            elif is_subset(ret_type, inferred):
                node.inferenced_type = self.compare_types(inferred, ret_type)
        else:
            node.inferenced_type = ErrorType()