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;
		}
Ejemplo n.º 2
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.Length + 1];
            expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam;
            if(expectedTemplateParams.Length > 1)
                isExpression.TemplateParameterList.CopyTo (expectedTemplateParams, 1);

            var tpl_params = new DeducedTypeDictionary(expectedTemplateParams);

            var tpd = new TemplateParameterDeduction(tpl_params, ctxt);
            bool retTrue = false;

            if (isExpression.EqualityTest) // 6.
            {
                // a)
                if (isExpression.TypeSpecialization != null)
                {
                    tpd.EnforceTypeEqualityWhenDeducing = true;
                    retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck);
                    tpd.EnforceTypeEqualityWhenDeducing = false;
                }
                else // b)
                {
                    var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true);
                    retTrue = r.Item1;
                    tpl_params[isExpression.TypeAliasIdentifierHash] = new TemplateParameterSymbol(null, r.Item2);
                }
            }
            else // 5.
                retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck);

            if (retTrue && isExpression.TemplateParameterList != null)
                foreach (var p in isExpression.TemplateParameterList)
                    if (!tpd.Handle(p, tpl_params[p.NameHash] != null ? tpl_params[p.NameHash].Base : null))
                        return false;

            //TODO: Put all tpl_params results into the resolver context or make a new scope or something!

            return retTrue;
        }
        ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly=true)
        {
            // Deduce template parameters later on
            AbstractType[] baseExpression;
            ISymbolValue baseValue;
            TemplateInstanceExpression tix;

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

            var methodOverloads = new List<AbstractType>();

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

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

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

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

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

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

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

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

                        if (classDef == null)
                            continue;

                        foreach (var i in GetOpCalls(tit, requireStaticItems))
                                methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol);

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

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

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

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

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

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

            #region If explicit template type args were given, try to associate them with each overload
            if (tix != null)
            {
                var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs);
                var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs);
                methodOverloads.Clear();
                if(deducedOverloads != null)
                    methodOverloads.AddRange(deducedOverloads);
            }
            #endregion

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

            foreach (var ov in methodOverloads)
            {
                if (ov is MemberSymbol)
                {
                    var ms = ov as MemberSymbol;
                    var dm = ms.Definition as DMethod;

                    if (dm != null)
                    {
                        // In the case of an ufcs, insert the first argument into the CallArguments list
                        if (ms.IsUFCSResult && !hasHandledUfcsResultBefore)
                        {
                            callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument);
                            hasHandledUfcsResultBefore = true;
                        }
                        else if (!ms.IsUFCSResult && hasHandledUfcsResultBefore) // In the rare case of having a ufcs result occuring _after_ a normal member result, remove the initial arg again
                        {
                            callArguments.RemoveAt(0);
                            hasHandledUfcsResultBefore = false;
                        }

                        var deducedTypeDict = new DeducedTypeDictionary(ms);
                        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;
            }
        }