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;
14 using System.Reflection.Emit;
15 using System.Collections.Generic;
20 // Argument expression used for invocation
24 public enum AType : byte
27 Ref = 1, // ref modifier used
28 Out = 2, // out modifier used
29 Default = 3, // argument created from default parameter value
30 DynamicTypeName = 4, // System.Type argument for dynamic binding
31 ExtensionType = 5, // Instance expression inserted as the first argument
34 public readonly AType ArgType;
35 public Expression Expr;
37 public Argument (Expression expr, AType type)
43 public Argument (Expression expr)
46 throw new ArgumentNullException ();
51 public TypeSpec Type {
52 get { return Expr.Type; }
55 public Parameter.Modifier Modifier {
59 return Parameter.Modifier.OUT;
62 return Parameter.Modifier.REF;
65 return Parameter.Modifier.NONE;
70 public virtual Expression CreateExpressionTree (ResolveContext ec)
72 if (ArgType == AType.Default)
73 ec.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
75 return Expr.CreateExpressionTree (ec);
78 public string GetSignatureForError ()
80 if (Expr.eclass == ExprClass.MethodGroup)
81 return Expr.ExprClassName;
83 return TypeManager.CSharpName (Expr.Type);
87 get { return ArgType == AType.Ref || ArgType == AType.Out; }
90 public bool IsDefaultArgument {
91 get { return ArgType == AType.Default; }
94 public bool ResolveMethodGroup (ResolveContext ec)
96 SimpleName sn = Expr as SimpleName;
98 Expr = sn.GetMethodGroup ();
100 // FIXME: csc doesn't report any error if you try to use `ref' or
101 // `out' in a delegate creation expression.
102 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
109 public void Resolve (ResolveContext ec)
111 if (Expr == EmptyExpression.Null)
114 // using (ec.With (ResolveContext.Options.DoFlowAnalysis, true)) {
115 // Verify that the argument is readable
116 if (ArgType != AType.Out)
117 Expr = Expr.Resolve (ec);
119 // Verify that the argument is writeable
120 if (Expr != null && IsByRef)
121 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess.Instance);
124 Expr = EmptyExpression.Null;
128 public virtual void Emit (EmitContext ec)
135 AddressOp mode = AddressOp.Store;
136 if (ArgType == AType.Ref)
137 mode |= AddressOp.Load;
139 IMemoryLocation ml = (IMemoryLocation) Expr;
140 ml.AddressOf (ec, mode);
143 public Argument Clone (CloneContext clonectx)
145 Argument a = (Argument) MemberwiseClone ();
146 a.Expr = Expr.Clone (clonectx);
151 public class NamedArgument : Argument
153 public readonly string Name;
154 readonly Location loc;
155 LocalTemporary variable;
157 public NamedArgument (string name, Location loc, Expression expr)
158 : this (name, loc, expr, AType.None)
162 public NamedArgument (string name, Location loc, Expression expr, AType modifier)
163 : base (expr, modifier)
169 public override Expression CreateExpressionTree (ResolveContext ec)
171 ec.Report.Error (853, loc, "An expression tree cannot contain named argument");
172 return base.CreateExpressionTree (ec);
175 public override void Emit (EmitContext ec)
177 // TODO: Should guard against multiple emits
180 // Release temporary variable when used
181 if (variable != null)
182 variable.Release (ec);
185 public void EmitAssign (EmitContext ec)
187 var type = Expr.Type;
189 var ml = (IMemoryLocation) Expr;
190 ml.AddressOf (ec, AddressOp.Load);
191 type = ReferenceContainer.MakeType (type);
196 variable = new LocalTemporary (type);
202 public Location Location {
207 public class Arguments
210 List<NamedArgument> reordered;
212 public Arguments (int capacity)
214 args = new List<Argument> (capacity);
217 public void Add (Argument arg)
222 public void AddRange (Arguments args)
224 this.args.AddRange (args.args);
227 public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
229 Location loc = Location.Null;
230 var all = new ArrayInitializer (args.Count, loc);
232 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
234 foreach (Argument a in args) {
235 Arguments dargs = new Arguments (2);
237 // CSharpArgumentInfoFlags.None = 0
238 const string info_flags_enum = "CSharpArgumentInfoFlags";
239 Expression info_flags = new IntLiteral (0, loc);
241 if (a.Expr is Constant) {
242 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
243 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "Constant", loc), loc);
244 } else if (a.ArgType == Argument.AType.Ref) {
245 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
246 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsRef", loc), loc);
247 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
248 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
249 } else if (a.ArgType == Argument.AType.Out) {
250 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
251 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsOut", loc), loc);
252 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
253 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
254 } else if (a.ArgType == Argument.AType.DynamicTypeName) {
255 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
256 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "IsStaticType", loc), loc);
259 var arg_type = a.Expr.Type;
261 if (arg_type != InternalType.Dynamic && arg_type != InternalType.Null) {
262 MethodGroupExpr mg = a.Expr as MethodGroupExpr;
264 rc.Report.Error (1976, a.Expr.Location,
265 "The method group `{0}' cannot be used as an argument of dynamic operation. Consider using parentheses to invoke the method",
267 } else if (arg_type == InternalType.AnonymousMethod) {
268 rc.Report.Error (1977, a.Expr.Location,
269 "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast");
270 } else if (arg_type == TypeManager.void_type || arg_type == InternalType.Arglist || arg_type.IsPointer) {
271 rc.Report.Error (1978, a.Expr.Location,
272 "An expression of type `{0}' cannot be used as an argument of dynamic operation",
273 TypeManager.CSharpName (arg_type));
276 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
277 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "UseCompileTimeType", loc), loc);
281 NamedArgument na = a as NamedArgument;
283 info_flags = new Binary (Binary.Operator.BitwiseOr, info_flags,
284 new MemberAccess (new MemberAccess (binder, info_flags_enum, loc), "NamedArgument", loc), loc);
286 named_value = na.Name;
291 dargs.Add (new Argument (info_flags));
292 dargs.Add (new Argument (new StringLiteral (named_value, loc)));
293 all.Add (new Invocation (new MemberAccess (new MemberAccess (binder, "CSharpArgumentInfo", loc), "Create", loc), dargs));
299 public static Arguments CreateForExpressionTree (ResolveContext ec, Arguments args, params Expression[] e)
301 Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
302 for (int i = 0; i < e.Length; ++i) {
304 all.Add (new Argument (e[i]));
308 foreach (Argument a in args.args) {
309 Expression tree_arg = a.CreateExpressionTree (ec);
310 if (tree_arg != null)
311 all.Add (new Argument (tree_arg));
318 public void CheckArrayAsAttribute (CompilerContext ctx)
320 foreach (Argument arg in args) {
321 // Type is undefined (was error 246)
322 if (arg.Type == null)
325 if (arg.Type.IsArray)
326 ctx.Report.Warning (3016, 1, arg.Expr.Location, "Arrays as attribute arguments are not CLS-compliant");
330 public Arguments Clone (CloneContext ctx)
332 Arguments cloned = new Arguments (args.Count);
333 foreach (Argument a in args)
334 cloned.Add (a.Clone (ctx));
340 get { return args.Count; }
344 // Emits a list of resolved Arguments
346 public void Emit (EmitContext ec)
352 // if `dup_args' is true, a copy of the arguments will be left
353 // on the stack and return value will contain an array of access
355 // NOTE: It's caller responsibility is to release temporary variables
357 public Expression[] Emit (EmitContext ec, bool dup_args)
361 if (dup_args && Count != 0)
362 temps = new Expression [Count];
366 if (reordered != null && Count > 1) {
367 foreach (NamedArgument na in reordered)
373 foreach (Argument a in args) {
378 if (a.Expr is Constant) {
380 // No need to create a temporary variable for constants
384 ec.Emit (OpCodes.Dup);
385 temps[i] = lt = new LocalTemporary (a.Type);
395 public List<Argument>.Enumerator GetEnumerator ()
397 return args.GetEnumerator ();
401 // At least one argument is of dynamic type
403 public bool HasDynamic {
405 foreach (Argument a in args) {
406 if (a.Type == InternalType.Dynamic && !a.IsByRef)
414 public void Insert (int index, Argument arg)
416 args.Insert (index, arg);
419 public static System.Linq.Expressions.Expression[] MakeExpression (Arguments args, BuilderContext ctx)
421 if (args == null || args.Count == 0)
424 var exprs = new System.Linq.Expressions.Expression [args.Count];
425 for (int i = 0; i < exprs.Length; ++i) {
426 Argument a = args.args [i];
427 exprs[i] = a.Expr.MakeExpression (ctx);
433 public void MarkReorderedArgument (NamedArgument a)
436 // Constant expression can have no effect on left-to-right execution
438 if (a.Expr is Constant)
441 if (reordered == null)
442 reordered = new List<NamedArgument> ();
448 // Returns dynamic when at least one argument is of dynamic type
450 public void Resolve (ResolveContext ec, out bool dynamic)
453 foreach (Argument a in args) {
455 if (a.Type == InternalType.Dynamic && !a.IsByRef)
460 public void RemoveAt (int index)
462 args.RemoveAt (index);
465 public Argument this [int index] {
466 get { return args [index]; }
467 set { args [index] = value; }