Exemplo n.º 1
0
        public static function_node DeduceFunction(function_node func, expressions_list fact, bool alone, location loc, List<SyntaxTree.expression> syntax_nodes_parameters = null)
        {
            parameter_list formal = func.parameters;
            int formal_count = formal.Count;
            int fact_count = fact.Count;
            int generic_type_params_count = func.generic_parameters_count;
            type_node[] deduced = new type_node[generic_type_params_count];
            List<int> nils = new List<int>();
            int count_params_to_see = fact_count;

            var lambda_syntax_nodes = new Dictionary<string, function_lambda_definition>(); //lroman Получим список фактических параметров-лямбд текущей вызываемой подпрограммы
            if (syntax_nodes_parameters != null
                && syntax_nodes_parameters.Count > 0) //lroman
            {
                lambda_syntax_nodes = syntax_nodes_parameters
                    .OfType<function_lambda_definition>()
                    .ToDictionary(f => f.lambda_name, f => f);
            }

            var lambda_in_parameters = lambda_syntax_nodes.Count > 0; 
            var saved_lambdas_states = SaveLambdasStates(lambda_syntax_nodes.Select(ld => ld.Value)); // Сохраним типы лямбды перед вычислениями

            if (fact_count < formal_count)
            {
                //Сравниваем количества параметров
                parameter par = formal[fact_count];
                if (par.default_value == null && !par.is_params)
                {
                    if (alone)
                        throw new NoFunctionWithSameParametresNum(loc, alone, func);
                    return null;
                }
            }
            else
            {
                type_node last_params_type = null;
                bool last_is_params = false;
                parameter par = null;
                if (formal_count > 0)
                {
                    par = formal[formal_count - 1];
                    last_is_params = par.is_params;
                }
                if (last_is_params)
                {
                    array_internal_interface aii = par.type.get_internal_interface(internal_interface_kind.unsized_array_interface) as array_internal_interface;
                    last_params_type = aii.element_type;
                }
                if (fact_count > formal_count)
                {
                    //Фактических больше, чем формальных. Последний формальный должен быть params...
                    if (last_is_params)
                    {
                        for (int i = formal_count - 1; i < fact_count; ++i)
                        {
                            //Проверяем фактические, попадающие под params...
                            if (!DeduceInstanceTypes(last_params_type, fact[i].type, deduced, nils))
                            {
                                if (alone)
                                    throw new SimpleSemanticError(loc, "GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS", func.name);
                                return null;
                            }
                        }
                        count_params_to_see = formal_count - 1;
                    }
                    else
                    {
                        if (alone)
                            throw new NoFunctionWithSameParametresNum(loc, alone, func);
                        return null;
                    }
                }
            }
            bool need_params_work = (count_params_to_see > 0 && formal[count_params_to_see - 1].is_params);
            if (need_params_work)
            {
                count_params_to_see -= 1;
            }

            var continue_trying_to_infer_types = true; 
            Dictionary<string, delegate_internal_interface> formal_delegates = null; 

            while (continue_trying_to_infer_types) //Продолжаем пытаться вычислить типы до тех пор пока состояние о выведенных типах не будет отличаться от состояния на предыдущей итерации
            {
                var previous_deduce_state = deduced // Текущее состояние выведенных на данный момент типов. Простой список индексов с уже выведенными типами из массива deduced
                        .Select((t, i) => new { Type = t, Index = i })
                        .Where(t => t.Type != null)
                        .Select(t => t.Index)
                        .ToArray();

                for (int i = 0; i < count_params_to_see; ++i)
                {
                    if (!DeduceInstanceTypes(formal[i].type, fact[i].type, deduced, nils))
                    {
                        if (alone)
                            throw new SimpleSemanticError(loc, "GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS", func.name);
                        RestoreLambdasStates(lambda_syntax_nodes.Values.ToList(), saved_lambdas_states);
                        return null;
                    }

                }

                if (lambda_in_parameters)
                {
                    if (formal_delegates == null)
                    {
                        formal_delegates = new Dictionary<string, delegate_internal_interface>();

                        for (int i = 0; i < count_params_to_see; ++i)
                            //Выделим из формальных параметров те, которые соотвтествуют фактическим параметрам-лямбдам
                        {
                            var lambda_func = fact[i].type as delegated_methods;
                            if (lambda_func != null
                                && lambda_func.proper_methods.Count == 1
                                && LambdaHelper.IsLambdaName(lambda_func.proper_methods[0].simple_function_node.name))
                            {
                                formal_delegates.Add(LambdaHelper.GetLambdaNamePartWithoutGenerics(lambda_func.proper_methods[0].simple_function_node.name),
                                                     formal[i].type.get_internal_interface(
                                                         internal_interface_kind.delegate_interface) as
                                                     delegate_internal_interface);
                            }
                        }
                    }

                    foreach (var formal_delegate in formal_delegates)
                        //Перебираем все полученные формальные параемтры, соотвтетсвующие фактическим лямбдам
                    {
                        var lambda_syntax_node = lambda_syntax_nodes[formal_delegate.Key];
                        Exception on_lambda_body_compile_exception;
                            // Исключение которое может возникунть в результате компиляции тела лямбды если мы выберем неправильные типы параметров
                        if (!TryToDeduceTypesInLambda(lambda_syntax_node, formal_delegate.Value, deduced, nils,
                                                      out on_lambda_body_compile_exception))
                            //Пробуем вычислить типы из лямбд
                        {
                            RestoreLambdasStates(lambda_syntax_nodes.Values.ToList(), saved_lambdas_states);

                            if (on_lambda_body_compile_exception != null)
                            {
                                if (alone)
                                {
                                    throw on_lambda_body_compile_exception;
                                }

                                throw new FailedWhileTryingToCompileLambdaBodyWithGivenParametersException(
                                    on_lambda_body_compile_exception);
                            }

                            if (alone)
                            {
                                throw new SimpleSemanticError(loc, "GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS", func.name);
                            }
                            return null;
                        }
                    }
                }
                var current_deduce_state = deduced               //текущее состояние выведенных типов
                    .Select((t, ii) => new {Type = t, Index = ii})
                    .Where(t => t.Type != null)
                    .Select(t => t.Index)
                    .ToArray();

                if (previous_deduce_state.SequenceEqual(current_deduce_state)) // Если ничего с прошлой итерации не изменилось, то дальше нет смысла пробовать выводить. Выходим из цикла
                {
                    continue_trying_to_infer_types = false;
                }
            }

            RestoreLambdasStates(lambda_syntax_nodes.Values.ToList(), saved_lambdas_states);

            if (need_params_work)
            {
                type_node[] tmp_deduced = (type_node[])deduced.Clone();
                List<int> tmp_nils = new List<int>();
                tmp_nils.AddRange(nils);
                if (!DeduceInstanceTypes(formal[count_params_to_see].type, fact[count_params_to_see].type, deduced, nils))
                {
                    //Второй шанс. Учитываем слово params.
                    deduced = tmp_deduced;
                    nils = tmp_nils;
                    if (!DeduceInstanceTypes(formal[count_params_to_see].type.element_type, fact[count_params_to_see].type, deduced, nils))
                    {
                        if (alone)
                            throw new SimpleSemanticError(loc, "GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS", func.name);
                        return null;
                    }
                }
            }
            //Вывели всё, что могли. Теперь проверяем.
            for (int i = 0; i < generic_type_params_count; ++i)
            {
                if (deduced[i] == null)
                {
                    if (alone)
                        throw new SimpleSemanticError(loc, "CAN_NOT_DEDUCE_TYPE_PARAMS_FROM_CALL_{0}", func.name);
                    return null;
                }
            }
            foreach (int num in nils)
            {
                if (!type_table.is_with_nil_allowed(deduced[num]))
                {
                    if (alone)
                        throw new SimpleSemanticError(loc, "GENERIC_FUNCTION_{0}_CAN_NOT_BE_CALLED_WITH_THESE_PARAMETERS", func.name);
                    return null;
                }
            }
            foreach (type_node tt in deduced)
            {
                CompilationErrorWithLocation check_err = generic_parameter_eliminations.check_type_generic_useful(tt, loc);
                if (check_err != null)
                {
                    if (alone)
                        throw check_err;
                    return null;
                }
            }
            //Итак, вывели все параметры. Теперь инстанцируем.
            List<type_node> deduced_list = new List<type_node>(generic_type_params_count);
            deduced_list.AddRange(deduced);
            return func.get_instance(deduced_list, alone, loc);
        }