private bool AddMethodToCache(SmallType pType, MethodSyntax pMethod, out MethodDefinition pDefinition)
        {
            //Check for duplicate method definitions
            Compiler.FindResult found;
            if (pMethod.SyntaxType == SyntaxType.Method)
            {
                found = _unit.MethodExists(pType, pMethod);
            }
            else if (pMethod.SyntaxType == SyntaxType.CastDefinition)
            {
                found = _unit.CastExists(pType, pMethod.Type, out MethodDefinition pDef);
            }
            else
            {
                throw new InvalidOperationException("Unknown method type " + pMethod.SyntaxType.ToString());
            }

            if (found != Compiler.FindResult.NotFound)
            {
                if (pMethod.SyntaxType == SyntaxType.Method)
                {
                    CompilerErrors.MethodDuplicate(pMethod, pMethod.Span);
                }
                else if (pMethod.SyntaxType == SyntaxType.CastDefinition)
                {
                    CompilerErrors.CastDuplicate(pMethod.Parameters[0].Type, pMethod.Type, pMethod.Span);
                }
                pDefinition = default;
                return(false);
            }
            else
            {
                //Create the tuple type if we are returning more than one value from a method
                //This will cache it in our SmallTypeCache so it can be found later
                if (pMethod.ReturnValues.Count > 1)
                {
                    SmallTypeCache.GetOrCreateTuple(SyntaxHelper.SelectNodeTypes(pMethod.ReturnValues));
                }

                //Set method and return types
                foreach (var p in pMethod.Parameters)
                {
                    _unit.FromString(p.TypeNode, out SmallType t);
                    p.TypeNode.SetType(t);
                }
                foreach (var r in pMethod.ReturnValues)
                {
                    _unit.FromString(r, out SmallType t);
                    r.SetType(t);
                }

                //Add method
                pDefinition = _unit.AddMethod(pType, pMethod);
                return(true);
            }
        }
Beispiel #2
0
        private bool TryPolyMethod(MethodSyntax pMethod, ref MethodCallSyntax pCallSite)
        {
            System.Diagnostics.Debug.Assert(pMethod.Parameters.Count == pCallSite.Arguments.Count);

            //Get name of the new method
            StringBuilder name = new StringBuilder(pMethod.Name + "!!!");

            for (int i = 0; i < pMethod.Parameters.Count; i++)
            {
                if (pMethod.Parameters[i].Type.IsTrait)
                {
                    name.Append(pCallSite.Arguments[i].Type.Name + "_");
                }
            }
            name = name.Remove(name.Length - 1, 1);

            //Ensure we haven't polymorphed this method before
            if (!_polydMethods.ContainsKey(name.ToString()))
            {
                List <TypedIdentifierSyntax> parameters = new List <TypedIdentifierSyntax>(pMethod.Parameters.Count);
                for (int i = 0; i < pMethod.Parameters.Count; i++)
                {
                    TypedIdentifierSyntax parm;
                    if (pMethod.Parameters[i].Type.IsTrait)
                    {
                        //Ensure the argument implements the proper trait... we haven't done type checking yet
                        if (!pCallSite.Arguments[i].Type.IsAssignableFrom(pMethod.Parameters[i].Type))
                        {
                            return(false);
                        }

                        parm = SyntaxFactory.TypedIdentifier(SyntaxFactory.Type(pCallSite.Arguments[i].Type.Name), pMethod.Parameters[i].Value);
                    }
                    else
                    {
                        parm = (TypedIdentifierSyntax)Visit(pMethod.Parameters[i]);
                    }
                    parameters.Add(parm);
                }

                var method = SyntaxFactory.Method(pMethod.Scope, name.ToString(), pMethod.ReturnValues, parameters, (BlockSyntax)Visit(pMethod.Body)).FromNode(pMethod);
                var tiv    = new Typing.TypeInferenceVisitor(_unit);
                tiv.Visit(method);
                _unit.AddMethod(null, method);

                if (!_polydMethods.ContainsKey(name.ToString()))
                {
                    _polydMethods.Add(name.ToString(), new List <MethodSyntax>());
                }
                _polydMethods[name.ToString()].Add(method);
            }

            //Have the call site point to the new method
            List <SyntaxNode> arguments = new List <SyntaxNode>(pCallSite.Arguments.Count);

            foreach (var a in pCallSite.Arguments)
            {
                arguments.Add(Visit(a));
            }

            pCallSite = SyntaxFactory.MethodCall(name.ToString(), arguments);

            return(true);
        }