public Expression ReportAmbiguousMatchError <T>(Source src, List <T> candidates, params Expression[] args) where T : ParametersMember
        {
            foreach (var a in args)
            {
                if (a.IsInvalid)
                {
                    return(Expression.Invalid);
                }
            }

            return(Error(src, ErrorCode.E0109, "Ambiguous match" + NameResolver.SuggestCandidates(candidates)));
        }
        public Expression CompileCall(AstCall e)
        {
            // Builtin struct initialization
            if (e.Base is AstBuiltinType)
            {
                var dt = NameResolver.GetType(Namescope, e.Base);

                if (dt.IsStruct)
                {
                    // Default ctor
                    if (e.Arguments.Count == 0)
                    {
                        return(new Default(e.Source, dt));
                    }

                    dt.PopulateMembers();

                    Constructor  ctor;
                    Expression[] args;
                    return(TryResolveConstructorOverload(e.Source, dt.Constructors, e.Arguments, out ctor, out args)
                        ? new NewObject(e.Source, ctor, args)
                        : Error(e.Source, ErrorCode.E3125, dt.Quote() + " has no constructors matching the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(dt.Constructors)));
                }

                return(Error(e.Source, ErrorCode.E3126, dt.Quote() + " must be instantiated using 'new' because it is not a struct"));
            }

            var pe = ResolveExpression(e.Base, null);

            switch (pe.ExpressionType)
            {
            case PartialExpressionType.Block:
            case PartialExpressionType.Type:
            case PartialExpressionType.Namespace:
                if (e.Base is AstIdentifier)
                {
                    var p2 = NameResolver.TryResolveUsingType(Namescope, e.Base as AstIdentifier, null);
                    if (p2 != null)
                    {
                        pe = p2;
                    }
                }
                break;
            }

            var sym = CompilePartial(pe);

            if (sym.IsInvalid)
            {
                return(Expression.Invalid);
            }

            // Delegate call
            if (sym.ReturnType.IsDelegate)
            {
                var dt = (DelegateType)sym.ReturnType;
                dt.AssignBaseType();
                var args = TryApplyDefaultValuesOnArgumentList(sym.Source, dt.Parameters, CompileArgumentList(e.Arguments));
                return(TryApplyImplicitCastsOnArgumentList(dt.Parameters, args)
                    ? new CallDelegate(e.Source, sym, args)
                    : Error(e.Source, ErrorCode.E3127, "Call to delegate of type " + dt.Quote() + " has some invalid arguments " +
                            PrintableArgumentList(e.Arguments)));
            }

            // Using static fall back
            if (!(sym is MethodGroup) && e.Base is AstIdentifier)
            {
                var p2 = NameResolver.TryResolveUsingType(Namescope, e.Base as AstIdentifier, null);
                if (p2 != null)
                {
                    sym = CompilePartial(p2);
                    if (sym.IsInvalid)
                    {
                        return(Expression.Invalid);
                    }
                }
            }

            // Method call
            if (sym is MethodGroup)
            {
                var g = sym as MethodGroup;

                Method       method;
                Expression[] args;
                return(TryResolveMethodOverload(e.Source, g.Candidates, e.Arguments, out method, out args)
                    ? (g.IsQualified && g.Object != null && method.IsStatic
                            ? Error(sym.Source, ErrorCode.E3123, method.Quote() + " is static -- qualify with the type name") :
                       g.Object == null && !method.IsStatic
                            ? Error(sym.Source, ErrorCode.E3124, method.Quote() + " is non-static and cannot be accessed from a static context")
                            : new CallMethod(e.Source, method.IsStatic ? null : g.Object, method, args))
                    : g.Candidates.Count == 1
                        ? Error(e.Source, ErrorCode.E3128, "Call to " + g.Candidates[0].Quote() + " has some invalid arguments " +
                                PrintableArgumentList(e.Arguments))
                        : Error(e.Source, ErrorCode.E3129, "No overloads of " + g.CandidatesBaseName.Quote() + " matches the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(g.Candidates)));
            }

            // Extension method call
            if (sym is ExtensionGroup)
            {
                var g = sym as ExtensionGroup;

                Method       method;
                Expression[] args;
                var          astArgs = new AstArgument[e.Arguments.Count + 1];
                astArgs[0] = new AstIL(g.Object);
                for (int i = 0; i < e.Arguments.Count; i++)
                {
                    astArgs[i + 1] = e.Arguments[i];
                }

                return(TryResolveMethodOverload(e.Source, g.Candidates, astArgs, out method, out args)
                    ? new CallMethod(e.Source, null, method, args)
                    : g.Candidates.Count == 1
                        ? Error(e.Source, ErrorCode.E3128, "Call to " + g.Candidates[0].Quote() + " has some invalid arguments " +
                                PrintableArgumentList(astArgs))
                        : Error(e.Source, ErrorCode.E3129, "No overloads of " + g.CandidatesBaseName.Quote() + " matches the argument list " +
                                PrintableArgumentList(e.Arguments) +
                                NameResolver.SuggestCandidates(g.Candidates)));
            }

            return(Error(e.Source, ErrorCode.E3130, "Instances of type " + sym.ReturnType.Quote() + " cannot be called as a function"));
        }
Ejemplo n.º 3
0
        public Expression CompileNewExpression(AstNew e)
        {
            // Implicitly typed arrays
            if (e.OptionalType == null)
            {
                if (e.OptionalArguments != null)
                {
                    return(Error(e.Source, ErrorCode.E2001, "Array constructors cannot have argument list"));
                }
                if (e.OptionalArraySize != null)
                {
                    return(Error(e.Source, ErrorCode.E2002, "Cannot specify size on implicitly typed arrays"));
                }
                if (e.OptionalCollectionInitializer == null || e.OptionalCollectionInitializer.Count == 0)
                {
                    return(Error(e.Source, ErrorCode.E2003, "Must provide non-empty initializer list for implicitly typed arrays"));
                }

                var values = new Expression[e.OptionalCollectionInitializer.Count];
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = CompileExpression(e.OptionalCollectionInitializer[i]);
                }

                var et = TryGetImplicitElementType(values);

                if (et == null)
                {
                    return(Error(e.Source, ErrorCode.E2004, "No best type found for implicitly typed array"));
                }

                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = CompileImplicitCast(e.Source, et, values[i]);
                }

                return(et.IsValueType || et.IsReferenceType
                        ? new NewArray(e.Source, TypeBuilder.GetArray(et), values) :
                       et != DataType.Invalid
                        ? Error(e.Source, ErrorCode.E2080, "Cannot create an implicitly typed array of type " + et.Quote())
                        : Expression.Invalid);
            }

            var dt = NameResolver.GetType(Namescope, e.OptionalType);

            switch (dt.TypeType)
            {
            case TypeType.RefArray:
            {
                if (e.OptionalArguments != null)
                {
                    return(Error(e.Source, ErrorCode.E2005, "Array constructors cannot have argument list"));
                }

                var        at   = dt as RefArrayType;
                Expression size = null;

                if (e.OptionalArraySize != null)
                {
                    size = CompileImplicitCast(e.Source, Essentials.Int, CompileExpression(e.OptionalArraySize));
                    if (size.IsInvalid)
                    {
                        return(Expression.Invalid);
                    }
                }

                if (e.OptionalCollectionInitializer != null)
                {
                    var values = new Expression[e.OptionalCollectionInitializer.Count];
                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = CompileExpression(e.OptionalCollectionInitializer[i]);
                    }

                    if (size != null)
                    {
                        var c = Compiler.ConstantFolder.TryMakeConstant(size);
                        if (c == null || !c.Value.Equals(values.Length))
                        {
                            return(Error(size.Source, ErrorCode.E2006, "Inconsistent array size and initializer list length"));
                        }
                    }

                    switch (at.ElementType.BuiltinType)
                    {
                    case BuiltinType.Bool:
                    case BuiltinType.Byte:
                    case BuiltinType.Char:
                    case BuiltinType.Double:
                    case BuiltinType.Int:
                    case BuiltinType.Float:
                    case BuiltinType.Long:
                    case BuiltinType.SByte:
                    case BuiltinType.Short:
                    case BuiltinType.UInt:
                    case BuiltinType.ULong:
                    case BuiltinType.UShort:
                        // Disable warning on primitive types
                        break;

                    default:
                        if (TryGetImplicitElementType(values) == at.ElementType)
                        {
                            Log.Warning3(e.Source, ErrorCode.W2007, "Array can be instantiated as implicitly typed array (new[] { ... })");
                        }

                        break;
                    }

                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = CompileImplicitCast(values[i].Source, at.ElementType, values[i]);
                    }

                    return(new NewArray(e.Source, at, values));
                }

                return(new NewArray(e.Source, at, size));
            }

            case TypeType.Class:
            case TypeType.Struct:
            case TypeType.GenericParameter:
            {
                if (dt.IsStatic)
                {
                    return(Error(e.Source, ErrorCode.E2090, "Cannot instantiate static class"));
                }

                if (e.OptionalArguments != null || e.OptionalCollectionInitializer != null)
                {
                    if (e.OptionalArraySize != null)
                    {
                        return(Error(e.Source, ErrorCode.E2008, "Object constructors cannot have array size"));
                    }

                    Expression newObject;

                    if (dt.IsStruct && (e.OptionalArguments == null || e.OptionalArguments.Count == 0))
                    {
                        newObject = new Default(e.Source, dt);
                    }
                    else
                    {
                        dt.PopulateMembers();

                        Constructor  ctor;
                        Expression[] args;

                        if (!TryResolveConstructorOverload(e.Source, dt.Constructors, e.OptionalArguments ?? AstArgument.Empty, out ctor, out args))
                        {
                            return(e.OptionalArguments != null && e.OptionalArguments.Count > 0
                                    ? (dt.Constructors.Count == 1
                                        ? Error(e.Source, ErrorCode.E2009, "Call to " + (dt + PrintableParameterList(dt.Constructors[0].Parameters)).Quote() + " has some invalid arguments " +
                                                PrintableArgumentList(e.OptionalArguments))
                                        : Error(e.Source, ErrorCode.E2009, dt.Quote() + " has no constructors matching the argument list " +
                                                PrintableArgumentList(e.OptionalArguments) +
                                                NameResolver.SuggestCandidates(dt.Constructors)))
                                    : Error(e.Source, ErrorCode.E0000, dt.Quote() + " has no default constructor"));
                        }

                        newObject = new NewObject(e.Source, ctor, args);
                    }

                    if (e.OptionalCollectionInitializer != null && e.OptionalCollectionInitializer.Count > 0)
                    {
                        var var = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("collection"), newObject.ReturnType);
                        CurrentVariableScope.Variables.Add(var.Name, var);

                        Expression root = new StoreLocal(e.Source, var, newObject);

                        // See if it is a member initializer or collection initializer
                        var containsAssignOp = false;

                        foreach (var i in e.OptionalCollectionInitializer)
                        {
                            if (i is AstBinary && (i as AstBinary).IsAssign)
                            {
                                containsAssignOp = true;
                                break;
                            }
                        }

                        if (containsAssignOp)
                        {
                            var initedMembers = new List <string>();

                            // Assign members
                            foreach (var i in e.OptionalCollectionInitializer)
                            {
                                var binOp = i as AstBinary;
                                if (binOp == null || binOp.Type != AstBinaryType.Assign || !(binOp.Left is AstIdentifier))
                                {
                                    Log.Error(i.Source, ErrorCode.E2077, "Invalid initalizer member declarator");
                                    continue;
                                }

                                var id     = (AstIdentifier)binOp.Left;
                                var member = new AstMember(new AstIdentifier(i.Source, var.Name), id);

                                if (binOp.Right is AstArrayInitializer)
                                {
                                    var ai         = binOp.Right as AstArrayInitializer;
                                    var collection = CompileExpression(member);

                                    var cvar = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType);
                                    CurrentVariableScope.Variables.Add(cvar.Name, cvar);

                                    root = new SequenceOp(root, new StoreLocal(collection.Source, cvar, collection));

                                    if (collection.IsInvalid)
                                    {
                                        continue;
                                    }

                                    foreach (var ci in ai.Values)
                                    {
                                        root = new SequenceOp(root, CompileAddToCollection(cvar.Name, ci));
                                    }
                                }
                                else
                                {
                                    var assign = CompileAssign(new AstBinary(AstBinaryType.Assign, member, i.Source, binOp.Right));
                                    root = new SequenceOp(root, assign);

                                    if (assign.IsInvalid)
                                    {
                                        continue;
                                    }
                                }

                                foreach (var m in initedMembers)
                                {
                                    if (m == id.Symbol)
                                    {
                                        Log.Error(i.Source, ErrorCode.E2078, "Duplicate initialization of member " + id.Symbol.Quote());
                                        break;
                                    }
                                }

                                initedMembers.Add(id.Symbol);
                            }
                        }
                        else
                        {
                            // Add to collection
                            foreach (var i in e.OptionalCollectionInitializer)
                            {
                                root = new SequenceOp(root, CompileAddToCollection(var.Name, i));
                            }
                        }

                        return(new SequenceOp(root, new LoadLocal(e.Source, var)));
                    }

                    if (e.OptionalType is AstBuiltinType && dt.IsStruct)
                    {
                        Log.Warning(e.Source, ErrorCode.W0000, "Redundant 'new' operator on builtin struct initialization");
                    }

                    return(newObject);
                }

                return(Error(e.Source, ErrorCode.E2011, "Must provide argument list for object constructor"));
            }

            case TypeType.Delegate:
            {
                if (e.OptionalArguments == null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Must provide argument list for delegate constructor"));
                }

                var args = CompileArgumentList(e.OptionalArguments);

                if (e.OptionalCollectionInitializer != null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have collection initializer"));
                }
                if (e.OptionalArraySize != null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have array size"));
                }
                if (args.Length != 1 || args[0].ExpressionType != ExpressionType.MethodGroup)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction requires one method argument"));
                }

                return(CompileImplicitCast(e.Source, dt, args[0]));
            }

            case TypeType.Invalid:
                return(Expression.Invalid);

            default:
                return(Error(e.Source, ErrorCode.E2012, "Instances of type " + dt.Quote() + " cannot be created using 'new' because it is not a class, struct or array type"));
            }
        }