Beispiel #1
0
        private static bool DeduceParams(IEnumerable <ISemantic> givenTemplateArguments,
                                         bool isMethodCall,
                                         ResolutionContext ctxt,
                                         DSymbol overload,
                                         DNode tplNode,
                                         DeducedTypeDictionary deducedTypes)
        {
            bool isLegitOverload = true;

            var paramEnum = tplNode.TemplateParameters.GetEnumerator();

            var args = givenTemplateArguments ?? new List <ISemantic> ();

            var argEnum = args.GetEnumerator();

            foreach (var expectedParam in tplNode.TemplateParameters)
            {
                if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam))
                {
                    isLegitOverload = false;
                    break;                     // Don't check further params if mismatch has been found
                }
            }

            if (!isMethodCall && argEnum.MoveNext())
            {
                // There are too many arguments passed - discard this overload
                isLegitOverload = false;
            }
            return(isLegitOverload);
        }
        static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt)
        {
            // Get actual overloads
            var matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(template.NameHash, new[] { template }, ctxt, template.DeclarationOrExpressionBase, false);

            if (matchingChild != null)             // Currently requried for proper UFCS resolution - sustain template's Tag
            {
                foreach (var ch in matchingChild)
                {
                    var ds = ch as DSymbol;

                    if (ds != null)
                    {
                        var newDeducedTypes = new DeducedTypeDictionary(ds);
                        foreach (var tps in template.DeducedTypes)
                        {
                            newDeducedTypes[tps.Parameter] = tps;
                        }
                        ds.DeducedTypes = newDeducedTypes.ToReadonly();
                    }
                    ch.Tag = template.Tag;
                }
            }

            return(matchingChild);
        }
Beispiel #3
0
        private static List <AbstractType> DeduceOverloads(
            IEnumerable <AbstractType> rawOverloadList,
            IEnumerable <ISemantic> givenTemplateArguments,
            bool isMethodCall,
            ResolutionContext ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null && givenTemplateArguments.FirstOrDefault() != null;

            var filteredOverloads = new List <AbstractType>();

            if (rawOverloadList == null)
            {
                return(filteredOverloads);
            }

            foreach (var o in rawOverloadList)
            {
                var overload = o as DSymbol;
                if (overload == null)
                {
                    if (!hasTemplateArgsPassed)
                    {
                        filteredOverloads.Add(o);
                    }
                    continue;
                }

                var tplNode = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(overload);
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                    {
                        filteredOverloads.Add(overload);
                    }
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary(tplNode);

                if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly();                     // Assign calculated types to final result
                    filteredOverloads.Add(overload);
                }
                else
                {
                    overload.DeducedTypes = null;
                }
            }
            return(filteredOverloads);
        }
Beispiel #4
0
 static bool CheckAndDeduceTypeAgainstTplParameter(TemplateParameter handledParameter,
                                                   ISemantic argumentToCheck,
                                                   DeducedTypeDictionary deducedTypes,
                                                   ResolutionContext ctxt)
 {
     return(new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(handledParameter, argumentToCheck));
 }
Beispiel #5
0
 static bool CheckAndDeduceTypeTuple(TemplateTupleParameter tupleParameter,
                                     IEnumerable <ISemantic> typeChain,
                                     DeducedTypeDictionary deducedTypes,
                                     ResolutionContext ctxt)
 {
     return(new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(tupleParameter, typeChain));
 }
        public static bool AllParamatersSatisfied(DeducedTypeDictionary deductions)
        {
            foreach (var kv in deductions)
                if (kv.Value == null || kv.Value==null)
                    return false;

            return true;
        }
        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);
        }
Beispiel #8
0
        public static bool AllParamatersSatisfied(DeducedTypeDictionary deductions)
        {
            foreach (var kv in deductions)
            {
                if (kv.Value == null || kv.Value == null)
                {
                    return(false);
                }
            }

            return(true);
        }
		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 == null  ? 1 : (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.ArtificialFirstSpecParam] = new TemplateParameterSymbol(isExpression.ArtificialFirstSpecParam, 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] != null ? tpl_params[p].Base : null))
						return false;

			if (retTrue)
			{
				foreach (var kv in tpl_params)
					ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value;
			}

			return retTrue;
		}
        public string GenTooltipSignature(DNode dn, bool templateParamCompletion = false, 
			int currentMethodParam = -1, ITypeDeclaration baseType=null, DeducedTypeDictionary deducedType = null)
        {
            var sb = new StringBuilder();

            if (dn is DMethod)
                S (dn as DMethod, sb, templateParamCompletion, currentMethodParam, baseType, deducedType);
            else if (dn is DModule) {
                sb.Append ("<i>(Module)</i> ").Append ((dn as DModule).ModuleName);
            } else if (dn is DClassLike)
                S (dn as DClassLike, sb, deducedType);
            else if(dn != null)
                AttributesTypeAndName (dn, sb, baseType, -1, deducedType);

            return sb.ToString ();
        }
        void AttributesTypeAndName(DNode dn, StringBuilder sb,
                                   ITypeDeclaration baseType          = null, int highlightTemplateParam = -1,
                                   DeducedTypeDictionary deducedTypes = null)
        {
            AppendAttributes(dn, sb, baseType == null);

            if (dn.Type != null || baseType != null)
            {
                sb.Append(DCodeToMarkup((baseType ?? dn.Type).ToString(true))).Append(' ');
            }

            // Maybe highlight variables/method names?
            sb.Append(dn.Name);

            AppendTemplateParams(dn, sb, highlightTemplateParam, deducedTypes);
        }
Beispiel #12
0
        static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt)
        {
            // Prepare a new context
            bool pop = !ctxt.ScopedBlockIsInNodeHierarchy(template.Definition);

            if (pop)
            {
                ctxt.PushNewScope(template.Definition);
            }

            // Introduce the deduced params to the current resolution context
            ctxt.CurrentContext.IntroduceTemplateParameterTypes(template);

            // Get actual overloads
            var matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(template.NameHash, new[] { template }, ctxt);

            if (matchingChild != null)             // Currently requried for proper UFCS resolution - sustain template's Tag
            {
                foreach (var ch in matchingChild)
                {
                    var ds = ch as DSymbol;

                    if (ds != null)
                    {
                        var newDeducedTypes = new DeducedTypeDictionary(ds);
                        foreach (var tps in template.DeducedTypes)
                        {
                            newDeducedTypes[tps.Parameter] = tps;
                        }
                        ds.DeducedTypes = newDeducedTypes.ToReadonly();
                    }
                    ch.Tag = template.Tag;
                }
            }

            // Undo context-related changes
            if (pop)
            {
                ctxt.Pop();
            }
            else
            {
                ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template);
            }

            return(matchingChild);
        }
        public bool Handle(TemplateParameter parameter, ISemantic argumentToAnalyze)
        {
            // Packages aren't allowed at all
            if (argumentToAnalyze is PackageSymbol)
                return false;

            // Module symbols can be used as alias only
            if (argumentToAnalyze is ModuleSymbol &&
                !(parameter is TemplateAliasParameter))
                return false;

            //TODO: Handle __FILE__ and __LINE__ correctly - so don't evaluate them at the template declaration but at the point of instantiation

            /*
             * Introduce previously deduced parameters into current resolution context
             * to allow value parameter to be of e.g. type T whereas T is already set somewhere before
             */
            DeducedTypeDictionary _prefLocalsBackup = null;
            if (ctxt != null && ctxt.CurrentContext != null)
            {
                _prefLocalsBackup = ctxt.CurrentContext.DeducedTemplateParameters;

                var d = new DeducedTypeDictionary();
                foreach (var kv in TargetDictionary)
                    if (kv.Value != null)
                        d[kv.Key] = kv.Value;
                ctxt.CurrentContext.DeducedTemplateParameters = d;
            }

            bool res = false;

            if (parameter is TemplateAliasParameter)
                res = Handle((TemplateAliasParameter)parameter, argumentToAnalyze);
            else if (parameter is TemplateThisParameter)
                res = Handle((TemplateThisParameter)parameter, argumentToAnalyze);
            else if (parameter is TemplateTypeParameter)
                res = Handle((TemplateTypeParameter)parameter, argumentToAnalyze);
            else if (parameter is TemplateValueParameter)
                res = Handle((TemplateValueParameter)parameter, argumentToAnalyze);
            else if (parameter is TemplateTupleParameter)
                res = Handle((TemplateTupleParameter)parameter, new[] { argumentToAnalyze });

            if (ctxt != null && ctxt.CurrentContext != null)
                ctxt.CurrentContext.DeducedTemplateParameters = _prefLocalsBackup;

            return res;
        }
		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;
		}
        void S(DClassLike dc, StringBuilder sb, DeducedTypeDictionary deducedTypes = null)
        {
            AppendAttributes(dc, sb);

            sb.Append(DCodeToMarkup(DTokens.GetTokenString(dc.ClassType))).Append(' ');

            sb.Append(DCodeToMarkup(dc.Name));

            AppendTemplateParams(dc, sb, -1, deducedTypes);

            if (dc.BaseClasses != null && dc.BaseClasses.Count != 0)
            {
                sb.AppendLine(" : ");
                sb.Append(" ");
                foreach (var bc in dc.BaseClasses)
                {
                    sb.Append(' ').Append(DCodeToMarkup(bc.ToString())).Append(',');
                }

                RemoveLastChar(sb, ',');
            }

            AppendConstraint(dc, sb);
        }
        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);
                        var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt);

                        if(dm.Parameters.Count == 0 && callArguments.Count > 0)
                            continue;

                        int currentArg = 0;
                        bool add = true;
                        if (dm.Parameters.Count > 0 || callArguments.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] = new TemplateParameterSymbol(tpar, null);
                                            add = true;
                                        }
                                        else
                                            break;
                                    }
                                }
                            }
                        }

                        if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs))
                        {
                            ms.DeducedTypes = deducedTypeDict.ToReadonly();
                            var pop = ctxt.ScopedBlock != dm;
                            if(pop)
                                ctxt.PushNewScope(dm);
                            ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms);

                            var bt=ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt);

                            if(pop)
                                ctxt.Pop();
                            else
                                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;
            }
        }
        static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt)
        {
            // Get actual overloads
            var matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier( template.NameHash, new[]{ template }, ctxt);

            if (matchingChild != null) // Currently requried for proper UFCS resolution - sustain template's Tag
                foreach (var ch in matchingChild)
                {
                    var ds = ch as DSymbol;
                    if (ds != null)
                    {
                        var newDeducedTypes = new DeducedTypeDictionary(ds);
                        foreach (var tps in template.DeducedTypes)
                            newDeducedTypes[tps.Parameter] = tps;
                        ds.DeducedTypes = newDeducedTypes.ToReadonly();
                    }
                    ch.Tag = template.Tag;
                }

            return matchingChild;
        }
Beispiel #18
0
        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);
            }
        }
Beispiel #19
0
        /// <summary>
        /// Checks results for implicit type convertability
        /// </summary>
        public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolverContextStack ctxt = null)
        {
            var resToCheck = AbstractType.Get(resultToCheck);

            // Initially remove aliases from results
            var _r = DResolver.StripMemberSymbols(resToCheck);

            if (_r == null)
            {
                return(IsEqual(resToCheck, targetType));
            }
            resToCheck = _r;

            targetType = DResolver.StripAliasSymbol(targetType);

            if (targetType is DSymbol)
            {
                var tpn = ((DSymbol)targetType).Definition as TemplateParameterNode;

                if (tpn != null)
                {
                    var par = tpn.Parent as DNode;

                    if (par != null && par.TemplateParameters != null)
                    {
                        var dedParam = new DeducedTypeDictionary {
                            ParameterOwner = par
                        };
                        foreach (var tp in par.TemplateParameters)
                        {
                            dedParam[tp.Name] = null;
                        }

                        return(new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck));
                    }
                }
            }

            _r = DResolver.StripMemberSymbols(targetType);
            if (_r == null)
            {
                return(false);
            }
            targetType = _r;

            if (resToCheck is PrimitiveType && targetType is PrimitiveType)
            {
                var sr1 = (PrimitiveType)resToCheck;
                var sr2 = (PrimitiveType)targetType;

                if (sr1.TypeToken == sr2.TypeToken && sr1.Modifier == sr2.Modifier)
                {
                    return(true);
                }

                switch (sr2.TypeToken)
                {
                case DTokens.Int:
                    return(sr1.TypeToken == DTokens.Uint);

                case DTokens.Uint:
                    return(sr1.TypeToken == DTokens.Int);
                    //TODO: Further types that can be converted into each other implicitly
                }
            }
            else if (resToCheck is UserDefinedType && targetType is UserDefinedType)
            {
                return(IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType));
            }
            else if (resToCheck is DelegateType && targetType is DelegateType)
            {
                //TODO
            }
            else if (resToCheck is ArrayType && targetType is ArrayType)
            {
                var ar1 = (ArrayType)resToCheck;
                var ar2 = (ArrayType)targetType;

                // Key as well as value types must be matching!
                var ar1_n = ar1.KeyType == null;
                var ar2_n = ar2.KeyType == null;

                if (ar1_n != ar2_n)
                {
                    return(false);
                }

                if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt))
                {
                    return(IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt));
                }
            }

            else if (resToCheck is TypeTuple && targetType is TypeTuple)
            {
                return(true);
            }
            else if (resToCheck is ExpressionTuple && targetType is ExpressionTuple)
            {
                return(true);
            }

            /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue)
             * {
             *      return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value);
             * }*/

            // http://dlang.org/type.html
            //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly?

            return(false);
        }
        /*void S(DelegateType dt, StringBuilder sb, bool templArgs = false, int curArg = -1)
         * {
         *      if (dt.ReturnType != null)
         *              sb.Append(DCodeToMarkup(dt.ReturnType.ToCode(true))).Append(' ');
         *
         *      // Parameters
         *      sb.Append('(');
         *
         *      if (dt.Parameters != null)
         *      {
         *              for (int i = 0; i < dt.Parameters.Length; i++)
         *              {
         *                      sb.AppendLine();
         *                      sb.Append("  ");
         *
         *                      var parm = dt.Parameters[i];
         *
         *                      var indexBackup = sb.Length;
         *
         *                      //TODO: Show deduced parameters
         *                      AttributesTypeAndName(parm, sb);
         *
         *                      if (!templArgs && curArg == i)
         *                      {
         *                              //TODO: Optimize
         *                              var contentToUnderline = sb.ToString(indexBackup, sb.Length - indexBackup);
         *                              sb.Remove(indexBackup, contentToUnderline.Length);
         *                              AppendFormat(contentToUnderline, sb, FormatFlags.Underline);
         *                      }
         *
         *                      if (parm is DVariable && (parm as DVariable).Initializer != null)
         *                              sb.Append(" = ").Append((parm as DVariable).Initializer.ToString());
         *
         *                      sb.Append(',');
         *              }
         *
         *              RemoveLastChar(sb, ',');
         *              sb.AppendLine();
         *      }
         *
         *      sb.Append(')');
         * }*/

        void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null,
               DeducedTypeDictionary deducedTypes           = null)
        {
            AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes);

            // Parameters
            sb.Append('(');

            if (dm.Parameters.Count != 0)
            {
                for (int i = 0; i < dm.Parameters.Count; i++)
                {
                    if ((SignatureFlags & TooltipSignatureFlags.NoLineBreakedMethodParameters) == 0)
                    {
                        sb.AppendLine().Append("  ");
                    }

                    var parm = dm.Parameters[i] as DNode;

                    var indexBackup = sb.Length;

                    var addSqareBrackets = (this.SignatureFlags & TooltipSignatureFlags.NoEnsquaredDefaultParams) == 0;

                    var isOpt = (this.SignatureFlags & TooltipSignatureFlags.NoDefaultParams) == 0 && parm is DVariable && (parm as DVariable).Initializer != null;

                    if (isOpt && addSqareBrackets)
                    {
                        sb.Append('[');
                    }

                    //TODO: Show deduced parameters
                    AttributesTypeAndName(parm, sb);

                    if (!templArgs && curArg == i)
                    {
                        //TODO: Optimize
                        var contentToUnderline = sb.ToString(indexBackup, sb.Length - indexBackup);
                        sb.Remove(indexBackup, contentToUnderline.Length);
                        AppendFormat(contentToUnderline, sb, FormatFlags.Underline);
                    }

                    if (isOpt)
                    {
                        sb.Append(" = ").Append(DCodeToMarkup((parm as DVariable).Initializer.ToString()));
                        if (addSqareBrackets)
                        {
                            sb.Append(']');
                        }
                    }

                    sb.Append(',');
                }

                RemoveLastChar(sb, ',');
                if ((SignatureFlags & TooltipSignatureFlags.NoLineBreakedMethodParameters) == 0)
                {
                    sb.AppendLine();
                }
            }

            sb.Append(')');

            AppendConstraint(dm, sb);
        }
        private static bool DeduceParam(ResolutionContext ctxt, 
			DSymbol overload, 
			DeducedTypeDictionary deducedTypes,
			IEnumerator<ISemantic> argEnum, 
			TemplateParameter expectedParam)
        {
            if (expectedParam is TemplateThisParameter && overload.Base != null)
            {
                var ttp = (TemplateThisParameter)expectedParam;

                // Get the type of the type of 'this' - so of the result that is the overload's base
                var t = DResolver.StripMemberSymbols(overload.Base);

                if (t == null || t.DeclarationOrExpressionBase == null)
                    return false;

                //TODO: Still not sure if it's ok to pass a type result to it
                // - looking at things like typeof(T) that shall return e.g. const(A) instead of A only.

                if (!CheckAndDeduceTypeAgainstTplParameter(ttp, t, deducedTypes, ctxt))
                    return false;

                return true;
            }

            // Used when no argument but default arg given
            bool useDefaultType = false;
            if (argEnum.MoveNext() || (useDefaultType = HasDefaultType(expectedParam)))
            {
                // On tuples, take all following arguments and pass them to the check function
                if (expectedParam is TemplateTupleParameter)
                {
                    var tupleItems = new List<ISemantic>();
                    // A tuple must at least contain one item!
                    tupleItems.Add(argEnum.Current);
                    while (argEnum.MoveNext())
                        tupleItems.Add(argEnum.Current);

                    if (!CheckAndDeduceTypeTuple((TemplateTupleParameter)expectedParam, tupleItems, deducedTypes, ctxt))
                        return false;
                }
                else if (argEnum.Current != null)
                {
                    if (!CheckAndDeduceTypeAgainstTplParameter(expectedParam, argEnum.Current, deducedTypes, ctxt))
                        return false;
                }
                else if (useDefaultType && CheckAndDeduceTypeAgainstTplParameter(expectedParam, null, deducedTypes, ctxt))
                {
                    // It's legit - just do nothing
                }
                else
                    return false;
            }
            else if(expectedParam is TemplateTupleParameter)
            {
                if(!CheckAndDeduceTypeTuple(expectedParam as TemplateTupleParameter, null, deducedTypes, ctxt))
                    return false;
            }
            // There might be too few args - but that doesn't mean that it's not correct - it's only required that all parameters got satisfied with a type
            else if (!deducedTypes.AllParamatersSatisfied)
                return false;

            return true;
        }
        static void HandleDMethodOverload(ResolutionContext ctxt, bool eval, ISymbolValue baseValue, List <ISemantic> callArguments, bool returnBaseTypeOnly, List <AbstractType> argTypeFilteredOverloads, ref bool hasHandledUfcsResultBefore,
                                          MemberSymbol ms, ref AbstractType untemplatedMethod)
        {
            var dm = ms.Definition as DMethod;

            if (dm == null)
            {
                return;
            }



            ISemantic firstUfcsArg;
            bool      isUfcs = UFCSResolver.IsUfcsResult(ms, out firstUfcsArg);

            // In the case of an ufcs, insert the first argument into the CallArguments list
            if (isUfcs && !hasHandledUfcsResultBefore)
            {
                callArguments.Insert(0, eval ? baseValue as ISemantic : firstUfcsArg);
                hasHandledUfcsResultBefore = true;
            }
            else if (!isUfcs && 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;
            }

            if (dm.Parameters.Count == 0 && callArguments.Count > 0)
            {
                return;
            }

            var deducedTypeDict        = new DeducedTypeDictionary(ms);
            var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt);

            var back = ctxt.ScopedBlock;

            using (ctxt.Push(ms))
            {
                if (ctxt.ScopedBlock != back)
                {
                    ctxt.CurrentContext.DeducedTemplateParameters = deducedTypeDict;
                }

                bool add        = true;
                int  currentArg = 0;
                if (dm.Parameters.Count > 0 || callArguments.Count > 0)
                {
                    bool hadDTuples = false;
                    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 &&
                            (hadDTuples |= TryHandleMethodArgumentTuple(ctxt, ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)))
                        {
                            continue;
                        }
                        else if (currentArg < callArguments.Count)
                        {
                            if (!(add = templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])))
                            {
                                break;
                            }
                        }
                        else
                        {
                            // If there are more parameters than arguments given, check if the param has default values
                            add = !(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer != null;

                            // Assume that all further method parameters do have default values - and don't check further parameters
                            break;
                        }
                    }

                    // Too few args
                    if (!hadDTuples && currentArg < callArguments.Count)
                    {
                        add = false;
                    }
                }

                if (!add)
                {
                    return;
                }

                // If type params were unassigned, try to take the defaults
                if (dm.TemplateParameters != null)
                {
                    foreach (var tpar in dm.TemplateParameters)
                    {
                        if (deducedTypeDict[tpar] == null && !templateParamDeduction.Handle(tpar, null))
                        {
                            return;
                        }
                    }
                }

                if (deducedTypeDict.AllParamatersSatisfied)
                {
                    ms.DeducedTypes = deducedTypeDict.ToReadonly();
                    var bt = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt) ?? ms.Base;

                    if (eval || !returnBaseTypeOnly)
                    {
                        bt = new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes)
                        {
                            Tag = ms.Tag
                        }
                    }
                    ;

                    if (dm.TemplateParameters == null || dm.TemplateParameters.Length == 0)
                    {
                        untemplatedMethod = bt;                         //ISSUE: Have another state that indicates an ambiguous non-templated method matching.
                    }
                    argTypeFilteredOverloads.Add(bt);
                }
            }
        }
Beispiel #23
0
        private static List <AbstractType> DeduceOverloads(
            IEnumerable <AbstractType> rawOverloadList,
            IEnumerable <ISemantic> givenTemplateArguments,
            bool isMethodCall,
            ResolverContextStack ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null;

            if (hasTemplateArgsPassed)
            {
                var enumm = givenTemplateArguments.GetEnumerator();
                hasTemplateArgsPassed = enumm.MoveNext();
                enumm.Dispose();
            }

            var filteredOverloads = new List <AbstractType>();

            if (rawOverloadList == null)
            {
                return(filteredOverloads);
            }

            foreach (var o in DResolver.StripAliasSymbols(rawOverloadList))
            {
                if (!(o is DSymbol))
                {
                    if (!hasTemplateArgsPassed)
                    {
                        filteredOverloads.Add(o);
                    }
                    continue;
                }

                var overload = (DSymbol)o;
                var tplNode  = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(overload);
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                    {
                        filteredOverloads.Add(overload);
                    }
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary {
                    ParameterOwner = tplNode
                };
                foreach (var param in tplNode.TemplateParameters)
                {
                    deducedTypes[param.Name] = null;                     // Init all params to null to let deduction functions know what params there are
                }
                if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly();                     // Assign calculated types to final result
                    filteredOverloads.Add(overload);
                }
                else
                {
                    overload.DeducedTypes = null;
                }
            }
            return(filteredOverloads);
        }
        static bool CheckAndDeduceTypeTuple(TemplateTupleParameter tupleParameter, 
			IEnumerable<ISemantic> typeChain,
			DeducedTypeDictionary deducedTypes,
			ResolutionContext ctxt)
        {
            return new Templates.TemplateParameterDeduction(deducedTypes,ctxt).Handle(tupleParameter,typeChain);
        }
        private static List <AbstractType> DeduceOverloads(
            IEnumerable <AbstractType> rawOverloadList,
            IEnumerable <ISemantic> givenTemplateArguments,
            bool isMethodCall,
            ResolutionContext ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null && givenTemplateArguments.FirstOrDefault() != null;

            var filteredOverloads = new List <AbstractType>();

            if (rawOverloadList == null)
            {
                return(filteredOverloads);
            }

            foreach (var o in rawOverloadList)
            {
                var overload = o as DSymbol;
                while (overload is TemplateParameterSymbol)
                {
                    overload = overload.Base as DSymbol;
                }
                if (overload == null)
                {
                    if (!hasTemplateArgsPassed)
                    {
                        filteredOverloads.Add(o);
                    }
                    continue;
                }
                else if (overload.Tag is TypeDeclarationResolver.AliasTag &&
                         (hasTemplateArgsPassed || !(overload.DeclarationOrExpressionBase is TemplateInstanceExpression)))
                {
                    TypeDeclarationResolver.ResetDeducedSymbols(overload);
                }

                var tplNode = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(o);
                    continue;
                }

                bool ignoreOtherOverloads;
                var  hook = D_Parser.Resolver.ResolutionHooks.HookRegistry.TryDeduce(overload, givenTemplateArguments, out ignoreOtherOverloads);
                if (hook != null)
                {
                    filteredOverloads.Add(hook);
                    if (ignoreOtherOverloads)
                    {
                        break;
                    }
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                    {
                        filteredOverloads.Add(o);
                    }
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary(overload);

                if (deducedTypes.AllParamatersSatisfied)                 // Happens e.g. after resolving a class/interface definition
                {
                    filteredOverloads.Add(o);
                }
                else if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly();                     // Assign calculated types to final result
                    filteredOverloads.Add(o);
                }
                else
                {
                    overload.DeducedTypes = null;
                }
            }
            return(filteredOverloads);
        }
Beispiel #26
0
        /// <summary>
        /// Checks results for implicit type convertability 
        /// </summary>
        public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolverContextStack ctxt=null)
        {
            var resToCheck = AbstractType.Get(resultToCheck);

            // Initially remove aliases from results
            var _r=DResolver.StripMemberSymbols(resToCheck);
            if(_r==null)
                return IsEqual(resToCheck,targetType);
            resToCheck = _r;

            targetType = DResolver.StripAliasSymbol(targetType);

            if (targetType is DSymbol)
            {
                var tpn = ((DSymbol)targetType).Definition as TemplateParameterNode;

                if (tpn!=null)
                {
                    var par = tpn.Parent as DNode;

                    if (par != null && par.TemplateParameters != null)
                    {
                        var dedParam = new DeducedTypeDictionary { ParameterOwner=par };
                        foreach (var tp in par.TemplateParameters)
                            dedParam[tp.Name] = null;

                        return new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck);
                    }
                }
            }

            _r = DResolver.StripMemberSymbols(targetType);
            if (_r == null)
                return false;
            targetType = _r;

            if (resToCheck is PrimitiveType && targetType is PrimitiveType)
            {
                var sr1 = (PrimitiveType)resToCheck;
                var sr2 = (PrimitiveType)targetType;

                if (sr1.TypeToken == sr2.TypeToken && sr1.Modifier == sr2.Modifier)
                    return true;

                switch (sr2.TypeToken)
                {
                    case DTokens.Int:
                        return sr1.TypeToken == DTokens.Uint;
                    case DTokens.Uint:
                        return sr1.TypeToken == DTokens.Int;
                    //TODO: Further types that can be converted into each other implicitly
                }
            }
            else if (resToCheck is UserDefinedType && targetType is UserDefinedType)
                return IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType);
            else if (resToCheck is DelegateType && targetType is DelegateType)
            {
                //TODO
            }
            else if (resToCheck is ArrayType && targetType is ArrayType)
            {
                var ar1 = (ArrayType)resToCheck;
                var ar2 = (ArrayType)targetType;

                // Key as well as value types must be matching!
                var ar1_n= ar1.KeyType==null;
                var ar2_n=ar2.KeyType==null;

                if (ar1_n != ar2_n)
                    return false;

                if(ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt))
                    return IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt);
            }

            else if (resToCheck is TypeTuple && targetType is TypeTuple)
            {
                return true;
            }
            else if (resToCheck is ExpressionTuple && targetType is ExpressionTuple)
            {
                return true;
            }
            /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue)
            {
                return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value);
            }*/

            // http://dlang.org/type.html
            //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly?

            return false;
        }
Beispiel #27
0
        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 == null  ? 1 : (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.ArtificialFirstSpecParam] = new TemplateParameterSymbol(isExpression.ArtificialFirstSpecParam, 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] != null ? tpl_params[p].Base : null))
                    {
                        return(false);
                    }
                }
            }

            if (retTrue)
            {
                foreach (var kv in tpl_params)
                {
                    ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value;
                }
            }

            return(retTrue);
        }
        private bool TryHandleMethodArgumentTuple(ref bool add,
			List<ISemantic> callArguments, 
			DMethod dm, 
			DeducedTypeDictionary deducedTypeDict, int currentParameter,ref int currentArg)
        {
            // .. so only check if it's an identifer & if the id represents a tuple parameter
            var id = dm.Parameters[currentParameter].Type as IdentifierDeclaration;
            var curNode = dm as DNode;
            TemplateParameter tpar = null;
            while (curNode != null && !curNode.TryGetTemplateParameter(id.IdHash, out tpar))
                curNode = curNode.Parent as DNode;

            if (!(tpar is TemplateTupleParameter))
                return false;

            int lastArgumentToTake = -1;
            /*
             * Note: an expression tuple parameter can occur also somewhere in between the parameter list!
             * void write(A...)(bool b, A a, double d) {}
             *
             * can be matched by
             * write(true, 1.2) as well as
             * write(true, "asdf", 1.2) as well as
             * write(true, 123, true, 'c', [3,4,5], 3.4) !
             */

            TemplateParameterSymbol tps;
            DTuple tuple = null;
            if (deducedTypeDict.TryGetValue(tpar, out tps) && tps != null)
            {
                if (tps.Base is DTuple)
                {
                    tuple = tps.Base as DTuple;
                    lastArgumentToTake = currentParameter + (tuple.Items == null ? 0 : (tuple.Items.Length-1));
                }
                else
                {
                    // Error: Type param must be tuple!
                }
            }
            // - Get the (amount of) arguments that shall be put into the tuple
            else if (currentParameter == dm.Parameters.Count - 1)
            {
                // The usual case: A tuple of a variable length is put at the end of a parameter list..
                // take all arguments from i until the end of the argument list..
                lastArgumentToTake = callArguments.Count - 1;

                // Also accept empty tuples..
                if (callArguments.Count == 0)
                    lastArgumentToTake = 0;
            }
            else
            {
                // Get the type of the next expected parameter
                var nextExpectedParameter = DResolver.StripMemberSymbols(TypeDeclarationResolver.ResolveSingle(dm.Parameters[currentParameter + 1].Type, ctxt));

                // Look for the first argument whose type is equal to the next parameter's type..
                for (int k = currentArg; k < callArguments.Count; k++)
                {
                    if (ResultComparer.IsEqual(AbstractType.Get(callArguments[k]), nextExpectedParameter))
                    {
                        // .. and assume the tuple to go from i to the previous argument..
                        lastArgumentToTake = k - 1;
                        break;
                    }
                }
            }

            if (lastArgumentToTake < 0)
            {
                // An error occurred somewhere..
                add = false;
                return true;
            }

            int argCountToHandle = lastArgumentToTake - currentArg;
            if (argCountToHandle > 0)
                argCountToHandle++;

            if (tuple != null)
            {
                // - If there's been set an explicit type tuple, compare all arguments' types with those in the tuple
                if(tuple.Items != null)
                    foreach (ISemantic item in tuple.Items)
                    {
                        if (currentArg >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[currentArg++], AbstractType.Get(item), ctxt))
                        {
                            add = false;
                            return true;
                        }
                    }
            }
            else
            {
                // - If there was no explicit initialization, put all arguments' types into a type tuple
                var argsToTake = new ISemantic[argCountToHandle];
                callArguments.CopyTo(currentArg, argsToTake, 0, argsToTake.Length);
                currentArg += argsToTake.Length;
                var tt = new DTuple(null, argsToTake);
                tps = new TemplateParameterSymbol(tpar, tt);

                //   and set the actual template tuple parameter deduction
                deducedTypeDict[tpar] = tps;
            }
            add = true;
            return true;
        }
 public TemplateParameterDeduction(DeducedTypeDictionary DeducedParameters, ResolutionContext ctxt)
 {
     this.ctxt = ctxt;
     this.TargetDictionary = DeducedParameters;
 }
        void AppendTemplateParams(DNode dn, StringBuilder sb, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null)
        {
            if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0)
            {
                sb.Append('(');

                for (int i = 0; i < dn.TemplateParameters.Length; i++)
                {
                    var param = dn.TemplateParameters[i];
                    if (param != null)
                    {
                        var tps = deducedTypes != null ? deducedTypes[param] : null;

                        string str;

                        if (tps == null)
                        {
                            str = param.ToString();
                        }
                        else if (tps.ParameterValue != null)
                        {
                            str = tps.ParameterValue.ToCode();
                        }
                        else if (tps.Base != null)
                        {
                            str = tps.Base.ToCode();
                        }
                        else
                        {
                            str = param.ToString();
                        }

                        AppendFormat(DCodeToMarkup(str), sb, i != highlightTemplateParam ? FormatFlags.None : FormatFlags.Underline);
                        sb.Append(',');
                    }
                }

                RemoveLastChar(sb, ',');

                sb.Append(')');
            }
        }
        public string GenTooltipSignature(DNode dn, bool templateParamCompletion = false,
                                          int currentMethodParam = -1, ITypeDeclaration baseType = null, DeducedTypeDictionary deducedType = null)
        {
            var sb = new StringBuilder();

            if (dn is DMethod)
            {
                S(dn as DMethod, sb, templateParamCompletion, currentMethodParam, baseType, deducedType);
            }
            else if (dn is DModule)
            {
                sb.Append("<i>(Module)</i> ").Append((dn as DModule).ModuleName);
            }
            else if (dn is DClassLike)
            {
                S(dn as DClassLike, sb, deducedType);
            }
            else if (dn != null)
            {
                AttributesTypeAndName(dn, sb, baseType, -1, deducedType);
            }

            return(sb.ToString());
        }
Beispiel #32
0
        private static bool DeduceParam(ResolutionContext ctxt,
                                        DSymbol overload,
                                        DeducedTypeDictionary deducedTypes,
                                        IEnumerator <ISemantic> argEnum,
                                        TemplateParameter expectedParam)
        {
            if (expectedParam is TemplateThisParameter && overload.Base != null)
            {
                var ttp = (TemplateThisParameter)expectedParam;

                // Get the type of the type of 'this' - so of the result that is the overload's base
                var t = DResolver.StripMemberSymbols(overload.Base);

                if (t == null || t.DeclarationOrExpressionBase == null)
                {
                    return(false);
                }

                //TODO: Still not sure if it's ok to pass a type result to it
                // - looking at things like typeof(T) that shall return e.g. const(A) instead of A only.

                if (!CheckAndDeduceTypeAgainstTplParameter(ttp, t, deducedTypes, ctxt))
                {
                    return(false);
                }

                return(true);
            }

            // Used when no argument but default arg given
            bool useDefaultType = false;

            if (argEnum.MoveNext() || (useDefaultType = HasDefaultType(expectedParam)))
            {
                // On tuples, take all following arguments and pass them to the check function
                if (expectedParam is TemplateTupleParameter)
                {
                    var tupleItems = new List <ISemantic>();
                    // A tuple must at least contain one item!
                    tupleItems.Add(argEnum.Current);
                    while (argEnum.MoveNext())
                    {
                        tupleItems.Add(argEnum.Current);
                    }

                    if (!CheckAndDeduceTypeTuple((TemplateTupleParameter)expectedParam, tupleItems, deducedTypes, ctxt))
                    {
                        return(false);
                    }
                }
                else if (argEnum.Current != null)
                {
                    if (!CheckAndDeduceTypeAgainstTplParameter(expectedParam, argEnum.Current, deducedTypes, ctxt))
                    {
                        return(false);
                    }
                }
                else if (useDefaultType && CheckAndDeduceTypeAgainstTplParameter(expectedParam, null, deducedTypes, ctxt))
                {
                    // It's legit - just do nothing
                }
                else
                {
                    return(false);
                }
            }
            else if (expectedParam is TemplateTupleParameter)
            {
                if (!CheckAndDeduceTypeTuple(expectedParam as TemplateTupleParameter, null, deducedTypes, ctxt))
                {
                    return(false);
                }
            }
            // There might be too few args - but that doesn't mean that it's not correct - it's only required that all parameters got satisfied with a type
            else if (!deducedTypes.AllParamatersSatisfied)
            {
                return(false);
            }

            return(true);
        }
Beispiel #33
0
        /// <summary>
        /// Checks results for implicit type convertability
        /// </summary>
        public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolutionContext ctxt = null)
        {
            var  resToCheck = AbstractType.Get(resultToCheck);
            bool isVariable = resToCheck is MemberSymbol;

            // Initially remove aliases from results
            var _r = DResolver.StripMemberSymbols(resToCheck);

            if (_r == null)
            {
                return(IsEqual(resToCheck, targetType));
            }
            resToCheck = _r;

            if (targetType is DSymbol)
            {
                var tpn = ((DSymbol)targetType).Definition as TemplateParameter.Node;

                if (tpn != null)
                {
                    var par = tpn.Parent as DNode;

                    if (par != null && par.TemplateParameters != null)
                    {
                        var dedParam = new DeducedTypeDictionary(par);

                        return(new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck));
                    }
                }
            }

            _r = DResolver.StripMemberSymbols(targetType);
            if (_r == null)
            {
                return(false);
            }
            targetType = _r;

            if (resToCheck is PrimitiveType && targetType is PrimitiveType)
            {
                var sr1 = (PrimitiveType)resToCheck;
                var sr2 = (PrimitiveType)targetType;

                //if (sr1.TypeToken == sr2.TypeToken /*&& sr1.Modifier == sr2.Modifier*/)
                //	return true;

                return(IsPrimitiveTypeImplicitlyConvertible(sr1.TypeToken, sr2.TypeToken));
            }
            else if (resToCheck is UserDefinedType && targetType is UserDefinedType)
            {
                return(IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType));
            }
            else if (resToCheck is DelegateType && targetType is DelegateType)
            {
                return(IsEqual(resToCheck, targetType));                //TODO: Can non-equal delegates be converted into each other?
            }
            else if (resToCheck is ArrayType && targetType is ArrayType)
            {
                var ar1 = (ArrayType)resToCheck;
                var ar2 = (ArrayType)targetType;

                // Key as well as value types must be matching!
                var ar1_n = ar1.KeyType == null;
                var ar2_n = ar2.KeyType == null;

                if (ar1_n != ar2_n)
                {
                    return(false);
                }

                if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt))
                {
                    return(IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt));
                }
            }
            else if (resToCheck is DSymbol && targetType is DSymbol)
            {
                var r1 = resToCheck as DSymbol;
                var r2 = targetType as DSymbol;

                if (r1.Definition == r2.Definition)
                {
                    //TODO: Compare template param deductions
                    return(true);
                }
            }
            else if (resToCheck is DTuple && targetType is DTuple)
            {
                var tup1 = resToCheck as DTuple;
                var tup2 = resToCheck as DTuple;

                //TODO
                return(true);
            }

            /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue)
             * {
             *      return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value);
             * }*/

            // http://dlang.org/type.html
            //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly?
            else if (!isVariable &&
                     resToCheck is ArrayType &&
                     targetType is PointerType && ((targetType = (targetType as PointerType).Base) is PrimitiveType) &&
                     DTokens.IsBasicType_Character((targetType as PrimitiveType).TypeToken))
            {
                return((resultToCheck as ArrayType).IsString);
            }


            return(false);
        }
        private static bool DeduceParams(IEnumerable<ISemantic> givenTemplateArguments, 
			bool isMethodCall, 
			ResolverContextStack ctxt, 
			DSymbol overload, 
			DNode tplNode, 
			DeducedTypeDictionary deducedTypes)
        {
            bool isLegitOverload = true;

            var paramEnum = tplNode.TemplateParameters.GetEnumerator();

            var args= givenTemplateArguments == null ? new List<ISemantic>() : givenTemplateArguments;

            if (overload is MemberSymbol && ((MemberSymbol)overload).IsUFCSResult){
                var l = new List<ISemantic>();
                l.Add(overload.Base); // The base stores the first argument('s type)
                l.AddRange(args);
                args = l;
            }

            var argEnum = args.GetEnumerator();
            foreach (var expectedParam in tplNode.TemplateParameters)
                if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam))
                {
                    isLegitOverload = false;
                    break; // Don't check further params if mismatch has been found
                }

            if (!isMethodCall && argEnum.MoveNext())
            {
                // There are too many arguments passed - discard this overload
                isLegitOverload = false;
            }
            return isLegitOverload;
        }
Beispiel #35
0
        /// <summary>
        /// Takes the class passed via the tr, and resolves its base class and/or implemented interfaces.
        /// Also usable for enums.
        ///
        /// Never returns null. Instead, the original 'tr' object will be returned if no base class was resolved.
        /// Will clone 'tr', whereas the new object will contain the base class.
        /// </summary>
        public static TemplateIntermediateType ResolveClassOrInterface(DClassLike dc, ResolutionContext ctxt, ISyntaxRegion instanceDeclaration, bool ResolveFirstBaseIdOnly = false, IEnumerable <TemplateParameterSymbol> extraDeducedTemplateParams = null)
        {
            if (parsedClassInstanceDecls == null)
            {
                parsedClassInstanceDecls = new List <ISyntaxRegion> ();
            }

            switch (dc.ClassType)
            {
            case DTokens.Class:
            case DTokens.Interface:
                break;

            default:
                if (dc.BaseClasses.Count != 0)
                {
                    ctxt.LogError(dc, "Only classes and interfaces may inherit from other classes/interfaces");
                }
                return(null);
            }

            bool isClass = dc.ClassType == DTokens.Class;

            if (bcStack > 6 || (instanceDeclaration != null && parsedClassInstanceDecls.Contains(instanceDeclaration)))
            {
                return(isClass ? new ClassType(dc, instanceDeclaration, null) as TemplateIntermediateType : new InterfaceType(dc, instanceDeclaration));
            }

            if (instanceDeclaration != null)
            {
                parsedClassInstanceDecls.Add(instanceDeclaration);
            }
            bcStack++;

            var deducedTypes = new DeducedTypeDictionary(dc);
            var tix          = instanceDeclaration as TemplateInstanceExpression;

            if (tix != null && (ctxt.Options & ResolutionOptions.NoTemplateParameterDeduction) == 0)
            {
                bool hasUndeterminedArgs;
                var  givenTemplateArguments = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasUndeterminedArgs);

                if (!TemplateInstanceHandler.DeduceParams(givenTemplateArguments, false, ctxt, null, dc, deducedTypes))
                {
                    parsedClassInstanceDecls.Remove(instanceDeclaration);
                    bcStack--;
                    return(null);
                }
            }

            if (extraDeducedTemplateParams != null)
            {
                foreach (var tps in extraDeducedTemplateParams)
                {
                    deducedTypes[tps.Parameter] = tps;
                }
            }


            if (dc.BaseClasses == null || dc.BaseClasses.Count < 1)
            {
                parsedClassInstanceDecls.Remove(instanceDeclaration);
                bcStack--;

                // The Object class has no further base class;
                // Normal class instances have the object as base class;
                // Interfaces must not have any default base class/interface
                return(isClass ? new ClassType(dc, instanceDeclaration, dc.NameHash != ObjectNameHash ? ctxt.ParseCache.ObjectClassResult : null, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) :
                       new InterfaceType(dc, instanceDeclaration, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) as TemplateIntermediateType);
            }


            #region Base class & interface resolution
            AbstractType[] res;
            var            pop = ctxt.ScopedBlock != dc.Parent;
            if (pop)
            {
                ctxt.PushNewScope(dc.Parent as IBlockNode);
            }

            foreach (var kv in deducedTypes)
            {
                ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value;
            }

            TemplateIntermediateType baseClass = null;
            var interfaces = new List <InterfaceType>();
            try
            {
                for (int i = 0; i < (ResolveFirstBaseIdOnly ? 1 : dc.BaseClasses.Count); i++)
                {
                    var type = dc.BaseClasses[i];

                    // If there's an explicit 'Object' inheritance, also return the pre-resolved object class
                    if (type is IdentifierDeclaration &&
                        (type as IdentifierDeclaration).IdHash == ObjectNameHash)
                    {
                        if (baseClass != null)
                        {
                            ctxt.LogError(new ResolutionError(dc, "Class must not have two base classes"));
                            continue;
                        }
                        else if (i != 0)
                        {
                            ctxt.LogError(new ResolutionError(dc, "The base class name must preceed base interfaces"));
                            continue;
                        }

                        baseClass = ctxt.ParseCache.ObjectClassResult;
                        continue;
                    }

                    if (type == null || (type is IdentifierDeclaration && (type as IdentifierDeclaration).IdHash == dc.NameHash) || dc.NodeRoot == dc)
                    {
                        ctxt.LogError(new ResolutionError(dc, "A class cannot inherit from itself"));
                        continue;
                    }

                    res = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(type, ctxt));

                    ctxt.CheckForSingleResult(res, type);

                    if (res != null && res.Length != 0)
                    {
                        var r = res[0];
                        if (r is ClassType || r is TemplateType)
                        {
                            if (!isClass)
                            {
                                ctxt.LogError(new ResolutionError(type, "An interface cannot inherit from non-interfaces"));
                            }
                            else if (i == 0)
                            {
                                baseClass = r as TemplateIntermediateType;
                            }
                            else
                            {
                                ctxt.LogError(new ResolutionError(dc, "The base " + (r is ClassType ?  "class" : "template") + " name must preceed base interfaces"));
                            }
                        }
                        else if (r is InterfaceType)
                        {
                            interfaces.Add(r as InterfaceType);

                            if (isClass && dc.NameHash != ObjectNameHash && baseClass == null)
                            {
                                baseClass = ctxt.ParseCache.ObjectClassResult;
                            }
                        }
                        else
                        {
                            ctxt.LogError(new ResolutionError(type, "Resolved class is neither a class nor an interface"));
                            continue;
                        }
                    }
                }
            }
            finally
            {
                bcStack--;
                parsedClassInstanceDecls.Remove(instanceDeclaration);
            }

            if (pop)
            {
                ctxt.Pop();
            }
            else
            {
                foreach (var kv in deducedTypes)                 // May be backup old tps?
                {
                    ctxt.CurrentContext.DeducedTemplateParameters.Remove(kv.Key);
                }
            }

            #endregion

            if (isClass)
            {
                return(new ClassType(dc, instanceDeclaration, baseClass, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null));
            }

            return(new InterfaceType(dc, instanceDeclaration, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null));
        }
Beispiel #36
0
        /// <summary>
        /// Checks results for implicit type convertability 
        /// </summary>
        public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolutionContext ctxt=null)
        {
            var resToCheck = AbstractType.Get(resultToCheck);
            bool isVariable = resToCheck is MemberSymbol;

            // Initially remove aliases from results
            var _r=DResolver.StripMemberSymbols(resToCheck);
            if(_r==null)
                return IsEqual(resToCheck,targetType);
            resToCheck = _r;

            targetType = DResolver.StripAliasSymbol(targetType);

            if (targetType is DSymbol)
            {
                var tpn = ((DSymbol)targetType).Definition as TemplateParameter.Node;

                if (tpn!=null)
                {
                    var par = tpn.Parent as DNode;

                    if (par != null && par.TemplateParameters != null)
                    {
                        var dedParam = new DeducedTypeDictionary(par);

                        return new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck);
                    }
                }
            }

            _r = DResolver.StripMemberSymbols(targetType);
            if (_r == null)
                return false;
            targetType = _r;

            if (resToCheck is PrimitiveType && targetType is PrimitiveType)
            {
                var sr1 = (PrimitiveType)resToCheck;
                var sr2 = (PrimitiveType)targetType;

                if (sr1.TypeToken == sr2.TypeToken /*&& sr1.Modifier == sr2.Modifier*/)
                    return true;

                return ImplicitConvertabilityTable.Contains((sr2.TypeToken << 8) + sr1.TypeToken);
            }
            else if (resToCheck is UserDefinedType && targetType is UserDefinedType)
                return IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType);
            else if (resToCheck is DelegateType && targetType is DelegateType)
                return IsEqual(resToCheck, targetType); //TODO: Can non-equal delegates be converted into each other?
            else if (resToCheck is ArrayType && targetType is ArrayType)
            {
                var ar1 = (ArrayType)resToCheck;
                var ar2 = (ArrayType)targetType;

                // Key as well as value types must be matching!
                var ar1_n = ar1.KeyType == null;
                var ar2_n = ar2.KeyType == null;

                if (ar1_n != ar2_n)
                    return false;

                if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt))
                    return IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt);
            }
            else if (resToCheck is DSymbol && targetType is DSymbol)
            {
                var r1 = resToCheck as DSymbol;
                var r2 = targetType as DSymbol;

                if (r1.Definition == r2.Definition)
                {
                    //TODO: Compare template param deductions
                    return true;
                }
            }
            else if (resToCheck is DTuple && targetType is DTuple)
            {
                var tup1 = resToCheck as DTuple;
                var tup2 = resToCheck as DTuple;

                //TODO
                return true;
            }
            /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue)
            {
                return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value);
            }*/

            // http://dlang.org/type.html
            //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly?
            else if (!isVariable &&
                resToCheck is ArrayType &&
                targetType is PointerType && ((targetType = (targetType as PointerType).Base) is PrimitiveType) &&
                DTokens.IsBasicType_Character((targetType as PrimitiveType).TypeToken))
                return (resultToCheck as ArrayType).IsString;

            return false;
        }
        private static List<AbstractType> DeduceOverloads(
			IEnumerable<AbstractType> rawOverloadList, 
			IEnumerable<ISemantic> givenTemplateArguments, 
			bool isMethodCall, 
			ResolutionContext ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null && givenTemplateArguments.FirstOrDefault() != null;

            var filteredOverloads = new List<AbstractType>();

            if (rawOverloadList == null)
                return filteredOverloads;

            foreach (var o in rawOverloadList)
            {
                var overload = o as DSymbol;
                while (overload is TemplateParameterSymbol)
                    overload = overload.Base as DSymbol;
                if (overload == null)
                {
                    if (!hasTemplateArgsPassed)
                        filteredOverloads.Add(o);
                    continue;
                }
                else if (overload.Tag is TypeDeclarationResolver.AliasTag &&
                    (hasTemplateArgsPassed || !(overload.DeclarationOrExpressionBase is TemplateInstanceExpression)))
                    TypeDeclarationResolver.ResetDeducedSymbols(overload);

                var tplNode = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(o);
                    continue;
                }

                bool ignoreOtherOverloads;
                var hook = D_Parser.Resolver.ResolutionHooks.HookRegistry.TryDeduce(overload, givenTemplateArguments, out ignoreOtherOverloads);
                if (hook != null)
                {
                    filteredOverloads.Add(hook);
                    if (ignoreOtherOverloads)
                        break;
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                        filteredOverloads.Add(o);
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary(overload);

                if (deducedTypes.AllParamatersSatisfied) // Happens e.g. after resolving a class/interface definition
                    filteredOverloads.Add(o);
                else if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result
                    filteredOverloads.Add(o);
                }
                else
                    overload.DeducedTypes = null;
            }
            return filteredOverloads;
        }
        static bool CheckAndDeduceTypeAgainstTplParameter(TemplateParameter handledParameter, 
			ISemantic argumentToCheck,
			DeducedTypeDictionary deducedTypes,
			ResolutionContext ctxt)
        {
            return new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(handledParameter, argumentToCheck);
        }
        void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null,
			DeducedTypeDictionary deducedTypes = null)
        {
            AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes);

            // Parameters
            sb.Append ('(');

            if (dm.Parameters.Count != 0) {
                for (int i = 0; i < dm.Parameters.Count; i++) {
                    sb.AppendLine ();
                    sb.Append ("  ");

                    var parm = dm.Parameters [i] as DNode;

                    var indexBackup = sb.Length;

                    //TODO: Show deduced parameters
                    AttributesTypeAndName(parm , sb);

                    if (!templArgs && curArg == i) {
                        //TODO: Optimize
                        var contentToUnderline = sb.ToString(indexBackup, sb.Length-indexBackup);
                        sb.Remove (indexBackup, contentToUnderline.Length);
                        AppendFormat (contentToUnderline, sb, FormatFlags.Underline);
                    }

                    if (parm is DVariable && (parm as DVariable).Initializer != null)
                        sb.Append(" = ").Append((parm as DVariable).Initializer.ToString());

                    sb.Append (',');
                }

                RemoveLastChar (sb, ',');
                sb.AppendLine ();
            }

            sb.Append (')');
        }
        private static List<AbstractType> DeduceOverloads(
			IEnumerable<AbstractType> rawOverloadList, 
			IEnumerable<ISemantic> givenTemplateArguments, 
			bool isMethodCall, 
			ResolutionContext ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null && givenTemplateArguments.FirstOrDefault() != null;

            var filteredOverloads = new List<AbstractType>();

            if (rawOverloadList == null)
                return filteredOverloads;

            foreach (var o in rawOverloadList)
            {
                var overload = o as DSymbol;
                if (overload == null)
                {
                    if(!hasTemplateArgsPassed)
                        filteredOverloads.Add(o);
                    continue;
                }

                var tplNode = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(overload);
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                        filteredOverloads.Add(overload);
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary(overload);

                if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result
                    filteredOverloads.Add(overload);
                }
                else
                    overload.DeducedTypes = null;
            }
            return filteredOverloads;
        }
		void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null,
			DeducedTypeDictionary deducedTypes = null)
		{
			AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes);

			AppendParameters(dm.Parameters, sb, templArgs, curArg);

			AppendConstraint(dm, sb);
		}
        private static bool DeduceParams(IEnumerable<ISemantic> givenTemplateArguments, 
			bool isMethodCall, 
			ResolutionContext ctxt, 
			DSymbol overload, 
			DNode tplNode, 
			DeducedTypeDictionary deducedTypes)
        {
            bool isLegitOverload = true;

            var paramEnum = tplNode.TemplateParameters.GetEnumerator();

            var args = givenTemplateArguments ?? new List<ISemantic> ();

            var argEnum = args.GetEnumerator();
            foreach (var expectedParam in tplNode.TemplateParameters)
                if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam))
                {
                    isLegitOverload = false;
                    break; // Don't check further params if mismatch has been found
                }

            if (!isMethodCall && argEnum.MoveNext())
            {
                // There are too many arguments passed - discard this overload
                isLegitOverload = false;
            }
            return isLegitOverload;
        }
		void S(DClassLike dc, StringBuilder sb, DeducedTypeDictionary deducedTypes = null)
		{
			AppendAttributes(dc, sb);

			sb.Append(DCodeToMarkup(DTokens.GetTokenString(dc.ClassType))).Append(' ');

			sb.Append(DCodeToMarkup(dc.Name));

			AppendTemplateParams(dc, sb, -1, deducedTypes);

			if (dc.BaseClasses != null && dc.BaseClasses.Count != 0)
			{
				sb.AppendLine(" : ");
				sb.Append(" ");
				foreach (var bc in dc.BaseClasses)
					sb.Append(' ').Append(DCodeToMarkup(bc.ToString())).Append(',');

				RemoveLastChar(sb, ',');
			}

			AppendConstraint(dc, sb);
		}
        internal static bool TryHandleMethodArgumentTuple(ResolutionContext ctxt, ref bool add,
                                                          List <ISemantic> callArguments,
                                                          DMethod dm,
                                                          DeducedTypeDictionary deducedTypeDict, int currentParameter, ref int currentArg)
        {
            // .. so only check if it's an identifer & if the id represents a tuple parameter
            var id                 = dm.Parameters[currentParameter].Type as IdentifierDeclaration;
            var curNode            = dm as DNode;
            TemplateParameter tpar = null;

            while (curNode != null && !curNode.TryGetTemplateParameter(id.IdHash, out tpar))
            {
                curNode = curNode.Parent as DNode;
            }

            if (!(tpar is TemplateTupleParameter))
            {
                return(false);
            }

            int lastArgumentToTake = -1;

            /*
             * Note: an expression tuple parameter can occur also somewhere in between the parameter list!
             * void write(A...)(bool b, A a, double d) {}
             *
             * can be matched by
             * write(true, 1.2) as well as
             * write(true, "asdf", 1.2) as well as
             * write(true, 123, true, 'c', [3,4,5], 3.4) !
             */

            TemplateParameterSymbol tps;
            DTuple tuple = null;

            if (deducedTypeDict.TryGetValue(tpar, out tps) && tps != null)
            {
                if (tps.Base is DTuple)
                {
                    tuple = tps.Base as DTuple;
                    lastArgumentToTake = currentParameter + (tuple.Items == null ? 0 : (tuple.Items.Length - 1));
                }
                else
                {
                    // Error: Type param must be tuple!
                }
            }
            // - Get the (amount of) arguments that shall be put into the tuple
            else if (currentParameter == dm.Parameters.Count - 1)
            {
                // The usual case: A tuple of a variable length is put at the end of a parameter list..
                // take all arguments from i until the end of the argument list..
                // ; Also accept empty tuples
                lastArgumentToTake = callArguments.Count - 1;
            }
            else
            {
                // Get the type of the next expected parameter
                var nextExpectedParameter = DResolver.StripMemberSymbols(TypeDeclarationResolver.ResolveSingle(dm.Parameters[currentParameter + 1].Type, ctxt));

                // Look for the first argument whose type is equal to the next parameter's type..
                for (int k = currentArg; k < callArguments.Count; k++)
                {
                    if (ResultComparer.IsEqual(AbstractType.Get(callArguments[k]), nextExpectedParameter))
                    {
                        // .. and assume the tuple to go from i to the previous argument..
                        lastArgumentToTake = k - 1;
                        break;
                    }
                }
            }

            int argCountToHandle = lastArgumentToTake - currentArg + 1;

            if (tuple != null)
            {
                // - If there's been set an explicit type tuple, compare all arguments' types with those in the tuple
                if (tuple.Items != null)
                {
                    foreach (ISemantic item in tuple.Items)
                    {
                        if (currentArg >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[currentArg++], AbstractType.Get(item), ctxt))
                        {
                            add = false;
                            return(true);
                        }
                    }
                }
            }
            else
            {
                // - If there was no explicit initialization, put all arguments' types into a type tuple
                var argsToTake = new ISemantic[argCountToHandle];
                callArguments.CopyTo(currentArg, argsToTake, 0, argsToTake.Length);
                currentArg += argsToTake.Length;
                var tt = new DTuple(null, argsToTake);
                tps = new TemplateParameterSymbol(tpar, tt);

                //   and set the actual template tuple parameter deduction
                deducedTypeDict[tpar] = tps;
            }
            add = true;
            return(true);
        }
		void AttributesTypeAndName(DNode dn, StringBuilder sb,
			ITypeDeclaration baseType = null, int highlightTemplateParam = -1,
			DeducedTypeDictionary deducedTypes = null)
		{
			AppendAttributes(dn, sb, baseType == null);

			if (dn.Type != null || baseType != null)
				sb.Append(DCodeToMarkup((baseType ?? dn.Type).ToString(true))).Append(' ');

			// Maybe highlight variables/method names?
			sb.Append(dn.Name);

			AppendTemplateParams(dn, sb, highlightTemplateParam, deducedTypes);
		}
		void AppendTemplateParams(DNode dn, StringBuilder sb, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null)
		{
			if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0)
			{
				sb.Append('(');

				for (int i = 0; i < dn.TemplateParameters.Length; i++)
				{
					var param = dn.TemplateParameters[i];
					if (param != null)
					{
						var tps = deducedTypes != null ? deducedTypes[param] : null;

						string str;

						if (tps == null)
							str = param.ToString();
						else if (tps.ParameterValue != null)
							str = tps.ParameterValue.ToCode();
						else if (tps.Base != null)
							str = tps.Base.ToCode();
						else
							str = param.ToString();

						AppendFormat(DCodeToMarkup(str), sb, i != highlightTemplateParam ? FormatFlags.None : FormatFlags.Underline);
						sb.Append(',');
					}
				}

				RemoveLastChar(sb, ',');

				sb.Append(')');
			}
		}
        private static List<AbstractType> DeduceOverloads(
			IEnumerable<AbstractType> rawOverloadList, 
			IEnumerable<ISemantic> givenTemplateArguments, 
			bool isMethodCall, 
			ResolverContextStack ctxt)
        {
            bool hasTemplateArgsPassed = givenTemplateArguments != null;
            if (hasTemplateArgsPassed)
            {
                var enumm = givenTemplateArguments.GetEnumerator();
                hasTemplateArgsPassed = enumm.MoveNext();
                enumm.Dispose();
            }

            var filteredOverloads = new List<AbstractType>();

            if (rawOverloadList == null)
                return filteredOverloads;

            foreach (var o in DResolver.StripAliasSymbols(rawOverloadList))
            {
                if (!(o is DSymbol))
                {
                    if(!hasTemplateArgsPassed)
                        filteredOverloads.Add(o);
                    continue;
                }

                var overload = (DSymbol)o;
                var tplNode = overload.Definition;

                // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params
                if (tplNode == null)
                {
                    filteredOverloads.Add(overload);
                    continue;
                }

                // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit.
                if (tplNode.TemplateParameters == null)
                {
                    if (!hasTemplateArgsPassed || isMethodCall)
                        filteredOverloads.Add(overload);
                    continue;
                }

                var deducedTypes = new DeducedTypeDictionary { ParameterOwner=tplNode };
                foreach (var param in tplNode.TemplateParameters)
                    deducedTypes[param.Name] = null; // Init all params to null to let deduction functions know what params there are

                if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes))
                {
                    overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result
                    filteredOverloads.Add(overload);
                }
                else
                    overload.DeducedTypes = null;
            }
            return filteredOverloads;
        }