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
29 DynamicStatic
= 4 // static argument for dynamic binding
32 public readonly AType ArgType
;
33 public Expression Expr
;
35 public Argument (Expression expr
, AType type
)
41 public Argument (Expression expr
)
44 throw new ArgumentNullException ();
50 get { return Expr.Type; }
53 public Parameter
.Modifier Modifier
{
57 return Parameter
.Modifier
.OUT
;
60 return Parameter
.Modifier
.REF
;
63 return Parameter
.Modifier
.NONE
;
68 public virtual Expression
CreateExpressionTree (ResolveContext ec
)
70 if (ArgType
== AType
.Default
)
71 Report
.Error (854, Expr
.Location
, "An expression tree cannot contain an invocation which uses optional parameter");
73 return Expr
.CreateExpressionTree (ec
);
76 public string GetSignatureForError ()
78 if (Expr
.eclass
== ExprClass
.MethodGroup
)
79 return Expr
.ExprClassName
;
81 return TypeManager
.CSharpName (Expr
.Type
);
85 get { return ArgType == AType.Ref || ArgType == AType.Out; }
88 public bool IsDefaultArgument
{
89 get { return ArgType == AType.Default; }
92 public bool ResolveMethodGroup (ResolveContext ec
)
94 SimpleName sn
= Expr
as SimpleName
;
96 Expr
= sn
.GetMethodGroup ();
98 // FIXME: csc doesn't report any error if you try to use `ref' or
99 // `out' in a delegate creation expression.
100 Expr
= Expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
107 public void Resolve (ResolveContext ec
)
109 if (Expr
== EmptyExpression
.Null
)
112 using (ec
.With (ResolveContext
.Options
.DoFlowAnalysis
, true)) {
113 // Verify that the argument is readable
114 if (ArgType
!= AType
.Out
)
115 Expr
= Expr
.Resolve (ec
);
117 // Verify that the argument is writeable
118 if (Expr
!= null && IsByRef
)
119 Expr
= Expr
.ResolveLValue (ec
, EmptyExpression
.OutAccess
);
122 Expr
= EmptyExpression
.Null
;
126 public virtual void Emit (EmitContext ec
)
133 AddressOp mode
= AddressOp
.Store
;
134 if (ArgType
== AType
.Ref
)
135 mode
|= AddressOp
.Load
;
137 IMemoryLocation ml
= (IMemoryLocation
) Expr
;
138 ParameterReference pr
= ml
as ParameterReference
;
141 // ParameterReferences might already be references, so we want
142 // to pass just the value
144 if (pr
!= null && pr
.IsRef
)
147 ml
.AddressOf (ec
, mode
);
150 public Argument
Clone (CloneContext clonectx
)
152 Argument a
= (Argument
) MemberwiseClone ();
153 a
.Expr
= Expr
.Clone (clonectx
);
158 public class NamedArgument
: Argument
160 public readonly LocatedToken Name
;
161 LocalTemporary variable
;
163 public NamedArgument (LocatedToken name
, Expression expr
)
169 public override Expression
CreateExpressionTree (ResolveContext ec
)
171 Report
.Error (853, Name
.Location
, "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
)
188 variable
= new LocalTemporary (Expr
.Type
);
195 public class Arguments
197 ArrayList args
; // TODO: This should really be linked list
198 ArrayList reordered
; // TODO: LinkedList
200 public Arguments (int capacity
)
202 args
= new ArrayList (capacity
);
205 public int Add (Argument arg
)
207 return args
.Add (arg
);
210 public void AddRange (Arguments args
)
212 this.args
.AddRange (args
.args
);
215 public ArrayList
CreateDynamicBinderArguments ()
217 ArrayList all
= new ArrayList (args
.Count
);
218 Location loc
= Location
.Null
;
220 MemberAccess binder
= DynamicExpressionStatement
.GetBinderNamespace (loc
);
222 foreach (Argument a
in args
) {
223 Arguments dargs
= new Arguments (2);
225 // CSharpArgumentInfoFlags.None = 0
226 const string info_flags_enum
= "CSharpArgumentInfoFlags";
227 Expression info_flags
= new IntLiteral (0, loc
);
229 if (a
.Expr
is Constant
) {
230 // Any constant is emitted as a literal
231 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
232 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "LiteralConstant", loc
));
233 } else if (a
.ArgType
== Argument
.AType
.Ref
) {
234 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
235 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsRef", loc
));
236 } else if (a
.ArgType
== Argument
.AType
.Out
) {
237 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
238 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsOut", loc
));
239 } else if (a
.ArgType
== Argument
.AType
.DynamicStatic
) {
240 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
241 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsStaticType", loc
));
244 if (!TypeManager
.IsDynamicType (a
.Expr
.Type
)) {
245 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
246 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "UseCompileTimeType", loc
));
250 NamedArgument na
= a
as NamedArgument
;
252 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
253 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "NamedArgument", loc
));
255 named_value
= na
.Name
.Value
;
260 dargs
.Add (new Argument (info_flags
));
261 dargs
.Add (new Argument (new StringLiteral (named_value
, loc
)));
262 all
.Add (new New (new MemberAccess (binder
, "CSharpArgumentInfo", loc
), dargs
, loc
));
268 public static Arguments
CreateForExpressionTree (ResolveContext ec
, Arguments args
, params Expression
[] e
)
270 Arguments all
= new Arguments ((args
== null ? 0 : args
.Count
) + e
.Length
);
271 for (int i
= 0; i
< e
.Length
; ++i
) {
273 all
.Add (new Argument (e
[i
]));
277 foreach (Argument a
in args
.args
) {
278 Expression tree_arg
= a
.CreateExpressionTree (ec
);
279 if (tree_arg
!= null)
280 all
.Add (new Argument (tree_arg
));
287 public void CheckArrayAsAttribute ()
289 foreach (Argument arg
in args
) {
290 // Type is undefined (was error 246)
291 if (arg
.Type
== null)
294 if (arg
.Type
.IsArray
)
295 Report
.Warning (3016, 1, arg
.Expr
.Location
, "Arrays as attribute arguments are not CLS-compliant");
299 public Arguments
Clone (CloneContext ctx
)
301 Arguments cloned
= new Arguments (args
.Count
);
302 foreach (Argument a
in args
)
303 cloned
.Add (a
.Clone (ctx
));
309 get { return args.Count; }
313 // Emits a list of resolved Arguments
315 public void Emit (EmitContext ec
)
317 Emit (ec
, false, null);
321 // if `dup_args' is true, a copy of the arguments will be left
322 // on the stack. If `dup_args' is true, you can specify `this_arg'
323 // which will be duplicated before any other args. Only EmitCall
324 // should be using this interface.
326 public void Emit (EmitContext ec
, bool dup_args
, LocalTemporary this_arg
)
328 LocalTemporary
[] temps
= null;
330 if (dup_args
&& Count
!= 0)
331 temps
= new LocalTemporary
[Count
];
333 if (reordered
!= null && Count
> 1) {
334 foreach (NamedArgument na
in reordered
)
339 foreach (Argument a
in args
) {
342 ec
.ig
.Emit (OpCodes
.Dup
);
343 (temps
[i
++] = new LocalTemporary (a
.Type
)).Store (ec
);
348 if (this_arg
!= null)
351 for (i
= 0; i
< temps
.Length
; i
++) {
353 temps
[i
].Release (ec
);
358 public bool GetAttributableValue (ResolveContext ec
, out object[] values
)
360 values
= new object [args
.Count
];
361 for (int j
= 0; j
< values
.Length
; ++j
) {
362 Argument a
= this [j
];
363 if (!a
.Expr
.GetAttributableValue (ec
, a
.Type
, out values
[j
]))
370 public IEnumerator
GetEnumerator ()
372 return args
.GetEnumerator ();
375 public void Insert (int index
, Argument arg
)
377 args
.Insert (index
, arg
);
380 public void MarkReorderedArgument (NamedArgument a
)
383 // Constant expression can have no effect on left-to-right execution
385 if (a
.Expr
is Constant
)
388 if (reordered
== null)
389 reordered
= new ArrayList ();
395 // Returns dynamic when at least one argument is of dynamic type
397 public void Resolve (ResolveContext ec
, out bool dynamic)
400 foreach (Argument a
in args
) {
402 dynamic |= TypeManager
.IsDynamicType (a
.Type
);
406 public void MutateHoistedGenericType (AnonymousMethodStorey storey
)
408 foreach (Argument a
in args
)
409 a
.Expr
.MutateHoistedGenericType (storey
);
412 public void RemoveAt (int index
)
414 args
.RemoveAt (index
);
417 public Argument
this [int index
] {
418 get { return (Argument) args [index]; }
419 set { args [index] = value; }