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
.Collections
;
14 using System
.Reflection
;
15 using System
.Reflection
.Emit
;
20 // Argument expression used for invocation
24 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
31 public readonly AType ArgType
;
32 public Expression Expr
;
34 public Argument (Expression expr
, AType type
)
40 public Argument (Expression expr
)
43 throw new ArgumentNullException ();
49 get { return Expr.Type; }
52 public Parameter
.Modifier Modifier
{
56 return Parameter
.Modifier
.OUT
;
59 return Parameter
.Modifier
.REF
;
62 return Parameter
.Modifier
.NONE
;
67 public virtual Expression
CreateExpressionTree (EmitContext ec
)
69 if (ArgType
== AType
.Default
)
70 Report
.Error (854, Expr
.Location
, "An expression tree cannot contain an invocation which uses optional parameter");
72 return Expr
.CreateExpressionTree (ec
);
75 public string GetSignatureForError ()
77 if (Expr
.eclass
== ExprClass
.MethodGroup
)
78 return Expr
.ExprClassName
;
80 return TypeManager
.CSharpName (Expr
.Type
);
84 get { return ArgType == AType.Ref || ArgType == AType.Out; }
87 public bool IsDefaultArgument
{
88 get { return ArgType == AType.Default; }
91 public bool ResolveMethodGroup (EmitContext ec
)
93 SimpleName sn
= Expr
as SimpleName
;
95 Expr
= sn
.GetMethodGroup ();
97 // FIXME: csc doesn't report any error if you try to use `ref' or
98 // `out' in a delegate creation expression.
99 Expr
= Expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
106 public void Resolve (EmitContext ec
)
108 if (Expr
== EmptyExpression
.Null
)
111 using (ec
.With (EmitContext
.Flags
.DoFlowAnalysis
, true)) {
112 // Verify that the argument is readable
113 if (ArgType
!= AType
.Out
)
114 Expr
= Expr
.Resolve (ec
);
116 // Verify that the argument is writeable
117 if (Expr
!= null && IsByRef
)
118 Expr
= Expr
.ResolveLValue (ec
, EmptyExpression
.OutAccess
);
121 Expr
= EmptyExpression
.Null
;
125 public virtual void Emit (EmitContext ec
)
132 AddressOp mode
= AddressOp
.Store
;
133 if (ArgType
== AType
.Ref
)
134 mode
|= AddressOp
.Load
;
136 IMemoryLocation ml
= (IMemoryLocation
) Expr
;
137 ParameterReference pr
= ml
as ParameterReference
;
140 // ParameterReferences might already be references, so we want
141 // to pass just the value
143 if (pr
!= null && pr
.IsRef
)
146 ml
.AddressOf (ec
, mode
);
149 public Argument
Clone (CloneContext clonectx
)
151 Argument a
= (Argument
) MemberwiseClone ();
152 a
.Expr
= Expr
.Clone (clonectx
);
157 public class NamedArgument
: Argument
159 public readonly LocatedToken Name
;
160 LocalTemporary variable
;
162 public NamedArgument (LocatedToken name
, Expression expr
)
168 public override Expression
CreateExpressionTree (EmitContext ec
)
170 Report
.Error (853, Name
.Location
, "An expression tree cannot contain named argument");
171 return base.CreateExpressionTree (ec
);
174 public override void Emit (EmitContext ec
)
176 // TODO: Should guard against multiple emits
179 // Release temporary variable when used
180 if (variable
!= null)
181 variable
.Release (ec
);
184 public void EmitAssign (EmitContext ec
)
187 variable
= new LocalTemporary (Expr
.Type
);
194 public class Arguments
196 ArrayList args
; // TODO: This should really be linked list
197 ArrayList reordered
; // TODO: LinkedList
199 public Arguments (int capacity
)
201 args
= new ArrayList (capacity
);
204 public int Add (Argument arg
)
206 return args
.Add (arg
);
209 public void AddRange (Arguments args
)
211 this.args
.AddRange (args
.args
);
214 public ArrayList
CreateDynamicBinderArguments ()
216 ArrayList all
= new ArrayList (args
.Count
);
217 Location loc
= Location
.Null
;
219 MemberAccess binder
= DynamicExpressionStatement
.GetBinderNamespace (loc
);
221 foreach (Argument a
in args
) {
222 Arguments dargs
= new Arguments (2);
224 // TODO: Inspect a.Type or a.Expression
226 // CSharpArgumentInfoFlags.None = 0
227 dargs
.Add (new Argument (new IntLiteral (0, loc
)));
230 dargs
.Add (new Argument (new NullLiteral (loc
)));
231 all
.Add (new New (new MemberAccess (binder
, "CSharpArgumentInfo", loc
), dargs
, loc
));
237 public static Arguments
CreateForExpressionTree (EmitContext ec
, Arguments args
, params Expression
[] e
)
239 Arguments all
= new Arguments ((args
== null ? 0 : args
.Count
) + e
.Length
);
240 for (int i
= 0; i
< e
.Length
; ++i
) {
242 all
.Add (new Argument (e
[i
]));
246 foreach (Argument a
in args
.args
) {
247 Expression tree_arg
= a
.CreateExpressionTree (ec
);
248 if (tree_arg
!= null)
249 all
.Add (new Argument (tree_arg
));
256 public void CheckArrayAsAttribute ()
258 foreach (Argument arg
in args
) {
259 // Type is undefined (was error 246)
260 if (arg
.Type
== null)
263 if (arg
.Type
.IsArray
)
264 Report
.Warning (3016, 1, arg
.Expr
.Location
, "Arrays as attribute arguments are not CLS-compliant");
268 public Arguments
Clone (CloneContext ctx
)
270 Arguments cloned
= new Arguments (args
.Count
);
271 foreach (Argument a
in args
)
272 cloned
.Add (a
.Clone (ctx
));
278 get { return args.Count; }
282 // Emits a list of resolved Arguments
284 public void Emit (EmitContext ec
)
286 Emit (ec
, false, null);
290 // if `dup_args' is true, a copy of the arguments will be left
291 // on the stack. If `dup_args' is true, you can specify `this_arg'
292 // which will be duplicated before any other args. Only EmitCall
293 // should be using this interface.
295 public void Emit (EmitContext ec
, bool dup_args
, LocalTemporary this_arg
)
297 LocalTemporary
[] temps
= null;
299 if (dup_args
&& Count
!= 0)
300 temps
= new LocalTemporary
[Count
];
302 if (reordered
!= null && Count
> 1) {
303 foreach (NamedArgument na
in reordered
)
308 foreach (Argument a
in args
) {
311 ec
.ig
.Emit (OpCodes
.Dup
);
312 (temps
[i
++] = new LocalTemporary (a
.Type
)).Store (ec
);
317 if (this_arg
!= null)
320 for (i
= 0; i
< temps
.Length
; i
++) {
322 temps
[i
].Release (ec
);
327 public bool GetAttributableValue (EmitContext ec
, out object[] values
)
329 values
= new object [args
.Count
];
330 for (int j
= 0; j
< values
.Length
; ++j
) {
331 Argument a
= this [j
];
332 if (!a
.Expr
.GetAttributableValue (ec
, a
.Type
, out values
[j
]))
339 public IEnumerator
GetEnumerator ()
341 return args
.GetEnumerator ();
344 public void Insert (int index
, Argument arg
)
346 args
.Insert (index
, arg
);
349 public void MarkReorderedArgument (NamedArgument a
)
352 // Constant expression can have no effect on left-to-right execution
354 if (a
.Expr
is Constant
)
357 if (reordered
== null)
358 reordered
= new ArrayList ();
364 // Returns dynamic when at least one argument is of dynamic type
366 public void Resolve (EmitContext ec
, out bool dynamic)
369 foreach (Argument a
in args
) {
371 dynamic |= TypeManager
.IsDynamicType (a
.Type
);
375 public void MutateHoistedGenericType (AnonymousMethodStorey storey
)
377 foreach (Argument a
in args
)
378 a
.Expr
.MutateHoistedGenericType (storey
);
381 public void RemoveAt (int index
)
383 args
.RemoveAt (index
);
386 public Argument
this [int index
] {
387 get { return (Argument) args [index]; }
388 set { args [index] = value; }