ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true) { // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix); 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 { EvalError(call, "Variable must be a delegate, not anything else", mr); return(null); } } 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) { EvalError(call, "TODO", dg); return(null); } //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 || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) { continue; } foreach (var i in GetOpCalls(tit, requireStaticItems)) { 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! */ 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) { 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>(); bool hasNonFinalArgs = false; if (call.Arguments != null) { foreach (var arg in call.Arguments) { callArguments.Add(E(arg)); } } #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs); methodOverloads.Clear(); if (deducedOverloads != null) { methodOverloads.AddRange(deducedOverloads); } } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); bool hasHandledUfcsResultBefore = false; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { var ms = ov as MemberSymbol; var dm = ms.Definition as DMethod; if (dm != null) { // In the case of an ufcs, insert the first argument into the CallArguments list if (ms.IsUFCSResult && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument); hasHandledUfcsResultBefore = true; } else if (!ms.IsUFCSResult && hasHandledUfcsResultBefore) // In the rare case of having a ufcs result occuring _after_ a normal member result, remove the initial arg again { callArguments.RemoveAt(0); hasHandledUfcsResultBefore = false; } var deducedTypeDict = new DeducedTypeDictionary(ms); if (dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (!deducedTypeDict.ContainsKey(tpar.NameHash)) { deducedTypeDict[tpar.NameHash] = null; } } } var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); int currentArg = 0; bool add = true; if (callArguments.Count > 0 || dm.Parameters.Count > 0) { for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; // Handle the usage of tuples: Tuples may only be used as as-is, so not as an array, pointer or in a modified way.. if (paramType is IdentifierDeclaration && TryHandleMethodArgumentTuple(ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) { continue; } else if (currentArg < callArguments.Count) { if (!templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])) { add = false; break; } } else { // If there are more parameters than arguments given, check if the param has default values if (!(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer == null) { add = false; break; } // Assume that all further method parameters do have default values - and don't check further parameters break; } } } // If type params were unassigned, try to take the defaults if (add && dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar.NameHash] == null) { add = templateParamDeduction.Handle(tpar, null); if (!add) { if (hasNonFinalArgs) { deducedTypeDict[tpar.NameHash] = new TemplateParameterSymbol(tpar, null); add = true; } else { break; } } } } } if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs)) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); if (eval || !returnBaseTypeOnly) { argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); } else { argTypeFilteredOverloads.Add(bt); } } } } else if (ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (!eval || 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.Count != 0 ? argTypeFilteredOverloads[0] : null); } }
public static AbstractType EvalMethodCall(AbstractType[] baseExpression, ISymbolValue baseValue, TemplateInstanceExpression tix, ResolutionContext ctxt, PostfixExpression_MethodCall call, out List <ISemantic> callArguments, out ISymbolValue delegateValue, bool returnBaseTypeOnly, AbstractSymbolValueProvider ValueProvider = null) { //TODO: Refactor this crap! delegateValue = null; callArguments = null; 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 = baseExpression; var nextResults = new List <AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is AmbiguousType) { nextResults.AddRange((b as AmbiguousType).Overloads); } else if (b is TemplateParameterSymbol) { nextResults.Add((b as TemplateParameterSymbol).Base); } else 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 (ValueProvider != null) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else { ValueProvider.LogError(call, "Variable must be a delegate, not anything else"); return(null); } } else { var bt = mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt); // Must be of type delegate if (bt is DelegateType) { var ret = HandleCallDelegateType(ValueProvider, bt as DelegateType, methodOverloads, returnBaseTypeOnly); if (ret is ISymbolValue) { delegateValue = ret as ISymbolValue; return(null); } else if (ret is AbstractType) { return(ret as AbstractType); } } 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 ret = HandleCallDelegateType(ValueProvider, b as DelegateType, methodOverloads, returnBaseTypeOnly); if (ret is ISymbolValue) { delegateValue = ret as ISymbolValue; return(null); } else if (ret is AbstractType) { return(ret as AbstractType); } } else if (b is ClassType || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) { continue; } foreach (var i in ExpressionTypeEvaluation.GetOpCalls(tit, requireStaticItems)) { 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! */ 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) { methodOverloads.Add(b); } else if (b is PrimitiveType) // dmd 2.066: Uniform Construction Syntax. creal(3) is of type creal. { methodOverloads.Add(b); } } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) { return(null); } // Get all arguments' types callArguments = new List <ISemantic>(); if (call.Arguments != null) { if (ValueProvider != null) { foreach (var arg in call.Arguments) { callArguments.Add(arg != null ? Evaluation.EvaluateValue(arg, ValueProvider) : null); } } else { foreach (var arg in call.Arguments) { callArguments.Add(arg != null ? ExpressionTypeEvaluation.EvaluateType(arg, ctxt) : null); } } } #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt); methodOverloads.Clear(); if (deducedOverloads != null) { methodOverloads.AddRange(deducedOverloads); } } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); bool hasHandledUfcsResultBefore = false; AbstractType untemplatedMethodResult = null; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { HandleDMethodOverload(ctxt, ValueProvider != null, baseValue, callArguments, returnBaseTypeOnly, argTypeFilteredOverloads, ref hasHandledUfcsResultBefore, ov as MemberSymbol, ref untemplatedMethodResult); } else if (ov is DelegateType) { var dg = ov as DelegateType; var bt = dg.Base ?? TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { if (dg.Base == null) { if (dg.IsFunctionLiteral) { dg = new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters); } else { dg = new DelegateType(bt, dg.DeclarationOrExpressionBase as DelegateDeclaration, dg.Parameters); } } argTypeFilteredOverloads.Add(new DelegateCallSymbol(dg, call)); } } else if (ov is PrimitiveType) // dmd 2.066: Uniform Construction Syntax. creal(3) is of type creal. { if (ValueProvider != null) { if (callArguments == null || callArguments.Count != 1) { ValueProvider.LogError(call, "Uniform construction syntax expects exactly one argument"); } else { var pv = callArguments[0] as PrimitiveValue; if (pv == null) { ValueProvider.LogError(call, "Uniform construction syntax expects one built-in scalar value as first argument"); } else { delegateValue = new PrimitiveValue(pv.Value, ov as PrimitiveType, pv.ImaginaryPart); } } } argTypeFilteredOverloads.Add(ov); } } // Prefer untemplated methods over templated ones if (untemplatedMethodResult != null) { return(untemplatedMethodResult); } #endregion return(AmbiguousType.Get(argTypeFilteredOverloads, tix)); }
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); } }