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
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 ();
51 get { return Expr.Type; }
54 public Parameter
.Modifier Modifier
{
58 return Parameter
.Modifier
.OUT
;
61 return Parameter
.Modifier
.REF
;
64 return Parameter
.Modifier
.NONE
;
69 public virtual Expression
CreateExpressionTree (ResolveContext ec
)
71 if (ArgType
== AType
.Default
)
72 ec
.Report
.Error (854, Expr
.Location
, "An expression tree cannot contain an invocation which uses optional parameter");
74 return Expr
.CreateExpressionTree (ec
);
77 public string GetSignatureForError ()
79 if (Expr
.eclass
== ExprClass
.MethodGroup
)
80 return Expr
.ExprClassName
;
82 return TypeManager
.CSharpName (Expr
.Type
);
86 get { return ArgType == AType.Ref || ArgType == AType.Out; }
89 public bool IsDefaultArgument
{
90 get { return ArgType == AType.Default; }
93 public bool ResolveMethodGroup (ResolveContext ec
)
95 SimpleName sn
= Expr
as SimpleName
;
97 Expr
= sn
.GetMethodGroup ();
99 // FIXME: csc doesn't report any error if you try to use `ref' or
100 // `out' in a delegate creation expression.
101 Expr
= Expr
.Resolve (ec
, ResolveFlags
.VariableOrValue
| ResolveFlags
.MethodGroup
);
108 public void Resolve (ResolveContext ec
)
110 if (Expr
== EmptyExpression
.Null
)
113 using (ec
.With (ResolveContext
.Options
.DoFlowAnalysis
, true)) {
114 // Verify that the argument is readable
115 if (ArgType
!= AType
.Out
)
116 Expr
= Expr
.Resolve (ec
);
118 // Verify that the argument is writeable
119 if (Expr
!= null && IsByRef
)
120 Expr
= Expr
.ResolveLValue (ec
, EmptyExpression
.OutAccess
.Instance
);
123 Expr
= EmptyExpression
.Null
;
127 public virtual void Emit (EmitContext ec
)
134 AddressOp mode
= AddressOp
.Store
;
135 if (ArgType
== AType
.Ref
)
136 mode
|= AddressOp
.Load
;
138 IMemoryLocation ml
= (IMemoryLocation
) Expr
;
139 ml
.AddressOf (ec
, mode
);
142 public Argument
Clone (CloneContext clonectx
)
144 Argument a
= (Argument
) MemberwiseClone ();
145 a
.Expr
= Expr
.Clone (clonectx
);
150 public class NamedArgument
: Argument
152 public readonly string Name
;
153 readonly Location loc
;
154 LocalTemporary variable
;
156 public NamedArgument (string name
, Location loc
, Expression expr
)
157 : this (name
, loc
, expr
, AType
.None
)
161 public NamedArgument (string name
, Location loc
, Expression expr
, AType modifier
)
162 : base (expr
, modifier
)
168 public override Expression
CreateExpressionTree (ResolveContext ec
)
170 ec
.Report
.Error (853, loc
, "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
)
186 var type
= Expr
.Type
;
188 var ml
= (IMemoryLocation
) Expr
;
189 ml
.AddressOf (ec
, AddressOp
.Load
);
190 type
= TypeManager
.GetReferenceType (type
);
195 variable
= new LocalTemporary (type
);
201 public Location Location
{
206 public class Arguments
209 List
<NamedArgument
> reordered
;
211 public Arguments (int capacity
)
213 args
= new List
<Argument
> (capacity
);
216 public void Add (Argument arg
)
221 public void AddRange (Arguments args
)
223 this.args
.AddRange (args
.args
);
226 public ArrayInitializer
CreateDynamicBinderArguments (ResolveContext rc
)
228 Location loc
= Location
.Null
;
229 var all
= new ArrayInitializer (args
.Count
, loc
);
231 MemberAccess binder
= DynamicExpressionStatement
.GetBinderNamespace (loc
);
233 foreach (Argument a
in args
) {
234 Arguments dargs
= new Arguments (2);
236 // CSharpArgumentInfoFlags.None = 0
237 const string info_flags_enum
= "CSharpArgumentInfoFlags";
238 Expression info_flags
= new IntLiteral (0, loc
);
240 var constant
= a
.Expr
as Constant
;
241 if (constant
!= null && constant
.IsLiteral
) {
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 } else if (a
.ArgType
== Argument
.AType
.Out
) {
248 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
249 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsOut", loc
), loc
);
250 } else if (a
.ArgType
== Argument
.AType
.DynamicTypeName
) {
251 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
252 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "IsStaticType", loc
), loc
);
255 var arg_type
= a
.Expr
.Type
;
257 if (!TypeManager
.IsDynamicType (arg_type
)) {
258 MethodGroupExpr mg
= a
.Expr
as MethodGroupExpr
;
260 rc
.Report
.Error (1976, a
.Expr
.Location
,
261 "The method group `{0}' cannot be used as an argument of dynamic operation. Consider using parentheses to invoke the method",
263 } else if (arg_type
== InternalType
.AnonymousMethod
) {
264 rc
.Report
.Error (1977, a
.Expr
.Location
,
265 "An anonymous method or lambda expression cannot be used as an argument of dynamic operation. Consider using a cast");
266 } else if (arg_type
== TypeManager
.void_type
|| arg_type
== InternalType
.Arglist
|| arg_type
.IsPointer
) {
267 rc
.Report
.Error (1978, a
.Expr
.Location
,
268 "An expression of type `{0}' cannot be used as an argument of dynamic operation",
269 TypeManager
.CSharpName (arg_type
));
272 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
273 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "UseCompileTimeType", loc
), loc
);
277 NamedArgument na
= a
as NamedArgument
;
279 info_flags
= new Binary (Binary
.Operator
.BitwiseOr
, info_flags
,
280 new MemberAccess (new MemberAccess (binder
, info_flags_enum
, loc
), "NamedArgument", loc
), loc
);
282 named_value
= na
.Name
;
287 dargs
.Add (new Argument (info_flags
));
288 dargs
.Add (new Argument (new StringLiteral (named_value
, loc
)));
289 all
.Add (new Invocation (new MemberAccess (new MemberAccess (binder
, "CSharpArgumentInfo", loc
), "Create", loc
), dargs
));
295 public static Arguments
CreateForExpressionTree (ResolveContext ec
, Arguments args
, params Expression
[] e
)
297 Arguments all
= new Arguments ((args
== null ? 0 : args
.Count
) + e
.Length
);
298 for (int i
= 0; i
< e
.Length
; ++i
) {
300 all
.Add (new Argument (e
[i
]));
304 foreach (Argument a
in args
.args
) {
305 Expression tree_arg
= a
.CreateExpressionTree (ec
);
306 if (tree_arg
!= null)
307 all
.Add (new Argument (tree_arg
));
314 public void CheckArrayAsAttribute (CompilerContext ctx
)
316 foreach (Argument arg
in args
) {
317 // Type is undefined (was error 246)
318 if (arg
.Type
== null)
321 if (arg
.Type
.IsArray
)
322 ctx
.Report
.Warning (3016, 1, arg
.Expr
.Location
, "Arrays as attribute arguments are not CLS-compliant");
326 public Arguments
Clone (CloneContext ctx
)
328 Arguments cloned
= new Arguments (args
.Count
);
329 foreach (Argument a
in args
)
330 cloned
.Add (a
.Clone (ctx
));
336 get { return args.Count; }
340 // Emits a list of resolved Arguments
342 public void Emit (EmitContext ec
)
344 Emit (ec
, false, null);
348 // if `dup_args' is true, a copy of the arguments will be left
349 // on the stack. If `dup_args' is true, you can specify `this_arg'
350 // which will be duplicated before any other args. Only EmitCall
351 // should be using this interface.
353 public void Emit (EmitContext ec
, bool dup_args
, LocalTemporary this_arg
)
355 LocalTemporary
[] temps
= null;
357 if (dup_args
&& Count
!= 0)
358 temps
= new LocalTemporary
[Count
];
360 if (reordered
!= null && Count
> 1) {
361 foreach (NamedArgument na
in reordered
)
366 foreach (Argument a
in args
) {
369 ec
.ig
.Emit (OpCodes
.Dup
);
370 (temps
[i
++] = new LocalTemporary (a
.Type
)).Store (ec
);
375 if (this_arg
!= null)
378 for (i
= 0; i
< temps
.Length
; i
++) {
380 temps
[i
].Release (ec
);
385 public bool GetAttributableValue (ResolveContext ec
, out object[] values
)
387 values
= new object [args
.Count
];
388 for (int j
= 0; j
< values
.Length
; ++j
) {
389 Argument a
= this [j
];
390 if (!a
.Expr
.GetAttributableValue (ec
, a
.Type
, out values
[j
]))
397 public IEnumerator
<Argument
> GetEnumerator ()
399 return args
.GetEnumerator ();
403 // At least one argument is of dynamic type
405 public bool HasDynamic
{
407 foreach (Argument a
in args
) {
408 if (TypeManager
.IsDynamicType (a
.Type
))
416 public void Insert (int index
, Argument arg
)
418 args
.Insert (index
, arg
);
421 public static System
.Linq
.Expressions
.Expression
[] MakeExpression (Arguments args
, BuilderContext ctx
)
423 if (args
== null || args
.Count
== 0)
426 var exprs
= new System
.Linq
.Expressions
.Expression
[args
.Count
];
427 for (int i
= 0; i
< exprs
.Length
; ++i
) {
428 Argument a
= (Argument
) args
.args
[i
];
429 exprs
[i
] = a
.Expr
.MakeExpression (ctx
);
435 public void MarkReorderedArgument (NamedArgument a
)
438 // Constant expression can have no effect on left-to-right execution
440 if (a
.Expr
is Constant
)
443 if (reordered
== null)
444 reordered
= new List
<NamedArgument
> ();
450 // Returns dynamic when at least one argument is of dynamic type
452 public void Resolve (ResolveContext ec
, out bool dynamic)
455 foreach (Argument a
in args
) {
457 dynamic |= TypeManager
.IsDynamicType (a
.Type
);
461 public void MutateHoistedGenericType (AnonymousMethodStorey storey
)
463 foreach (Argument a
in args
)
464 a
.Expr
.MutateHoistedGenericType (storey
);
467 public void RemoveAt (int index
)
469 args
.RemoveAt (index
);
472 public Argument
this [int index
] {
473 get { return (Argument) args [index]; }
474 set { args [index] = value; }