ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true) { // Deduce template parameters later on AbstractType[] baseExpression = null; ISymbolValue baseValue = null; TemplateInstanceExpression tix = null; bool isUFCSFunction = false; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix, out isUFCSFunction); var methodOverloads = new List <AbstractType>(); #region Search possible methods, opCalls or delegates that could be called bool requireStaticItems = true; //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit IEnumerable <AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression); var nextResults = new List <AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is MemberSymbol) { var mr = (MemberSymbol)b; if (mr.Definition is DMethod) { methodOverloads.Add(mr); continue; } else if (mr.Definition is DVariable) { // If we've got a variable here, get its base type/value reference if (eval) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else { throw new EvaluationException(call, "Variable must be a delegate, not anything else", mr); } } else { var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt)); // Must be of type delegate if (bt is DelegateType) { //TODO: Ensure that there's no further overload - inform the user elsewise if (returnBaseTypeOnly) { return(bt); } else { return(new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase)); } } else { /* * If mr.Node is not a method, so e.g. if it's a variable * pointing to a delegate * * class Foo * { * string opCall() { return "asdf"; } * } * * Foo f=new Foo(); * f(); -- calls opCall, opCall is not static */ nextResults.Add(bt); requireStaticItems = false; } //TODO: Can other types work as function/are callable? } } } else if (b is DelegateType) { var dg = (DelegateType)b; /* * int a = delegate(x) { return x*2; } (12); // a is 24 after execution * auto dg=delegate(x) {return x*3;}; * int b = dg(4); */ if (dg.IsFunctionLiteral) { methodOverloads.Add(dg); } else { // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method. if (eval) { throw new EvaluationException(call, "TODO", dg); } //TODO //if(returnBaseTypeOnly) //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments. return(dg); } } else if (b is ClassType) { /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = ((ClassType)b).Definition; if (classDef == null) { continue; } foreach (var i in classDef) { if (i.Name == "opCall" && i is DMethod && (!requireStaticItems || (i as DNode).IsStatic)) { methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol); } } } /* * Every struct can contain a default ctor: * * struct S { int a; bool b; } * * auto s = S(1,true); -- ok * auto s2= new S(2,false); -- error, no constructor found! */ else if (b is StructType && methodOverloads.Count == 0) { //TODO: Deduce parameters return(b); } /* * If the overload is a template, it quite exclusively means that we'll handle a method that is the only * child inside a template + that is named as the template. */ else if (b is TemplateType && ImplicitTemplateProperties.ContainsEquallyNamedChildrenOnly(((TemplateType)b).Definition)) { methodOverloads.Add(b); } } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) { return(null); } // Get all arguments' types var callArguments = new List <ISemantic>(); // If it's sure that we got a ufcs call here, add the base expression's type as first argument type if (isUFCSFunction) { callArguments.Add(eval ? (ISemantic)baseValue : ((MemberSymbol)baseExpression[0]).Base); } if (call.Arguments != null) { foreach (var arg in call.Arguments) { callArguments.Add(E(arg)); } } #region Deduce template parameters and filter out unmatching overloads // First add optionally given template params // http://dlang.org/template.html#function-templates var tplParamDeductionArguments = tix == null ? new List <ISemantic>() : TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt); // Then add the arguments[' member types] foreach (var arg in callArguments) { if (arg is VariableValue) { tplParamDeductionArguments.Add(ValueProvider[((VariableValue)arg).Variable]); } else if (arg is AbstractType) { tplParamDeductionArguments.Add(DResolver.StripMemberSymbols((AbstractType)arg)); } else { tplParamDeductionArguments.Add(arg); } } var templateParamFilteredOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads( methodOverloads, tplParamDeductionArguments.Count > 0 ? tplParamDeductionArguments.ToArray() : null, true, ctxt); #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); if (templateParamFilteredOverloads != null) { foreach (var ov in templateParamFilteredOverloads) { if (ov is MemberSymbol) { var ms = (MemberSymbol)ov; var dm = ms.Definition as DMethod; bool add = false; if (dm != null) { ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); add = false; if (callArguments.Count == 0 && dm.Parameters.Count == 0) { add = true; } else { for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = TypeDeclarationResolver.ResolveSingle(dm.Parameters[i].Type, ctxt); // TODO: Expression tuples & variable argument lengths if (i >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[i], paramType, ctxt)) { continue; } add = true; } } if (add) { var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); } } ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); } } else if (ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters)); } } } } #endregion if (eval) { // Convert ISemantic[] to ISymbolValue[] var args = new List <ISymbolValue>(callArguments.Count); foreach (var a in callArguments) { args.Add(a as ISymbolValue); } // Execute/Evaluate the variable contents etc. return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray())); } else { // Check if one overload remains and return that one. ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call); return(argTypeFilteredOverloads != null && argTypeFilteredOverloads.Count != 0 ? argTypeFilteredOverloads[0] : null); } }