Beispiel #1
0
        /// <summary>
        /// Associates the given arguments with the template parameters specified in the type/method declarations
        /// and filters out unmatching overloads.
        /// </summary>
        /// <param name="rawOverloadList">Can be either type results or method results</param>
        /// <param name="givenTemplateArguments">A list of already resolved arguments passed explicitly
        /// in the !(...) section of a template instantiation
        /// or call arguments given in the (...) appendix
        /// that follows a method identifier</param>
        /// <param name="isMethodCall">If true, arguments that exceed the expected parameter count will be ignored as far as all parameters could be satisfied.</param>
        /// <param name="ctxt"></param>
        /// <returns>A filtered list of overloads which mostly fit to the specified arguments.
        /// Usually contains only 1 element.
        /// The 'TemplateParameters' property of the results will be also filled for further usage regarding smart completion etc.</returns>
        public static AbstractType[] DeduceParamsAndFilterOverloads(IEnumerable <AbstractType> rawOverloadList,
                                                                    IEnumerable <ISemantic> givenTemplateArguments,
                                                                    bool isMethodCall,
                                                                    ResolverContextStack ctxt)
        {
            if (rawOverloadList == null)
            {
                return(null);
            }

            var filteredOverloads = DeduceOverloads(rawOverloadList, givenTemplateArguments, isMethodCall, ctxt);

            AbstractType[] sortedAndFilteredOverloads = null;

            // If there are >1 overloads, filter from most to least specialized template param
            if (filteredOverloads.Count > 1)
            {
                sortedAndFilteredOverloads = SpecializationOrdering.FilterFromMostToLeastSpecialized(filteredOverloads, ctxt);
            }
            else if (filteredOverloads.Count == 1)
            {
                sortedAndFilteredOverloads = new[] { filteredOverloads[0] }
            }
            ;
            else
            {
                return(null);
            }

            if (sortedAndFilteredOverloads != null &&
                sortedAndFilteredOverloads.Length == 1 &&
                sortedAndFilteredOverloads[0] is TemplateType)
            {
                ImplicitTemplateProperties.TryGetImplicitProperty((TemplateType)sortedAndFilteredOverloads[0], ctxt, out sortedAndFilteredOverloads);
            }

            return(sortedAndFilteredOverloads);
        }
Beispiel #2
0
        ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true)
        {
            // Deduce template parameters later on
            AbstractType[]             baseExpression = null;
            ISymbolValue               baseValue      = null;
            TemplateInstanceExpression tix            = null;
            bool isUFCSFunction = false;

            GetRawCallOverloads(call, out baseExpression, out baseValue, out tix, out isUFCSFunction);

            var methodOverloads = new List <AbstractType>();

            #region Search possible methods, opCalls or delegates that could be called
            bool requireStaticItems = true;             //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit
            IEnumerable <AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression);
            var nextResults = new List <AbstractType>();

            while (scanResults != null)
            {
                foreach (var b in scanResults)
                {
                    if (b is MemberSymbol)
                    {
                        var mr = (MemberSymbol)b;

                        if (mr.Definition is DMethod)
                        {
                            methodOverloads.Add(mr);
                            continue;
                        }
                        else if (mr.Definition is DVariable)
                        {
                            // If we've got a variable here, get its base type/value reference
                            if (eval)
                            {
                                var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue;

                                if (dgVal != null)
                                {
                                    nextResults.Add(dgVal.Definition);
                                    continue;
                                }
                                else
                                {
                                    throw new EvaluationException(call, "Variable must be a delegate, not anything else", mr);
                                }
                            }
                            else
                            {
                                var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt));

                                // Must be of type delegate
                                if (bt is DelegateType)
                                {
                                    //TODO: Ensure that there's no further overload - inform the user elsewise

                                    if (returnBaseTypeOnly)
                                    {
                                        return(bt);
                                    }
                                    else
                                    {
                                        return(new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase));
                                    }
                                }
                                else
                                {
                                    /*
                                     * If mr.Node is not a method, so e.g. if it's a variable
                                     * pointing to a delegate
                                     *
                                     * class Foo
                                     * {
                                     *	string opCall() {  return "asdf";  }
                                     * }
                                     *
                                     * Foo f=new Foo();
                                     * f(); -- calls opCall, opCall is not static
                                     */
                                    nextResults.Add(bt);
                                    requireStaticItems = false;
                                }
                                //TODO: Can other types work as function/are callable?
                            }
                        }
                    }
                    else if (b is DelegateType)
                    {
                        var dg = (DelegateType)b;

                        /*
                         * int a = delegate(x) { return x*2; } (12); // a is 24 after execution
                         * auto dg=delegate(x) {return x*3;};
                         * int b = dg(4);
                         */

                        if (dg.IsFunctionLiteral)
                        {
                            methodOverloads.Add(dg);
                        }
                        else
                        {
                            // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method.
                            if (eval)
                            {
                                throw new EvaluationException(call, "TODO", dg);
                            }
                            //TODO
                            //if(returnBaseTypeOnly)
                            //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments.
                            return(dg);
                        }
                    }
                    else if (b is ClassType)
                    {
                        /*
                         * auto a = MyStruct(); -- opCall-Overloads can be used
                         */
                        var classDef = ((ClassType)b).Definition;

                        if (classDef == null)
                        {
                            continue;
                        }

                        foreach (var i in classDef)
                        {
                            if (i.Name == "opCall" && i is DMethod && (!requireStaticItems || (i as DNode).IsStatic))
                            {
                                methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol);
                            }
                        }
                    }

                    /*
                     * Every struct can contain a default ctor:
                     *
                     * struct S { int a; bool b; }
                     *
                     * auto s = S(1,true); -- ok
                     * auto s2= new S(2,false); -- error, no constructor found!
                     */
                    else if (b is StructType && methodOverloads.Count == 0)
                    {
                        //TODO: Deduce parameters
                        return(b);
                    }

                    /*
                     * If the overload is a template, it quite exclusively means that we'll handle a method that is the only
                     * child inside a template + that is named as the template.
                     */
                    else if (b is TemplateType &&
                             ImplicitTemplateProperties.ContainsEquallyNamedChildrenOnly(((TemplateType)b).Definition))
                    {
                        methodOverloads.Add(b);
                    }
                }

                scanResults = nextResults.Count == 0 ? null : nextResults.ToArray();
                nextResults.Clear();
            }
            #endregion

            if (methodOverloads.Count == 0)
            {
                return(null);
            }

            // Get all arguments' types
            var callArguments = new List <ISemantic>();

            // If it's sure that we got a ufcs call here, add the base expression's type as first argument type
            if (isUFCSFunction)
            {
                callArguments.Add(eval ? (ISemantic)baseValue : ((MemberSymbol)baseExpression[0]).Base);
            }

            if (call.Arguments != null)
            {
                foreach (var arg in call.Arguments)
                {
                    callArguments.Add(E(arg));
                }
            }

            #region Deduce template parameters and filter out unmatching overloads
            // First add optionally given template params
            // http://dlang.org/template.html#function-templates
            var tplParamDeductionArguments = tix == null ?
                                             new List <ISemantic>() :
                                             TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt);

            // Then add the arguments[' member types]
            foreach (var arg in callArguments)
            {
                if (arg is VariableValue)
                {
                    tplParamDeductionArguments.Add(ValueProvider[((VariableValue)arg).Variable]);
                }
                else if (arg is AbstractType)
                {
                    tplParamDeductionArguments.Add(DResolver.StripMemberSymbols((AbstractType)arg));
                }
                else
                {
                    tplParamDeductionArguments.Add(arg);
                }
            }

            var templateParamFilteredOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(
                methodOverloads,
                tplParamDeductionArguments.Count > 0 ? tplParamDeductionArguments.ToArray() : null,
                true, ctxt);
            #endregion

            #region Filter by parameter-argument comparison
            var argTypeFilteredOverloads = new List <AbstractType>();

            if (templateParamFilteredOverloads != null)
            {
                foreach (var ov in templateParamFilteredOverloads)
                {
                    if (ov is MemberSymbol)
                    {
                        var  ms  = (MemberSymbol)ov;
                        var  dm  = ms.Definition as DMethod;
                        bool add = false;

                        if (dm != null)
                        {
                            ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms);

                            add = false;

                            if (callArguments.Count == 0 && dm.Parameters.Count == 0)
                            {
                                add = true;
                            }
                            else
                            {
                                for (int i = 0; i < dm.Parameters.Count; i++)
                                {
                                    var paramType = TypeDeclarationResolver.ResolveSingle(dm.Parameters[i].Type, ctxt);

                                    // TODO: Expression tuples & variable argument lengths
                                    if (i >= callArguments.Count ||
                                        !ResultComparer.IsImplicitlyConvertible(callArguments[i], paramType, ctxt))
                                    {
                                        continue;
                                    }

                                    add = true;
                                }
                            }

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

                                if (returnBaseTypeOnly)
                                {
                                    argTypeFilteredOverloads.Add(bt);
                                }
                                else
                                {
                                    argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms);
                                }
                            }

                            ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms);
                        }
                    }
                    else if (ov is DelegateType)
                    {
                        var dg = (DelegateType)ov;
                        var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt);

                        //TODO: Param-Arg check
                        if (returnBaseTypeOnly)
                        {
                            argTypeFilteredOverloads.Add(bt);
                        }
                        else
                        {
                            argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters));
                        }
                    }
                }
            }
            #endregion

            if (eval)
            {
                // Convert ISemantic[] to ISymbolValue[]
                var args = new List <ISymbolValue>(callArguments.Count);

                foreach (var a in callArguments)
                {
                    args.Add(a as ISymbolValue);
                }

                // Execute/Evaluate the variable contents etc.
                return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray()));
            }
            else
            {
                // Check if one overload remains and return that one.
                ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call);
                return(argTypeFilteredOverloads != null && argTypeFilteredOverloads.Count != 0 ?
                       argTypeFilteredOverloads[0] : null);
            }
        }