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
;
16 using System
.Collections
.Generic
;
21 // Argument expression used for invocation
25 public enum AType
: byte
28 Ref
= 1, // ref modifier used
29 Out
= 2, // out modifier used
30 Default
= 3, // argument created from default parameter value
31 DynamicTypeName
= 4 // System.Type argument for dynamic binding
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 ();
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
= TypeManager
.GetReferenceType (type
);
196 variable
= new LocalTemporary (type
);
202 public Location Location
{
207 public class Arguments
210 ArrayList reordered
; // TODO: LinkedList
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 ArrayList
CreateDynamicBinderArguments (ResolveContext rc
)
229 ArrayList all
= new ArrayList (args
.Count
);
230 Location loc
= Location
.Null
;
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 var constant
= a
.Expr
as Constant
;
242 if (constant
!= null && constant
.IsLiteral
) {
243 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
244 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "LiteralConstant", loc
));
245 } else if (a
.ArgType
== Argument
.AType
.Ref
) {
246 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
247 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsRef", loc
));
248 } else if (a
.ArgType
== Argument
.AType
.Out
) {
249 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
250 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsOut", loc
));
251 } else if (a
.ArgType
== Argument
.AType
.DynamicTypeName
) {
252 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
253 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsStaticType", loc
));
256 var arg_type
= a
.Expr
.Type
;
258 if (!TypeManager
.IsDynamicType (arg_type
)) {
259 MethodGroupExpr mg
= a
.Expr
as MethodGroupExpr
;
261 rc
.Report
.Error (1976, a
.Expr
.Location
,
262 "The method group `{0}' cannot be used as an argument of dynamic operation. Consider using parentheses to invoke the method",
264 } else if (arg_type
== InternalType
.AnonymousMethod
) {
265 rc
.Report
.Error (1977, a
.Expr
.Location
,
266 "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast");
267 } else if (arg_type
== TypeManager
.void_type
|| arg_type
== InternalType
.Arglist
|| arg_type
.IsPointer
) {
268 rc
.Report
.Error (1978, a
.Expr
.Location
,
269 "An expression of type `{0}' cannot be used as an argument of dynamic operation",
270 TypeManager
.CSharpName (arg_type
));
273 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
274 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "UseCompileTimeType", loc
));
278 NamedArgument na
= a
as NamedArgument
;
280 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
281 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "NamedArgument", loc
));
283 named_value
= na
.Name
;
288 dargs
.Add (new Argument (info_flags
));
289 dargs
.Add (new Argument (new StringLiteral (named_value
, loc
)));
290 all
.Add (new Invocation (new MemberAccess (new MemberAccess (binder
, "CSharpArgumentInfo", loc
), "Create", loc
), dargs
));
296 public static Arguments
CreateForExpressionTree (ResolveContext ec
, Arguments args
, params Expression
[] e
)
298 Arguments all
= new Arguments ((args
== null ? 0 : args
.Count
) + e
.Length
);
299 for (int i
= 0; i
< e
.Length
; ++i
) {
301 all
.Add (new Argument (e
[i
]));
305 foreach (Argument a
in args
.args
) {
306 Expression tree_arg
= a
.CreateExpressionTree (ec
);
307 if (tree_arg
!= null)
308 all
.Add (new Argument (tree_arg
));
315 public void CheckArrayAsAttribute (CompilerContext ctx
)
317 foreach (Argument arg
in args
) {
318 // Type is undefined (was error 246)
319 if (arg
.Type
== null)
322 if (arg
.Type
.IsArray
)
323 ctx
.Report
.Warning (3016, 1, arg
.Expr
.Location
, "Arrays as attribute arguments are not CLS-compliant");
327 public Arguments
Clone (CloneContext ctx
)
329 Arguments cloned
= new Arguments (args
.Count
);
330 foreach (Argument a
in args
)
331 cloned
.Add (a
.Clone (ctx
));
337 get { return args.Count; }
341 // Emits a list of resolved Arguments
343 public void Emit (EmitContext ec
)
345 Emit (ec
, false, null);
349 // if `dup_args' is true, a copy of the arguments will be left
350 // on the stack. If `dup_args' is true, you can specify `this_arg'
351 // which will be duplicated before any other args. Only EmitCall
352 // should be using this interface.
354 public void Emit (EmitContext ec
, bool dup_args
, LocalTemporary this_arg
)
356 LocalTemporary
[] temps
= null;
358 if (dup_args
&& Count
!= 0)
359 temps
= new LocalTemporary
[Count
];
361 if (reordered
!= null && Count
> 1) {
362 foreach (NamedArgument na
in reordered
)
367 foreach (Argument a
in args
) {
370 ec
.ig
.Emit (OpCodes
.Dup
);
371 (temps
[i
++] = new LocalTemporary (a
.Type
)).Store (ec
);
376 if (this_arg
!= null)
379 for (i
= 0; i
< temps
.Length
; i
++) {
381 temps
[i
].Release (ec
);
386 public bool GetAttributableValue (ResolveContext ec
, out object[] values
)
388 values
= new object [args
.Count
];
389 for (int j
= 0; j
< values
.Length
; ++j
) {
390 Argument a
= this [j
];
391 if (!a
.Expr
.GetAttributableValue (ec
, a
.Type
, out values
[j
]))
398 public IEnumerator
GetEnumerator ()
400 return args
.GetEnumerator ();
404 // At least one argument is of dynamic type
406 public bool HasDynamic
{
408 foreach (Argument a
in args
) {
409 if (TypeManager
.IsDynamicType (a
.Type
))
417 public void Insert (int index
, Argument arg
)
419 args
.Insert (index
, arg
);
423 public static System
.Linq
.Expressions
.Expression
[] MakeExpression (Arguments args
, BuilderContext ctx
)
425 if (args
== null || args
.Count
== 0)
428 var exprs
= new System
.Linq
.Expressions
.Expression
[args
.Count
];
429 for (int i
= 0; i
< exprs
.Length
; ++i
) {
430 Argument a
= (Argument
) args
.args
[i
];
431 exprs
[i
] = a
.Expr
.MakeExpression (ctx
);
438 public void MarkReorderedArgument (NamedArgument a
)
441 // Constant expression can have no effect on left-to-right execution
443 if (a
.Expr
is Constant
)
446 if (reordered
== null)
447 reordered
= new ArrayList ();
453 // Returns dynamic when at least one argument is of dynamic type
455 public void Resolve (ResolveContext ec
, out bool dynamic)
458 foreach (Argument a
in args
) {
460 dynamic |= TypeManager
.IsDynamicType (a
.Type
);
464 public void MutateHoistedGenericType (AnonymousMethodStorey storey
)
466 foreach (Argument a
in args
)
467 a
.Expr
.MutateHoistedGenericType (storey
);
470 public void RemoveAt (int index
)
472 args
.RemoveAt (index
);
475 public Argument
this [int index
] {
476 get { return (Argument) args [index]; }
477 set { args [index] = value; }