Пример #1
0
        public void Evaluate(ComputationContext ctx)
        {
            if (this.Evaluation == null)
            {
                // trap only lambdas, name reference is a call, not passing function around
                // for example here trapping lambda into closure is necessary
                // ((x) => x*x)()
                // and here is not (regular call)
                // f()
                if (this.TrapLambdaClosure(ctx, ref this.callee))
                {
                    ConvertToExplicitInvoke(ctx);
                }

                {
                    EntityInstance eval = this.Callee.Evaluation.Components.Cast <EntityInstance>();

                    this.Callee.DereferencedCount_LEGACY = ctx.Env.DereferencedOnce(eval, out IEntityInstance __eval, out bool via_pointer) ? 1 : 0;
                    this.DereferencingCount = this.Callee.DereferencedCount_LEGACY;
                    if (this.Callee.DereferencedCount_LEGACY > 0)
                    {
                        eval = __eval.Cast <EntityInstance>();
                    }

                    if (!(this.Name.Binding.Match.Instance.Target is FunctionDefinition) &&
                        eval.Target.Cast <TypeDefinition>().InvokeFunctions().Any())
                    {
                        // if we call a "closure", like my_closure() it is implicit calling "invoke"
                        // so make it explicit on the fly
                        ConvertToExplicitInvoke(ctx);
                    }
                }

                IEnumerable <EntityInstance> matches = this.Name.Binding.Matches
                                                       .Select(it =>
                {
                    if (it.Instance.Target.IsFunction())
                    {
                        return(it.Instance);
                    }
                    else if (it.Instance.Target is Property prop)
                    {
                        return(prop.Getter?.InstanceOf?.TranslateThrough(it.Instance));
                    }
                    else
                    {
                        return(null);
                    }
                })
                                                       .Where(it => it != null);

                if (!matches.Any())
                {
                    this.resolution = new Option <CallResolution>(null);
                    if (!this.Callee.Evaluation.Components.IsJoker) // do not cascade errors
                    {
                        ctx.AddError(ErrorCode.NotFunctionType, this.Callee);
                    }
                }
                else
                {
                    IEnumerable <CallResolution> targets = matches
                                                           .Select(it => CallResolution.Create(ctx, this.Name.TemplateArguments, this,
                                                                                               createCallContext(ctx, this.Name, it.TargetFunction), targetFunctionInstance: it))
                                                           .Where(it => it != null)
                                                           .StoreReadOnly();
                    targets = targets.Where(it => it.RequiredParametersUsed()).StoreReadOnly();
                    targets = targets.Where(it => it.CorrectlyFormedArguments()).StoreReadOnly();
                    targets = targets.Where(it => it.ArgumentTypesMatchParameters(ctx)).StoreReadOnly();
                    if (this.RequestedOutcomeTypeName != null)
                    {
                        targets = targets.Where(it => it.OutcomeMatchesRequest(ctx)).StoreReadOnly();
                    }

                    targets = resolveOverloading(targets).StoreReadOnly();

                    this.resolution = new Option <CallResolution>(targets.FirstOrDefault());

                    if (!targets.Any())
                    {
                        ctx.AddError(ErrorCode.TargetFunctionNotFound, this);
                    }
                    else
                    {
                        if (targets.Count() > 1)
                        {
                            ctx.ErrorManager.AddError(ErrorCode.NOTEST_AmbiguousOverloadedCall, this,
                                                      targets.Select(it => it.TargetFunctionInstance.Target));
                        }

                        foreach (var group in this.Resolution.GetArgumentsMultipleTargeted())
                        {
                            // we only report second "override" because if there are more
                            // it is more likely user forgot to mark parameter variadic
                            ctx.ErrorManager.AddError(ErrorCode.ArgumentForFunctionAlreadyGiven, group.Skip(1).FirstOrDefault());
                        }

                        foreach (FunctionParameter param in this.Resolution.GetUnfulfilledVariadicParameters())
                        {
                            ctx.ErrorManager.AddError(ErrorCode.InvalidNumberVariadicArguments, this, param);
                        }


                        if (targets.Count() == 1)
                        {
                            this.Resolution.EnhanceArguments(ctx);
                        }

                        this.Resolution.SetMappings(ctx);

                        // filtering here is a bit shaky -- if we don't use type inference
                        // we have to filter by what we bind to, but if we use inference
                        // we use target instance (functor or function, not a variable) because only it
                        // is altered by type inference

                        if (this.Resolution.InferredTemplateArguments == null)
                        {
                            // leave only binding which was used for mapping
                            this.Name.Binding.Filter(it => it.IsIdentical(this.Resolution.TargetFunctionInstance));
                        }
                        else
                        {
                            NameReference this_name = this.Name;
                            this_name.DetachFrom(this);
                            this.callee = this_name.Recreate(this.Resolution.InferredTemplateArguments
                                                             .Select(it => new TemplateArgument(it)),
                                                             this.Resolution.TargetFunctionInstance, this_name.Binding.Match.IsLocal);
                            this.callee.AttachTo(this);

                            this.Callee.Evaluated(ctx, EvaluationCall.AdHocCrossJump);

                            if (!this.Name.Binding.HasMatch)
                            {
                                throw new Exception("We've just lost our binding, probably something wrong with template translations");
                            }
                        }

                        this.Evaluation = this.Resolution.Evaluation;

                        if (ctx.Env.IsReferenceOfType(this.Evaluation.Aggregate))
                        {
                            // basically we are saying that the outcome of the function has the lifetime
                            // equal to the shortest lifetime of arguments
                            // or local if the function has not arguments at all
                            Lifetime lifetime = null;
                            foreach (FunctionArgument arg in this.Resolution.ActualArguments)
                            {
                                // todo: we should check if the expression is not passed implictly by reference
                                if (arg == this.Resolution.MetaThisArgument || ctx.Env.IsReferenceOfType(arg.Evaluation.Aggregate))
                                {
                                    lifetime = arg.Evaluation.Aggregate.Lifetime.Shorter(lifetime);
                                }
                            }

                            if (lifetime == null)
                            {
                                lifetime = Lifetime.Create(this);
                            }

                            if (this.Evaluation.Aggregate.Lifetime != lifetime)
                            {
                                this.Evaluation = EvaluationInfo.Create(
                                    this.Evaluation.Components.Rebuild(ctx, lifetime, deep: false),
                                    this.Evaluation.Aggregate.Build(lifetime));
                            }
                        }
                    }
                }


                if (this.Evaluation == null)
                {
                    this.Evaluation = Environment.JokerEval;
                }

                foreach (IExpression arg in UserArguments)
                {
                    arg.ValidateValueExpression(ctx);
                }
            }
        }