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); } } }