/// <summary> /// Called when an application of a function is encountered. /// </summary> //$TODO: move to Analyzer. public static DataType Apply( Analyzer analyzer, FunType func, List <DataType> pos, IDictionary <string, DataType> hash, DataType kw, DataType star, Exp call) { analyzer.RemoveUncalled(func); if (func.Definition != null && !func.Definition.called) { analyzer.CalledFunctions++; func.Definition.called = true; } if (func.Definition == null) { // func without definition (possibly builtins) return(func.GetReturnType()); } else if (call != null && analyzer.InStack(call)) { // Recursive call, ignore. func.SelfType = null; return(DataType.Unknown); } if (call != null) { analyzer.pushStack(call); } var pTypes = new List <DataType>(); // Python: bind first parameter to self type if (func.SelfType != null) { pTypes.Add(func.SelfType); } else if (func.Class != null) { pTypes.Add(func.Class.getCanon()); } if (pos != null) { pTypes.AddRange(pos); } BindMethodAttrs(analyzer, func); State funcTable = new State(func.env, State.StateType.FUNCTION); if (func.Table.Parent != null) { funcTable.Path = func.Table.Parent.ExtendPath(analyzer, func.Definition.name.Name); } else { funcTable.Path = func.Definition.name.Name; } DataType fromType = BindParameters(analyzer, call, func.Definition, funcTable, func.Definition.parameters, func.Definition.vararg, func.Definition.kwarg, pTypes, func.defaultTypes, hash, kw, star); if (func.arrows.TryGetValue(fromType, out var cachedTo)) { func.SelfType = null; return(cachedTo); } else { DataType toType = func.Definition.body.Accept(new TypeTransformer(funcTable, analyzer)); if (MissingReturn(toType)) { analyzer.putProblem(func.Definition.name, "Function doesn't always return a value"); if (call != null) { analyzer.putProblem(call, "Call doesn't always return a value"); } } toType = UnionType.remove(toType, DataType.Cont); func.addMapping(fromType, toType); func.SelfType = null; return(toType); } }