private bool evalIsExpression_WithAliases(IsExpression isExpression, AbstractType typeToCheck) { /* * Note: It's needed to let the abstract ast scanner also scan through IsExpressions etc. * in order to find aliases and/or specified template parameters! */ var expectedTemplateParams = new TemplateParameter[isExpression.TemplateParameterList.Length + 1]; expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam; if(expectedTemplateParams.Length > 1) isExpression.TemplateParameterList.CopyTo (expectedTemplateParams, 1); var tpl_params = new DeducedTypeDictionary(expectedTemplateParams); var tpd = new TemplateParameterDeduction(tpl_params, ctxt); bool retTrue = false; if (isExpression.EqualityTest) // 6. { // a) if (isExpression.TypeSpecialization != null) { tpd.EnforceTypeEqualityWhenDeducing = true; retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); tpd.EnforceTypeEqualityWhenDeducing = false; } else // b) { var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true); retTrue = r.Item1; tpl_params[isExpression.TypeAliasIdentifierHash] = new TemplateParameterSymbol(null, r.Item2); } } else // 5. retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); if (retTrue && isExpression.TemplateParameterList != null) foreach (var p in isExpression.TemplateParameterList) if (!tpd.Handle(p, tpl_params[p.NameHash] != null ? tpl_params[p.NameHash].Base : null)) return false; //TODO: Put all tpl_params results into the resolver context or make a new scope or something! return retTrue; }
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; } }