2 // expression.cs: Expression representation for the IL tree.
\r
5 // Miguel de Icaza (miguel@ximian.com)
\r
7 // (C) 2001 Ximian, Inc.
\r
12 namespace Mono.CSharp {
\r
14 using System.Collections;
\r
15 using System.Reflection;
\r
16 using System.Reflection.Emit;
\r
20 /// This is just a helper class, it is generated by Unary, UnaryMutator
\r
21 /// when an overloaded method has been found. It just emits the code for a
\r
24 public class StaticCallExpr : ExpressionStatement {
\r
28 StaticCallExpr (MethodInfo m, ArrayList a, Location l)
\r
33 type = m.ReturnType;
\r
34 eclass = ExprClass.Value;
\r
38 public override Expression DoResolve (EmitContext ec)
\r
41 // We are born fully resolved
\r
46 public override void Emit (EmitContext ec)
\r
49 Invocation.EmitArguments (ec, mi, args);
\r
51 ec.ig.Emit (OpCodes.Call, mi);
\r
55 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
\r
56 Expression e, Location loc)
\r
61 args = new ArrayList (1);
\r
62 args.Add (new Argument (e, Argument.AType.Expression));
\r
63 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
\r
68 return new StaticCallExpr ((MethodInfo) method, args, loc);
\r
71 public override void EmitStatement (EmitContext ec)
\r
74 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
\r
75 ec.ig.Emit (OpCodes.Pop);
\r
80 /// Unary expressions.
\r
84 /// Unary implements unary expressions. It derives from
\r
85 /// ExpressionStatement becuase the pre/post increment/decrement
\r
86 /// operators can be used in a statement context.
\r
88 public class Unary : Expression {
\r
89 public enum Operator : byte {
\r
90 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
\r
91 Indirection, AddressOf, TOP
\r
94 public Operator Oper;
\r
95 public Expression Expr;
\r
97 public Unary (Operator op, Expression expr, Location loc)
\r
105 /// Returns a stringified representation of the Operator
\r
107 static public string OperName (Operator oper)
\r
110 case Operator.UnaryPlus:
\r
112 case Operator.UnaryNegation:
\r
114 case Operator.LogicalNot:
\r
116 case Operator.OnesComplement:
\r
118 case Operator.AddressOf:
\r
120 case Operator.Indirection:
\r
124 return oper.ToString ();
\r
127 static string [] oper_names;
\r
131 oper_names = new string [(int)Operator.TOP];
\r
133 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
\r
134 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
\r
135 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
\r
136 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
\r
137 oper_names [(int) Operator.Indirection] = "op_Indirection";
\r
138 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
\r
141 void Error23 (Type t)
\r
144 23, "Operator " + OperName (Oper) +
\r
145 " cannot be applied to operand of type '" +
\r
146 TypeManager.CSharpName (t) + "'");
\r
150 /// The result has been already resolved:
\r
152 /// FIXME: a minus constant -128 sbyte cant be turned into a
\r
155 static Expression TryReduceNegative (Constant expr)
\r
157 Expression e = null;
\r
159 if (expr is IntConstant)
\r
160 e = new IntConstant (-((IntConstant) expr).Value);
\r
161 else if (expr is UIntConstant){
\r
162 uint value = ((UIntConstant) expr).Value;
\r
164 if (value < 2147483649)
\r
165 return new IntConstant (-(int)value);
\r
167 e = new LongConstant (value);
\r
169 else if (expr is LongConstant)
\r
170 e = new LongConstant (-((LongConstant) expr).Value);
\r
171 else if (expr is ULongConstant){
\r
172 ulong value = ((ULongConstant) expr).Value;
\r
174 if (value < 9223372036854775809)
\r
175 return new LongConstant(-(long)value);
\r
177 else if (expr is FloatConstant)
\r
178 e = new FloatConstant (-((FloatConstant) expr).Value);
\r
179 else if (expr is DoubleConstant)
\r
180 e = new DoubleConstant (-((DoubleConstant) expr).Value);
\r
181 else if (expr is DecimalConstant)
\r
182 e = new DecimalConstant (-((DecimalConstant) expr).Value);
\r
183 else if (expr is ShortConstant)
\r
184 e = new IntConstant (-((ShortConstant) expr).Value);
\r
185 else if (expr is UShortConstant)
\r
186 e = new IntConstant (-((UShortConstant) expr).Value);
\r
191 // This routine will attempt to simplify the unary expression when the
\r
192 // argument is a constant. The result is returned in 'result' and the
\r
193 // function returns true or false depending on whether a reduction
\r
194 // was performed or not
\r
196 bool Reduce (EmitContext ec, Constant e, out Expression result)
\r
198 Type expr_type = e.Type;
\r
201 case Operator.UnaryPlus:
\r
205 case Operator.UnaryNegation:
\r
206 result = TryReduceNegative (e);
\r
209 case Operator.LogicalNot:
\r
210 if (expr_type != TypeManager.bool_type) {
\r
212 Error23 (expr_type);
\r
216 BoolConstant b = (BoolConstant) e;
\r
217 result = new BoolConstant (!(b.Value));
\r
220 case Operator.OnesComplement:
\r
221 if (!((expr_type == TypeManager.int32_type) ||
\r
222 (expr_type == TypeManager.uint32_type) ||
\r
223 (expr_type == TypeManager.int64_type) ||
\r
224 (expr_type == TypeManager.uint64_type) ||
\r
225 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
\r
227 Error23 (expr_type);
\r
231 if (e is EnumConstant){
\r
232 EnumConstant enum_constant = (EnumConstant) e;
\r
233 Expression reduced;
\r
235 if (Reduce (ec, enum_constant.Child, out reduced)){
\r
236 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
\r
244 if (expr_type == TypeManager.int32_type){
\r
245 result = new IntConstant (~ ((IntConstant) e).Value);
\r
246 } else if (expr_type == TypeManager.uint32_type){
\r
247 result = new UIntConstant (~ ((UIntConstant) e).Value);
\r
248 } else if (expr_type == TypeManager.int64_type){
\r
249 result = new LongConstant (~ ((LongConstant) e).Value);
\r
250 } else if (expr_type == TypeManager.uint64_type){
\r
251 result = new ULongConstant (~ ((ULongConstant) e).Value);
\r
254 Error23 (expr_type);
\r
259 case Operator.AddressOf:
\r
263 case Operator.Indirection:
\r
267 throw new Exception ("Can not constant fold: " + Oper.ToString());
\r
270 Expression ResolveOperator (EmitContext ec)
\r
272 Type expr_type = Expr.Type;
\r
275 // Step 1: Perform Operator Overload location
\r
280 op_name = oper_names [(int) Oper];
\r
282 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
\r
285 Expression e = StaticCallExpr.MakeSimpleCall (
\r
286 ec, (MethodGroupExpr) mg, Expr, loc);
\r
289 Error23 (expr_type);
\r
296 // Only perform numeric promotions on:
\r
299 if (expr_type == null)
\r
303 // Step 2: Default operations on CLI native types.
\r
306 // Attempt to use a constant folding operation.
\r
307 if (Expr is Constant){
\r
310 if (Reduce (ec, (Constant) Expr, out result))
\r
315 case Operator.LogicalNot:
\r
316 if (expr_type != TypeManager.bool_type) {
\r
317 Error23 (Expr.Type);
\r
321 type = TypeManager.bool_type;
\r
324 case Operator.OnesComplement:
\r
325 if (!((expr_type == TypeManager.int32_type) ||
\r
326 (expr_type == TypeManager.uint32_type) ||
\r
327 (expr_type == TypeManager.int64_type) ||
\r
328 (expr_type == TypeManager.uint64_type) ||
\r
329 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
\r
332 e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
\r
334 type = TypeManager.int32_type;
\r
337 e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
\r
339 type = TypeManager.uint32_type;
\r
342 e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
\r
344 type = TypeManager.int64_type;
\r
347 e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
\r
349 type = TypeManager.uint64_type;
\r
352 Error23 (expr_type);
\r
358 case Operator.AddressOf:
\r
359 if (Expr.eclass != ExprClass.Variable){
\r
360 Error (211, "Cannot take the address of non-variables");
\r
364 if (!ec.InUnsafe) {
\r
365 UnsafeError (loc);
\r
369 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
\r
373 string ptr_type_name = Expr.Type.FullName + "*";
\r
374 type = TypeManager.LookupType (ptr_type_name);
\r
378 case Operator.Indirection:
\r
384 if (!expr_type.IsPointer){
\r
387 "The * or -> operator can only be applied to pointers");
\r
392 // We create an Indirection expression, because
\r
393 // it can implement the IMemoryLocation.
\r
395 return new Indirection (Expr, loc);
\r
397 case Operator.UnaryPlus:
\r
399 // A plus in front of something is just a no-op, so return the child.
\r
403 case Operator.UnaryNegation:
\r
405 // Deals with -literals
\r
406 // int operator- (int x)
\r
407 // long operator- (long x)
\r
408 // float operator- (float f)
\r
409 // double operator- (double d)
\r
410 // decimal operator- (decimal d)
\r
412 Expression expr = null;
\r
415 // transform - - expr into expr
\r
417 if (Expr is Unary){
\r
418 Unary unary = (Unary) Expr;
\r
420 if (unary.Oper == Operator.UnaryNegation)
\r
425 // perform numeric promotions to int,
\r
429 // The following is inneficient, because we call
\r
430 // ConvertImplicit too many times.
\r
432 // It is also not clear if we should convert to Float
\r
433 // or Double initially.
\r
435 if (expr_type == TypeManager.uint32_type){
\r
437 // FIXME: handle exception to this rule that
\r
438 // permits the int value -2147483648 (-2^31) to
\r
439 // bt wrote as a decimal interger literal
\r
441 type = TypeManager.int64_type;
\r
442 Expr = ConvertImplicit (ec, Expr, type, loc);
\r
446 if (expr_type == TypeManager.uint64_type){
\r
448 // FIXME: Handle exception of 'long value'
\r
449 // -92233720368547758087 (-2^63) to be wrote as
\r
450 // decimal integer literal.
\r
452 Error23 (expr_type);
\r
456 if (expr_type == TypeManager.float_type){
\r
461 expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
\r
468 expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
\r
475 expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
\r
482 Error23 (expr_type);
\r
486 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
\r
487 TypeManager.CSharpName (expr_type) + "'");
\r
491 public override Expression DoResolve (EmitContext ec)
\r
493 if (Oper == Operator.AddressOf)
\r
494 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
\r
496 Expr = Expr.Resolve (ec);
\r
501 eclass = ExprClass.Value;
\r
502 return ResolveOperator (ec);
\r
505 public override void Emit (EmitContext ec)
\r
507 ILGenerator ig = ec.ig;
\r
508 Type expr_type = Expr.Type;
\r
511 case Operator.UnaryPlus:
\r
512 throw new Exception ("This should be caught by Resolve");
\r
514 case Operator.UnaryNegation:
\r
516 ig.Emit (OpCodes.Neg);
\r
519 case Operator.LogicalNot:
\r
521 ig.Emit (OpCodes.Ldc_I4_0);
\r
522 ig.Emit (OpCodes.Ceq);
\r
525 case Operator.OnesComplement:
\r
527 ig.Emit (OpCodes.Not);
\r
530 case Operator.AddressOf:
\r
531 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
\r
535 throw new Exception ("This should not happen: Operator = "
\r
536 + Oper.ToString ());
\r
541 /// This will emit the child expression for 'ec' avoiding the logical
\r
542 /// not. The parent will take care of changing brfalse/brtrue
\r
544 public void EmitLogicalNot (EmitContext ec)
\r
546 if (Oper != Operator.LogicalNot)
\r
547 throw new Exception ("EmitLogicalNot can only be called with !expr");
\r
552 public override string ToString ()
\r
554 return "Unary (" + Oper + ", " + Expr + ")";
\r
560 // Unary operators are turned into Indirection expressions
\r
561 // after semantic analysis (this is so we can take the address
\r
562 // of an indirection).
\r
564 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
\r
566 LocalTemporary temporary;
\r
567 bool have_temporary;
\r
569 public Indirection (Expression expr, Location l)
\r
572 this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
\r
573 eclass = ExprClass.Variable;
\r
577 void LoadExprValue (EmitContext ec)
\r
581 public override void Emit (EmitContext ec)
\r
583 ILGenerator ig = ec.ig;
\r
585 if (temporary != null){
\r
586 if (have_temporary){
\r
587 temporary.Emit (ec);
\r
591 ec.ig.Emit (OpCodes.Dup);
\r
592 temporary.Store (ec);
\r
593 have_temporary = true;
\r
597 LoadFromPtr (ig, Type);
\r
600 public void EmitAssign (EmitContext ec, Expression source)
\r
602 if (temporary != null){
\r
603 if (have_temporary){
\r
604 temporary.Emit (ec);
\r
608 ec.ig.Emit (OpCodes.Dup);
\r
609 temporary.Store (ec);
\r
610 have_temporary = true;
\r
615 StoreFromPtr (ec.ig, type);
\r
618 public void AddressOf (EmitContext ec, AddressOp Mode)
\r
620 if (temporary != null){
\r
621 if (have_temporary){
\r
622 temporary.Emit (ec);
\r
626 ec.ig.Emit (OpCodes.Dup);
\r
627 temporary.Store (ec);
\r
628 have_temporary = true;
\r
633 public override Expression DoResolve (EmitContext ec)
\r
636 // Born fully resolved
\r
641 public new void CacheTemporaries (EmitContext ec)
\r
643 temporary = new LocalTemporary (ec, type);
\r
648 /// Unary Mutator expressions (pre and post ++ and --)
\r
652 /// UnaryMutator implements ++ and -- expressions. It derives from
\r
653 /// ExpressionStatement becuase the pre/post increment/decrement
\r
654 /// operators can be used in a statement context.
\r
656 /// FIXME: Idea, we could split this up in two classes, one simpler
\r
657 /// for the common case, and one with the extra fields for more complex
\r
658 /// classes (indexers require temporary access; overloaded require method)
\r
660 /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
\r
661 /// PostDecrement, that way we could save the 'Mode' byte as well.
\r
663 public class UnaryMutator : ExpressionStatement {
\r
664 public enum Mode : byte {
\r
665 PreIncrement, PreDecrement, PostIncrement, PostDecrement
\r
670 LocalTemporary temp_storage;
\r
673 // This is expensive for the simplest case.
\r
677 public UnaryMutator (Mode m, Expression e, Location l)
\r
684 static string OperName (Mode mode)
\r
686 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
\r
690 void Error23 (Type t)
\r
693 23, "Operator " + OperName (mode) +
\r
694 " cannot be applied to operand of type '" +
\r
695 TypeManager.CSharpName (t) + "'");
\r
699 /// Returns whether an object of type 't' can be incremented
\r
700 /// or decremented with add/sub (ie, basically whether we can
\r
701 /// use pre-post incr-decr operations on it, but it is not a
\r
702 /// System.Decimal, which we require operator overloading to catch)
\r
704 static bool IsIncrementableNumber (Type t)
\r
706 return (t == TypeManager.sbyte_type) ||
\r
707 (t == TypeManager.byte_type) ||
\r
708 (t == TypeManager.short_type) ||
\r
709 (t == TypeManager.ushort_type) ||
\r
710 (t == TypeManager.int32_type) ||
\r
711 (t == TypeManager.uint32_type) ||
\r
712 (t == TypeManager.int64_type) ||
\r
713 (t == TypeManager.uint64_type) ||
\r
714 (t == TypeManager.char_type) ||
\r
715 (t.IsSubclassOf (TypeManager.enum_type)) ||
\r
716 (t == TypeManager.float_type) ||
\r
717 (t == TypeManager.double_type) ||
\r
718 (t.IsPointer && t != TypeManager.void_ptr_type);
\r
721 Expression ResolveOperator (EmitContext ec)
\r
723 Type expr_type = expr.Type;
\r
726 // Step 1: Perform Operator Overload location
\r
731 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
\r
732 op_name = "op_Increment";
\r
734 op_name = "op_Decrement";
\r
736 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
\r
738 if (mg == null && expr_type.BaseType != null)
\r
739 mg = MemberLookup (ec, expr_type.BaseType, op_name,
\r
740 MemberTypes.Method, AllBindingFlags, loc);
\r
743 method = StaticCallExpr.MakeSimpleCall (
\r
744 ec, (MethodGroupExpr) mg, expr, loc);
\r
746 type = method.Type;
\r
751 // The operand of the prefix/postfix increment decrement operators
\r
752 // should be an expression that is classified as a variable,
\r
753 // a property access or an indexer access
\r
756 if (expr.eclass == ExprClass.Variable){
\r
757 if (IsIncrementableNumber (expr_type) ||
\r
758 expr_type == TypeManager.decimal_type){
\r
761 } else if (expr.eclass == ExprClass.IndexerAccess){
\r
762 IndexerAccess ia = (IndexerAccess) expr;
\r
764 temp_storage = new LocalTemporary (ec, expr.Type);
\r
766 expr = ia.ResolveLValue (ec, temp_storage);
\r
771 } else if (expr.eclass == ExprClass.PropertyAccess){
\r
772 PropertyExpr pe = (PropertyExpr) expr;
\r
774 if (pe.VerifyAssignable ())
\r
779 expr.Error118 ("variable, indexer or property access");
\r
783 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
\r
784 TypeManager.CSharpName (expr_type) + "'");
\r
788 public override Expression DoResolve (EmitContext ec)
\r
790 expr = expr.Resolve (ec);
\r
795 eclass = ExprClass.Value;
\r
796 return ResolveOperator (ec);
\r
799 static int PtrTypeSize (Type t)
\r
801 return GetTypeSize (t.GetElementType ());
\r
805 // Loads the proper "1" into the stack based on the type
\r
807 static void LoadOne (ILGenerator ig, Type t)
\r
809 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
\r
810 ig.Emit (OpCodes.Ldc_I8, 1L);
\r
811 else if (t == TypeManager.double_type)
\r
812 ig.Emit (OpCodes.Ldc_R8, 1.0);
\r
813 else if (t == TypeManager.float_type)
\r
814 ig.Emit (OpCodes.Ldc_R4, 1.0F);
\r
815 else if (t.IsPointer){
\r
816 int n = PtrTypeSize (t);
\r
819 ig.Emit (OpCodes.Sizeof, t);
\r
821 IntConstant.EmitInt (ig, n);
\r
823 ig.Emit (OpCodes.Ldc_I4_1);
\r
828 // FIXME: We need some way of avoiding the use of temp_storage
\r
829 // for some types of storage (parameters, local variables,
\r
830 // static fields) and single-dimension array access.
\r
832 void EmitCode (EmitContext ec, bool is_expr)
\r
834 ILGenerator ig = ec.ig;
\r
835 IAssignMethod ia = (IAssignMethod) expr;
\r
836 Type expr_type = expr.Type;
\r
838 if (temp_storage == null)
\r
839 temp_storage = new LocalTemporary (ec, expr_type);
\r
841 ia.CacheTemporaries (ec);
\r
842 ig.Emit (OpCodes.Nop);
\r
844 case Mode.PreIncrement:
\r
845 case Mode.PreDecrement:
\r
846 if (method == null){
\r
849 LoadOne (ig, expr_type);
\r
852 // Select the opcode based on the check state (then the type)
\r
853 // and the actual operation
\r
855 if (ec.CheckState){
\r
856 if (expr_type == TypeManager.int32_type ||
\r
857 expr_type == TypeManager.int64_type){
\r
858 if (mode == Mode.PreDecrement)
\r
859 ig.Emit (OpCodes.Sub_Ovf);
\r
861 ig.Emit (OpCodes.Add_Ovf);
\r
862 } else if (expr_type == TypeManager.uint32_type ||
\r
863 expr_type == TypeManager.uint64_type){
\r
864 if (mode == Mode.PreDecrement)
\r
865 ig.Emit (OpCodes.Sub_Ovf_Un);
\r
867 ig.Emit (OpCodes.Add_Ovf_Un);
\r
869 if (mode == Mode.PreDecrement)
\r
870 ig.Emit (OpCodes.Sub_Ovf);
\r
872 ig.Emit (OpCodes.Add_Ovf);
\r
875 if (mode == Mode.PreDecrement)
\r
876 ig.Emit (OpCodes.Sub);
\r
878 ig.Emit (OpCodes.Add);
\r
883 temp_storage.Store (ec);
\r
884 ia.EmitAssign (ec, temp_storage);
\r
886 temp_storage.Emit (ec);
\r
889 case Mode.PostIncrement:
\r
890 case Mode.PostDecrement:
\r
894 if (method == null){
\r
898 ig.Emit (OpCodes.Dup);
\r
900 LoadOne (ig, expr_type);
\r
902 if (ec.CheckState){
\r
903 if (expr_type == TypeManager.int32_type ||
\r
904 expr_type == TypeManager.int64_type){
\r
905 if (mode == Mode.PostDecrement)
\r
906 ig.Emit (OpCodes.Sub_Ovf);
\r
908 ig.Emit (OpCodes.Add_Ovf);
\r
909 } else if (expr_type == TypeManager.uint32_type ||
\r
910 expr_type == TypeManager.uint64_type){
\r
911 if (mode == Mode.PostDecrement)
\r
912 ig.Emit (OpCodes.Sub_Ovf_Un);
\r
914 ig.Emit (OpCodes.Add_Ovf_Un);
\r
916 if (mode == Mode.PostDecrement)
\r
917 ig.Emit (OpCodes.Sub_Ovf);
\r
919 ig.Emit (OpCodes.Add_Ovf);
\r
922 if (mode == Mode.PostDecrement)
\r
923 ig.Emit (OpCodes.Sub);
\r
925 ig.Emit (OpCodes.Add);
\r
931 temp_storage.Store (ec);
\r
932 ia.EmitAssign (ec, temp_storage);
\r
937 public override void Emit (EmitContext ec)
\r
939 EmitCode (ec, true);
\r
943 public override void EmitStatement (EmitContext ec)
\r
945 EmitCode (ec, false);
\r
951 /// Base class for the 'Is' and 'As' classes.
\r
955 /// FIXME: Split this in two, and we get to save the 'Operator' Oper
\r
958 public abstract class Probe : Expression {
\r
959 public readonly Expression ProbeType;
\r
960 protected Expression expr;
\r
961 protected Type probe_type;
\r
963 public Probe (Expression expr, Expression probe_type, Location l)
\r
965 ProbeType = probe_type;
\r
970 public Expression Expr {
\r
976 public override Expression DoResolve (EmitContext ec)
\r
978 probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
\r
980 if (probe_type == null)
\r
983 expr = expr.Resolve (ec);
\r
990 /// Implementation of the 'is' operator.
\r
992 public class Is : Probe {
\r
993 public Is (Expression expr, Expression probe_type, Location l)
\r
994 : base (expr, probe_type, l)
\r
999 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
\r
1004 public override void Emit (EmitContext ec)
\r
1006 ILGenerator ig = ec.ig;
\r
1011 case Action.AlwaysFalse:
\r
1012 ig.Emit (OpCodes.Pop);
\r
1013 IntConstant.EmitInt (ig, 0);
\r
1015 case Action.AlwaysTrue:
\r
1016 ig.Emit (OpCodes.Pop);
\r
1017 ig.Emit (OpCodes.Nop);
\r
1018 IntConstant.EmitInt (ig, 1);
\r
1020 case Action.LeaveOnStack:
\r
1021 // the 'e != null' rule.
\r
1023 case Action.Probe:
\r
1024 ig.Emit (OpCodes.Isinst, probe_type);
\r
1025 ig.Emit (OpCodes.Ldnull);
\r
1026 ig.Emit (OpCodes.Cgt_Un);
\r
1029 throw new Exception ("never reached");
\r
1032 public override Expression DoResolve (EmitContext ec)
\r
1034 Expression e = base.DoResolve (ec);
\r
1036 if ((e == null) || (expr == null))
\r
1039 Type etype = expr.Type;
\r
1040 bool warning_always_matches = false;
\r
1041 bool warning_never_matches = false;
\r
1043 type = TypeManager.bool_type;
\r
1044 eclass = ExprClass.Value;
\r
1047 // First case, if at compile time, there is an implicit conversion
\r
1048 // then e != null (objects) or true (value types)
\r
1050 e = ConvertImplicitStandard (ec, expr, probe_type, loc);
\r
1053 if (etype.IsValueType)
\r
1054 action = Action.AlwaysTrue;
\r
1056 action = Action.LeaveOnStack;
\r
1058 warning_always_matches = true;
\r
1059 } else if (ExplicitReferenceConversionExists (etype, probe_type)){
\r
1061 // Second case: explicit reference convresion
\r
1063 if (expr is NullLiteral)
\r
1064 action = Action.AlwaysFalse;
\r
1066 action = Action.Probe;
\r
1068 action = Action.AlwaysFalse;
\r
1069 warning_never_matches = true;
\r
1072 if (RootContext.WarningLevel >= 1){
\r
1073 if (warning_always_matches)
\r
1076 "The expression is always of type '" +
\r
1077 TypeManager.CSharpName (probe_type) + "'");
\r
1078 else if (warning_never_matches){
\r
1079 if (!(probe_type.IsInterface || expr.Type.IsInterface))
\r
1082 "The expression is never of type '" +
\r
1083 TypeManager.CSharpName (probe_type) + "'");
\r
1092 /// Implementation of the 'as' operator.
\r
1094 public class As : Probe {
\r
1095 public As (Expression expr, Expression probe_type, Location l)
\r
1096 : base (expr, probe_type, l)
\r
1100 bool do_isinst = false;
\r
1102 public override void Emit (EmitContext ec)
\r
1104 ILGenerator ig = ec.ig;
\r
1109 ig.Emit (OpCodes.Isinst, probe_type);
\r
1112 static void Error_CannotConvertType (Type source, Type target, Location loc)
\r
1115 39, loc, "as operator can not convert from '" +
\r
1116 TypeManager.CSharpName (source) + "' to '" +
\r
1117 TypeManager.CSharpName (target) + "'");
\r
1120 public override Expression DoResolve (EmitContext ec)
\r
1122 Expression e = base.DoResolve (ec);
\r
1127 type = probe_type;
\r
1128 eclass = ExprClass.Value;
\r
1129 Type etype = expr.Type;
\r
1131 if (TypeManager.IsValueType (probe_type)){
\r
1132 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
\r
1133 TypeManager.CSharpName (probe_type) + " is a value type");
\r
1138 e = ConvertImplicit (ec, expr, probe_type, loc);
\r
1141 do_isinst = false;
\r
1145 if (ExplicitReferenceConversionExists (etype, probe_type)){
\r
1150 Error_CannotConvertType (etype, probe_type, loc);
\r
1156 /// This represents a typecast in the source language.
\r
1158 /// FIXME: Cast expressions have an unusual set of parsing
\r
1159 /// rules, we need to figure those out.
\r
1161 public class Cast : Expression {
\r
1162 Expression target_type;
\r
1165 public Cast (Expression cast_type, Expression expr, Location loc)
\r
1167 this.target_type = cast_type;
\r
1172 public Expression TargetType {
\r
1174 return target_type;
\r
1178 public Expression Expr {
\r
1188 /// Attempts to do a compile-time folding of a constant cast.
\r
1190 Expression TryReduce (EmitContext ec, Type target_type)
\r
1192 if (expr is ByteConstant){
\r
1193 byte v = ((ByteConstant) expr).Value;
\r
1195 if (target_type == TypeManager.sbyte_type)
\r
1196 return new SByteConstant ((sbyte) v);
\r
1197 if (target_type == TypeManager.short_type)
\r
1198 return new ShortConstant ((short) v);
\r
1199 if (target_type == TypeManager.ushort_type)
\r
1200 return new UShortConstant ((ushort) v);
\r
1201 if (target_type == TypeManager.int32_type)
\r
1202 return new IntConstant ((int) v);
\r
1203 if (target_type == TypeManager.uint32_type)
\r
1204 return new UIntConstant ((uint) v);
\r
1205 if (target_type == TypeManager.int64_type)
\r
1206 return new LongConstant ((long) v);
\r
1207 if (target_type == TypeManager.uint64_type)
\r
1208 return new ULongConstant ((ulong) v);
\r
1209 if (target_type == TypeManager.float_type)
\r
1210 return new FloatConstant ((float) v);
\r
1211 if (target_type == TypeManager.double_type)
\r
1212 return new DoubleConstant ((double) v);
\r
1213 if (target_type == TypeManager.char_type)
\r
1214 return new CharConstant ((char) v);
\r
1215 if (target_type == TypeManager.decimal_type)
\r
1216 return new DecimalConstant ((decimal) v);
\r
1218 if (expr is SByteConstant){
\r
1219 sbyte v = ((SByteConstant) expr).Value;
\r
1221 if (target_type == TypeManager.byte_type)
\r
1222 return new ByteConstant ((byte) v);
\r
1223 if (target_type == TypeManager.short_type)
\r
1224 return new ShortConstant ((short) v);
\r
1225 if (target_type == TypeManager.ushort_type)
\r
1226 return new UShortConstant ((ushort) v);
\r
1227 if (target_type == TypeManager.int32_type)
\r
1228 return new IntConstant ((int) v);
\r
1229 if (target_type == TypeManager.uint32_type)
\r
1230 return new UIntConstant ((uint) v);
\r
1231 if (target_type == TypeManager.int64_type)
\r
1232 return new LongConstant ((long) v);
\r
1233 if (target_type == TypeManager.uint64_type)
\r
1234 return new ULongConstant ((ulong) v);
\r
1235 if (target_type == TypeManager.float_type)
\r
1236 return new FloatConstant ((float) v);
\r
1237 if (target_type == TypeManager.double_type)
\r
1238 return new DoubleConstant ((double) v);
\r
1239 if (target_type == TypeManager.char_type)
\r
1240 return new CharConstant ((char) v);
\r
1241 if (target_type == TypeManager.decimal_type)
\r
1242 return new DecimalConstant ((decimal) v);
\r
1244 if (expr is ShortConstant){
\r
1245 short v = ((ShortConstant) expr).Value;
\r
1247 if (target_type == TypeManager.byte_type)
\r
1248 return new ByteConstant ((byte) v);
\r
1249 if (target_type == TypeManager.sbyte_type)
\r
1250 return new SByteConstant ((sbyte) v);
\r
1251 if (target_type == TypeManager.ushort_type)
\r
1252 return new UShortConstant ((ushort) v);
\r
1253 if (target_type == TypeManager.int32_type)
\r
1254 return new IntConstant ((int) v);
\r
1255 if (target_type == TypeManager.uint32_type)
\r
1256 return new UIntConstant ((uint) v);
\r
1257 if (target_type == TypeManager.int64_type)
\r
1258 return new LongConstant ((long) v);
\r
1259 if (target_type == TypeManager.uint64_type)
\r
1260 return new ULongConstant ((ulong) v);
\r
1261 if (target_type == TypeManager.float_type)
\r
1262 return new FloatConstant ((float) v);
\r
1263 if (target_type == TypeManager.double_type)
\r
1264 return new DoubleConstant ((double) v);
\r
1265 if (target_type == TypeManager.char_type)
\r
1266 return new CharConstant ((char) v);
\r
1267 if (target_type == TypeManager.decimal_type)
\r
1268 return new DecimalConstant ((decimal) v);
\r
1270 if (expr is UShortConstant){
\r
1271 ushort v = ((UShortConstant) expr).Value;
\r
1273 if (target_type == TypeManager.byte_type)
\r
1274 return new ByteConstant ((byte) v);
\r
1275 if (target_type == TypeManager.sbyte_type)
\r
1276 return new SByteConstant ((sbyte) v);
\r
1277 if (target_type == TypeManager.short_type)
\r
1278 return new ShortConstant ((short) v);
\r
1279 if (target_type == TypeManager.int32_type)
\r
1280 return new IntConstant ((int) v);
\r
1281 if (target_type == TypeManager.uint32_type)
\r
1282 return new UIntConstant ((uint) v);
\r
1283 if (target_type == TypeManager.int64_type)
\r
1284 return new LongConstant ((long) v);
\r
1285 if (target_type == TypeManager.uint64_type)
\r
1286 return new ULongConstant ((ulong) v);
\r
1287 if (target_type == TypeManager.float_type)
\r
1288 return new FloatConstant ((float) v);
\r
1289 if (target_type == TypeManager.double_type)
\r
1290 return new DoubleConstant ((double) v);
\r
1291 if (target_type == TypeManager.char_type)
\r
1292 return new CharConstant ((char) v);
\r
1293 if (target_type == TypeManager.decimal_type)
\r
1294 return new DecimalConstant ((decimal) v);
\r
1296 if (expr is IntConstant){
\r
1297 int v = ((IntConstant) expr).Value;
\r
1299 if (target_type == TypeManager.byte_type)
\r
1300 return new ByteConstant ((byte) v);
\r
1301 if (target_type == TypeManager.sbyte_type)
\r
1302 return new SByteConstant ((sbyte) v);
\r
1303 if (target_type == TypeManager.short_type)
\r
1304 return new ShortConstant ((short) v);
\r
1305 if (target_type == TypeManager.ushort_type)
\r
1306 return new UShortConstant ((ushort) v);
\r
1307 if (target_type == TypeManager.uint32_type)
\r
1308 return new UIntConstant ((uint) v);
\r
1309 if (target_type == TypeManager.int64_type)
\r
1310 return new LongConstant ((long) v);
\r
1311 if (target_type == TypeManager.uint64_type)
\r
1312 return new ULongConstant ((ulong) v);
\r
1313 if (target_type == TypeManager.float_type)
\r
1314 return new FloatConstant ((float) v);
\r
1315 if (target_type == TypeManager.double_type)
\r
1316 return new DoubleConstant ((double) v);
\r
1317 if (target_type == TypeManager.char_type)
\r
1318 return new CharConstant ((char) v);
\r
1319 if (target_type == TypeManager.decimal_type)
\r
1320 return new DecimalConstant ((decimal) v);
\r
1322 if (expr is UIntConstant){
\r
1323 uint v = ((UIntConstant) expr).Value;
\r
1325 if (target_type == TypeManager.byte_type)
\r
1326 return new ByteConstant ((byte) v);
\r
1327 if (target_type == TypeManager.sbyte_type)
\r
1328 return new SByteConstant ((sbyte) v);
\r
1329 if (target_type == TypeManager.short_type)
\r
1330 return new ShortConstant ((short) v);
\r
1331 if (target_type == TypeManager.ushort_type)
\r
1332 return new UShortConstant ((ushort) v);
\r
1333 if (target_type == TypeManager.int32_type)
\r
1334 return new IntConstant ((int) v);
\r
1335 if (target_type == TypeManager.int64_type)
\r
1336 return new LongConstant ((long) v);
\r
1337 if (target_type == TypeManager.uint64_type)
\r
1338 return new ULongConstant ((ulong) v);
\r
1339 if (target_type == TypeManager.float_type)
\r
1340 return new FloatConstant ((float) v);
\r
1341 if (target_type == TypeManager.double_type)
\r
1342 return new DoubleConstant ((double) v);
\r
1343 if (target_type == TypeManager.char_type)
\r
1344 return new CharConstant ((char) v);
\r
1345 if (target_type == TypeManager.decimal_type)
\r
1346 return new DecimalConstant ((decimal) v);
\r
1348 if (expr is LongConstant){
\r
1349 long v = ((LongConstant) expr).Value;
\r
1351 if (target_type == TypeManager.byte_type)
\r
1352 return new ByteConstant ((byte) v);
\r
1353 if (target_type == TypeManager.sbyte_type)
\r
1354 return new SByteConstant ((sbyte) v);
\r
1355 if (target_type == TypeManager.short_type)
\r
1356 return new ShortConstant ((short) v);
\r
1357 if (target_type == TypeManager.ushort_type)
\r
1358 return new UShortConstant ((ushort) v);
\r
1359 if (target_type == TypeManager.int32_type)
\r
1360 return new IntConstant ((int) v);
\r
1361 if (target_type == TypeManager.uint32_type)
\r
1362 return new UIntConstant ((uint) v);
\r
1363 if (target_type == TypeManager.uint64_type)
\r
1364 return new ULongConstant ((ulong) v);
\r
1365 if (target_type == TypeManager.float_type)
\r
1366 return new FloatConstant ((float) v);
\r
1367 if (target_type == TypeManager.double_type)
\r
1368 return new DoubleConstant ((double) v);
\r
1369 if (target_type == TypeManager.char_type)
\r
1370 return new CharConstant ((char) v);
\r
1371 if (target_type == TypeManager.decimal_type)
\r
1372 return new DecimalConstant ((decimal) v);
\r
1374 if (expr is ULongConstant){
\r
1375 ulong v = ((ULongConstant) expr).Value;
\r
1377 if (target_type == TypeManager.byte_type)
\r
1378 return new ByteConstant ((byte) v);
\r
1379 if (target_type == TypeManager.sbyte_type)
\r
1380 return new SByteConstant ((sbyte) v);
\r
1381 if (target_type == TypeManager.short_type)
\r
1382 return new ShortConstant ((short) v);
\r
1383 if (target_type == TypeManager.ushort_type)
\r
1384 return new UShortConstant ((ushort) v);
\r
1385 if (target_type == TypeManager.int32_type)
\r
1386 return new IntConstant ((int) v);
\r
1387 if (target_type == TypeManager.uint32_type)
\r
1388 return new UIntConstant ((uint) v);
\r
1389 if (target_type == TypeManager.int64_type)
\r
1390 return new LongConstant ((long) v);
\r
1391 if (target_type == TypeManager.float_type)
\r
1392 return new FloatConstant ((float) v);
\r
1393 if (target_type == TypeManager.double_type)
\r
1394 return new DoubleConstant ((double) v);
\r
1395 if (target_type == TypeManager.char_type)
\r
1396 return new CharConstant ((char) v);
\r
1397 if (target_type == TypeManager.decimal_type)
\r
1398 return new DecimalConstant ((decimal) v);
\r
1400 if (expr is FloatConstant){
\r
1401 float v = ((FloatConstant) expr).Value;
\r
1403 if (target_type == TypeManager.byte_type)
\r
1404 return new ByteConstant ((byte) v);
\r
1405 if (target_type == TypeManager.sbyte_type)
\r
1406 return new SByteConstant ((sbyte) v);
\r
1407 if (target_type == TypeManager.short_type)
\r
1408 return new ShortConstant ((short) v);
\r
1409 if (target_type == TypeManager.ushort_type)
\r
1410 return new UShortConstant ((ushort) v);
\r
1411 if (target_type == TypeManager.int32_type)
\r
1412 return new IntConstant ((int) v);
\r
1413 if (target_type == TypeManager.uint32_type)
\r
1414 return new UIntConstant ((uint) v);
\r
1415 if (target_type == TypeManager.int64_type)
\r
1416 return new LongConstant ((long) v);
\r
1417 if (target_type == TypeManager.uint64_type)
\r
1418 return new ULongConstant ((ulong) v);
\r
1419 if (target_type == TypeManager.double_type)
\r
1420 return new DoubleConstant ((double) v);
\r
1421 if (target_type == TypeManager.char_type)
\r
1422 return new CharConstant ((char) v);
\r
1423 if (target_type == TypeManager.decimal_type)
\r
1424 return new DecimalConstant ((decimal) v);
\r
1426 if (expr is DoubleConstant){
\r
1427 double v = ((DoubleConstant) expr).Value;
\r
1429 if (target_type == TypeManager.byte_type)
\r
1430 return new ByteConstant ((byte) v);
\r
1431 if (target_type == TypeManager.sbyte_type)
\r
1432 return new SByteConstant ((sbyte) v);
\r
1433 if (target_type == TypeManager.short_type)
\r
1434 return new ShortConstant ((short) v);
\r
1435 if (target_type == TypeManager.ushort_type)
\r
1436 return new UShortConstant ((ushort) v);
\r
1437 if (target_type == TypeManager.int32_type)
\r
1438 return new IntConstant ((int) v);
\r
1439 if (target_type == TypeManager.uint32_type)
\r
1440 return new UIntConstant ((uint) v);
\r
1441 if (target_type == TypeManager.int64_type)
\r
1442 return new LongConstant ((long) v);
\r
1443 if (target_type == TypeManager.uint64_type)
\r
1444 return new ULongConstant ((ulong) v);
\r
1445 if (target_type == TypeManager.float_type)
\r
1446 return new FloatConstant ((float) v);
\r
1447 if (target_type == TypeManager.char_type)
\r
1448 return new CharConstant ((char) v);
\r
1449 if (target_type == TypeManager.decimal_type)
\r
1450 return new DecimalConstant ((decimal) v);
\r
1456 public override Expression DoResolve (EmitContext ec)
\r
1458 expr = expr.Resolve (ec);
\r
1462 int errors = Report.Errors;
\r
1464 type = ec.DeclSpace.ResolveType (target_type, false, Location);
\r
1469 eclass = ExprClass.Value;
\r
1471 if (expr is Constant){
\r
1472 Expression e = TryReduce (ec, type);
\r
1478 expr = ConvertExplicit (ec, expr, type, loc);
\r
1482 public override void Emit (EmitContext ec)
\r
1485 // This one will never happen
\r
1487 throw new Exception ("Should not happen");
\r
1492 /// Binary operators
\r
1494 public class Binary : Expression {
\r
1495 public enum Operator : byte {
\r
1496 Multiply, Division, Modulus,
\r
1497 Addition, Subtraction,
\r
1498 LeftShift, RightShift,
\r
1499 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
\r
1500 Equality, Inequality,
\r
1510 Expression left, right;
\r
1513 // After resolution, method might contain the operator overload
\r
1516 protected MethodBase method;
\r
1517 ArrayList Arguments;
\r
1519 bool DelegateOperation;
\r
1521 // This must be kept in sync with Operator!!!
\r
1522 static string [] oper_names;
\r
1526 oper_names = new string [(int) Operator.TOP];
\r
1528 oper_names [(int) Operator.Multiply] = "op_Multiply";
\r
1529 oper_names [(int) Operator.Division] = "op_Division";
\r
1530 oper_names [(int) Operator.Modulus] = "op_Modulus";
\r
1531 oper_names [(int) Operator.Addition] = "op_Addition";
\r
1532 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
\r
1533 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
\r
1534 oper_names [(int) Operator.RightShift] = "op_RightShift";
\r
1535 oper_names [(int) Operator.LessThan] = "op_LessThan";
\r
1536 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
\r
1537 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
\r
1538 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
\r
1539 oper_names [(int) Operator.Equality] = "op_Equality";
\r
1540 oper_names [(int) Operator.Inequality] = "op_Inequality";
\r
1541 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
\r
1542 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
\r
1543 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
\r
1544 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
\r
1545 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
\r
1548 public Binary (Operator oper, Expression left, Expression right, Location loc)
\r
1552 this.right = right;
\r
1556 public Operator Oper {
\r
1565 public Expression Left {
\r
1574 public Expression Right {
\r
1585 /// Returns a stringified representation of the Operator
\r
1587 static string OperName (Operator oper)
\r
1590 case Operator.Multiply:
\r
1592 case Operator.Division:
\r
1594 case Operator.Modulus:
\r
1596 case Operator.Addition:
\r
1598 case Operator.Subtraction:
\r
1600 case Operator.LeftShift:
\r
1602 case Operator.RightShift:
\r
1604 case Operator.LessThan:
\r
1606 case Operator.GreaterThan:
\r
1608 case Operator.LessThanOrEqual:
\r
1610 case Operator.GreaterThanOrEqual:
\r
1612 case Operator.Equality:
\r
1614 case Operator.Inequality:
\r
1616 case Operator.BitwiseAnd:
\r
1618 case Operator.BitwiseOr:
\r
1620 case Operator.ExclusiveOr:
\r
1622 case Operator.LogicalOr:
\r
1624 case Operator.LogicalAnd:
\r
1628 return oper.ToString ();
\r
1631 public override string ToString ()
\r
1633 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
\r
1634 right.ToString () + ")";
\r
1637 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
\r
1639 if (expr.Type == target_type)
\r
1642 return ConvertImplicit (ec, expr, target_type, Location.Null);
\r
1645 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
\r
1648 34, loc, "Operator '" + OperName (oper)
\r
1649 + "' is ambiguous on operands of type '"
\r
1650 + TypeManager.CSharpName (l) + "' "
\r
1651 + "and '" + TypeManager.CSharpName (r)
\r
1656 // Note that handling the case l == Decimal || r == Decimal
\r
1657 // is taken care of by the Step 1 Operator Overload resolution.
\r
1659 bool DoNumericPromotions (EmitContext ec, Type l, Type r)
\r
1661 if (l == TypeManager.double_type || r == TypeManager.double_type){
\r
1663 // If either operand is of type double, the other operand is
\r
1664 // conveted to type double.
\r
1666 if (r != TypeManager.double_type)
\r
1667 right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
\r
1668 if (l != TypeManager.double_type)
\r
1669 left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
\r
1671 type = TypeManager.double_type;
\r
1672 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
\r
1674 // if either operand is of type float, the other operand is
\r
1675 // converted to type float.
\r
1677 if (r != TypeManager.double_type)
\r
1678 right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
\r
1679 if (l != TypeManager.double_type)
\r
1680 left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
\r
1681 type = TypeManager.float_type;
\r
1682 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
\r
1686 // If either operand is of type ulong, the other operand is
\r
1687 // converted to type ulong. or an error ocurrs if the other
\r
1688 // operand is of type sbyte, short, int or long
\r
1690 if (l == TypeManager.uint64_type){
\r
1691 if (r != TypeManager.uint64_type){
\r
1692 if (right is IntConstant){
\r
1693 IntConstant ic = (IntConstant) right;
\r
1695 e = TryImplicitIntConversion (l, ic);
\r
1698 } else if (right is LongConstant){
\r
1699 long ll = ((LongConstant) right).Value;
\r
1702 right = new ULongConstant ((ulong) ll);
\r
1704 e = ImplicitNumericConversion (ec, right, l, loc);
\r
1709 other = right.Type;
\r
1711 if (left is IntConstant){
\r
1712 e = TryImplicitIntConversion (r, (IntConstant) left);
\r
1715 } else if (left is LongConstant){
\r
1716 long ll = ((LongConstant) left).Value;
\r
1719 left = new ULongConstant ((ulong) ll);
\r
1721 e = ImplicitNumericConversion (ec, left, r, loc);
\r
1725 other = left.Type;
\r
1728 if ((other == TypeManager.sbyte_type) ||
\r
1729 (other == TypeManager.short_type) ||
\r
1730 (other == TypeManager.int32_type) ||
\r
1731 (other == TypeManager.int64_type))
\r
1732 Error_OperatorAmbiguous (loc, oper, l, r);
\r
1733 type = TypeManager.uint64_type;
\r
1734 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
\r
1736 // If either operand is of type long, the other operand is converted
\r
1739 if (l != TypeManager.int64_type)
\r
1740 left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
\r
1741 if (r != TypeManager.int64_type)
\r
1742 right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
\r
1744 type = TypeManager.int64_type;
\r
1745 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
\r
1747 // If either operand is of type uint, and the other
\r
1748 // operand is of type sbyte, short or int, othe operands are
\r
1749 // converted to type long.
\r
1751 Type other = null;
\r
1753 if (l == TypeManager.uint32_type){
\r
1754 if (right is IntConstant){
\r
1755 IntConstant ic = (IntConstant) right;
\r
1756 int val = ic.Value;
\r
1759 right = new UIntConstant ((uint) val);
\r
1766 else if (r == TypeManager.uint32_type){
\r
1767 if (left is IntConstant){
\r
1768 IntConstant ic = (IntConstant) left;
\r
1769 int val = ic.Value;
\r
1772 left = new UIntConstant ((uint) val);
\r
1781 if ((other == TypeManager.sbyte_type) ||
\r
1782 (other == TypeManager.short_type) ||
\r
1783 (other == TypeManager.int32_type)){
\r
1784 left = ForceConversion (ec, left, TypeManager.int64_type);
\r
1785 right = ForceConversion (ec, right, TypeManager.int64_type);
\r
1786 type = TypeManager.int64_type;
\r
1789 // if either operand is of type uint, the other
\r
1790 // operand is converd to type uint
\r
1792 left = ForceConversion (ec, left, TypeManager.uint32_type);
\r
1793 right = ForceConversion (ec, right, TypeManager.uint32_type);
\r
1794 type = TypeManager.uint32_type;
\r
1796 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
\r
1797 if (l != TypeManager.decimal_type)
\r
1798 left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
\r
1800 if (r != TypeManager.decimal_type)
\r
1801 right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
\r
1802 type = TypeManager.decimal_type;
\r
1804 left = ForceConversion (ec, left, TypeManager.int32_type);
\r
1805 right = ForceConversion (ec, right, TypeManager.int32_type);
\r
1807 type = TypeManager.int32_type;
\r
1810 return (left != null) && (right != null);
\r
1813 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
\r
1815 Report.Error (19, loc,
\r
1816 "Operator " + name + " cannot be applied to operands of type '" +
\r
1817 TypeManager.CSharpName (l) + "' and '" +
\r
1818 TypeManager.CSharpName (r) + "'");
\r
1821 void Error_OperatorCannotBeApplied ()
\r
1823 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
\r
1826 static bool is_32_or_64 (Type t)
\r
1828 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
\r
1829 t == TypeManager.int64_type || t == TypeManager.uint64_type);
\r
1832 static bool is_unsigned (Type t)
\r
1834 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
\r
1835 t == TypeManager.short_type || t == TypeManager.byte_type);
\r
1838 Expression CheckShiftArguments (EmitContext ec)
\r
1841 Type l = left.Type;
\r
1842 Type r = right.Type;
\r
1844 e = ForceConversion (ec, right, TypeManager.int32_type);
\r
1846 Error_OperatorCannotBeApplied ();
\r
1851 if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
\r
1852 ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
\r
1853 ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
\r
1854 ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
\r
1860 Error_OperatorCannotBeApplied ();
\r
1864 Expression ResolveOperator (EmitContext ec)
\r
1866 Type l = left.Type;
\r
1867 Type r = right.Type;
\r
1869 bool overload_failed = false;
\r
1872 // Step 1: Perform Operator Overload location
\r
1874 Expression left_expr, right_expr;
\r
1876 string op = oper_names [(int) oper];
\r
1878 MethodGroupExpr union;
\r
1879 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
\r
1881 right_expr = MemberLookup (
\r
1882 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
\r
1883 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
\r
1885 union = (MethodGroupExpr) left_expr;
\r
1887 if (union != null) {
\r
1888 Arguments = new ArrayList ();
\r
1889 Arguments.Add (new Argument (left, Argument.AType.Expression));
\r
1890 Arguments.Add (new Argument (right, Argument.AType.Expression));
\r
1892 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
\r
1893 if (method != null) {
\r
1894 MethodInfo mi = (MethodInfo) method;
\r
1896 type = mi.ReturnType;
\r
1899 overload_failed = true;
\r
1904 // Step 2: Default operations on CLI native types.
\r
1908 // Step 0: String concatenation (because overloading will get this wrong)
\r
1910 if (oper == Operator.Addition){
\r
1912 // If any of the arguments is a string, cast to string
\r
1915 if (l == TypeManager.string_type){
\r
1917 if (r == TypeManager.void_type) {
\r
1918 Error_OperatorCannotBeApplied ();
\r
1922 if (r == TypeManager.string_type){
\r
1923 if (left is Constant && right is Constant){
\r
1924 StringConstant ls = (StringConstant) left;
\r
1925 StringConstant rs = (StringConstant) right;
\r
1927 return new StringConstant (
\r
1928 ls.Value + rs.Value);
\r
1931 // string + string
\r
1932 method = TypeManager.string_concat_string_string;
\r
1934 // string + object
\r
1935 method = TypeManager.string_concat_object_object;
\r
1936 right = ConvertImplicit (ec, right,
\r
1937 TypeManager.object_type, loc);
\r
1938 if (right == null){
\r
1939 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
\r
1943 type = TypeManager.string_type;
\r
1945 Arguments = new ArrayList ();
\r
1946 Arguments.Add (new Argument (left, Argument.AType.Expression));
\r
1947 Arguments.Add (new Argument (right, Argument.AType.Expression));
\r
1951 } else if (r == TypeManager.string_type){
\r
1952 // object + string
\r
1954 if (l == TypeManager.void_type) {
\r
1955 Error_OperatorCannotBeApplied ();
\r
1959 method = TypeManager.string_concat_object_object;
\r
1960 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
\r
1961 if (left == null){
\r
1962 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
\r
1965 Arguments = new ArrayList ();
\r
1966 Arguments.Add (new Argument (left, Argument.AType.Expression));
\r
1967 Arguments.Add (new Argument (right, Argument.AType.Expression));
\r
1969 type = TypeManager.string_type;
\r
1975 // Transform a + ( - b) into a - b
\r
1977 if (right is Unary){
\r
1978 Unary right_unary = (Unary) right;
\r
1980 if (right_unary.Oper == Unary.Operator.UnaryNegation){
\r
1981 oper = Operator.Subtraction;
\r
1982 right = right_unary.Expr;
\r
1988 if (oper == Operator.Equality || oper == Operator.Inequality){
\r
1989 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
\r
1990 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
\r
1991 Error_OperatorCannotBeApplied ();
\r
1995 type = TypeManager.bool_type;
\r
2000 // operator != (object a, object b)
\r
2001 // operator == (object a, object b)
\r
2003 // For this to be used, both arguments have to be reference-types.
\r
2004 // Read the rationale on the spec (14.9.6)
\r
2006 // Also, if at compile time we know that the classes do not inherit
\r
2007 // one from the other, then we catch the error there.
\r
2009 if (!(l.IsValueType || r.IsValueType)){
\r
2010 type = TypeManager.bool_type;
\r
2015 if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
\r
2019 // Also, a standard conversion must exist from either one
\r
2021 if (!(StandardConversionExists (left, r) ||
\r
2022 StandardConversionExists (right, l))){
\r
2023 Error_OperatorCannotBeApplied ();
\r
2027 // We are going to have to convert to an object to compare
\r
2029 if (l != TypeManager.object_type)
\r
2030 left = new EmptyCast (left, TypeManager.object_type);
\r
2031 if (r != TypeManager.object_type)
\r
2032 right = new EmptyCast (right, TypeManager.object_type);
\r
2035 // FIXME: CSC here catches errors cs254 and cs252
\r
2041 // One of them is a valuetype, but the other one is not.
\r
2043 if (!l.IsValueType || !r.IsValueType) {
\r
2044 Error_OperatorCannotBeApplied ();
\r
2049 // Only perform numeric promotions on:
\r
2050 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
\r
2052 if (oper == Operator.Addition || oper == Operator.Subtraction) {
\r
2053 if (l.IsSubclassOf (TypeManager.delegate_type) &&
\r
2054 r.IsSubclassOf (TypeManager.delegate_type)) {
\r
2056 Arguments = new ArrayList ();
\r
2057 Arguments.Add (new Argument (left, Argument.AType.Expression));
\r
2058 Arguments.Add (new Argument (right, Argument.AType.Expression));
\r
2060 if (oper == Operator.Addition)
\r
2061 method = TypeManager.delegate_combine_delegate_delegate;
\r
2063 method = TypeManager.delegate_remove_delegate_delegate;
\r
2066 Error_OperatorCannotBeApplied ();
\r
2070 DelegateOperation = true;
\r
2076 // Pointer arithmetic:
\r
2078 // T* operator + (T* x, int y);
\r
2079 // T* operator + (T* x, uint y);
\r
2080 // T* operator + (T* x, long y);
\r
2081 // T* operator + (T* x, ulong y);
\r
2083 // T* operator + (int y, T* x);
\r
2084 // T* operator + (uint y, T *x);
\r
2085 // T* operator + (long y, T *x);
\r
2086 // T* operator + (ulong y, T *x);
\r
2088 // T* operator - (T* x, int y);
\r
2089 // T* operator - (T* x, uint y);
\r
2090 // T* operator - (T* x, long y);
\r
2091 // T* operator - (T* x, ulong y);
\r
2093 // long operator - (T* x, T *y)
\r
2096 if (r.IsPointer && oper == Operator.Subtraction){
\r
2098 return new PointerArithmetic (
\r
2099 false, left, right, TypeManager.int64_type,
\r
2101 } else if (is_32_or_64 (r))
\r
2102 return new PointerArithmetic (
\r
2103 oper == Operator.Addition, left, right, l, loc);
\r
2104 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
\r
2105 return new PointerArithmetic (
\r
2106 true, right, left, r, loc);
\r
2110 // Enumeration operators
\r
2112 bool lie = TypeManager.IsEnumType (l);
\r
2113 bool rie = TypeManager.IsEnumType (r);
\r
2117 // U operator - (E e, E f)
\r
2118 if (lie && rie && oper == Operator.Subtraction){
\r
2120 type = TypeManager.EnumToUnderlying (l);
\r
2123 Error_OperatorCannotBeApplied ();
\r
2128 // operator + (E e, U x)
\r
2129 // operator - (E e, U x)
\r
2131 if (oper == Operator.Addition || oper == Operator.Subtraction){
\r
2132 Type enum_type = lie ? l : r;
\r
2133 Type other_type = lie ? r : l;
\r
2134 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
\r
2137 if (underlying_type != other_type){
\r
2138 Error_OperatorCannotBeApplied ();
\r
2147 temp = ConvertImplicit (ec, right, l, loc);
\r
2151 Error_OperatorCannotBeApplied ();
\r
2155 temp = ConvertImplicit (ec, left, r, loc);
\r
2156 if (temp != null){
\r
2160 Error_OperatorCannotBeApplied ();
\r
2165 if (oper == Operator.Equality || oper == Operator.Inequality ||
\r
2166 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
\r
2167 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
\r
2168 type = TypeManager.bool_type;
\r
2172 if (oper == Operator.BitwiseAnd ||
\r
2173 oper == Operator.BitwiseOr ||
\r
2174 oper == Operator.ExclusiveOr){
\r
2178 Error_OperatorCannotBeApplied ();
\r
2182 if (oper == Operator.LeftShift || oper == Operator.RightShift)
\r
2183 return CheckShiftArguments (ec);
\r
2185 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
\r
2186 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
\r
2187 Error_OperatorCannotBeApplied ();
\r
2191 type = TypeManager.bool_type;
\r
2196 // operator & (bool x, bool y)
\r
2197 // operator | (bool x, bool y)
\r
2198 // operator ^ (bool x, bool y)
\r
2200 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
\r
2201 if (oper == Operator.BitwiseAnd ||
\r
2202 oper == Operator.BitwiseOr ||
\r
2203 oper == Operator.ExclusiveOr){
\r
2210 // Pointer comparison
\r
2212 if (l.IsPointer && r.IsPointer){
\r
2213 if (oper == Operator.Equality || oper == Operator.Inequality ||
\r
2214 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
\r
2215 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
\r
2216 type = TypeManager.bool_type;
\r
2222 // We are dealing with numbers
\r
2224 if (overload_failed){
\r
2225 Error_OperatorCannotBeApplied ();
\r
2230 // This will leave left or right set to null if there is an error
\r
2232 DoNumericPromotions (ec, l, r);
\r
2233 if (left == null || right == null){
\r
2234 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
\r
2239 // reload our cached types if required
\r
2244 if (oper == Operator.BitwiseAnd ||
\r
2245 oper == Operator.BitwiseOr ||
\r
2246 oper == Operator.ExclusiveOr){
\r
2248 if (!((l == TypeManager.int32_type) ||
\r
2249 (l == TypeManager.uint32_type) ||
\r
2250 (l == TypeManager.int64_type) ||
\r
2251 (l == TypeManager.uint64_type)))
\r
2254 Error_OperatorCannotBeApplied ();
\r
2259 if (oper == Operator.Equality ||
\r
2260 oper == Operator.Inequality ||
\r
2261 oper == Operator.LessThanOrEqual ||
\r
2262 oper == Operator.LessThan ||
\r
2263 oper == Operator.GreaterThanOrEqual ||
\r
2264 oper == Operator.GreaterThan){
\r
2265 type = TypeManager.bool_type;
\r
2271 public override Expression DoResolve (EmitContext ec)
\r
2273 left = left.Resolve (ec);
\r
2274 right = right.Resolve (ec);
\r
2276 if (left == null || right == null)
\r
2279 if (left.Type == null)
\r
2280 throw new Exception (
\r
2281 "Resolve returned non null, but did not set the type! (" +
\r
2282 left + ") at Line: " + loc.Row);
\r
2283 if (right.Type == null)
\r
2284 throw new Exception (
\r
2285 "Resolve returned non null, but did not set the type! (" +
\r
2286 right + ") at Line: "+ loc.Row);
\r
2288 eclass = ExprClass.Value;
\r
2290 if (left is Constant && right is Constant){
\r
2291 Expression e = ConstantFold.BinaryFold (
\r
2292 ec, oper, (Constant) left, (Constant) right, loc);
\r
2297 return ResolveOperator (ec);
\r
2301 /// EmitBranchable is called from Statement.EmitBoolExpression in the
\r
2302 /// context of a conditional bool expression. This function will return
\r
2303 /// false if it is was possible to use EmitBranchable, or true if it was.
\r
2305 /// The expression's code is generated, and we will generate a branch to 'target'
\r
2306 /// if the resulting expression value is equal to isTrue
\r
2308 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
\r
2310 if (method != null)
\r
2313 ILGenerator ig = ec.ig;
\r
2316 // This is more complicated than it looks, but its just to avoid
\r
2317 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
\r
2318 // but on top of that we want for == and != to use a special path
\r
2319 // if we are comparing against null
\r
2321 if (oper == Operator.Equality || oper == Operator.Inequality){
\r
2322 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
\r
2324 if (left is NullLiteral){
\r
2327 ig.Emit (OpCodes.Brtrue, target);
\r
2329 ig.Emit (OpCodes.Brfalse, target);
\r
2331 } else if (right is NullLiteral){
\r
2334 ig.Emit (OpCodes.Brtrue, target);
\r
2336 ig.Emit (OpCodes.Brfalse, target);
\r
2339 } else if (!(oper == Operator.LessThan ||
\r
2340 oper == Operator.GreaterThan ||
\r
2341 oper == Operator.LessThanOrEqual ||
\r
2342 oper == Operator.GreaterThanOrEqual))
\r
2350 bool isUnsigned = is_unsigned (left.Type);
\r
2353 case Operator.Equality:
\r
2355 ig.Emit (OpCodes.Beq, target);
\r
2357 ig.Emit (OpCodes.Bne_Un, target);
\r
2360 case Operator.Inequality:
\r
2362 ig.Emit (OpCodes.Bne_Un, target);
\r
2364 ig.Emit (OpCodes.Beq, target);
\r
2367 case Operator.LessThan:
\r
2370 ig.Emit (OpCodes.Blt_Un, target);
\r
2372 ig.Emit (OpCodes.Blt, target);
\r
2375 ig.Emit (OpCodes.Bge_Un, target);
\r
2377 ig.Emit (OpCodes.Bge, target);
\r
2380 case Operator.GreaterThan:
\r
2383 ig.Emit (OpCodes.Bgt_Un, target);
\r
2385 ig.Emit (OpCodes.Bgt, target);
\r
2388 ig.Emit (OpCodes.Ble_Un, target);
\r
2390 ig.Emit (OpCodes.Ble, target);
\r
2393 case Operator.LessThanOrEqual:
\r
2396 ig.Emit (OpCodes.Ble_Un, target);
\r
2398 ig.Emit (OpCodes.Ble, target);
\r
2401 ig.Emit (OpCodes.Bgt_Un, target);
\r
2403 ig.Emit (OpCodes.Bgt, target);
\r
2407 case Operator.GreaterThanOrEqual:
\r
2410 ig.Emit (OpCodes.Bge_Un, target);
\r
2412 ig.Emit (OpCodes.Bge, target);
\r
2415 ig.Emit (OpCodes.Blt_Un, target);
\r
2417 ig.Emit (OpCodes.Blt, target);
\r
2427 public override void Emit (EmitContext ec)
\r
2429 ILGenerator ig = ec.ig;
\r
2430 Type l = left.Type;
\r
2431 Type r = right.Type;
\r
2434 if (method != null) {
\r
2436 // Note that operators are static anyway
\r
2438 if (Arguments != null)
\r
2439 Invocation.EmitArguments (ec, method, Arguments);
\r
2441 if (method is MethodInfo)
\r
2442 ig.Emit (OpCodes.Call, (MethodInfo) method);
\r
2444 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
\r
2446 if (DelegateOperation)
\r
2447 ig.Emit (OpCodes.Castclass, type);
\r
2453 // Handle short-circuit operators differently
\r
2456 if (oper == Operator.LogicalAnd){
\r
2457 Label load_zero = ig.DefineLabel ();
\r
2458 Label end = ig.DefineLabel ();
\r
2461 ig.Emit (OpCodes.Brfalse, load_zero);
\r
2463 ig.Emit (OpCodes.Br, end);
\r
2464 ig.MarkLabel (load_zero);
\r
2465 ig.Emit (OpCodes.Ldc_I4_0);
\r
2466 ig.MarkLabel (end);
\r
2468 } else if (oper == Operator.LogicalOr){
\r
2469 Label load_one = ig.DefineLabel ();
\r
2470 Label end = ig.DefineLabel ();
\r
2473 ig.Emit (OpCodes.Brtrue, load_one);
\r
2475 ig.Emit (OpCodes.Br, end);
\r
2476 ig.MarkLabel (load_one);
\r
2477 ig.Emit (OpCodes.Ldc_I4_1);
\r
2478 ig.MarkLabel (end);
\r
2486 case Operator.Multiply:
\r
2487 if (ec.CheckState){
\r
2488 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
\r
2489 opcode = OpCodes.Mul_Ovf;
\r
2490 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
\r
2491 opcode = OpCodes.Mul_Ovf_Un;
\r
2493 opcode = OpCodes.Mul;
\r
2495 opcode = OpCodes.Mul;
\r
2499 case Operator.Division:
\r
2500 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
\r
2501 opcode = OpCodes.Div_Un;
\r
2503 opcode = OpCodes.Div;
\r
2506 case Operator.Modulus:
\r
2507 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
\r
2508 opcode = OpCodes.Rem_Un;
\r
2510 opcode = OpCodes.Rem;
\r
2513 case Operator.Addition:
\r
2514 if (ec.CheckState){
\r
2515 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
\r
2516 opcode = OpCodes.Add_Ovf;
\r
2517 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
\r
2518 opcode = OpCodes.Add_Ovf_Un;
\r
2520 opcode = OpCodes.Add;
\r
2522 opcode = OpCodes.Add;
\r
2525 case Operator.Subtraction:
\r
2526 if (ec.CheckState){
\r
2527 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
\r
2528 opcode = OpCodes.Sub_Ovf;
\r
2529 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
\r
2530 opcode = OpCodes.Sub_Ovf_Un;
\r
2532 opcode = OpCodes.Sub;
\r
2534 opcode = OpCodes.Sub;
\r
2537 case Operator.RightShift:
\r
2538 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
\r
2539 opcode = OpCodes.Shr_Un;
\r
2541 opcode = OpCodes.Shr;
\r
2544 case Operator.LeftShift:
\r
2545 opcode = OpCodes.Shl;
\r
2548 case Operator.Equality:
\r
2549 opcode = OpCodes.Ceq;
\r
2552 case Operator.Inequality:
\r
2553 ec.ig.Emit (OpCodes.Ceq);
\r
2554 ec.ig.Emit (OpCodes.Ldc_I4_0);
\r
2556 opcode = OpCodes.Ceq;
\r
2559 case Operator.LessThan:
\r
2560 opcode = OpCodes.Clt;
\r
2563 case Operator.GreaterThan:
\r
2564 opcode = OpCodes.Cgt;
\r
2567 case Operator.LessThanOrEqual:
\r
2568 ec.ig.Emit (OpCodes.Cgt);
\r
2569 ec.ig.Emit (OpCodes.Ldc_I4_0);
\r
2571 opcode = OpCodes.Ceq;
\r
2574 case Operator.GreaterThanOrEqual:
\r
2575 ec.ig.Emit (OpCodes.Clt);
\r
2576 ec.ig.Emit (OpCodes.Ldc_I4_1);
\r
2578 opcode = OpCodes.Sub;
\r
2581 case Operator.BitwiseOr:
\r
2582 opcode = OpCodes.Or;
\r
2585 case Operator.BitwiseAnd:
\r
2586 opcode = OpCodes.And;
\r
2589 case Operator.ExclusiveOr:
\r
2590 opcode = OpCodes.Xor;
\r
2594 throw new Exception ("This should not happen: Operator = "
\r
2595 + oper.ToString ());
\r
2601 public bool IsBuiltinOperator {
\r
2603 return method == null;
\r
2608 public class PointerArithmetic : Expression {
\r
2609 Expression left, right;
\r
2613 // We assume that 'l' is always a pointer
\r
2615 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
\r
2619 eclass = ExprClass.Variable;
\r
2623 is_add = is_addition;
\r
2626 public override Expression DoResolve (EmitContext ec)
\r
2629 // We are born fully resolved
\r
2634 public override void Emit (EmitContext ec)
\r
2636 Type op_type = left.Type;
\r
2637 ILGenerator ig = ec.ig;
\r
2638 int size = GetTypeSize (op_type.GetElementType ());
\r
2640 if (right.Type.IsPointer){
\r
2642 // handle (pointer - pointer)
\r
2646 ig.Emit (OpCodes.Sub);
\r
2650 ig.Emit (OpCodes.Sizeof, op_type);
\r
2652 IntLiteral.EmitInt (ig, size);
\r
2653 ig.Emit (OpCodes.Div);
\r
2655 ig.Emit (OpCodes.Conv_I8);
\r
2658 // handle + and - on (pointer op int)
\r
2661 ig.Emit (OpCodes.Conv_I);
\r
2665 ig.Emit (OpCodes.Sizeof, op_type);
\r
2667 IntLiteral.EmitInt (ig, size);
\r
2668 ig.Emit (OpCodes.Mul);
\r
2671 ig.Emit (OpCodes.Add);
\r
2673 ig.Emit (OpCodes.Sub);
\r
2679 /// Implements the ternary conditional operator (?:)
\r
2681 public class Conditional : Expression {
\r
2682 Expression expr, trueExpr, falseExpr;
\r
2684 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
\r
2687 this.trueExpr = trueExpr;
\r
2688 this.falseExpr = falseExpr;
\r
2692 public Expression Expr {
\r
2698 public Expression TrueExpr {
\r
2704 public Expression FalseExpr {
\r
2710 public override Expression DoResolve (EmitContext ec)
\r
2712 expr = expr.Resolve (ec);
\r
2717 if (expr.Type != TypeManager.bool_type)
\r
2718 expr = Expression.ConvertImplicitRequired (
\r
2719 ec, expr, TypeManager.bool_type, loc);
\r
2721 trueExpr = trueExpr.Resolve (ec);
\r
2722 falseExpr = falseExpr.Resolve (ec);
\r
2724 if (trueExpr == null || falseExpr == null)
\r
2727 eclass = ExprClass.Value;
\r
2728 if (trueExpr.Type == falseExpr.Type)
\r
2729 type = trueExpr.Type;
\r
2732 Type true_type = trueExpr.Type;
\r
2733 Type false_type = falseExpr.Type;
\r
2735 if (trueExpr is NullLiteral){
\r
2736 type = false_type;
\r
2738 } else if (falseExpr is NullLiteral){
\r
2744 // First, if an implicit conversion exists from trueExpr
\r
2745 // to falseExpr, then the result type is of type falseExpr.Type
\r
2747 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
\r
2748 if (conv != null){
\r
2750 // Check if both can convert implicitl to each other's type
\r
2752 if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
\r
2754 "Can not compute type of conditional expression " +
\r
2755 "as '" + TypeManager.CSharpName (trueExpr.Type) +
\r
2756 "' and '" + TypeManager.CSharpName (falseExpr.Type) +
\r
2757 "' convert implicitly to each other");
\r
2760 type = false_type;
\r
2762 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
\r
2766 Error (173, "The type of the conditional expression can " +
\r
2767 "not be computed because there is no implicit conversion" +
\r
2768 " from '" + TypeManager.CSharpName (trueExpr.Type) + "'" +
\r
2769 " and '" + TypeManager.CSharpName (falseExpr.Type) + "'");
\r
2774 if (expr is BoolConstant){
\r
2775 BoolConstant bc = (BoolConstant) expr;
\r
2786 public override void Emit (EmitContext ec)
\r
2788 ILGenerator ig = ec.ig;
\r
2789 Label false_target = ig.DefineLabel ();
\r
2790 Label end_target = ig.DefineLabel ();
\r
2792 Statement.EmitBoolExpression (ec, expr, false_target, false);
\r
2793 trueExpr.Emit (ec);
\r
2794 ig.Emit (OpCodes.Br, end_target);
\r
2795 ig.MarkLabel (false_target);
\r
2796 falseExpr.Emit (ec);
\r
2797 ig.MarkLabel (end_target);
\r
2803 /// Local variables
\r
2805 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
\r
2806 public readonly string Name;
\r
2807 public readonly Block Block;
\r
2808 VariableInfo variable_info;
\r
2811 public LocalVariableReference (Block block, string name, Location l)
\r
2816 eclass = ExprClass.Variable;
\r
2819 // Setting 'is_readonly' to false will allow you to create a writable
\r
2820 // reference to a read-only variable. This is used by foreach and using.
\r
2821 public LocalVariableReference (Block block, string name, Location l,
\r
2822 VariableInfo variable_info, bool is_readonly)
\r
2823 : this (block, name, l)
\r
2825 this.variable_info = variable_info;
\r
2826 this.is_readonly = is_readonly;
\r
2829 public VariableInfo VariableInfo {
\r
2831 if (variable_info == null) {
\r
2832 variable_info = Block.GetVariableInfo (Name);
\r
2833 is_readonly = variable_info.ReadOnly;
\r
2835 return variable_info;
\r
2839 public bool IsAssigned (EmitContext ec, Location loc)
\r
2841 return VariableInfo.IsAssigned (ec, loc);
\r
2844 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
\r
2846 return VariableInfo.IsFieldAssigned (ec, name, loc);
\r
2849 public void SetAssigned (EmitContext ec)
\r
2851 VariableInfo.SetAssigned (ec);
\r
2854 public void SetFieldAssigned (EmitContext ec, string name)
\r
2856 VariableInfo.SetFieldAssigned (ec, name);
\r
2859 public bool IsReadOnly {
\r
2861 if (variable_info == null) {
\r
2862 variable_info = Block.GetVariableInfo (Name);
\r
2863 is_readonly = variable_info.ReadOnly;
\r
2865 return is_readonly;
\r
2869 public override Expression DoResolve (EmitContext ec)
\r
2871 VariableInfo vi = VariableInfo;
\r
2873 if (Block.IsConstant (Name)) {
\r
2874 Expression e = Block.GetConstantExpression (Name);
\r
2880 if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
\r
2883 type = vi.VariableType;
\r
2887 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
2889 VariableInfo vi = VariableInfo;
\r
2891 if (ec.DoFlowAnalysis)
\r
2892 ec.SetVariableAssigned (vi);
\r
2894 Expression e = DoResolve (ec);
\r
2900 Error (1604, "cannot assign to '" + Name + "' because it is readonly");
\r
2907 public override void Emit (EmitContext ec)
\r
2909 VariableInfo vi = VariableInfo;
\r
2910 ILGenerator ig = ec.ig;
\r
2912 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
\r
2916 public void EmitAssign (EmitContext ec, Expression source)
\r
2918 ILGenerator ig = ec.ig;
\r
2919 VariableInfo vi = VariableInfo;
\r
2921 vi.Assigned = true;
\r
2925 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
\r
2928 public void AddressOf (EmitContext ec, AddressOp mode)
\r
2930 VariableInfo vi = VariableInfo;
\r
2932 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
\r
2937 /// This represents a reference to a parameter in the intermediate
\r
2938 /// representation.
\r
2940 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
\r
2944 public Parameter.Modifier mod;
\r
2945 public bool is_ref, is_out;
\r
2947 public ParameterReference (Parameters pars, int idx, string name, Location loc)
\r
2953 eclass = ExprClass.Variable;
\r
2956 public bool IsAssigned (EmitContext ec, Location loc)
\r
2958 if (!is_out || !ec.DoFlowAnalysis)
\r
2961 if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
\r
2962 Report.Error (165, loc,
\r
2963 "Use of unassigned local variable '" + name + "'");
\r
2970 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
\r
2972 if (!is_out || !ec.DoFlowAnalysis)
\r
2975 if (ec.CurrentBranching.IsParameterAssigned (idx))
\r
2978 if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
\r
2979 Report.Error (170, loc,
\r
2980 "Use of possibly unassigned field '" + field_name + "'");
\r
2987 public void SetAssigned (EmitContext ec)
\r
2989 if (is_out && ec.DoFlowAnalysis)
\r
2990 ec.CurrentBranching.SetParameterAssigned (idx);
\r
2993 public void SetFieldAssigned (EmitContext ec, string field_name)
\r
2995 if (is_out && ec.DoFlowAnalysis)
\r
2996 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
\r
3000 // Notice that for ref/out parameters, the type exposed is not the
\r
3001 // same type exposed externally.
\r
3003 // for "ref int a":
\r
3004 // externally we expose "int&"
\r
3005 // here we expose "int".
\r
3007 // We record this in "is_ref". This means that the type system can treat
\r
3008 // the type as it is expected, but when we generate the code, we generate
\r
3009 // the alternate kind of code.
\r
3011 public override Expression DoResolve (EmitContext ec)
\r
3013 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
\r
3014 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
\r
3015 is_out = (mod & Parameter.Modifier.OUT) != 0;
\r
3016 eclass = ExprClass.Variable;
\r
3018 if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
\r
3024 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
3026 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
\r
3027 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
\r
3028 is_out = (mod & Parameter.Modifier.OUT) != 0;
\r
3029 eclass = ExprClass.Variable;
\r
3031 if (is_out && ec.DoFlowAnalysis)
\r
3032 ec.SetParameterAssigned (idx);
\r
3037 static void EmitLdArg (ILGenerator ig, int x)
\r
3041 case 0: ig.Emit (OpCodes.Ldarg_0); break;
\r
3042 case 1: ig.Emit (OpCodes.Ldarg_1); break;
\r
3043 case 2: ig.Emit (OpCodes.Ldarg_2); break;
\r
3044 case 3: ig.Emit (OpCodes.Ldarg_3); break;
\r
3045 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
\r
3048 ig.Emit (OpCodes.Ldarg, x);
\r
3052 // This method is used by parameters that are references, that are
\r
3053 // being passed as references: we only want to pass the pointer (that
\r
3054 // is already stored in the parameter, not the address of the pointer,
\r
3055 // and not the value of the variable).
\r
3057 public void EmitLoad (EmitContext ec)
\r
3059 ILGenerator ig = ec.ig;
\r
3060 int arg_idx = idx;
\r
3065 EmitLdArg (ig, arg_idx);
\r
3068 public override void Emit (EmitContext ec)
\r
3070 ILGenerator ig = ec.ig;
\r
3071 int arg_idx = idx;
\r
3076 EmitLdArg (ig, arg_idx);
\r
3082 // If we are a reference, we loaded on the stack a pointer
\r
3083 // Now lets load the real value
\r
3085 LoadFromPtr (ig, type);
\r
3088 public void EmitAssign (EmitContext ec, Expression source)
\r
3090 ILGenerator ig = ec.ig;
\r
3091 int arg_idx = idx;
\r
3097 EmitLdArg (ig, arg_idx);
\r
3102 StoreFromPtr (ig, type);
\r
3104 if (arg_idx <= 255)
\r
3105 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
\r
3107 ig.Emit (OpCodes.Starg, arg_idx);
\r
3111 public void AddressOf (EmitContext ec, AddressOp mode)
\r
3113 int arg_idx = idx;
\r
3119 if (arg_idx <= 255)
\r
3120 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
\r
3122 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
\r
3124 if (arg_idx <= 255)
\r
3125 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
\r
3127 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
\r
3134 /// Invocation of methods or delegates.
\r
3136 public class Invocation : ExpressionStatement {
\r
3137 public ArrayList Arguments;
\r
3140 MethodBase method = null;
\r
3143 static Hashtable method_parameter_cache;
\r
3144 static MemberFilter CompareName;
\r
3146 static Invocation ()
\r
3148 method_parameter_cache = new PtrHashtable ();
\r
3152 // arguments is an ArrayList, but we do not want to typecast,
\r
3153 // as it might be null.
\r
3155 // FIXME: only allow expr to be a method invocation or a
\r
3156 // delegate invocation (7.5.5)
\r
3158 public Invocation (Expression expr, ArrayList arguments, Location l)
\r
3161 Arguments = arguments;
\r
3163 CompareName = new MemberFilter (compare_name_filter);
\r
3166 public Expression Expr {
\r
3173 /// Returns the Parameters (a ParameterData interface) for the
\r
3176 public static ParameterData GetParameterData (MethodBase mb)
\r
3178 object pd = method_parameter_cache [mb];
\r
3182 return (ParameterData) pd;
\r
3185 ip = TypeManager.LookupParametersByBuilder (mb);
\r
3187 method_parameter_cache [mb] = ip;
\r
3189 return (ParameterData) ip;
\r
3191 ParameterInfo [] pi = mb.GetParameters ();
\r
3192 ReflectionParameters rp = new ReflectionParameters (pi);
\r
3193 method_parameter_cache [mb] = rp;
\r
3195 return (ParameterData) rp;
\r
3200 /// Determines "better conversion" as specified in 7.4.2.3
\r
3201 /// Returns : 1 if a->p is better
\r
3202 /// 0 if a->q or neither is better
\r
3204 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
\r
3206 Type argument_type = a.Type;
\r
3207 Expression argument_expr = a.Expr;
\r
3209 if (argument_type == null)
\r
3210 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
\r
3213 // This is a special case since csc behaves this way. I can't find
\r
3214 // it anywhere in the spec but oh well ...
\r
3216 if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
\r
3218 else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
\r
3224 if (argument_type == p)
\r
3227 if (argument_type == q)
\r
3231 // Now probe whether an implicit constant expression conversion
\r
3234 // An implicit constant expression conversion permits the following
\r
3237 // * A constant-expression of type 'int' can be converted to type
\r
3238 // sbyte, byute, short, ushort, uint, ulong provided the value of
\r
3239 // of the expression is withing the range of the destination type.
\r
3241 // * A constant-expression of type long can be converted to type
\r
3242 // ulong, provided the value of the constant expression is not negative
\r
3244 // FIXME: Note that this assumes that constant folding has
\r
3245 // taken place. We dont do constant folding yet.
\r
3248 if (argument_expr is IntConstant){
\r
3249 IntConstant ei = (IntConstant) argument_expr;
\r
3250 int value = ei.Value;
\r
3252 if (p == TypeManager.sbyte_type){
\r
3253 if (value >= SByte.MinValue && value <= SByte.MaxValue)
\r
3255 } else if (p == TypeManager.byte_type){
\r
3256 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
\r
3258 } else if (p == TypeManager.short_type){
\r
3259 if (value >= Int16.MinValue && value <= Int16.MaxValue)
\r
3261 } else if (p == TypeManager.ushort_type){
\r
3262 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
\r
3264 } else if (p == TypeManager.uint32_type){
\r
3266 // we can optimize this case: a positive int32
\r
3267 // always fits on a uint32
\r
3271 } else if (p == TypeManager.uint64_type){
\r
3273 // we can optimize this case: a positive int32
\r
3274 // always fits on a uint64
\r
3279 } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
\r
3280 LongConstant lc = (LongConstant) argument_expr;
\r
3282 if (p == TypeManager.uint64_type){
\r
3289 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
\r
3297 Expression p_tmp = new EmptyExpression (p);
\r
3298 Expression q_tmp = new EmptyExpression (q);
\r
3300 if (StandardConversionExists (p_tmp, q) == true &&
\r
3301 StandardConversionExists (q_tmp, p) == false)
\r
3304 if (p == TypeManager.sbyte_type)
\r
3305 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
\r
3306 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
\r
3309 if (p == TypeManager.short_type)
\r
3310 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
\r
3311 q == TypeManager.uint64_type)
\r
3314 if (p == TypeManager.int32_type)
\r
3315 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
\r
3318 if (p == TypeManager.int64_type)
\r
3319 if (q == TypeManager.uint64_type)
\r
3326 /// Determines "Better function"
\r
3329 /// and returns an integer indicating :
\r
3330 /// 0 if candidate ain't better
\r
3331 /// 1 if candidate is better than the current best match
\r
3333 static int BetterFunction (EmitContext ec, ArrayList args,
\r
3334 MethodBase candidate, MethodBase best,
\r
3335 bool expanded_form, Location loc)
\r
3337 ParameterData candidate_pd = GetParameterData (candidate);
\r
3338 ParameterData best_pd;
\r
3339 int argument_count;
\r
3342 argument_count = 0;
\r
3344 argument_count = args.Count;
\r
3346 int cand_count = candidate_pd.Count;
\r
3348 if (cand_count == 0 && argument_count == 0)
\r
3351 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
\r
3352 if (cand_count != argument_count)
\r
3355 if (best == null) {
\r
3358 if (argument_count == 0 && cand_count == 1 &&
\r
3359 candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
\r
3362 for (int j = argument_count; j > 0;) {
\r
3365 Argument a = (Argument) args [j];
\r
3366 Type t = candidate_pd.ParameterType (j);
\r
3368 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
\r
3369 if (expanded_form)
\r
3370 t = t.GetElementType ();
\r
3372 x = BetterConversion (ec, a, t, null, loc);
\r
3384 best_pd = GetParameterData (best);
\r
3386 int rating1 = 0, rating2 = 0;
\r
3388 for (int j = 0; j < argument_count; ++j) {
\r
3391 Argument a = (Argument) args [j];
\r
3393 Type ct = candidate_pd.ParameterType (j);
\r
3394 Type bt = best_pd.ParameterType (j);
\r
3396 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
\r
3397 if (expanded_form)
\r
3398 ct = ct.GetElementType ();
\r
3400 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
\r
3401 if (expanded_form)
\r
3402 bt = bt.GetElementType ();
\r
3404 x = BetterConversion (ec, a, ct, bt, loc);
\r
3405 y = BetterConversion (ec, a, bt, ct, loc);
\r
3414 if (rating1 > rating2)
\r
3420 public static string FullMethodDesc (MethodBase mb)
\r
3422 string ret_type = "";
\r
3424 if (mb is MethodInfo)
\r
3425 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType) + " ";
\r
3427 StringBuilder sb = new StringBuilder (ret_type + mb.Name);
\r
3428 ParameterData pd = GetParameterData (mb);
\r
3430 int count = pd.Count;
\r
3433 for (int i = count; i > 0; ) {
\r
3436 sb.Append (pd.ParameterDesc (count - i - 1));
\r
3442 return sb.ToString ();
\r
3445 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
\r
3447 MemberInfo [] miset;
\r
3448 MethodGroupExpr union;
\r
3453 return (MethodGroupExpr) mg2;
\r
3456 return (MethodGroupExpr) mg1;
\r
3459 MethodGroupExpr left_set = null, right_set = null;
\r
3460 int length1 = 0, length2 = 0;
\r
3462 left_set = (MethodGroupExpr) mg1;
\r
3463 length1 = left_set.Methods.Length;
\r
3465 right_set = (MethodGroupExpr) mg2;
\r
3466 length2 = right_set.Methods.Length;
\r
3468 ArrayList common = new ArrayList ();
\r
3470 foreach (MethodBase l in left_set.Methods){
\r
3471 foreach (MethodBase r in right_set.Methods){
\r
3479 miset = new MemberInfo [length1 + length2 - common.Count];
\r
3480 left_set.Methods.CopyTo (miset, 0);
\r
3484 foreach (MemberInfo mi in right_set.Methods){
\r
3485 if (!common.Contains (mi))
\r
3489 union = new MethodGroupExpr (miset, loc);
\r
3495 /// Determines is the candidate method, if a params method, is applicable
\r
3496 /// in its expanded form to the given set of arguments
\r
3498 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
\r
3502 if (arguments == null)
\r
3505 arg_count = arguments.Count;
\r
3507 ParameterData pd = GetParameterData (candidate);
\r
3509 int pd_count = pd.Count;
\r
3511 if (pd_count == 0)
\r
3514 if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
\r
3517 if (pd_count - 1 > arg_count)
\r
3520 if (pd_count == 1 && arg_count == 0)
\r
3524 // If we have come this far, the case which remains is when the number of parameters
\r
3525 // is less than or equal to the argument count.
\r
3527 for (int i = 0; i < pd_count - 1; ++i) {
\r
3529 Argument a = (Argument) arguments [i];
\r
3531 Parameter.Modifier a_mod = a.GetParameterModifier () &
\r
3532 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3533 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
\r
3534 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3536 if (a_mod == p_mod) {
\r
3538 if (a_mod == Parameter.Modifier.NONE)
\r
3539 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
\r
3542 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
\r
3543 Type pt = pd.ParameterType (i);
\r
3546 pt = TypeManager.LookupType (pt.FullName + "&");
\r
3556 Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
\r
3558 for (int i = pd_count - 1; i < arg_count; i++) {
\r
3559 Argument a = (Argument) arguments [i];
\r
3561 if (!StandardConversionExists (a.Expr, element_type))
\r
3568 static bool CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
\r
3570 Parameter.Modifier a_mod = a.GetParameterModifier () &
\r
3571 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3572 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
\r
3573 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3575 if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
\r
3576 if (a_mod == Parameter.Modifier.NONE)
\r
3577 if (!ImplicitConversionExists (ec, a.Expr, ptype))
\r
3580 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
\r
3581 Type pt = pd.ParameterType (i);
\r
3584 pt = TypeManager.LookupType (pt.FullName + "&");
\r
3596 /// Determines if the candidate method is applicable (section 14.4.2.1)
\r
3597 /// to the given set of arguments
\r
3599 static bool IsApplicable (EmitContext ec, ref ArrayList arguments, MethodBase candidate)
\r
3601 int arg_count, ps_count, po_count;
\r
3604 if (arguments == null)
\r
3607 arg_count = arguments.Count;
\r
3609 ParameterData pd = GetParameterData (candidate);
\r
3610 Parameters ps = GetFullParameters (candidate);
\r
3618 ps_count = ps.CountStandardParams();
\r
3619 po_count = ps.CountOptionalParams();
\r
3621 int pd_count = pd.Count;
\r
3623 // Validate argument count
\r
3624 if (po_count == 0) {
\r
3625 if (arg_count != pd.Count)
\r
3630 if ((arg_count < ps_count) || (arg_count > pd_count))
\r
3634 if (arg_count > 0) {
\r
3635 for (int i = arg_count; i > 0 ; ) {
\r
3638 Argument a = (Argument) arguments [i];
\r
3639 if (a.ArgType == Argument.AType.NoArg)
\r
3641 Parameter p = (Parameter) ps.FixedParameters[i];
\r
3642 a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
\r
3643 param_type = p.ParameterInitializer.Type;
\r
3647 param_type = pd.ParameterType (i);
\r
3649 Parameter p = (Parameter) ps.FixedParameters[i];
\r
3651 if ((p.ModFlags & Parameter.Modifier.REF) != 0)
\r
3653 a = new Argument (a.Expr, Argument.AType.Ref);
\r
3654 if (!a.Resolve(ec,Location.Null))
\r
3660 if (!CheckParameterAgainstArgument (ec, pd, i, a, param_type))
\r
3666 // If we have no arguments AND the first parameter is optional
\r
3667 // we must check for a candidate (the loop above wouldn't)
\r
3668 if (po_count > 0) {
\r
3669 ArrayList arglist = new ArrayList();
\r
3671 // Since we got so far, there's no need to check if
\r
3672 // arguments are optional; we simply retrieve
\r
3673 // parameter default values and build a brand-new
\r
3676 for (int i = 0; i < ps.FixedParameters.Length; i++) {
\r
3677 Parameter p = ps.FixedParameters[i];
\r
3678 Argument a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
\r
3679 a.Resolve(ec, Location.Null);
\r
3682 arguments = arglist;
\r
3686 // We've found a candidate, so we exchange the dummy NoArg arguments
\r
3687 // with new arguments containing the default value for that parameter
\r
3688 ArrayList newarglist = new ArrayList();
\r
3689 for (int i = 0; i < arg_count; i++) {
\r
3690 Argument a = (Argument) arguments [i];
\r
3691 Parameter p = null;
\r
3694 p = (Parameter) ps.FixedParameters[i];
\r
3696 if (a.ArgType == Argument.AType.NoArg){
\r
3697 a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
\r
3698 a.Resolve(ec, Location.Null);
\r
3701 if ((p != null) && ((p.ModFlags & Parameter.Modifier.REF) != 0))
\r
3703 a.ArgType = Argument.AType.Ref;
\r
3704 a.Resolve(ec, Location.Null);
\r
3706 newarglist.Add(a);
\r
3707 int n = pd_count - arg_count;
\r
3710 for (int x = 0; x < n; x++)
\r
3712 Parameter op = (Parameter) ps.FixedParameters[x + arg_count];
\r
3713 Argument b = new Argument (op.ParameterInitializer, Argument.AType.Expression);
\r
3714 b.Resolve(ec, Location.Null);
\r
3715 newarglist.Add (b);
\r
3719 arguments = newarglist;
\r
3723 static bool compare_name_filter (MemberInfo m, object filterCriteria)
\r
3725 return (m.Name == ((string) filterCriteria));
\r
3728 static Parameters GetFullParameters (MethodBase mb)
\r
3730 TypeContainer tc = TypeManager.LookupTypeContainer (mb.DeclaringType);
\r
3731 InternalParameters ip = TypeManager.LookupParametersByBuilder(mb);
\r
3733 return (ip != null) ? ip.Parameters : null;
\r
3736 // We need an overload for OverloadResolve because Invocation.DoResolve
\r
3737 // must pass Arguments by reference, since a later call to IsApplicable
\r
3738 // can change the argument list if optional parameters are defined
\r
3739 // in the method declaration
\r
3740 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
\r
3741 ArrayList Arguments, Location loc)
\r
3743 ArrayList a = Arguments;
\r
3744 return OverloadResolve (ec, me, ref a, loc);
\r
3748 /// Find the Applicable Function Members (7.4.2.1)
\r
3750 /// me: Method Group expression with the members to select.
\r
3751 /// it might contain constructors or methods (or anything
\r
3752 /// that maps to a method).
\r
3754 /// Arguments: ArrayList containing resolved Argument objects.
\r
3756 /// loc: The location if we want an error to be reported, or a Null
\r
3757 /// location for "probing" purposes.
\r
3759 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
\r
3760 /// that is the best match of me on Arguments.
\r
3763 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
\r
3764 ref ArrayList Arguments, Location loc)
\r
3766 ArrayList afm = new ArrayList ();
\r
3767 MethodBase method = null;
\r
3768 Type current_type = null;
\r
3769 int argument_count;
\r
3770 ArrayList candidates = new ArrayList ();
\r
3772 foreach (MethodBase candidate in me.Methods){
\r
3775 // If we're going one level higher in the class hierarchy, abort if
\r
3776 // we already found an applicable method.
\r
3777 if (candidate.DeclaringType != current_type) {
\r
3778 current_type = candidate.DeclaringType;
\r
3779 if (method != null)
\r
3783 // Check if candidate is applicable (section 14.4.2.1)
\r
3784 if (!IsApplicable (ec, ref Arguments, candidate))
\r
3787 candidates.Add (candidate);
\r
3788 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
\r
3793 method = candidate;
\r
3796 if (Arguments == null)
\r
3797 argument_count = 0;
\r
3799 argument_count = Arguments.Count;
\r
3803 // Now we see if we can find params functions, applicable in their expanded form
\r
3804 // since if they were applicable in their normal form, they would have been selected
\r
3807 bool chose_params_expanded = false;
\r
3809 if (method == null) {
\r
3810 candidates = new ArrayList ();
\r
3811 foreach (MethodBase candidate in me.Methods){
\r
3812 if (!IsParamsMethodApplicable (ec, Arguments, candidate))
\r
3815 candidates.Add (candidate);
\r
3817 int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
\r
3821 method = candidate;
\r
3822 chose_params_expanded = true;
\r
3826 if (method == null) {
\r
3828 // Okay so we have failed to find anything so we
\r
3829 // return by providing info about the closest match
\r
3831 for (int i = 0; i < me.Methods.Length; ++i) {
\r
3833 MethodBase c = (MethodBase) me.Methods [i];
\r
3834 ParameterData pd = GetParameterData (c);
\r
3836 if (pd.Count != argument_count)
\r
3839 VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
\r
3847 // Now check that there are no ambiguities i.e the selected method
\r
3848 // should be better than all the others
\r
3851 foreach (MethodBase candidate in candidates){
\r
3852 if (candidate == method)
\r
3856 // If a normal method is applicable in the sense that it has the same
\r
3857 // number of arguments, then the expanded params method is never applicable
\r
3858 // so we debar the params method.
\r
3860 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
\r
3861 IsApplicable (ec, ref Arguments, method))
\r
3864 int x = BetterFunction (ec, Arguments, method, candidate,
\r
3865 chose_params_expanded, loc);
\r
3870 "Ambiguous call when selecting function due to implicit casts");
\r
3876 // And now check if the arguments are all compatible, perform conversions
\r
3877 // if necessary etc. and return if everything is all right
\r
3879 if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
\r
3880 chose_params_expanded, null, loc))
\r
3886 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
\r
3887 int argument_count,
\r
3888 MethodBase method,
\r
3889 bool chose_params_expanded,
\r
3890 Type delegate_type,
\r
3893 return (VerifyArgumentsCompat (ec, Arguments, argument_count,
\r
3894 method, chose_params_expanded, delegate_type, loc, null));
\r
3897 public static bool VerifyArgumentsCompat (EmitContext ec,
\r
3898 ArrayList Arguments,
\r
3899 int argument_count,
\r
3900 MethodBase method,
\r
3901 bool chose_params_expanded,
\r
3902 Type delegate_type,
\r
3904 string InvokingProperty)
\r
3906 ParameterData pd = GetParameterData (method);
\r
3907 int pd_count = pd.Count;
\r
3909 for (int j = 0; j < argument_count; j++) {
\r
3910 Argument a = (Argument) Arguments [j];
\r
3911 Expression a_expr = a.Expr;
\r
3912 Type parameter_type = pd.ParameterType (j);
\r
3914 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
\r
3915 chose_params_expanded)
\r
3916 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
\r
3918 if (a.Type != parameter_type){
\r
3921 conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
\r
3923 if (conv == null) {
\r
3924 if (!Location.IsNull (loc)) {
\r
3925 if (delegate_type == null)
\r
3926 if (InvokingProperty == null)
\r
3927 Report.Error (1502, loc,
\r
3928 "The best overloaded match for method '" +
\r
3929 FullMethodDesc (method) +
\r
3930 "' has some invalid arguments");
\r
3932 Report.Error (1502, loc,
\r
3934 InvokingProperty +
\r
3935 "' has some invalid arguments");
\r
3937 Report.Error (1594, loc,
\r
3938 "Delegate '" + delegate_type.ToString () +
\r
3939 "' has some invalid arguments.");
\r
3940 Report.Error (1503, loc,
\r
3941 "Argument " + (j+1) +
\r
3942 ": Cannot convert from '" + Argument.FullDesc (a)
\r
3943 + "' to '" + pd.ParameterDesc (j) + "'");
\r
3950 // Update the argument with the implicit conversion
\r
3952 if (a_expr != conv)
\r
3956 Parameter.Modifier a_mod = a.GetParameterModifier () &
\r
3957 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3958 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
\r
3959 ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
\r
3962 if (a_mod != p_mod &&
\r
3963 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
\r
3964 if (!Location.IsNull (loc)) {
\r
3965 Report.Error (1502, loc,
\r
3966 "The best overloaded match for method '" + FullMethodDesc (method)+
\r
3967 "' has some invalid arguments");
\r
3968 Report.Error (1503, loc,
\r
3969 "Argument " + (j+1) +
\r
3970 ": Cannot convert from '" + Argument.FullDesc (a)
\r
3971 + "' to '" + pd.ParameterDesc (j) + "'");
\r
3981 public override Expression DoResolve (EmitContext ec)
\r
3984 // First, resolve the expression that is used to
\r
3985 // trigger the invocation
\r
3987 Expression expr_to_return = null;
\r
3989 if (expr is BaseAccess)
\r
3992 expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
\r
3996 if (expr is Invocation) {
\r
3997 // FIXME Calls which return an Array are not resolved (here or in the grammar)
\r
3998 expr = expr.Resolve(ec);
\r
4001 if (!(expr is MethodGroupExpr))
\r
4003 Type expr_type = expr.Type;
\r
4005 if (expr_type != null)
\r
4007 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
\r
4009 return (new DelegateInvocation (
\r
4010 this.expr, Arguments, loc)).Resolve (ec);
\r
4015 // Next, evaluate all the expressions in the argument list
\r
4017 if (Arguments != null)
\r
4019 foreach (Argument a in Arguments)
\r
4021 if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
\r
4022 Report.Error (999, "This item cannot have empty arguments");
\r
4024 if (!a.Resolve (ec, loc))
\r
4029 if (expr is MethodGroupExpr)
\r
4031 MethodGroupExpr mg = (MethodGroupExpr) expr;
\r
4032 method = OverloadResolve (ec, mg, ref Arguments, loc);
\r
4034 if (method == null)
\r
4037 "Could not find any applicable function for this argument list");
\r
4041 if ((method as MethodInfo) != null)
\r
4043 MethodInfo mi = method as MethodInfo;
\r
4044 type = TypeManager.TypeToCoreType (mi.ReturnType);
\r
4045 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
\r
4046 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
\r
4049 if ((method as ConstructorInfo) != null)
\r
4051 ConstructorInfo ci = method as ConstructorInfo;
\r
4052 type = TypeManager.void_type;
\r
4053 if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
\r
4054 SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);
\r
4057 if (type.IsPointer)
\r
4061 UnsafeError (loc);
\r
4065 eclass = ExprClass.Value;
\r
4066 expr_to_return = this;
\r
4069 if (expr is PropertyExpr)
\r
4071 PropertyExpr pe = ((PropertyExpr) expr);
\r
4072 pe.PropertyArgs = (ArrayList) Arguments.Clone();
\r
4073 Arguments.Clear();
\r
4074 Arguments = new ArrayList();
\r
4075 MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
\r
4077 if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
\r
4078 pe.PropertyArgs.Count, mi, false, null, loc, pe.Name))
\r
4081 expr_to_return = pe.DoResolve (ec);
\r
4082 expr_to_return.eclass = ExprClass.PropertyAccess;
\r
4086 if (expr is FieldExpr || expr is LocalVariableReference) {
\r
4087 // If we are here, expr must be an ArrayAccess
\r
4088 // FIXME: we should check dimensions, etc.
\r
4089 ArrayList idxs = new ArrayList();
\r
4090 foreach (Argument a in Arguments)
\r
4092 idxs.Add (a.Expr);
\r
4094 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
\r
4095 ArrayAccess aa = new ArrayAccess (ea, expr.Location);
\r
4096 expr_to_return = aa.DoResolve(ec);
\r
4097 expr_to_return.eclass = ExprClass.Variable;
\r
4100 return expr_to_return;
\r
4104 // Emits the list of arguments as an array
\r
4106 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
\r
4108 ILGenerator ig = ec.ig;
\r
4109 int count = arguments.Count - idx;
\r
4110 Argument a = (Argument) arguments [idx];
\r
4111 Type t = a.Expr.Type;
\r
4112 string array_type = t.FullName + "[]";
\r
4113 LocalBuilder array;
\r
4115 array = ig.DeclareLocal (TypeManager.LookupType (array_type));
\r
4116 IntConstant.EmitInt (ig, count);
\r
4117 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
\r
4118 ig.Emit (OpCodes.Stloc, array);
\r
4120 int top = arguments.Count;
\r
4121 for (int j = idx; j < top; j++){
\r
4122 a = (Argument) arguments [j];
\r
4124 ig.Emit (OpCodes.Ldloc, array);
\r
4125 IntConstant.EmitInt (ig, j - idx);
\r
4128 ArrayAccess.EmitStoreOpcode (ig, t);
\r
4130 ig.Emit (OpCodes.Ldloc, array);
\r
4134 /// Emits a list of resolved Arguments that are in the arguments
\r
4137 /// The MethodBase argument might be null if the
\r
4138 /// emission of the arguments is known not to contain
\r
4139 /// a 'params' field (for example in constructors or other routines
\r
4140 /// that keep their arguments in this structure)
\r
4142 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
\r
4146 pd = GetParameterData (mb);
\r
4151 // If we are calling a params method with no arguments, special case it
\r
4153 if (arguments == null){
\r
4154 if (pd != null && pd.Count > 0 &&
\r
4155 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
\r
4156 ILGenerator ig = ec.ig;
\r
4158 IntConstant.EmitInt (ig, 0);
\r
4159 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
\r
4164 int top = arguments.Count;
\r
4166 for (int i = 0; i < top; i++){
\r
4167 Argument a = (Argument) arguments [i];
\r
4170 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
\r
4172 // Special case if we are passing the same data as the
\r
4173 // params argument, do not put it in an array.
\r
4175 if (pd.ParameterType (i) == a.Type)
\r
4178 EmitParams (ec, i, arguments);
\r
4186 if (pd != null && pd.Count > top &&
\r
4187 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
\r
4188 ILGenerator ig = ec.ig;
\r
4190 IntConstant.EmitInt (ig, 0);
\r
4191 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
\r
4196 /// is_base tells whether we want to force the use of the 'call'
\r
4197 /// opcode instead of using callvirt. Call is required to call
\r
4198 /// a specific method, while callvirt will always use the most
\r
4199 /// recent method in the vtable.
\r
4201 /// is_static tells whether this is an invocation on a static method
\r
4203 /// instance_expr is an expression that represents the instance
\r
4204 /// it must be non-null if is_static is false.
\r
4206 /// method is the method to invoke.
\r
4208 /// Arguments is the list of arguments to pass to the method or constructor.
\r
4210 public static void EmitCall (EmitContext ec, bool is_base,
\r
4211 bool is_static, Expression instance_expr,
\r
4212 MethodBase method, ArrayList Arguments, Location loc)
\r
4214 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
\r
4217 public static void EmitCall (EmitContext ec, bool is_base,
\r
4218 bool is_static, Expression instance_expr,
\r
4219 MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)
\r
4221 ILGenerator ig = ec.ig;
\r
4222 bool struct_call = false;
\r
4224 Type decl_type = method.DeclaringType;
\r
4226 if (!RootContext.StdLib)
\r
4228 // Replace any calls to the system's System.Array type with calls to
\r
4229 // the newly created one.
\r
4230 if (method == TypeManager.system_int_array_get_length)
\r
4231 method = TypeManager.int_array_get_length;
\r
4232 else if (method == TypeManager.system_int_array_get_rank)
\r
4233 method = TypeManager.int_array_get_rank;
\r
4234 else if (method == TypeManager.system_object_array_clone)
\r
4235 method = TypeManager.object_array_clone;
\r
4236 else if (method == TypeManager.system_int_array_get_length_int)
\r
4237 method = TypeManager.int_array_get_length_int;
\r
4238 else if (method == TypeManager.system_int_array_get_lower_bound_int)
\r
4239 method = TypeManager.int_array_get_lower_bound_int;
\r
4240 else if (method == TypeManager.system_int_array_get_upper_bound_int)
\r
4241 method = TypeManager.int_array_get_upper_bound_int;
\r
4242 else if (method == TypeManager.system_void_array_copyto_array_int)
\r
4243 method = TypeManager.void_array_copyto_array_int;
\r
4247 // This checks the 'ConditionalAttribute' on the method, and the
\r
4248 // ObsoleteAttribute
\r
4250 TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
\r
4251 if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
\r
4253 if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
\r
4258 if (decl_type.IsValueType)
\r
4259 struct_call = true;
\r
4261 // If this is ourselves, push "this"
\r
4263 if (instance_expr == null)
\r
4265 ig.Emit (OpCodes.Ldarg_0);
\r
4270 // Push the instance expression
\r
4272 if (instance_expr.Type.IsValueType)
\r
4275 // Special case: calls to a function declared in a
\r
4276 // reference-type with a value-type argument need
\r
4277 // to have their value boxed.
\r
4279 struct_call = true;
\r
4280 if (decl_type.IsValueType)
\r
4283 // If the expression implements IMemoryLocation, then
\r
4284 // we can optimize and use AddressOf on the
\r
4287 // If not we have to use some temporary storage for
\r
4289 if (instance_expr is IMemoryLocation)
\r
4291 ((IMemoryLocation)instance_expr).
\r
4292 AddressOf (ec, AddressOp.LoadStore);
\r
4296 Type t = instance_expr.Type;
\r
4298 instance_expr.Emit (ec);
\r
4299 LocalBuilder temp = ig.DeclareLocal (t);
\r
4300 ig.Emit (OpCodes.Stloc, temp);
\r
4301 ig.Emit (OpCodes.Ldloca, temp);
\r
4306 instance_expr.Emit (ec);
\r
4307 ig.Emit (OpCodes.Box, instance_expr.Type);
\r
4311 instance_expr.Emit (ec);
\r
4315 if (prop_args != null && prop_args.Count > 0)
\r
4317 if (Arguments == null)
\r
4318 Arguments = new ArrayList();
\r
4320 for (int i = prop_args.Count-1; i >=0 ; i--)
\r
4322 Arguments.Insert (0,prop_args[i]);
\r
4327 EmitArguments (ec, method, Arguments);
\r
4329 if (is_static || struct_call || is_base)
\r
4331 if (method is MethodInfo)
\r
4333 ig.Emit (OpCodes.Call, (MethodInfo) method);
\r
4336 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
\r
4340 if (method is MethodInfo)
\r
4341 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
\r
4343 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
\r
4347 static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
\r
4349 int top = prop_args.Count;
\r
4351 for (int i = 0; i < top; i++)
\r
4353 Argument a = (Argument) prop_args [i];
\r
4358 public override void Emit (EmitContext ec)
\r
4360 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
\r
4363 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
\r
4366 public override void EmitStatement (EmitContext ec)
\r
4371 // Pop the return value if there is one
\r
4373 if (method is MethodInfo){
\r
4374 Type ret = ((MethodInfo)method).ReturnType;
\r
4375 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
\r
4376 ec.ig.Emit (OpCodes.Pop);
\r
4382 // This class is used to "disable" the code generation for the
\r
4383 // temporary variable when initializing value types.
\r
4385 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
\r
4386 public void AddressOf (EmitContext ec, AddressOp Mode)
\r
4393 /// Implements the new expression
\r
4395 public class New : ExpressionStatement {
\r
4396 public readonly ArrayList Arguments;
\r
4397 public readonly Expression RequestedType;
\r
4399 MethodBase method = null;
\r
4402 // If set, the new expression is for a value_target, and
\r
4403 // we will not leave anything on the stack.
\r
4405 Expression value_target;
\r
4406 bool value_target_set = false;
\r
4408 public New (Expression requested_type, ArrayList arguments, Location l)
\r
4410 RequestedType = requested_type;
\r
4411 Arguments = arguments;
\r
4415 public Expression ValueTypeVariable {
\r
4417 return value_target;
\r
4421 value_target = value;
\r
4422 value_target_set = true;
\r
4427 // This function is used to disable the following code sequence for
\r
4428 // value type initialization:
\r
4430 // AddressOf (temporary)
\r
4434 // Instead the provide will have provided us with the address on the
\r
4435 // stack to store the results.
\r
4437 static Expression MyEmptyExpression;
\r
4439 public void DisableTemporaryValueType ()
\r
4441 if (MyEmptyExpression == null)
\r
4442 MyEmptyExpression = new EmptyAddressOf ();
\r
4445 // To enable this, look into:
\r
4446 // test-34 and test-89 and self bootstrapping.
\r
4448 // For instance, we can avoid a copy by using 'newobj'
\r
4449 // instead of Call + Push-temp on value types.
\r
4450 // value_target = MyEmptyExpression;
\r
4453 public override Expression DoResolve (EmitContext ec)
\r
4455 type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
\r
4460 bool IsDelegate = TypeManager.IsDelegateType (type);
\r
4463 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
\r
4465 if (type.IsInterface || type.IsAbstract){
\r
4467 144, "It is not possible to create instances of interfaces " +
\r
4468 "or abstract classes");
\r
4472 bool is_struct = false;
\r
4473 is_struct = type.IsValueType;
\r
4474 eclass = ExprClass.Value;
\r
4477 // SRE returns a match for .ctor () on structs (the object constructor),
\r
4478 // so we have to manually ignore it.
\r
4480 if (is_struct && Arguments == null)
\r
4484 ml = MemberLookupFinal (ec, type, ".ctor",
\r
4485 MemberTypes.Constructor,
\r
4486 AllBindingFlags | BindingFlags.Public, loc);
\r
4491 if (! (ml is MethodGroupExpr)){
\r
4493 ml.Error118 ("method group");
\r
4499 if (Arguments != null){
\r
4500 foreach (Argument a in Arguments){
\r
4501 if (!a.Resolve (ec, loc))
\r
4506 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
\r
4511 if (method == null) {
\r
4512 if (!is_struct || Arguments.Count > 0) {
\r
4514 "New invocation: Can not find a constructor for " +
\r
4515 "this argument list");
\r
4523 // This DoEmit can be invoked in two contexts:
\r
4524 // * As a mechanism that will leave a value on the stack (new object)
\r
4525 // * As one that wont (init struct)
\r
4527 // You can control whether a value is required on the stack by passing
\r
4528 // need_value_on_stack. The code *might* leave a value on the stack
\r
4529 // so it must be popped manually
\r
4531 // If we are dealing with a ValueType, we have a few
\r
4532 // situations to deal with:
\r
4534 // * The target is a ValueType, and we have been provided
\r
4535 // the instance (this is easy, we are being assigned).
\r
4537 // * The target of New is being passed as an argument,
\r
4538 // to a boxing operation or a function that takes a
\r
4541 // In this case, we need to create a temporary variable
\r
4542 // that is the argument of New.
\r
4544 // Returns whether a value is left on the stack
\r
4546 bool DoEmit (EmitContext ec, bool need_value_on_stack)
\r
4548 bool is_value_type = type.IsValueType;
\r
4549 ILGenerator ig = ec.ig;
\r
4551 if (is_value_type){
\r
4552 IMemoryLocation ml;
\r
4554 // Allow DoEmit() to be called multiple times.
\r
4555 // We need to create a new LocalTemporary each time since
\r
4556 // you can't share LocalBuilders among ILGeneators.
\r
4557 if (!value_target_set)
\r
4558 value_target = new LocalTemporary (ec, type);
\r
4560 ml = (IMemoryLocation) value_target;
\r
4561 ml.AddressOf (ec, AddressOp.Store);
\r
4564 if (method != null)
\r
4565 Invocation.EmitArguments (ec, method, Arguments);
\r
4567 if (is_value_type){
\r
4568 if (method == null)
\r
4569 ig.Emit (OpCodes.Initobj, type);
\r
4571 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
\r
4572 if (need_value_on_stack){
\r
4573 value_target.Emit (ec);
\r
4578 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
\r
4583 public override void Emit (EmitContext ec)
\r
4585 DoEmit (ec, true);
\r
4588 public override void EmitStatement (EmitContext ec)
\r
4590 if (DoEmit (ec, false))
\r
4591 ec.ig.Emit (OpCodes.Pop);
\r
4596 /// 14.5.10.2: Represents an array creation expression.
\r
4600 /// There are two possible scenarios here: one is an array creation
\r
4601 /// expression that specifies the dimensions and optionally the
\r
4602 /// initialization data and the other which does not need dimensions
\r
4603 /// specified but where initialization data is mandatory.
\r
4605 public class ArrayCreation : ExpressionStatement {
\r
4606 Expression requested_base_type;
\r
4607 ArrayList initializers;
\r
4610 // The list of Argument types.
\r
4611 // This is used to construct the 'newarray' or constructor signature
\r
4613 ArrayList arguments;
\r
4616 // Method used to create the array object.
\r
4618 MethodBase new_method = null;
\r
4620 Type array_element_type;
\r
4621 Type underlying_type;
\r
4622 bool is_one_dimensional = false;
\r
4623 bool is_builtin_type = false;
\r
4624 bool expect_initializers = false;
\r
4625 int num_arguments = 0;
\r
4626 int dimensions = 0;
\r
4629 ArrayList array_data;
\r
4634 // The number of array initializers that we can handle
\r
4635 // via the InitializeArray method - through EmitStaticInitializers
\r
4637 int num_automatic_initializers;
\r
4639 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
\r
4641 this.requested_base_type = requested_base_type;
\r
4642 this.initializers = initializers;
\r
4646 arguments = new ArrayList ();
\r
4648 foreach (Expression e in exprs) {
\r
4649 arguments.Add (new Argument (e, Argument.AType.Expression));
\r
4654 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
\r
4656 this.requested_base_type = requested_base_type;
\r
4657 this.initializers = initializers;
\r
4661 //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
\r
4663 //string tmp = rank.Substring (rank.LastIndexOf ("["));
\r
4665 //dimensions = tmp.Length - 1;
\r
4666 expect_initializers = true;
\r
4669 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
\r
4671 StringBuilder sb = new StringBuilder (rank);
\r
4674 for (int i = 1; i < idx_count; i++)
\r
4679 return new ComposedCast (base_type, sb.ToString (), loc);
\r
4682 void Error_IncorrectArrayInitializer ()
\r
4684 Error (178, "Incorrectly structured array initializer");
\r
4687 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
\r
4689 if (specified_dims) {
\r
4690 Argument a = (Argument) arguments [idx];
\r
4692 if (!a.Resolve (ec, loc))
\r
4695 if (!(a.Expr is Constant)) {
\r
4696 Error (150, "A constant value is expected");
\r
4700 int value = (int) ((Constant) a.Expr).GetValue ();
\r
4702 if (value != probe.Count) {
\r
4703 Error_IncorrectArrayInitializer ();
\r
4707 bounds [idx] = value;
\r
4710 int child_bounds = -1;
\r
4711 foreach (object o in probe) {
\r
4712 if (o is ArrayList) {
\r
4713 int current_bounds = ((ArrayList) o).Count;
\r
4715 if (child_bounds == -1)
\r
4716 child_bounds = current_bounds;
\r
4718 else if (child_bounds != current_bounds){
\r
4719 Error_IncorrectArrayInitializer ();
\r
4722 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
\r
4726 if (child_bounds != -1){
\r
4727 Error_IncorrectArrayInitializer ();
\r
4731 Expression tmp = (Expression) o;
\r
4732 tmp = tmp.Resolve (ec);
\r
4736 // Console.WriteLine ("I got: " + tmp);
\r
4737 // Handle initialization from vars, fields etc.
\r
4739 Expression conv = ConvertImplicitRequired (
\r
4740 ec, tmp, underlying_type, loc);
\r
4742 if (conv == null)
\r
4745 if (conv is StringConstant)
\r
4746 array_data.Add (conv);
\r
4747 else if (conv is Constant) {
\r
4748 array_data.Add (conv);
\r
4749 num_automatic_initializers++;
\r
4751 array_data.Add (conv);
\r
4758 public void UpdateIndices (EmitContext ec)
\r
4761 for (ArrayList probe = initializers; probe != null;) {
\r
4762 if (probe.Count > 0 && probe [0] is ArrayList) {
\r
4763 Expression e = new IntConstant (probe.Count);
\r
4764 arguments.Add (new Argument (e, Argument.AType.Expression));
\r
4766 bounds [i++] = probe.Count;
\r
4768 probe = (ArrayList) probe [0];
\r
4771 Expression e = new IntConstant (probe.Count);
\r
4772 arguments.Add (new Argument (e, Argument.AType.Expression));
\r
4774 bounds [i++] = probe.Count;
\r
4781 public bool ValidateInitializers (EmitContext ec, Type array_type)
\r
4783 if (initializers == null) {
\r
4784 if (expect_initializers)
\r
4790 if (underlying_type == null)
\r
4794 // We use this to store all the date values in the order in which we
\r
4795 // will need to store them in the byte blob later
\r
4797 array_data = new ArrayList ();
\r
4798 bounds = new Hashtable ();
\r
4802 if (arguments != null) {
\r
4803 ret = CheckIndices (ec, initializers, 0, true);
\r
4806 arguments = new ArrayList ();
\r
4808 ret = CheckIndices (ec, initializers, 0, false);
\r
4813 UpdateIndices (ec);
\r
4815 if (arguments.Count != dimensions) {
\r
4816 Error_IncorrectArrayInitializer ();
\r
4824 void Error_NegativeArrayIndex ()
\r
4826 Error (284, "Can not create array with a negative size");
\r
4830 // Converts 'source' to an int, uint, long or ulong.
\r
4832 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
\r
4834 Expression target;
\r
4836 bool old_checked = ec.CheckState;
\r
4837 ec.CheckState = true;
\r
4839 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
\r
4840 if (target == null){
\r
4841 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
\r
4842 if (target == null){
\r
4843 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
\r
4844 if (target == null){
\r
4845 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
\r
4846 if (target == null)
\r
4847 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
\r
4851 ec.CheckState = old_checked;
\r
4854 // Only positive constants are allowed at compile time
\r
4856 if (target is Constant){
\r
4857 if (target is IntConstant){
\r
4858 if (((IntConstant) target).Value < 0){
\r
4859 Error_NegativeArrayIndex ();
\r
4864 if (target is LongConstant){
\r
4865 if (((LongConstant) target).Value < 0){
\r
4866 Error_NegativeArrayIndex ();
\r
4877 // Creates the type of the array
\r
4879 bool LookupType (EmitContext ec)
\r
4881 StringBuilder array_qualifier = new StringBuilder (rank);
\r
4884 // 'In the first form allocates an array instace of the type that results
\r
4885 // from deleting each of the individual expression from the expression list'
\r
4887 if (num_arguments > 0) {
\r
4888 array_qualifier.Append ("[");
\r
4889 for (int i = num_arguments-1; i > 0; i--)
\r
4890 array_qualifier.Append (",");
\r
4891 array_qualifier.Append ("]");
\r
4895 // Lookup the type
\r
4897 Expression array_type_expr;
\r
4898 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
\r
4899 string sss = array_qualifier.ToString ();
\r
4900 type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
\r
4905 underlying_type = type;
\r
4906 if (underlying_type.IsArray)
\r
4907 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
\r
4908 dimensions = type.GetArrayRank ();
\r
4913 public override Expression DoResolve (EmitContext ec)
\r
4917 if (!LookupType (ec))
\r
4921 // First step is to validate the initializers and fill
\r
4922 // in any missing bits
\r
4924 if (!ValidateInitializers (ec, type))
\r
4927 if (arguments == null)
\r
4930 arg_count = arguments.Count;
\r
4931 foreach (Argument a in arguments){
\r
4932 if (!a.Resolve (ec, loc))
\r
4935 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
\r
4936 if (real_arg == null)
\r
4939 a.Expr = real_arg;
\r
4943 array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
\r
4945 if (arg_count == 1) {
\r
4946 is_one_dimensional = true;
\r
4947 eclass = ExprClass.Value;
\r
4951 is_builtin_type = TypeManager.IsBuiltinType (type);
\r
4953 if (is_builtin_type) {
\r
4956 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
\r
4957 AllBindingFlags, loc);
\r
4959 if (!(ml is MethodGroupExpr)) {
\r
4960 ml.Error118 ("method group");
\r
4965 Error (-6, "New invocation: Can not find a constructor for " +
\r
4966 "this argument list");
\r
4970 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
\r
4972 if (new_method == null) {
\r
4973 Error (-6, "New invocation: Can not find a constructor for " +
\r
4974 "this argument list");
\r
4978 eclass = ExprClass.Value;
\r
4981 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
4982 ArrayList args = new ArrayList ();
\r
4984 if (arguments != null) {
\r
4985 for (int i = 0; i < arg_count; i++)
\r
4986 args.Add (TypeManager.int32_type);
\r
4989 Type [] arg_types = null;
\r
4991 if (args.Count > 0)
\r
4992 arg_types = new Type [args.Count];
\r
4994 args.CopyTo (arg_types, 0);
\r
4996 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
\r
4999 if (new_method == null) {
\r
5000 Error (-6, "New invocation: Can not find a constructor for " +
\r
5001 "this argument list");
\r
5005 eclass = ExprClass.Value;
\r
5010 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
\r
5015 int count = array_data.Count;
\r
5017 if (underlying_type.IsEnum)
\r
5018 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
\r
5020 factor = GetTypeSize (underlying_type);
\r
5022 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
\r
5024 data = new byte [(count * factor + 4) & ~3];
\r
5027 for (int i = 0; i < count; ++i) {
\r
5028 object v = array_data [i];
\r
5030 if (v is EnumConstant)
\r
5031 v = ((EnumConstant) v).Child;
\r
5033 if (v is Constant && !(v is StringConstant))
\r
5034 v = ((Constant) v).GetValue ();
\r
5040 if (underlying_type == TypeManager.int64_type){
\r
5041 if (!(v is Expression)){
\r
5042 long val = (long) v;
\r
5044 for (int j = 0; j < factor; ++j) {
\r
5045 data [idx + j] = (byte) (val & 0xFF);
\r
5049 } else if (underlying_type == TypeManager.uint64_type){
\r
5050 if (!(v is Expression)){
\r
5051 ulong val = (ulong) v;
\r
5053 for (int j = 0; j < factor; ++j) {
\r
5054 data [idx + j] = (byte) (val & 0xFF);
\r
5058 } else if (underlying_type == TypeManager.float_type) {
\r
5059 if (!(v is Expression)){
\r
5060 element = BitConverter.GetBytes ((float) v);
\r
5062 for (int j = 0; j < factor; ++j)
\r
5063 data [idx + j] = element [j];
\r
5065 } else if (underlying_type == TypeManager.double_type) {
\r
5066 if (!(v is Expression)){
\r
5067 element = BitConverter.GetBytes ((double) v);
\r
5069 for (int j = 0; j < factor; ++j)
\r
5070 data [idx + j] = element [j];
\r
5072 } else if (underlying_type == TypeManager.char_type){
\r
5073 if (!(v is Expression)){
\r
5074 int val = (int) ((char) v);
\r
5076 data [idx] = (byte) (val & 0xff);
\r
5077 data [idx+1] = (byte) (val >> 8);
\r
5079 } else if (underlying_type == TypeManager.short_type){
\r
5080 if (!(v is Expression)){
\r
5081 int val = (int) ((short) v);
\r
5083 data [idx] = (byte) (val & 0xff);
\r
5084 data [idx+1] = (byte) (val >> 8);
\r
5086 } else if (underlying_type == TypeManager.ushort_type){
\r
5087 if (!(v is Expression)){
\r
5088 int val = (int) ((ushort) v);
\r
5090 data [idx] = (byte) (val & 0xff);
\r
5091 data [idx+1] = (byte) (val >> 8);
\r
5093 } else if (underlying_type == TypeManager.int32_type) {
\r
5094 if (!(v is Expression)){
\r
5095 int val = (int) v;
\r
5097 data [idx] = (byte) (val & 0xff);
\r
5098 data [idx+1] = (byte) ((val >> 8) & 0xff);
\r
5099 data [idx+2] = (byte) ((val >> 16) & 0xff);
\r
5100 data [idx+3] = (byte) (val >> 24);
\r
5102 } else if (underlying_type == TypeManager.uint32_type) {
\r
5103 if (!(v is Expression)){
\r
5104 uint val = (uint) v;
\r
5106 data [idx] = (byte) (val & 0xff);
\r
5107 data [idx+1] = (byte) ((val >> 8) & 0xff);
\r
5108 data [idx+2] = (byte) ((val >> 16) & 0xff);
\r
5109 data [idx+3] = (byte) (val >> 24);
\r
5111 } else if (underlying_type == TypeManager.sbyte_type) {
\r
5112 if (!(v is Expression)){
\r
5113 sbyte val = (sbyte) v;
\r
5114 data [idx] = (byte) val;
\r
5116 } else if (underlying_type == TypeManager.byte_type) {
\r
5117 if (!(v is Expression)){
\r
5118 byte val = (byte) v;
\r
5119 data [idx] = (byte) val;
\r
5121 } else if (underlying_type == TypeManager.bool_type) {
\r
5122 if (!(v is Expression)){
\r
5123 bool val = (bool) v;
\r
5124 data [idx] = (byte) (val ? 1 : 0);
\r
5126 } else if (underlying_type == TypeManager.decimal_type){
\r
5127 if (!(v is Expression)){
\r
5128 int [] bits = Decimal.GetBits ((decimal) v);
\r
5131 for (int j = 0; j < 4; j++){
\r
5132 data [p++] = (byte) (bits [j] & 0xff);
\r
5133 data [p++] = (byte) ((bits [j] >> 8) & 0xff);
\r
5134 data [p++] = (byte) ((bits [j] >> 16) & 0xff);
\r
5135 data [p++] = (byte) (bits [j] >> 24);
\r
5139 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
\r
5148 // Emits the initializers for the array
\r
5150 void EmitStaticInitializers (EmitContext ec, bool is_expression)
\r
5153 // First, the static data
\r
5156 ILGenerator ig = ec.ig;
\r
5158 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
\r
5160 fb = RootContext.MakeStaticData (data);
\r
5162 if (is_expression)
\r
5163 ig.Emit (OpCodes.Dup);
\r
5164 ig.Emit (OpCodes.Ldtoken, fb);
\r
5165 ig.Emit (OpCodes.Call,
\r
5166 TypeManager.void_initializearray_array_fieldhandle);
\r
5170 // Emits pieces of the array that can not be computed at compile
\r
5171 // time (variables and string locations).
\r
5173 // This always expect the top value on the stack to be the array
\r
5175 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
\r
5177 ILGenerator ig = ec.ig;
\r
5178 int dims = bounds.Count;
\r
5179 int [] current_pos = new int [dims];
\r
5180 int top = array_data.Count;
\r
5181 LocalBuilder temp = ig.DeclareLocal (type);
\r
5183 ig.Emit (OpCodes.Stloc, temp);
\r
5185 MethodInfo set = null;
\r
5189 ModuleBuilder mb = null;
\r
5190 mb = CodeGen.ModuleBuilder;
\r
5191 args = new Type [dims + 1];
\r
5194 for (j = 0; j < dims; j++)
\r
5195 args [j] = TypeManager.int32_type;
\r
5197 args [j] = array_element_type;
\r
5199 set = mb.GetArrayMethod (
\r
5201 CallingConventions.HasThis | CallingConventions.Standard,
\r
5202 TypeManager.void_type, args);
\r
5205 for (int i = 0; i < top; i++){
\r
5207 Expression e = null;
\r
5209 if (array_data [i] is Expression)
\r
5210 e = (Expression) array_data [i];
\r
5214 // Basically we do this for string literals and
\r
5215 // other non-literal expressions
\r
5217 if (e is StringConstant || !(e is Constant) ||
\r
5218 num_automatic_initializers <= 2) {
\r
5219 Type etype = e.Type;
\r
5221 ig.Emit (OpCodes.Ldloc, temp);
\r
5223 for (int idx = 0; idx < dims; idx++)
\r
5224 IntConstant.EmitInt (ig, current_pos [idx]);
\r
5227 // If we are dealing with a struct, get the
\r
5228 // address of it, so we can store it.
\r
5230 if ((dims == 1) &&
\r
5231 etype.IsSubclassOf (TypeManager.value_type) &&
\r
5232 (!TypeManager.IsBuiltinType (etype) ||
\r
5233 etype == TypeManager.decimal_type)) {
\r
5238 // Let new know that we are providing
\r
5239 // the address where to store the results
\r
5241 n.DisableTemporaryValueType ();
\r
5244 ig.Emit (OpCodes.Ldelema, etype);
\r
5250 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
\r
5252 ig.Emit (OpCodes.Call, set);
\r
5257 // Advance counter
\r
5259 for (int j = dims - 1; j >= 0; j--){
\r
5260 current_pos [j]++;
\r
5261 if (current_pos [j] < (int) bounds [j])
\r
5263 current_pos [j] = 0;
\r
5267 if (is_expression)
\r
5268 ig.Emit (OpCodes.Ldloc, temp);
\r
5271 void EmitArrayArguments (EmitContext ec)
\r
5273 ILGenerator ig = ec.ig;
\r
5275 foreach (Argument a in arguments) {
\r
5276 Type atype = a.Type;
\r
5279 if (atype == TypeManager.uint64_type)
\r
5280 ig.Emit (OpCodes.Conv_Ovf_U4);
\r
5281 else if (atype == TypeManager.int64_type)
\r
5282 ig.Emit (OpCodes.Conv_Ovf_I4);
\r
5286 void DoEmit (EmitContext ec, bool is_statement)
\r
5288 ILGenerator ig = ec.ig;
\r
5290 EmitArrayArguments (ec);
\r
5291 if (is_one_dimensional)
\r
5292 ig.Emit (OpCodes.Newarr, array_element_type);
\r
5294 if (is_builtin_type)
\r
5295 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
\r
5297 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
\r
5300 if (initializers != null){
\r
5302 // FIXME: Set this variable correctly.
\r
5304 bool dynamic_initializers = true;
\r
5306 if (underlying_type != TypeManager.string_type &&
\r
5307 underlying_type != TypeManager.object_type) {
\r
5308 if (num_automatic_initializers > 2)
\r
5309 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
\r
5312 if (dynamic_initializers)
\r
5313 EmitDynamicInitializers (ec, !is_statement);
\r
5317 public override void Emit (EmitContext ec)
\r
5319 DoEmit (ec, false);
\r
5322 public override void EmitStatement (EmitContext ec)
\r
5324 DoEmit (ec, true);
\r
5330 /// Represents the 'this' construct
\r
5332 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
\r
5337 public This (Block block, Location loc)
\r
5340 this.block = block;
\r
5343 public This (Location loc)
\r
5348 public bool IsAssigned (EmitContext ec, Location loc)
\r
5353 return vi.IsAssigned (ec, loc);
\r
5356 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
\r
5361 return vi.IsFieldAssigned (ec, field_name, loc);
\r
5364 public void SetAssigned (EmitContext ec)
\r
5367 vi.SetAssigned (ec);
\r
5370 public void SetFieldAssigned (EmitContext ec, string field_name)
\r
5373 vi.SetFieldAssigned (ec, field_name);
\r
5376 public override Expression DoResolve (EmitContext ec)
\r
5378 eclass = ExprClass.Variable;
\r
5379 type = ec.ContainerType;
\r
5382 Error (26, "Keyword this not valid in static code");
\r
5386 if (block != null)
\r
5387 vi = block.ThisVariable;
\r
5392 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
5396 VariableInfo vi = ec.CurrentBlock.ThisVariable;
\r
5398 vi.SetAssigned (ec);
\r
5400 if (ec.TypeContainer is Class){
\r
5401 Error (1604, "Cannot assign to 'this'");
\r
5408 public override void Emit (EmitContext ec)
\r
5410 ILGenerator ig = ec.ig;
\r
5412 ig.Emit (OpCodes.Ldarg_0);
\r
5413 if (ec.TypeContainer is Struct)
\r
5414 ig.Emit (OpCodes.Ldobj, type);
\r
5417 public void EmitAssign (EmitContext ec, Expression source)
\r
5419 ILGenerator ig = ec.ig;
\r
5421 if (ec.TypeContainer is Struct){
\r
5422 ig.Emit (OpCodes.Ldarg_0);
\r
5424 ig.Emit (OpCodes.Stobj, type);
\r
5427 ig.Emit (OpCodes.Starg, 0);
\r
5431 public void AddressOf (EmitContext ec, AddressOp mode)
\r
5433 ec.ig.Emit (OpCodes.Ldarg_0);
\r
5436 // FIGURE OUT WHY LDARG_S does not work
\r
5438 // consider: struct X { int val; int P { set { val = value; }}}
\r
5440 // Yes, this looks very bad. Look at 'NOTAS' for
\r
5441 // an explanation.
\r
5442 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
\r
5447 /// Implements the typeof operator
\r
5449 public class TypeOf : Expression {
\r
5450 public readonly Expression QueriedType;
\r
5453 public TypeOf (Expression queried_type, Location l)
\r
5455 QueriedType = queried_type;
\r
5459 public override Expression DoResolve (EmitContext ec)
\r
5461 typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
\r
5463 if (typearg == null)
\r
5466 type = TypeManager.type_type;
\r
5467 eclass = ExprClass.Type;
\r
5471 public override void Emit (EmitContext ec)
\r
5473 ec.ig.Emit (OpCodes.Ldtoken, typearg);
\r
5474 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
\r
5477 public Type TypeArg {
\r
5478 get { return typearg; }
\r
5483 /// Implements the sizeof expression
\r
5485 public class SizeOf : Expression {
\r
5486 public readonly Expression QueriedType;
\r
5487 Type type_queried;
\r
5489 public SizeOf (Expression queried_type, Location l)
\r
5491 this.QueriedType = queried_type;
\r
5495 public override Expression DoResolve (EmitContext ec)
\r
5497 if (!ec.InUnsafe) {
\r
5498 Error (233, "Sizeof may only be used in an unsafe context " +
\r
5499 "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
\r
5503 type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
\r
5504 if (type_queried == null)
\r
5507 if (!TypeManager.IsUnmanagedType (type_queried)){
\r
5508 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
\r
5512 type = TypeManager.int32_type;
\r
5513 eclass = ExprClass.Value;
\r
5517 public override void Emit (EmitContext ec)
\r
5519 int size = GetTypeSize (type_queried);
\r
5522 ec.ig.Emit (OpCodes.Sizeof, type_queried);
\r
5524 IntConstant.EmitInt (ec.ig, size);
\r
5529 /// Implements the member access expression
\r
5531 public class MemberAccess : Expression, ITypeExpression {
\r
5532 public readonly string Identifier;
\r
5534 Expression member_lookup;
\r
5536 public MemberAccess (Expression expr, string id, Location l)
\r
5543 public Expression Expr {
\r
5549 static void error176 (Location loc, string name)
\r
5551 Report.Error (176, loc, "Static member '" +
\r
5552 name + "' cannot be accessed " +
\r
5553 "with an instance reference, qualify with a " +
\r
5554 "type name instead");
\r
5557 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
\r
5559 if (left_original == null)
\r
5562 if (!(left_original is SimpleName))
\r
5565 SimpleName sn = (SimpleName) left_original;
\r
5567 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
\r
5574 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
\r
5575 Expression left, Location loc,
\r
5576 Expression left_original)
\r
5578 bool left_is_type, left_is_explicit;
\r
5580 // If 'left' is null, then we're called from SimpleNameResolve and this is
\r
5581 // a member in the currently defining class.
\r
5582 if (left == null) {
\r
5583 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
\r
5584 left_is_explicit = false;
\r
5586 // Implicitly default to 'this' unless we're static.
\r
5587 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
\r
5590 left_is_type = left is TypeExpr;
\r
5591 left_is_explicit = true;
\r
5594 if (member_lookup is FieldExpr){
\r
5595 FieldExpr fe = (FieldExpr) member_lookup;
\r
5596 FieldInfo fi = fe.FieldInfo;
\r
5597 Type decl_type = fi.DeclaringType;
\r
5599 if (fi is FieldBuilder) {
\r
5600 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
\r
5603 object o = c.LookupConstantValue (ec);
\r
5604 object real_value = ((Constant) c.Expr).GetValue ();
\r
5606 return Constantify (real_value, fi.FieldType);
\r
5610 if (fi.IsLiteral) {
\r
5611 Type t = fi.FieldType;
\r
5615 if (fi is FieldBuilder)
\r
5616 o = TypeManager.GetValue ((FieldBuilder) fi);
\r
5618 o = fi.GetValue (fi);
\r
5620 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
\r
5621 if (left_is_explicit && !left_is_type &&
\r
5622 !IdenticalNameAndTypeName (ec, left_original, loc)) {
\r
5623 error176 (loc, fe.FieldInfo.Name);
\r
5627 Expression enum_member = MemberLookup (
\r
5628 ec, decl_type, "value__", MemberTypes.Field,
\r
5629 AllBindingFlags, loc);
\r
5631 Enum en = TypeManager.LookupEnum (decl_type);
\r
5635 c = Constantify (o, en.UnderlyingType);
\r
5637 c = Constantify (o, enum_member.Type);
\r
5639 return new EnumConstant (c, decl_type);
\r
5642 Expression exp = Constantify (o, t);
\r
5644 if (left_is_explicit && !left_is_type) {
\r
5645 error176 (loc, fe.FieldInfo.Name);
\r
5652 if (fi.FieldType.IsPointer && !ec.InUnsafe){
\r
5653 UnsafeError (loc);
\r
5658 if (member_lookup is EventExpr) {
\r
5660 EventExpr ee = (EventExpr) member_lookup;
\r
5663 // If the event is local to this class, we transform ourselves into
\r
5667 if (ee.EventInfo.DeclaringType == ec.ContainerType) {
\r
5668 MemberInfo mi = GetFieldFromEvent (ee);
\r
5672 // If this happens, then we have an event with its own
\r
5673 // accessors and private field etc so there's no need
\r
5674 // to transform ourselves : we should instead flag an error
\r
5676 Assign.error70 (ee.EventInfo, loc);
\r
5680 Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
\r
5683 Report.Error (-200, loc, "Internal error!!");
\r
5687 return ResolveMemberAccess (ec, ml, left, loc, left_original);
\r
5691 if (member_lookup is IMemberExpr) {
\r
5692 IMemberExpr me = (IMemberExpr) member_lookup;
\r
5694 if (left_is_type){
\r
5695 MethodGroupExpr mg = me as MethodGroupExpr;
\r
5696 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
\r
5697 mg.IsExplicitImpl = left_is_explicit;
\r
5699 if (!me.IsStatic){
\r
5700 if (IdenticalNameAndTypeName (ec, left_original, loc))
\r
5701 return member_lookup;
\r
5703 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
\r
5708 if (!me.IsInstance){
\r
5709 if (IdenticalNameAndTypeName (ec, left_original, loc))
\r
5710 return member_lookup;
\r
5712 if (left_is_explicit) {
\r
5713 error176 (loc, me.Name);
\r
5719 // Since we can not check for instance objects in SimpleName,
\r
5720 // becaue of the rule that allows types and variables to share
\r
5721 // the name (as long as they can be de-ambiguated later, see
\r
5722 // IdenticalNameAndTypeName), we have to check whether left
\r
5723 // is an instance variable in a static context
\r
5725 // However, if the left-hand value is explicitly given, then
\r
5726 // it is already our instance expression, so we aren't in
\r
5727 // static context.
\r
5730 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
\r
5731 IMemberExpr mexp = (IMemberExpr) left;
\r
5733 if (!mexp.IsStatic){
\r
5734 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
\r
5739 me.InstanceExpression = left;
\r
5742 return member_lookup;
\r
5745 if (member_lookup is TypeExpr){
\r
5746 member_lookup.Resolve (ec, ResolveFlags.Type);
\r
5747 return member_lookup;
\r
5750 Console.WriteLine ("Left is: " + left);
\r
5751 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
\r
5752 Environment.Exit (0);
\r
5756 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
\r
5759 throw new Exception ();
\r
5761 // Resolve the expression with flow analysis turned off, we'll do the definite
\r
5762 // assignment checks later. This is because we don't know yet what the expression
\r
5763 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
\r
5764 // definite assignment check on the actual field and not on the whole struct.
\r
5767 Expression original = expr;
\r
5768 expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
\r
5773 if (expr is SimpleName){
\r
5774 SimpleName child_expr = (SimpleName) expr;
\r
5776 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
\r
5778 return new_expr.Resolve (ec, flags);
\r
5782 // TODO: I mailed Ravi about this, and apparently we can get rid
\r
5783 // of this and put it in the right place.
\r
5785 // Handle enums here when they are in transit.
\r
5786 // Note that we cannot afford to hit MemberLookup in this case because
\r
5787 // it will fail to find any members at all
\r
5790 int errors = Report.Errors;
\r
5792 Type expr_type = expr.Type;
\r
5793 if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
\r
5795 Enum en = TypeManager.LookupEnum (expr_type);
\r
5798 object value = en.LookupEnumValue (ec, Identifier, loc);
\r
5800 if (value != null){
\r
5801 Constant c = Constantify (value, en.UnderlyingType);
\r
5802 return new EnumConstant (c, expr_type);
\r
5807 if (expr_type.IsPointer){
\r
5808 Error (23, "The '.' operator can not be applied to pointer operands (" +
\r
5809 TypeManager.CSharpName (expr_type) + ")");
\r
5813 member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
\r
5815 if (member_lookup == null)
\r
5817 // Error has already been reported.
\r
5818 if (errors < Report.Errors)
\r
5822 // Try looking the member up from the same type, if we find
\r
5823 // it, we know that the error was due to limited visibility
\r
5825 object lookup = TypeManager.MemberLookup (
\r
5826 expr_type, expr_type, AllMemberTypes, AllBindingFlags |
\r
5827 BindingFlags.NonPublic, Identifier);
\r
5829 if (lookup == null)
\r
5830 Error (117, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
\r
5833 if ((expr_type != ec.ContainerType) &&
\r
5834 ec.ContainerType.IsSubclassOf (expr_type))
\r
5837 // Although a derived class can access protected members of
\r
5838 // its base class it cannot do so through an instance of the
\r
5839 // base class (CS1540). If the expr_type is a parent of the
\r
5840 // ec.ContainerType and the lookup succeeds with the latter one,
\r
5841 // then we are in this situation.
\r
5843 lookup = TypeManager.MemberLookup(
\r
5844 ec.ContainerType, ec.ContainerType, AllMemberTypes,
\r
5845 AllBindingFlags, Identifier);
\r
5847 if (lookup != null)
\r
5848 Error (1540, "Cannot access protected member '" +
\r
5849 expr_type + "." + Identifier + "' " +
\r
5850 "via a qualifier of type '" + TypeManager.CSharpName (expr_type) + "'; the " +
\r
5851 "qualifier must be of type '" + TypeManager.CSharpName (ec.ContainerType) + "' " +
\r
5852 "(or derived from it)");
\r
5854 Error (122, "'" + expr_type + "." + Identifier + "' " +
\r
5855 "is inaccessible because of its protection level");
\r
5857 Error (122, "'" + expr_type + "." + Identifier + "' " +
\r
5858 "is inaccessible because of its protection level");
\r
5863 if (member_lookup is TypeExpr){
\r
5864 member_lookup.Resolve (ec, ResolveFlags.Type);
\r
5865 return member_lookup;
\r
5866 } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
\r
5869 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
\r
5870 if (member_lookup == null)
\r
5873 // The following DoResolve/DoResolveLValue will do the definite assignment
\r
5876 if (right_side != null)
\r
5877 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
\r
5879 member_lookup = member_lookup.DoResolve (ec);
\r
5881 return member_lookup;
\r
5884 public override Expression DoResolve (EmitContext ec)
\r
5886 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
\r
5887 ResolveFlags.SimpleName | ResolveFlags.Type);
\r
5890 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
5892 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
\r
5893 ResolveFlags.SimpleName | ResolveFlags.Type);
\r
5896 public Expression DoResolveType (EmitContext ec)
\r
5898 return DoResolve (ec, null, ResolveFlags.Type);
\r
5901 public override void Emit (EmitContext ec)
\r
5903 throw new Exception ("Should not happen");
\r
5906 public override string ToString ()
\r
5908 return expr + "." + Identifier;
\r
5915 /// Implements checked expressions
\r
5917 public class CheckedExpr : Expression {
\r
5919 public Expression Expr;
\r
5921 public CheckedExpr (Expression e, Location l)
\r
5927 public override Expression DoResolve (EmitContext ec)
\r
5929 bool last_const_check = ec.ConstantCheckState;
\r
5931 ec.ConstantCheckState = true;
\r
5932 Expr = Expr.Resolve (ec);
\r
5933 ec.ConstantCheckState = last_const_check;
\r
5938 if (Expr is Constant)
\r
5941 eclass = Expr.eclass;
\r
5946 public override void Emit (EmitContext ec)
\r
5948 bool last_check = ec.CheckState;
\r
5949 bool last_const_check = ec.ConstantCheckState;
\r
5951 ec.CheckState = true;
\r
5952 ec.ConstantCheckState = true;
\r
5954 ec.CheckState = last_check;
\r
5955 ec.ConstantCheckState = last_const_check;
\r
5961 /// Implements the unchecked expression
\r
5963 public class UnCheckedExpr : Expression {
\r
5965 public Expression Expr;
\r
5967 public UnCheckedExpr (Expression e, Location l)
\r
5973 public override Expression DoResolve (EmitContext ec)
\r
5975 bool last_const_check = ec.ConstantCheckState;
\r
5977 ec.ConstantCheckState = false;
\r
5978 Expr = Expr.Resolve (ec);
\r
5979 ec.ConstantCheckState = last_const_check;
\r
5984 if (Expr is Constant)
\r
5987 eclass = Expr.eclass;
\r
5992 public override void Emit (EmitContext ec)
\r
5994 bool last_check = ec.CheckState;
\r
5995 bool last_const_check = ec.ConstantCheckState;
\r
5997 ec.CheckState = false;
\r
5998 ec.ConstantCheckState = false;
\r
6000 ec.CheckState = last_check;
\r
6001 ec.ConstantCheckState = last_const_check;
\r
6007 /// An Element Access expression.
\r
6009 /// During semantic analysis these are transformed into
\r
6010 /// IndexerAccess or ArrayAccess
\r
6012 public class ElementAccess : Expression {
\r
6013 public ArrayList Arguments;
\r
6014 public Expression Expr;
\r
6016 public ElementAccess (Expression e, ArrayList e_list, Location l)
\r
6022 if (e_list == null)
\r
6025 Arguments = new ArrayList ();
\r
6026 foreach (Expression tmp in e_list)
\r
6027 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
\r
6031 bool CommonResolve (EmitContext ec)
\r
6033 Expr = Expr.Resolve (ec);
\r
6035 if (Expr == null)
\r
6038 if (Arguments == null)
\r
6041 foreach (Argument a in Arguments){
\r
6042 if (!a.Resolve (ec, loc))
\r
6049 Expression MakePointerAccess ()
\r
6051 Type t = Expr.Type;
\r
6053 if (t == TypeManager.void_ptr_type){
\r
6056 "The array index operation is not valid for void pointers");
\r
6059 if (Arguments.Count != 1){
\r
6062 "A pointer must be indexed by a single value");
\r
6065 Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
\r
6067 return new Indirection (p, loc);
\r
6070 public override Expression DoResolve (EmitContext ec)
\r
6072 if (!CommonResolve (ec))
\r
6076 // We perform some simple tests, and then to "split" the emit and store
\r
6077 // code we create an instance of a different class, and return that.
\r
6079 // I am experimenting with this pattern.
\r
6081 Type t = Expr.Type;
\r
6084 return (new ArrayAccess (this, loc)).Resolve (ec);
\r
6085 else if (t.IsPointer)
\r
6086 return MakePointerAccess ();
\r
6088 return (new IndexerAccess (this, loc)).Resolve (ec);
\r
6091 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
6093 if (!CommonResolve (ec))
\r
6096 Type t = Expr.Type;
\r
6098 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
\r
6099 else if (t.IsPointer)
\r
6100 return MakePointerAccess ();
\r
6102 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
\r
6105 public override void Emit (EmitContext ec)
\r
6107 throw new Exception ("Should never be reached");
\r
6112 /// Implements array access
\r
6114 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
\r
6116 // Points to our "data" repository
\r
6120 LocalTemporary [] cached_locations;
\r
6122 public ArrayAccess (ElementAccess ea_data, Location l)
\r
6125 eclass = ExprClass.Variable;
\r
6129 public override Expression DoResolve (EmitContext ec)
\r
6131 ExprClass eclass = ea.Expr.eclass;
\r
6134 // As long as the type is valid
\r
6135 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
\r
6136 eclass == ExprClass.Value)) {
\r
6137 ea.Expr.Error118 ("variable or value");
\r
6142 Type t = ea.Expr.Type;
\r
6144 if (t == typeof (System.Object))
\r
6146 // We can't resolve now, but we
\r
6147 // have to try to access the array with a call
\r
6148 // to LateIndexGet in the runtime
\r
6150 Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
\r
6151 Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
\r
6152 ArrayList adims = new ArrayList();
\r
6154 ArrayList ainit = new ArrayList();
\r
6155 foreach (Argument a in ea.Arguments)
\r
6156 ainit.Add ((Expression) a.Expr);
\r
6158 adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));
\r
6160 Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
\r
6162 ArrayList args = new ArrayList();
\r
6163 args.Add (new Argument(ea.Expr, Argument.AType.Expression));
\r
6164 args.Add (new Argument(oace, Argument.AType.Expression));
\r
6165 args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
\r
6167 Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
\r
6168 lig_call = lig_call.Resolve(ec);
\r
6172 if (t.GetArrayRank () != ea.Arguments.Count){
\r
6174 "Incorrect number of indexes for array " +
\r
6175 " expected: " + t.GetArrayRank () + " got: " +
\r
6176 ea.Arguments.Count);
\r
6179 type = TypeManager.TypeToCoreType (t.GetElementType ());
\r
6180 if (type.IsPointer && !ec.InUnsafe){
\r
6181 UnsafeError (ea.Location);
\r
6185 foreach (Argument a in ea.Arguments){
\r
6186 Type argtype = a.Type;
\r
6188 if (argtype == TypeManager.int32_type ||
\r
6189 argtype == TypeManager.uint32_type ||
\r
6190 argtype == TypeManager.int64_type ||
\r
6191 argtype == TypeManager.uint64_type)
\r
6195 // Mhm. This is strage, because the Argument.Type is not the same as
\r
6196 // Argument.Expr.Type: the value changes depending on the ref/out setting.
\r
6198 // Wonder if I will run into trouble for this.
\r
6200 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
\r
6201 if (a.Expr == null)
\r
6205 eclass = ExprClass.Variable;
\r
6211 /// Emits the right opcode to load an object of Type 't'
\r
6212 /// from an array of T
\r
6214 static public void EmitLoadOpcode (ILGenerator ig, Type type)
\r
6216 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
\r
6217 ig.Emit (OpCodes.Ldelem_U1);
\r
6218 else if (type == TypeManager.sbyte_type)
\r
6219 ig.Emit (OpCodes.Ldelem_I1);
\r
6220 else if (type == TypeManager.short_type)
\r
6221 ig.Emit (OpCodes.Ldelem_I2);
\r
6222 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
\r
6223 ig.Emit (OpCodes.Ldelem_U2);
\r
6224 else if (type == TypeManager.int32_type)
\r
6225 ig.Emit (OpCodes.Ldelem_I4);
\r
6226 else if (type == TypeManager.uint32_type)
\r
6227 ig.Emit (OpCodes.Ldelem_U4);
\r
6228 else if (type == TypeManager.uint64_type)
\r
6229 ig.Emit (OpCodes.Ldelem_I8);
\r
6230 else if (type == TypeManager.int64_type)
\r
6231 ig.Emit (OpCodes.Ldelem_I8);
\r
6232 else if (type == TypeManager.float_type)
\r
6233 ig.Emit (OpCodes.Ldelem_R4);
\r
6234 else if (type == TypeManager.double_type)
\r
6235 ig.Emit (OpCodes.Ldelem_R8);
\r
6236 else if (type == TypeManager.intptr_type)
\r
6237 ig.Emit (OpCodes.Ldelem_I);
\r
6238 else if (type.IsValueType){
\r
6239 ig.Emit (OpCodes.Ldelema, type);
\r
6240 ig.Emit (OpCodes.Ldobj, type);
\r
6242 ig.Emit (OpCodes.Ldelem_Ref);
\r
6246 /// Emits the right opcode to store an object of Type 't'
\r
6247 /// from an array of T.
\r
6249 static public void EmitStoreOpcode (ILGenerator ig, Type t)
\r
6251 t = TypeManager.TypeToCoreType (t);
\r
6252 if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
\r
6253 t = TypeManager.EnumToUnderlying (t);
\r
6254 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
\r
6255 t == TypeManager.bool_type)
\r
6256 ig.Emit (OpCodes.Stelem_I1);
\r
6257 else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
\r
6258 ig.Emit (OpCodes.Stelem_I2);
\r
6259 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
\r
6260 ig.Emit (OpCodes.Stelem_I4);
\r
6261 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
\r
6262 ig.Emit (OpCodes.Stelem_I8);
\r
6263 else if (t == TypeManager.float_type)
\r
6264 ig.Emit (OpCodes.Stelem_R4);
\r
6265 else if (t == TypeManager.double_type)
\r
6266 ig.Emit (OpCodes.Stelem_R8);
\r
6267 else if (t == TypeManager.intptr_type)
\r
6268 ig.Emit (OpCodes.Stelem_I);
\r
6269 else if (t.IsValueType){
\r
6270 ig.Emit (OpCodes.Stobj, t);
\r
6272 ig.Emit (OpCodes.Stelem_Ref);
\r
6275 MethodInfo FetchGetMethod ()
\r
6277 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
6278 int arg_count = ea.Arguments.Count;
\r
6279 Type [] args = new Type [arg_count];
\r
6282 for (int i = 0; i < arg_count; i++){
\r
6283 //args [i++] = a.Type;
\r
6284 args [i] = TypeManager.int32_type;
\r
6287 get = mb.GetArrayMethod (
\r
6288 ea.Expr.Type, "Get",
\r
6289 CallingConventions.HasThis |
\r
6290 CallingConventions.Standard,
\r
6296 MethodInfo FetchAddressMethod ()
\r
6298 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
6299 int arg_count = ea.Arguments.Count;
\r
6300 Type [] args = new Type [arg_count];
\r
6301 MethodInfo address;
\r
6302 string ptr_type_name;
\r
6305 ptr_type_name = type.FullName + "&";
\r
6306 ret_type = Type.GetType (ptr_type_name);
\r
6309 // It is a type defined by the source code we are compiling
\r
6311 if (ret_type == null){
\r
6312 ret_type = mb.GetType (ptr_type_name);
\r
6315 for (int i = 0; i < arg_count; i++){
\r
6316 //args [i++] = a.Type;
\r
6317 args [i] = TypeManager.int32_type;
\r
6320 address = mb.GetArrayMethod (
\r
6321 ea.Expr.Type, "Address",
\r
6322 CallingConventions.HasThis |
\r
6323 CallingConventions.Standard,
\r
6330 // Load the array arguments into the stack.
\r
6332 // If we have been requested to cache the values (cached_locations array
\r
6333 // initialized), then load the arguments the first time and store them
\r
6334 // in locals. otherwise load from local variables.
\r
6336 void LoadArrayAndArguments (EmitContext ec)
\r
6338 ILGenerator ig = ec.ig;
\r
6340 if (cached_locations == null){
\r
6341 ea.Expr.Emit (ec);
\r
6342 foreach (Argument a in ea.Arguments){
\r
6343 Type argtype = a.Expr.Type;
\r
6347 if (argtype == TypeManager.int64_type)
\r
6348 ig.Emit (OpCodes.Conv_Ovf_I);
\r
6349 else if (argtype == TypeManager.uint64_type)
\r
6350 ig.Emit (OpCodes.Conv_Ovf_I_Un);
\r
6355 if (cached_locations [0] == null){
\r
6356 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
\r
6357 ea.Expr.Emit (ec);
\r
6358 ig.Emit (OpCodes.Dup);
\r
6359 cached_locations [0].Store (ec);
\r
6363 foreach (Argument a in ea.Arguments){
\r
6364 Type argtype = a.Expr.Type;
\r
6366 cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
\r
6368 if (argtype == TypeManager.int64_type)
\r
6369 ig.Emit (OpCodes.Conv_Ovf_I);
\r
6370 else if (argtype == TypeManager.uint64_type)
\r
6371 ig.Emit (OpCodes.Conv_Ovf_I_Un);
\r
6373 ig.Emit (OpCodes.Dup);
\r
6374 cached_locations [j].Store (ec);
\r
6380 foreach (LocalTemporary lt in cached_locations)
\r
6384 public new void CacheTemporaries (EmitContext ec)
\r
6386 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
\r
6389 public override void Emit (EmitContext ec)
\r
6391 int rank = ea.Expr.Type.GetArrayRank ();
\r
6392 ILGenerator ig = ec.ig;
\r
6394 LoadArrayAndArguments (ec);
\r
6397 EmitLoadOpcode (ig, type);
\r
6399 MethodInfo method;
\r
6401 method = FetchGetMethod ();
\r
6402 ig.Emit (OpCodes.Call, method);
\r
6406 public void EmitAssign (EmitContext ec, Expression source)
\r
6408 int rank = ea.Expr.Type.GetArrayRank ();
\r
6409 ILGenerator ig = ec.ig;
\r
6410 Type t = source.Type;
\r
6412 LoadArrayAndArguments (ec);
\r
6415 // The stobj opcode used by value types will need
\r
6416 // an address on the stack, not really an array/array
\r
6420 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
\r
6421 (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
\r
6422 ig.Emit (OpCodes.Ldelema, t);
\r
6428 EmitStoreOpcode (ig, t);
\r
6430 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
6431 int arg_count = ea.Arguments.Count;
\r
6432 Type [] args = new Type [arg_count + 1];
\r
6435 for (int i = 0; i < arg_count; i++){
\r
6436 //args [i++] = a.Type;
\r
6437 args [i] = TypeManager.int32_type;
\r
6440 args [arg_count] = type;
\r
6442 set = mb.GetArrayMethod (
\r
6443 ea.Expr.Type, "Set",
\r
6444 CallingConventions.HasThis |
\r
6445 CallingConventions.Standard,
\r
6446 TypeManager.void_type, args);
\r
6448 ig.Emit (OpCodes.Call, set);
\r
6452 public void AddressOf (EmitContext ec, AddressOp mode)
\r
6454 int rank = ea.Expr.Type.GetArrayRank ();
\r
6455 ILGenerator ig = ec.ig;
\r
6457 LoadArrayAndArguments (ec);
\r
6460 ig.Emit (OpCodes.Ldelema, type);
\r
6462 MethodInfo address = FetchAddressMethod ();
\r
6463 ig.Emit (OpCodes.Call, address);
\r
6470 public ArrayList getters, setters;
\r
6471 static Hashtable map;
\r
6473 static Indexers ()
\r
6475 map = new Hashtable ();
\r
6478 Indexers (MemberInfo [] mi)
\r
6480 foreach (PropertyInfo property in mi){
\r
6481 MethodInfo get, set;
\r
6483 get = property.GetGetMethod (true);
\r
6485 if (getters == null)
\r
6486 getters = new ArrayList ();
\r
6488 getters.Add (get);
\r
6491 set = property.GetSetMethod (true);
\r
6493 if (setters == null)
\r
6494 setters = new ArrayList ();
\r
6495 setters.Add (set);
\r
6500 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
\r
6502 Indexers ix = (Indexers) map [lookup_type];
\r
6507 string p_name = TypeManager.IndexerPropertyName (lookup_type);
\r
6509 MemberInfo [] mi = TypeManager.MemberLookup (
\r
6510 caller_type, lookup_type, MemberTypes.Property,
\r
6511 BindingFlags.Public | BindingFlags.Instance, p_name);
\r
6513 if (mi == null || mi.Length == 0)
\r
6516 ix = new Indexers (mi);
\r
6517 map [lookup_type] = ix;
\r
6522 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
\r
6524 Indexers ix = (Indexers) map [lookup_type];
\r
6529 ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
\r
6533 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
\r
6534 if (ifaces != null) {
\r
6535 foreach (Type itype in ifaces) {
\r
6536 ix = GetIndexersForTypeOrInterface (caller_type, itype);
\r
6542 Report.Error (21, loc,
\r
6543 "Type '" + TypeManager.CSharpName (lookup_type) +
\r
6544 "' does not have any indexers defined");
\r
6550 /// Expressions that represent an indexer call.
\r
6552 public class IndexerAccess : Expression, IAssignMethod {
\r
6554 // Points to our "data" repository
\r
6556 MethodInfo get, set;
\r
6558 ArrayList set_arguments;
\r
6559 bool is_base_indexer;
\r
6561 protected Type indexer_type;
\r
6562 protected Type current_type;
\r
6563 protected Expression instance_expr;
\r
6564 protected ArrayList arguments;
\r
6566 public IndexerAccess (ElementAccess ea, Location loc)
\r
6567 : this (ea.Expr, false, loc)
\r
6569 this.arguments = ea.Arguments;
\r
6572 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
\r
6575 this.instance_expr = instance_expr;
\r
6576 this.is_base_indexer = is_base_indexer;
\r
6577 this.eclass = ExprClass.Value;
\r
6581 protected virtual bool CommonResolve (EmitContext ec)
\r
6583 indexer_type = instance_expr.Type;
\r
6584 current_type = ec.ContainerType;
\r
6589 public override Expression DoResolve (EmitContext ec)
\r
6591 if (!CommonResolve (ec))
\r
6595 // Step 1: Query for all 'Item' *properties*. Notice
\r
6596 // that the actual methods are pointed from here.
\r
6598 // This is a group of properties, piles of them.
\r
6600 if (ilist == null)
\r
6601 ilist = Indexers.GetIndexersForType (
\r
6602 current_type, indexer_type, loc);
\r
6605 // Step 2: find the proper match
\r
6607 if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
\r
6608 get = (MethodInfo) Invocation.OverloadResolve (
\r
6609 ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
\r
6612 Error (154, "indexer can not be used in this context, because " +
\r
6613 "it lacks a 'get' accessor");
\r
6617 type = get.ReturnType;
\r
6618 if (type.IsPointer && !ec.InUnsafe){
\r
6619 UnsafeError (loc);
\r
6623 eclass = ExprClass.IndexerAccess;
\r
6627 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
\r
6629 if (!CommonResolve (ec))
\r
6632 Type right_type = right_side.Type;
\r
6634 if (ilist == null)
\r
6635 ilist = Indexers.GetIndexersForType (
\r
6636 current_type, indexer_type, loc);
\r
6638 if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
\r
6639 set_arguments = (ArrayList) arguments.Clone ();
\r
6640 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
\r
6642 set = (MethodInfo) Invocation.OverloadResolve (
\r
6643 ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
\r
6647 Error (200, "indexer X.this [" + TypeManager.CSharpName (right_type) +
\r
6648 "] lacks a 'set' accessor");
\r
6652 type = TypeManager.void_type;
\r
6653 eclass = ExprClass.IndexerAccess;
\r
6657 public override void Emit (EmitContext ec)
\r
6659 Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
\r
6663 // source is ignored, because we already have a copy of it from the
\r
6664 // LValue resolution and we have already constructed a pre-cached
\r
6665 // version of the arguments (ea.set_arguments);
\r
6667 public void EmitAssign (EmitContext ec, Expression source)
\r
6669 Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
\r
6674 /// The base operator for method names
\r
6676 public class BaseAccess : Expression {
\r
6679 public BaseAccess (string member, Location l)
\r
6681 this.member = member;
\r
6685 public override Expression DoResolve (EmitContext ec)
\r
6687 Expression member_lookup;
\r
6688 Type current_type = ec.ContainerType;
\r
6689 Type base_type = current_type.BaseType;
\r
6693 Error (1511, "Keyword MyBase is not allowed in static method");
\r
6697 if (member == "New")
\r
6700 member_lookup = MemberLookup (ec, base_type, base_type, member,
\r
6701 AllMemberTypes, AllBindingFlags, loc);
\r
6703 if (member_lookup == null) {
\r
6705 TypeManager.CSharpName (base_type) + " does not " +
\r
6706 "contain a definition for '" + member + "'");
\r
6713 left = new TypeExpr (base_type, loc);
\r
6717 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
\r
6719 if (e is PropertyExpr){
\r
6720 PropertyExpr pe = (PropertyExpr) e;
\r
6728 public override void Emit (EmitContext ec)
\r
6730 throw new Exception ("Should never be called");
\r
6735 /// The base indexer operator
\r
6737 public class BaseIndexerAccess : IndexerAccess {
\r
6738 public BaseIndexerAccess (ArrayList args, Location loc)
\r
6739 : base (null, true, loc)
\r
6741 arguments = new ArrayList ();
\r
6742 foreach (Expression tmp in args)
\r
6743 arguments.Add (new Argument (tmp, Argument.AType.Expression));
\r
6746 protected override bool CommonResolve (EmitContext ec)
\r
6748 instance_expr = ec.This;
\r
6750 current_type = ec.ContainerType.BaseType;
\r
6751 indexer_type = current_type;
\r
6753 foreach (Argument a in arguments){
\r
6754 if (!a.Resolve (ec, loc))
\r
6763 /// This class exists solely to pass the Type around and to be a dummy
\r
6764 /// that can be passed to the conversion functions (this is used by
\r
6765 /// foreach implementation to typecast the object return value from
\r
6766 /// get_Current into the proper type. All code has been generated and
\r
6767 /// we only care about the side effect conversions to be performed
\r
6769 /// This is also now used as a placeholder where a no-action expression
\r
6770 /// is needed (the 'New' class).
\r
6772 public class EmptyExpression : Expression {
\r
6773 public EmptyExpression ()
\r
6775 type = TypeManager.object_type;
\r
6776 eclass = ExprClass.Value;
\r
6777 loc = Location.Null;
\r
6780 public EmptyExpression (Type t)
\r
6783 eclass = ExprClass.Value;
\r
6784 loc = Location.Null;
\r
6787 public override Expression DoResolve (EmitContext ec)
\r
6792 public override void Emit (EmitContext ec)
\r
6794 // nothing, as we only exist to not do anything.
\r
6798 // This is just because we might want to reuse this bad boy
\r
6799 // instead of creating gazillions of EmptyExpressions.
\r
6800 // (CanConvertImplicit uses it)
\r
6802 public void SetType (Type t)
\r
6808 public class UserCast : Expression {
\r
6809 MethodBase method;
\r
6810 Expression source;
\r
6812 public UserCast (MethodInfo method, Expression source, Location l)
\r
6814 this.method = method;
\r
6815 this.source = source;
\r
6816 type = method.ReturnType;
\r
6817 eclass = ExprClass.Value;
\r
6821 public override Expression DoResolve (EmitContext ec)
\r
6824 // We are born fully resolved
\r
6829 public override void Emit (EmitContext ec)
\r
6831 ILGenerator ig = ec.ig;
\r
6835 if (method is MethodInfo)
\r
6836 ig.Emit (OpCodes.Call, (MethodInfo) method);
\r
6838 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
\r
6844 // This class is used to "construct" the type during a typecast
\r
6845 // operation. Since the Type.GetType class in .NET can parse
\r
6846 // the type specification, we just use this to construct the type
\r
6847 // one bit at a time.
\r
6849 public class ComposedCast : Expression, ITypeExpression {
\r
6853 public ComposedCast (Expression left, string dim, Location l)
\r
6860 public Expression DoResolveType (EmitContext ec)
\r
6862 Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
\r
6863 if (ltype == null)
\r
6867 // ltype.Fullname is already fully qualified, so we can skip
\r
6868 // a lot of probes, and go directly to TypeManager.LookupType
\r
6870 string cname = ltype.FullName + dim;
\r
6871 type = TypeManager.LookupTypeDirect (cname);
\r
6872 if (type == null){
\r
6874 // For arrays of enumerations we are having a problem
\r
6875 // with the direct lookup. Need to investigate.
\r
6877 // For now, fall back to the full lookup in that case.
\r
6879 type = RootContext.LookupType (
\r
6880 ec.DeclSpace, cname, false, loc);
\r
6886 if (!ec.ResolvingTypeTree){
\r
6888 // If the above flag is set, this is being invoked from the ResolveType function.
\r
6889 // Upper layers take care of the type validity in this context.
\r
6891 if (!ec.InUnsafe && type.IsPointer){
\r
6892 UnsafeError (loc);
\r
6897 eclass = ExprClass.Type;
\r
6901 public override Expression DoResolve (EmitContext ec)
\r
6903 return DoResolveType (ec);
\r
6906 public override void Emit (EmitContext ec)
\r
6908 throw new Exception ("This should never be called");
\r
6911 public override string ToString ()
\r
6913 return left + dim;
\r
6918 // This class is used to represent the address of an array, used
\r
6919 // only by the Fixed statement, this is like the C "&a [0]" construct.
\r
6921 public class ArrayPtr : Expression {
\r
6924 public ArrayPtr (Expression array, Location l)
\r
6926 Type array_type = array.Type.GetElementType ();
\r
6928 this.array = array;
\r
6930 string array_ptr_type_name = array_type.FullName + "*";
\r
6932 type = Type.GetType (array_ptr_type_name);
\r
6933 if (type == null){
\r
6934 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
6936 type = mb.GetType (array_ptr_type_name);
\r
6939 eclass = ExprClass.Value;
\r
6943 public override void Emit (EmitContext ec)
\r
6945 ILGenerator ig = ec.ig;
\r
6948 IntLiteral.EmitInt (ig, 0);
\r
6949 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
\r
6952 public override Expression DoResolve (EmitContext ec)
\r
6955 // We are born fully resolved
\r
6962 // Used by the fixed statement
\r
6964 public class StringPtr : Expression {
\r
6967 public StringPtr (LocalBuilder b, Location l)
\r
6970 eclass = ExprClass.Value;
\r
6971 type = TypeManager.char_ptr_type;
\r
6975 public override Expression DoResolve (EmitContext ec)
\r
6977 // This should never be invoked, we are born in fully
\r
6978 // initialized state.
\r
6983 public override void Emit (EmitContext ec)
\r
6985 ILGenerator ig = ec.ig;
\r
6987 ig.Emit (OpCodes.Ldloc, b);
\r
6988 ig.Emit (OpCodes.Conv_I);
\r
6989 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
\r
6990 ig.Emit (OpCodes.Add);
\r
6995 // Implements the 'stackalloc' keyword
\r
6997 public class StackAlloc : Expression {
\r
7002 public StackAlloc (Expression type, Expression count, Location l)
\r
7005 this.count = count;
\r
7009 public override Expression DoResolve (EmitContext ec)
\r
7011 count = count.Resolve (ec);
\r
7012 if (count == null)
\r
7015 if (count.Type != TypeManager.int32_type){
\r
7016 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
\r
7017 if (count == null)
\r
7021 if (ec.InCatch || ec.InFinally){
\r
7023 "stackalloc can not be used in a catch or finally block");
\r
7027 otype = ec.DeclSpace.ResolveType (t, false, loc);
\r
7029 if (otype == null)
\r
7032 if (!TypeManager.VerifyUnManaged (otype, loc))
\r
7035 string ptr_name = otype.FullName + "*";
\r
7036 type = Type.GetType (ptr_name);
\r
7037 if (type == null){
\r
7038 ModuleBuilder mb = CodeGen.ModuleBuilder;
\r
7040 type = mb.GetType (ptr_name);
\r
7042 eclass = ExprClass.Value;
\r
7047 public override void Emit (EmitContext ec)
\r
7049 int size = GetTypeSize (otype);
\r
7050 ILGenerator ig = ec.ig;
\r
7053 ig.Emit (OpCodes.Sizeof, otype);
\r
7055 IntConstant.EmitInt (ig, size);
\r
7057 ig.Emit (OpCodes.Mul);
\r
7058 ig.Emit (OpCodes.Localloc);
\r