예제 #1
0
        public static AbstractType Resolve(ArrayDecl ad, ResolutionContext ctxt)
        {
            var valueTypes = Resolve(ad.ValueType, ctxt);

            ctxt.CheckForSingleResult(valueTypes, ad);

            AbstractType valueType        = null;
            AbstractType keyType          = null;
            int          fixedArrayLength = -1;

            if (valueTypes != null && valueTypes.Length != 0)
            {
                valueType = valueTypes[0];
            }

            ISymbolValue val;

            keyType = ResolveKey(ad, out fixedArrayLength, out val, ctxt);

            if (keyType == null || (keyType is PrimitiveType &&
                                    ((PrimitiveType)keyType).TypeToken == DTokens.Int))
            {
                if (fixedArrayLength >= 0)
                {
                    // D Magic: One might access tuple items directly in the pseudo array declaration - so stuff like Tup[0] i; becomes e.g. int i;
                    var dtup = DResolver.StripMemberSymbols(valueType) as DTuple;
                    if (dtup == null)
                    {
                        return(new ArrayType(valueType, fixedArrayLength, ad));
                    }

                    if (fixedArrayLength < dtup.Items.Length)
                    {
                        return(AbstractType.Get(dtup.Items [fixedArrayLength]));
                    }
                    else
                    {
                        ctxt.LogError(ad, "TypeTuple only consists of " + dtup.Items.Length + " items. Can't access item at index " + fixedArrayLength);
                        return(null);
                    }
                }
                return(new ArrayType(valueType, ad));
            }

            return(new AssocArrayType(valueType, keyType, ad));
        }
예제 #2
0
        public static AbstractType Resolve(TypeOfDeclaration typeOf, ResolutionContext ctxt)
        {
            // typeof(return)
            if (typeOf.Expression is TokenExpression && (typeOf.Expression as TokenExpression).Token == DTokens.Return)
            {
                var m = HandleNodeMatch(ctxt.ScopedBlock, ctxt, null, typeOf);
                if (m != null)
                {
                    return(m);
                }
            }
            // typeOf(myInt)  =>  int
            else if (typeOf.Expression != null)
            {
                var wantedTypes = Evaluation.EvaluateType(typeOf.Expression, ctxt);
                return(DResolver.StripMemberSymbols(wantedTypes));
            }

            return(null);
        }
예제 #3
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);
        }
예제 #4
0
        public static AbstractType GetMethodReturnType(DMethod method, ResolutionContext ctxt)
        {
            if ((ctxt.Options & ResolutionOptions.DontResolveBaseTypes) == ResolutionOptions.DontResolveBaseTypes)
            {
                return(null);
            }

            /*
             * If a method's type equals null, assume that it's an 'auto' function..
             * 1) Search for a return statement
             * 2) Resolve the returned expression
             * 3) Use that one as the method's type
             */
            bool pushMethodScope = ctxt.ScopedBlock != method;

            if (method.Type != null)
            {
                if (pushMethodScope)
                {
                    ctxt.PushNewScope(method);
                }

                //FIXME: Is it legal to explicitly return a nested type?
                var returnType = TypeDeclarationResolver.Resolve(method.Type, ctxt);

                if (pushMethodScope)
                {
                    ctxt.Pop();
                }

                ctxt.CheckForSingleResult(returnType, method.Type);
                if (returnType != null && returnType.Length > 0)
                {
                    return(returnType[0]);
                }
            }
            else if (method.Body != null)
            {
                ReturnStatement returnStmt = null;
                var             list       = new List <IStatement> {
                    method.Body
                };
                var list2 = new List <IStatement>();

                bool foundMatch = false;
                while (!foundMatch && list.Count > 0)
                {
                    foreach (var stmt in list)
                    {
                        if (stmt is ReturnStatement)
                        {
                            returnStmt = stmt as ReturnStatement;

                            var te = returnStmt.ReturnExpression as TokenExpression;
                            if (te == null || te.Token != DTokens.Null)
                            {
                                foundMatch = true;
                                break;
                            }
                        }

                        var statementContainingStatement = stmt as StatementContainingStatement;
                        if (statementContainingStatement != null)
                        {
                            list2.AddRange(statementContainingStatement.SubStatements);
                        }
                    }

                    list  = list2;
                    list2 = new List <IStatement>();
                }

                if (returnStmt != null && returnStmt.ReturnExpression != null)
                {
                    if (pushMethodScope)
                    {
                        var dedTypes = ctxt.CurrentContext.DeducedTemplateParameters;
                        ctxt.PushNewScope(method, returnStmt);

                        if (dedTypes.Count != 0)
                        {
                            foreach (var kv in dedTypes)
                            {
                                ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value;
                            }
                        }
                    }

                    var t = DResolver.StripMemberSymbols(Evaluation.EvaluateType(returnStmt.ReturnExpression, ctxt));

                    if (pushMethodScope)
                    {
                        ctxt.Pop();
                    }

                    return(t);
                }

                return(new PrimitiveType(DTokens.Void));
            }

            return(null);
        }
예제 #5
0
        /// <summary>
        /// The variable's or method's base type will be resolved (if auto type, the intializer's type will be taken).
        /// A class' base class will be searched.
        /// etc..
        /// </summary>
        public static AbstractType HandleNodeMatch(
            INode m,
            ResolutionContext ctxt,
            AbstractType resultBase = null,
            object typeBase         = null)
        {
            AbstractType ret = null;

            // See https://github.com/aBothe/Mono-D/issues/161
            int stkC;

            if (stackCalls == null)
            {
                stackCalls    = new Dictionary <INode, int>();
                stackCalls[m] = stkC = 1;
            }
            else if (stackCalls.TryGetValue(m, out stkC))
            {
                stackCalls[m] = ++stkC;
            }
            else
            {
                stackCalls[m] = stkC = 1;
            }

            /*
             * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy.
             * Edit: No, it is required nearly every time because of nested type declarations - then, we do need the
             * current block scope.
             */
            bool popAfterwards;
            {
                var newScope = m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode;
                popAfterwards = ctxt.ScopedBlock != newScope && newScope != null;
                if (popAfterwards)
                {
                    var options      = ctxt.CurrentContext.ContextDependentOptions;
                    var applyOptions = ctxt.ScopedBlockIsInNodeHierarchy(m);
                    ctxt.PushNewScope(newScope);
                    if (applyOptions)
                    {
                        ctxt.CurrentContext.ContextDependentOptions = options;
                    }
                }
            }

            var canResolveBase = ((ctxt.Options & ResolutionOptions.DontResolveBaseTypes) != ResolutionOptions.DontResolveBaseTypes) &&
                                 stkC < 10 && (m.Type == null || m.Type.ToString(false) != m.Name);

            // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context
            if (resultBase is DSymbol)
            {
                ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase);
            }

            var importSymbolNode = m as ImportSymbolNode;
            var variable         = m as DVariable;

            // Only import symbol aliases are allowed to search in the parse cache
            if (importSymbolNode != null)
            {
                ret = HandleImportSymbolMatch(importSymbolNode, ctxt);
            }
            else if (variable != null)
            {
                AbstractType bt = null;

                if (!(variable is EponymousTemplate))
                {
                    if (canResolveBase)
                    {
                        var bts = TypeDeclarationResolver.Resolve(variable.Type, ctxt);
                        ctxt.CheckForSingleResult(bts, variable.Type);

                        if (bts != null && bts.Length != 0)
                        {
                            bt = bts [0];
                        }

                        // For auto variables, use the initializer to get its type
                        else if (variable.Initializer != null)
                        {
                            bt = DResolver.StripMemberSymbols(Evaluation.EvaluateType(variable.Initializer, ctxt));
                        }

                        // Check if inside an foreach statement header
                        if (bt == null && ctxt.ScopedStatement != null)
                        {
                            bt = GetForeachIteratorType(variable, ctxt);
                        }
                    }

                    // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type
                    ret = variable.IsAlias ?
                          new AliasedType(variable, bt, typeBase as ISyntaxRegion) as MemberSymbol :
                          new MemberSymbol(variable, bt, typeBase as ISyntaxRegion);
                }
                else
                {
                    ret = new EponymousTemplateType(variable as EponymousTemplate, GetInvisibleTypeParameters(variable, ctxt).AsReadOnly(), typeBase as ISyntaxRegion);
                }
            }
            else if (m is DMethod)
            {
                ret = new MemberSymbol(m as DNode, canResolveBase ? GetMethodReturnType(m as DMethod, ctxt) : null, typeBase as ISyntaxRegion);
            }
            else if (m is DClassLike)
            {
                ret = HandleClassLikeMatch(m as DClassLike, ctxt, typeBase, canResolveBase);
            }
            else if (m is DModule)
            {
                var mod = (DModule)m;
                if (typeBase != null && typeBase.ToString() != mod.ModuleName)
                {
                    var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).FirstOrDefault();
                    if (pack != null)
                    {
                        ret = new PackageSymbol(pack, typeBase as ISyntaxRegion);
                    }
                }
                else
                {
                    ret = new ModuleSymbol(m as DModule, typeBase as ISyntaxRegion);
                }
            }
            else if (m is DEnum)
            {
                ret = new EnumType((DEnum)m, typeBase as ISyntaxRegion);
            }
            else if (m is TemplateParameter.Node)
            {
                //ResolveResult[] templateParameterType = null;

                //TODO: Resolve the specialization type
                //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt);
                ret = new TemplateParameterSymbol((m as TemplateParameter.Node).TemplateParameter, null, typeBase as ISyntaxRegion);
            }
            else if (m is NamedTemplateMixinNode)
            {
                var tmxNode = m as NamedTemplateMixinNode;
                ret = new MemberSymbol(tmxNode, canResolveBase ? ResolveSingle(tmxNode.Type, ctxt) : null, typeBase as ISyntaxRegion);
            }

            if (popAfterwards)
            {
                ctxt.Pop();
            }
            else if (resultBase is DSymbol)
            {
                ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase);
            }

            if (stkC == 1)
            {
                stackCalls.Remove(m);
            }
            else
            {
                stackCalls[m] = stkC - 1;
            }

            return(ret);
        }
예제 #6
0
        /// <summary>
        /// Used for searching further identifier list parts.
        ///
        /// a.b -- nextIdentifier would be 'b' whereas <param name="resultBases">resultBases</param> contained the resolution result for 'a'
        /// </summary>
        public static AbstractType[] ResolveFurtherTypeIdentifier(int nextIdentifierHash,
                                                                  IEnumerable <AbstractType> resultBases,
                                                                  ResolutionContext ctxt,
                                                                  object typeIdObject = null)
        {
            MemberSymbol statProp;

            if ((resultBases = DResolver.StripMemberSymbols(resultBases)) == null)
            {
                return(null);
            }

            var r = new List <AbstractType>();

            foreach (var b in resultBases)
            {
                if (b is UserDefinedType)
                {
                    var udt = b as UserDefinedType;
                    var bn  = udt.Definition as IBlockNode;

                    bool pop = !(b is MixinTemplateType);
                    if (!pop)
                    {
                        ctxt.PushNewScope(bn);
                    }
                    ctxt.CurrentContext.IntroduceTemplateParameterTypes(udt);

                    r.AddRange(SingleNodeNameScan.SearchChildrenAndResolve(ctxt, bn, nextIdentifierHash, typeIdObject));

                    List <TemplateParameterSymbol> dedTypes = null;
                    foreach (var t in r)
                    {
                        var ds = t as DSymbol;
                        if (ds != null && ds.DeducedTypes == null)
                        {
                            if (dedTypes == null)
                            {
                                dedTypes = ctxt.DeducedTypesInHierarchy;
                            }

                            ds.DeducedTypes = new System.Collections.ObjectModel.ReadOnlyCollection <TemplateParameterSymbol>(dedTypes);
                        }
                    }

                    statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash);
                    if (statProp != null)
                    {
                        r.Add(statProp);
                    }

                    ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt);
                    if (!pop)
                    {
                        ctxt.Pop();
                    }
                }
                else if (b is PackageSymbol)
                {
                    var pack = (b as PackageSymbol).Package;

                    var accessedModule = pack.GetModule(nextIdentifierHash);
                    if (accessedModule != null)
                    {
                        r.Add(new ModuleSymbol(accessedModule as DModule, typeIdObject as ISyntaxRegion, b as PackageSymbol));
                    }
                    else if ((pack = pack.GetPackage(nextIdentifierHash)) != null)
                    {
                        r.Add(new PackageSymbol(pack, typeIdObject as ISyntaxRegion));
                    }
                }
                else if (b is ModuleSymbol)
                {
                    r.AddRange(SingleNodeNameScan.SearchChildrenAndResolve(ctxt, (b as ModuleSymbol).Definition, nextIdentifierHash, typeIdObject));
                }
                else
                {
                    statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash);
                    if (statProp != null)
                    {
                        r.Add(statProp);
                    }
                }
                // TODO: Search for UFCS symbols
            }

            return(r.Count == 0 ? null : r.ToArray());
        }
예제 #7
0
        /// <summary>
        /// string[] s;
        ///
        /// foreach(i;s)
        /// {
        ///		// i is of type 'string'
        ///		writeln(i);
        /// }
        /// </summary>
        public static AbstractType GetForeachIteratorType(DVariable i, ResolutionContext ctxt)
        {
            var r       = new List <AbstractType>();
            var curStmt = ctxt.ScopedStatement;

            bool init = true;

            // Walk up statement hierarchy -- note that foreach loops can be nested
            while (curStmt != null)
            {
                if (init)
                {
                    init = false;
                }
                else
                {
                    curStmt = curStmt.Parent;
                }

                if (curStmt is ForeachStatement)
                {
                    var fe = (ForeachStatement)curStmt;

                    if (fe.ForeachTypeList == null)
                    {
                        continue;
                    }

                    // If the searched variable is declared in the header
                    int iteratorIndex = -1;

                    for (int j = 0; j < fe.ForeachTypeList.Length; j++)
                    {
                        if (fe.ForeachTypeList[j] == i)
                        {
                            iteratorIndex = j;
                            break;
                        }
                    }

                    if (iteratorIndex == -1)
                    {
                        continue;
                    }

                    bool keyIsSearched = iteratorIndex == 0 && fe.ForeachTypeList.Length > 1;


                    // foreach(var k, var v; 0 .. 9)
                    if (keyIsSearched && fe.IsRangeStatement)
                    {
                        // -- it's static type int, of course(?)
                        return(new PrimitiveType(DTokens.Int));
                    }

                    var aggregateType = Evaluation.EvaluateType(fe.Aggregate, ctxt);

                    aggregateType = DResolver.StripMemberSymbols(aggregateType);

                    if (aggregateType == null)
                    {
                        return(null);
                    }

                    // The most common way to do a foreach
                    if (aggregateType is AssocArrayType)
                    {
                        var ar = (AssocArrayType)aggregateType;

                        return(keyIsSearched ? ar.KeyType : ar.ValueType);
                    }
                    else if (aggregateType is UserDefinedType)
                    {
                        var tr = (UserDefinedType)aggregateType;

                        if (keyIsSearched || !(tr.Definition is IBlockNode))
                        {
                            continue;
                        }

                        bool foundIterPropertyMatch = false;
                        #region Foreach over Structs and Classes with Ranges

                        // Enlist all 'back'/'front' members
                        var t_l = new List <AbstractType>();

                        foreach (var n in (IBlockNode)tr.Definition)
                        {
                            if (fe.IsReverse ? n.Name == "back" : n.Name == "front")
                            {
                                t_l.Add(HandleNodeMatch(n, ctxt));
                            }
                        }

                        // Remove aliases
                        var iterPropertyTypes = DResolver.StripAliasSymbols(t_l);

                        foreach (var iterPropType in iterPropertyTypes)
                        {
                            if (iterPropType is MemberSymbol)
                            {
                                foundIterPropertyMatch = true;

                                var itp = (MemberSymbol)iterPropType;

                                // Only take non-parameterized methods
                                if (itp.Definition is DMethod && ((DMethod)itp.Definition).Parameters.Count != 0)
                                {
                                    continue;
                                }

                                // Handle its base type [return type] as iterator type
                                if (itp.Base != null)
                                {
                                    r.Add(itp.Base);
                                }

                                foundIterPropertyMatch = true;
                            }
                        }

                        if (foundIterPropertyMatch)
                        {
                            continue;
                        }
                        #endregion

                        #region Foreach over Structs and Classes with opApply
                        t_l.Clear();
                        r.Clear();

                        foreach (var n in (IBlockNode)tr.Definition)
                        {
                            if (n is DMethod &&
                                (fe.IsReverse ? n.Name == "opApplyReverse" : n.Name == "opApply"))
                            {
                                t_l.Add(HandleNodeMatch(n, ctxt));
                            }
                        }

                        iterPropertyTypes = DResolver.StripAliasSymbols(t_l);

                        foreach (var iterPropertyType in iterPropertyTypes)
                        {
                            if (iterPropertyType is MemberSymbol)
                            {
                                var mr = (MemberSymbol)iterPropertyType;
                                var dm = mr.Definition as DMethod;

                                if (dm == null || dm.Parameters.Count != 1)
                                {
                                    continue;
                                }

                                var dg = dm.Parameters[0].Type as DelegateDeclaration;

                                if (dg == null || dg.Parameters.Count != fe.ForeachTypeList.Length)
                                {
                                    continue;
                                }

                                var paramType = Resolve(dg.Parameters[iteratorIndex].Type, ctxt);

                                if (paramType != null && paramType.Length > 0)
                                {
                                    r.Add(paramType[0]);
                                }
                            }
                        }
                        #endregion
                    }

                    if (r.Count > 1)
                    {
                        ctxt.LogError(new ResolutionError(curStmt, "Ambigous iterator type"));
                    }

                    return(r.Count != 0 ? r[0] : null);
                }
            }

            return(null);
        }