2 // argument.cs: Argument expressions
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003-2008 Novell, Inc.
13 using System.Reflection.Emit;
14 using System.Collections.Generic;
19 // Argument expression used for invocation
23 public enum AType : byte
26 Ref = 1, // ref modifier used
27 Out = 2, // out modifier used
28 Default = 3, // argument created from default parameter value
29 DynamicTypeName = 4, // System.Type argument for dynamic binding
30 ExtensionType = 5, // Instance expression inserted as the first argument
33 public readonly AType ArgType;
34 public Expression Expr;
36 public Argument (Expression expr, AType type)
42 public Argument (Expression expr)
45 throw new ArgumentNullException ();
53 get { return ArgType == AType.Ref || ArgType == AType.Out; }
56 public bool IsDefaultArgument {
57 get { return ArgType == AType.Default; }
60 public Parameter.Modifier Modifier {
64 return Parameter.Modifier.OUT;
67 return Parameter.Modifier.REF;
70 return Parameter.Modifier.NONE;
75 public TypeSpec Type {
76 get { return Expr.Type; }
81 public Argument Clone (Expression expr)
83 Argument a = (Argument) MemberwiseClone ();
88 public Argument Clone (CloneContext clonectx)
90 return Clone (Expr.Clone (clonectx));
93 public virtual Expression CreateExpressionTree (ResolveContext ec)
95 if (ArgType == AType.Default)
96 ec.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
98 return Expr.CreateExpressionTree (ec);
101 public string GetSignatureForError ()
103 if (Expr.eclass == ExprClass.MethodGroup)
104 return Expr.ExprClassName;
106 return TypeManager.CSharpName (Expr.Type);
109 public bool ResolveMethodGroup (ResolveContext ec)
111 SimpleName sn = Expr as SimpleName;
113 Expr = sn.GetMethodGroup ();
115 // FIXME: csc doesn't report any error if you try to use `ref' or
116 // `out' in a delegate creation expression.
117 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
124 public void Resolve (ResolveContext ec)
126 if (Expr == EmptyExpression.Null)
129 // using (ec.With (ResolveContext.Options.DoFlowAnalysis, true)) {
130 // Verify that the argument is readable
131 if (ArgType != AType.Out)
132 Expr = Expr.Resolve (ec);
134 // Verify that the argument is writeable
135 if (Expr != null && IsByRef)
136 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess.Instance);
139 Expr = EmptyExpression.Null;
143 public virtual void Emit (EmitContext ec)
150 AddressOp mode = AddressOp.Store;
151 if (ArgType == AType.Ref)
152 mode |= AddressOp.Load;
154 IMemoryLocation ml = (IMemoryLocation) Expr;
155 ml.AddressOf (ec, mode);
159 public class NamedArgument : Argument
161 public readonly string Name;
162 readonly Location loc;
163 LocalTemporary variable;
165 public NamedArgument (string name, Location loc, Expression expr)
166 : this (name, loc, expr, AType.None)
170 public NamedArgument (string name, Location loc, Expression expr, AType modifier)
171 : base (expr, modifier)
177 public override Expression CreateExpressionTree (ResolveContext ec)
179 ec.Report.Error (853, loc, "An expression tree cannot contain named argument");
180 return base.CreateExpressionTree (ec);
183 public override void Emit (EmitContext ec)
185 // TODO: Should guard against multiple emits
188 // Release temporary variable when used
189 if (variable != null)
190 variable.Release (ec);
193 public void EmitAssign (EmitContext ec)
195 var type = Expr.Type;
197 var ml = (IMemoryLocation) Expr;
198 ml.AddressOf (ec, AddressOp.Load);
199 type = ReferenceContainer.MakeType (type);
204 variable = new LocalTemporary (type);
210 public Location Location {
215 public class Arguments
217 sealed class ArgumentsOrdered : Arguments
219 List<NamedArgument> ordered;
221 public ArgumentsOrdered (Arguments args)
225 ordered = new List<NamedArgument> ();
228 public void AddOrdered (NamedArgument na)
233 public override Expression[] Emit (EmitContext ec, bool dup_args)
235 foreach (NamedArgument na in ordered)
238 return base.Emit (ec, dup_args);
242 // Try not to add any more instances to this class, it's allocated a lot
245 public Arguments (int capacity)
247 args = new List<Argument> (capacity);
250 public void Add (Argument arg)
255 public void AddRange (Arguments args)
257 this.args.AddRange (args.args);
260 public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
262 Location loc = Location.Null;
263 var all = new ArrayInitializer (args.Count, loc);
265 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
267 foreach (Argument a in args) {
268 Arguments dargs = new Arguments (2);
270 // CSharpArgumentInfoFlags.None = 0
271 const string info_flags_enum = "CSharpArgumentInfoFlags";
272 Expression info_flags = new IntLiteral (0, loc);
274 if (a.Expr is Constant) {
275 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
276 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "Constant", loc), loc);
277 } else if (a.ArgType == Argument.AType.Ref) {
278 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
279 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsRef", loc), loc);
280 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
281 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
282 } else if (a.ArgType == Argument.AType.Out) {
283 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
284 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsOut", loc), loc);
285 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
286 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
287 } else if (a.ArgType == Argument.AType.DynamicTypeName) {
288 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
289 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsStaticType", loc), loc);
292 var arg_type = a.Expr.Type;
294 if (arg_type != InternalType.Dynamic && arg_type != InternalType.Null) {
295 MethodGroupExpr mg = a.Expr as MethodGroupExpr;
297 rc.Report.Error (1976, a.Expr.Location,
298 "The method group `{0}' cannot be used as an argument of dynamic operation. Consider using parentheses to invoke the method",
300 } else if (arg_type == InternalType.AnonymousMethod) {
301 rc.Report.Error (1977, a.Expr.Location,
302 "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast");
303 } else if (arg_type == TypeManager.void_type || arg_type == InternalType.Arglist || arg_type.IsPointer) {
304 rc.Report.Error (1978, a.Expr.Location,
305 "An expression of type `{0}' cannot be used as an argument of dynamic operation",
306 TypeManager.CSharpName (arg_type));
309 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
310 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
314 NamedArgument na = a as NamedArgument;
316 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
317 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "NamedArgument", loc), loc);
319 named_value = na.Name;
324 dargs.Add (new Argument (info_flags));
325 dargs.Add (new Argument (new StringLiteral (named_value, loc)));
326 all.Add (new Invocation (new MemberAccess (new MemberAccess (binder, "CSharpArgumentInfo", loc), "Create", loc), dargs));
332 public static Arguments CreateForExpressionTree (ResolveContext ec, Arguments args, params Expression[] e)
334 Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
335 for (int i = 0; i < e.Length; ++i) {
337 all.Add (new Argument (e[i]));
341 foreach (Argument a in args.args) {
342 Expression tree_arg = a.CreateExpressionTree (ec);
343 if (tree_arg != null)
344 all.Add (new Argument (tree_arg));
351 public void CheckArrayAsAttribute (CompilerContext ctx)
353 foreach (Argument arg in args) {
354 // Type is undefined (was error 246)
355 if (arg.Type == null)
358 if (arg.Type.IsArray)
359 ctx.Report.Warning (3016, 1, arg.Expr.Location, "Arrays as attribute arguments are not CLS-compliant");
363 public Arguments Clone (CloneContext ctx)
365 Arguments cloned = new Arguments (args.Count);
366 foreach (Argument a in args)
367 cloned.Add (a.Clone (ctx));
373 get { return args.Count; }
377 // Emits a list of resolved Arguments
379 public void Emit (EmitContext ec)
385 // if `dup_args' is true, a copy of the arguments will be left
386 // on the stack and return value will contain an array of access
388 // NOTE: It's caller responsibility is to release temporary variables
390 public virtual Expression[] Emit (EmitContext ec, bool dup_args)
394 if (dup_args && Count != 0)
395 temps = new Expression [Count];
401 foreach (Argument a in args) {
406 if (a.Expr is Constant || a.Expr is This) {
408 // No need to create a temporary variable for constants
412 ec.Emit (OpCodes.Dup);
413 temps[i] = lt = new LocalTemporary (a.Type);
423 public List<Argument>.Enumerator GetEnumerator ()
425 return args.GetEnumerator ();
429 // At least one argument is of dynamic type
431 public bool HasDynamic {
433 foreach (Argument a in args) {
434 if (a.Type == InternalType.Dynamic && !a.IsByRef)
443 // At least one argument is named argument
445 public bool HasNamed {
447 foreach (Argument a in args) {
448 if (a is NamedArgument)
457 public void Insert (int index, Argument arg)
459 args.Insert (index, arg);
462 public static System.Linq.Expressions.Expression[] MakeExpression (Arguments args, BuilderContext ctx)
464 if (args == null || args.Count == 0)
467 var exprs = new System.Linq.Expressions.Expression [args.Count];
468 for (int i = 0; i < exprs.Length; ++i) {
469 Argument a = args.args [i];
470 exprs[i] = a.Expr.MakeExpression (ctx);
477 // For named arguments when the order of execution is different
478 // to order of invocation
480 public Arguments MarkOrderedArgument (NamedArgument a)
483 // Constant expression have no effect on left-to-right execution
485 if (a.Expr is Constant)
488 ArgumentsOrdered ra = this as ArgumentsOrdered;
490 ra = new ArgumentsOrdered (this);
497 // Returns dynamic when at least one argument is of dynamic type
499 public void Resolve (ResolveContext ec, out bool dynamic)
502 foreach (Argument a in args) {
504 if (a.Type == InternalType.Dynamic && !a.IsByRef)
509 public void RemoveAt (int index)
511 args.RemoveAt (index);
514 public Argument this [int index] {
515 get { return args [index]; }
516 set { args [index] = value; }