2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// This is just a helper class, it is generated by Unary, UnaryMutator
22 /// when an overloaded method has been found. It just emits the code for a
25 public class StaticCallExpr : ExpressionStatement {
29 StaticCallExpr (MethodInfo m, ArrayList a)
35 eclass = ExprClass.Value;
38 public override Expression DoResolve (EmitContext ec)
41 // We are born fully resolved
46 public override void Emit (EmitContext ec)
49 Invocation.EmitArguments (ec, mi, args);
51 ec.ig.Emit (OpCodes.Call, mi);
55 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
56 Expression e, Location loc)
61 args = new ArrayList (1);
62 args.Add (new Argument (e, Argument.AType.Expression));
63 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
68 return new StaticCallExpr ((MethodInfo) method, args);
71 public override void EmitStatement (EmitContext ec)
74 if (type != TypeManager.void_type)
75 ec.ig.Emit (OpCodes.Pop);
80 /// Unary expressions.
84 /// Unary implements unary expressions. It derives from
85 /// ExpressionStatement becuase the pre/post increment/decrement
86 /// operators can be used in a statement context.
88 public class Unary : Expression {
89 public enum Operator : byte {
90 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
91 Indirection, AddressOf, TOP
95 public Expression Expr;
98 public Unary (Operator op, Expression expr, Location loc)
106 /// Returns a stringified representation of the Operator
108 static public string OperName (Operator oper)
111 case Operator.UnaryPlus:
113 case Operator.UnaryNegation:
115 case Operator.LogicalNot:
117 case Operator.OnesComplement:
119 case Operator.AddressOf:
121 case Operator.Indirection:
125 return oper.ToString ();
128 static string [] oper_names;
132 oper_names = new string [(int)Operator.TOP];
134 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
135 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
136 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
137 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
138 oper_names [(int) Operator.Indirection] = "op_Indirection";
139 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
142 void Error23 (Type t)
145 23, loc, "Operator " + OperName (Oper) +
146 " cannot be applied to operand of type `" +
147 TypeManager.CSharpName (t) + "'");
151 /// The result has been already resolved:
153 /// FIXME: a minus constant -128 sbyte cant be turned into a
156 static Expression TryReduceNegative (Expression expr)
160 if (expr is IntConstant)
161 e = new IntConstant (-((IntConstant) expr).Value);
162 else if (expr is UIntConstant){
163 uint value = ((UIntConstant) expr).Value;
165 if (value < 2147483649)
166 return new IntConstant (-(int)value);
168 e = new LongConstant (value);
170 else if (expr is LongConstant)
171 e = new LongConstant (-((LongConstant) expr).Value);
172 else if (expr is FloatConstant)
173 e = new FloatConstant (-((FloatConstant) expr).Value);
174 else if (expr is DoubleConstant)
175 e = new DoubleConstant (-((DoubleConstant) expr).Value);
176 else if (expr is DecimalConstant)
177 e = new DecimalConstant (-((DecimalConstant) expr).Value);
178 else if (expr is ShortConstant)
179 e = new IntConstant (-((ShortConstant) expr).Value);
180 else if (expr is UShortConstant)
181 e = new IntConstant (-((UShortConstant) expr).Value);
185 Expression Reduce (EmitContext ec, Expression e)
187 Type expr_type = e.Type;
190 case Operator.UnaryPlus:
193 case Operator.UnaryNegation:
194 return TryReduceNegative (e);
196 case Operator.LogicalNot:
197 if (expr_type != TypeManager.bool_type) {
202 BoolConstant b = (BoolConstant) e;
203 return new BoolConstant (!(b.Value));
205 case Operator.OnesComplement:
206 if (!((expr_type == TypeManager.int32_type) ||
207 (expr_type == TypeManager.uint32_type) ||
208 (expr_type == TypeManager.int64_type) ||
209 (expr_type == TypeManager.uint64_type) ||
210 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
215 if (e is EnumConstant){
216 EnumConstant enum_constant = (EnumConstant) e;
218 Expression reduced = Reduce (ec, enum_constant.Child);
220 return new EnumConstant ((Constant) reduced, enum_constant.Type);
223 if (expr_type == TypeManager.int32_type)
224 return new IntConstant (~ ((IntConstant) e).Value);
225 if (expr_type == TypeManager.uint32_type)
226 return new UIntConstant (~ ((UIntConstant) e).Value);
227 if (expr_type == TypeManager.int64_type)
228 return new LongConstant (~ ((LongConstant) e).Value);
229 if (expr_type == TypeManager.uint64_type)
230 return new ULongConstant (~ ((ULongConstant) e).Value);
235 throw new Exception ("Can not constant fold");
238 Expression ResolveOperator (EmitContext ec)
240 Type expr_type = Expr.Type;
243 // Step 1: Perform Operator Overload location
248 op_name = oper_names [(int) Oper];
250 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
253 Expression e = StaticCallExpr.MakeSimpleCall (
254 ec, (MethodGroupExpr) mg, Expr, loc);
264 // Only perform numeric promotions on:
267 if (expr_type == null)
271 // Step 2: Default operations on CLI native types.
273 if (Expr is Constant)
274 return Reduce (ec, Expr);
276 if (Oper == Operator.LogicalNot){
277 if (expr_type != TypeManager.bool_type) {
282 type = TypeManager.bool_type;
286 if (Oper == Operator.OnesComplement) {
287 if (!((expr_type == TypeManager.int32_type) ||
288 (expr_type == TypeManager.uint32_type) ||
289 (expr_type == TypeManager.int64_type) ||
290 (expr_type == TypeManager.uint64_type) ||
291 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
294 e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
296 type = TypeManager.int32_type;
299 e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
301 type = TypeManager.uint32_type;
304 e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
306 type = TypeManager.int64_type;
309 e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
311 type = TypeManager.uint64_type;
321 if (Oper == Operator.UnaryPlus) {
323 // A plus in front of something is just a no-op, so return the child.
329 // Deals with -literals
330 // int operator- (int x)
331 // long operator- (long x)
332 // float operator- (float f)
333 // double operator- (double d)
334 // decimal operator- (decimal d)
336 if (Oper == Operator.UnaryNegation){
340 // transform - - expr into expr
343 Unary unary = (Unary) Expr;
345 if (unary.Oper == Operator.UnaryNegation)
350 // perform numeric promotions to int,
354 // The following is inneficient, because we call
355 // ConvertImplicit too many times.
357 // It is also not clear if we should convert to Float
358 // or Double initially.
360 if (expr_type == TypeManager.uint32_type){
362 // FIXME: handle exception to this rule that
363 // permits the int value -2147483648 (-2^31) to
364 // bt wrote as a decimal interger literal
366 type = TypeManager.int64_type;
367 Expr = ConvertImplicit (ec, Expr, type, loc);
371 if (expr_type == TypeManager.uint64_type){
373 // FIXME: Handle exception of `long value'
374 // -92233720368547758087 (-2^63) to be wrote as
375 // decimal integer literal.
381 if (expr_type == TypeManager.float_type){
386 e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
393 e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
400 e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
411 if (Oper == Operator.AddressOf){
412 if (Expr.eclass != ExprClass.Variable){
413 Error (211, loc, "Cannot take the address of non-variables");
422 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
427 // This construct is needed because dynamic types
428 // are not known by Type.GetType, so we have to try then to use
429 // ModuleBuilder.GetType.
431 string ptr_type_name = Expr.Type.FullName + "*";
432 type = Type.GetType (ptr_type_name);
434 type = CodeGen.ModuleBuilder.GetType (ptr_type_name);
439 if (Oper == Operator.Indirection){
445 if (!expr_type.IsPointer){
448 "The * or -> operator can only be applied to pointers");
453 // We create an Indirection expression, because
454 // it can implement the IMemoryLocation.
456 return new Indirection (Expr);
459 Error (187, loc, "No such operator '" + OperName (Oper) + "' defined for type '" +
460 TypeManager.CSharpName (expr_type) + "'");
464 public override Expression DoResolve (EmitContext ec)
466 Expr = Expr.Resolve (ec);
471 eclass = ExprClass.Value;
472 return ResolveOperator (ec);
475 public override void Emit (EmitContext ec)
477 ILGenerator ig = ec.ig;
478 Type expr_type = Expr.Type;
481 case Operator.UnaryPlus:
482 throw new Exception ("This should be caught by Resolve");
484 case Operator.UnaryNegation:
486 ig.Emit (OpCodes.Neg);
489 case Operator.LogicalNot:
491 ig.Emit (OpCodes.Ldc_I4_0);
492 ig.Emit (OpCodes.Ceq);
495 case Operator.OnesComplement:
497 ig.Emit (OpCodes.Not);
500 case Operator.AddressOf:
501 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
505 throw new Exception ("This should not happen: Operator = "
511 /// This will emit the child expression for `ec' avoiding the logical
512 /// not. The parent will take care of changing brfalse/brtrue
514 public void EmitLogicalNot (EmitContext ec)
516 if (Oper != Operator.LogicalNot)
517 throw new Exception ("EmitLogicalNot can only be called with !expr");
522 public override string ToString ()
524 return "Unary (" + Oper + ", " + Expr + ")";
530 // Unary operators are turned into Indirection expressions
531 // after semantic analysis (this is so we can take the address
532 // of an indirection).
534 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
536 LocalTemporary temporary;
539 public Indirection (Expression expr)
542 this.type = expr.Type.GetElementType ();
543 eclass = ExprClass.Variable;
546 void LoadExprValue (EmitContext ec)
550 public override void Emit (EmitContext ec)
552 ILGenerator ig = ec.ig;
554 if (temporary != null){
560 ec.ig.Emit (OpCodes.Dup);
561 temporary.Store (ec);
562 have_temporary = true;
566 LoadFromPtr (ig, Type);
569 public void EmitAssign (EmitContext ec, Expression source)
571 if (temporary != null){
577 ec.ig.Emit (OpCodes.Dup);
578 temporary.Store (ec);
579 have_temporary = true;
584 StoreFromPtr (ec.ig, type);
587 public void AddressOf (EmitContext ec, AddressOp Mode)
589 if (temporary != null){
595 ec.ig.Emit (OpCodes.Dup);
596 temporary.Store (ec);
597 have_temporary = true;
602 public override Expression DoResolve (EmitContext ec)
605 // Born fully resolved
610 public new void CacheTemporaries (EmitContext ec)
612 temporary = new LocalTemporary (ec, type);
617 /// Unary Mutator expressions (pre and post ++ and --)
621 /// UnaryMutator implements ++ and -- expressions. It derives from
622 /// ExpressionStatement becuase the pre/post increment/decrement
623 /// operators can be used in a statement context.
625 /// FIXME: Idea, we could split this up in two classes, one simpler
626 /// for the common case, and one with the extra fields for more complex
627 /// classes (indexers require temporary access; overloaded require method)
629 /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
630 /// PostDecrement, that way we could save the `Mode' byte as well.
632 public class UnaryMutator : ExpressionStatement {
633 public enum Mode : byte {
634 PreIncrement, PreDecrement, PostIncrement, PostDecrement
640 LocalTemporary temp_storage;
643 // This is expensive for the simplest case.
647 public UnaryMutator (Mode m, Expression e, Location l)
654 static string OperName (Mode mode)
656 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
660 void Error23 (Type t)
663 23, loc, "Operator " + OperName (mode) +
664 " cannot be applied to operand of type `" +
665 TypeManager.CSharpName (t) + "'");
669 /// Returns whether an object of type `t' can be incremented
670 /// or decremented with add/sub (ie, basically whether we can
671 /// use pre-post incr-decr operations on it, but it is not a
672 /// System.Decimal, which we require operator overloading to catch)
674 static bool IsIncrementableNumber (Type t)
676 return (t == TypeManager.sbyte_type) ||
677 (t == TypeManager.byte_type) ||
678 (t == TypeManager.short_type) ||
679 (t == TypeManager.ushort_type) ||
680 (t == TypeManager.int32_type) ||
681 (t == TypeManager.uint32_type) ||
682 (t == TypeManager.int64_type) ||
683 (t == TypeManager.uint64_type) ||
684 (t == TypeManager.char_type) ||
685 (t.IsSubclassOf (TypeManager.enum_type)) ||
686 (t == TypeManager.float_type) ||
687 (t == TypeManager.double_type) ||
688 (t.IsPointer && t != TypeManager.void_ptr_type);
691 Expression ResolveOperator (EmitContext ec)
693 Type expr_type = expr.Type;
696 // Step 1: Perform Operator Overload location
701 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
702 op_name = "op_Increment";
704 op_name = "op_Decrement";
706 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
708 if (mg == null && expr_type.BaseType != null)
709 mg = MemberLookup (ec, expr_type.BaseType, op_name,
710 MemberTypes.Method, AllBindingFlags, loc);
713 method = StaticCallExpr.MakeSimpleCall (
714 ec, (MethodGroupExpr) mg, expr, loc);
721 // The operand of the prefix/postfix increment decrement operators
722 // should be an expression that is classified as a variable,
723 // a property access or an indexer access
726 if (expr.eclass == ExprClass.Variable){
727 if (IsIncrementableNumber (expr_type) ||
728 expr_type == TypeManager.decimal_type){
731 } else if (expr.eclass == ExprClass.IndexerAccess){
732 IndexerAccess ia = (IndexerAccess) expr;
734 temp_storage = new LocalTemporary (ec, expr.Type);
736 expr = ia.ResolveLValue (ec, temp_storage);
741 } else if (expr.eclass == ExprClass.PropertyAccess){
742 PropertyExpr pe = (PropertyExpr) expr;
744 if (pe.VerifyAssignable ())
749 report118 (loc, expr, "variable, indexer or property access");
753 Error (187, loc, "No such operator '" + OperName (mode) + "' defined for type '" +
754 TypeManager.CSharpName (expr_type) + "'");
758 public override Expression DoResolve (EmitContext ec)
760 expr = expr.Resolve (ec);
765 eclass = ExprClass.Value;
766 return ResolveOperator (ec);
769 static int PtrTypeSize (Type t)
771 return GetTypeSize (t.GetElementType ());
775 // Loads the proper "1" into the stack based on the type
777 static void LoadOne (ILGenerator ig, Type t)
779 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
780 ig.Emit (OpCodes.Ldc_I8, 1L);
781 else if (t == TypeManager.double_type)
782 ig.Emit (OpCodes.Ldc_R8, 1.0);
783 else if (t == TypeManager.float_type)
784 ig.Emit (OpCodes.Ldc_R4, 1.0F);
785 else if (t.IsPointer){
786 int n = PtrTypeSize (t);
789 ig.Emit (OpCodes.Sizeof, t);
791 IntConstant.EmitInt (ig, n);
793 ig.Emit (OpCodes.Ldc_I4_1);
798 // FIXME: We need some way of avoiding the use of temp_storage
799 // for some types of storage (parameters, local variables,
800 // static fields) and single-dimension array access.
802 void EmitCode (EmitContext ec, bool is_expr)
804 ILGenerator ig = ec.ig;
805 IAssignMethod ia = (IAssignMethod) expr;
806 Type expr_type = expr.Type;
808 if (temp_storage == null)
809 temp_storage = new LocalTemporary (ec, expr_type);
811 ia.CacheTemporaries (ec);
812 ig.Emit (OpCodes.Nop);
814 case Mode.PreIncrement:
815 case Mode.PreDecrement:
819 LoadOne (ig, expr_type);
822 // Select the opcode based on the check state (then the type)
823 // and the actual operation
826 if (expr_type == TypeManager.int32_type ||
827 expr_type == TypeManager.int64_type){
828 if (mode == Mode.PreDecrement)
829 ig.Emit (OpCodes.Sub_Ovf);
831 ig.Emit (OpCodes.Add_Ovf);
832 } else if (expr_type == TypeManager.uint32_type ||
833 expr_type == TypeManager.uint64_type){
834 if (mode == Mode.PreDecrement)
835 ig.Emit (OpCodes.Sub_Ovf_Un);
837 ig.Emit (OpCodes.Add_Ovf_Un);
839 if (mode == Mode.PreDecrement)
840 ig.Emit (OpCodes.Sub_Ovf);
842 ig.Emit (OpCodes.Add_Ovf);
845 if (mode == Mode.PreDecrement)
846 ig.Emit (OpCodes.Sub);
848 ig.Emit (OpCodes.Add);
853 temp_storage.Store (ec);
854 ia.EmitAssign (ec, temp_storage);
856 temp_storage.Emit (ec);
859 case Mode.PostIncrement:
860 case Mode.PostDecrement:
868 ig.Emit (OpCodes.Dup);
870 LoadOne (ig, expr_type);
873 if (expr_type == TypeManager.int32_type ||
874 expr_type == TypeManager.int64_type){
875 if (mode == Mode.PostDecrement)
876 ig.Emit (OpCodes.Sub_Ovf);
878 ig.Emit (OpCodes.Add_Ovf);
879 } else if (expr_type == TypeManager.uint32_type ||
880 expr_type == TypeManager.uint64_type){
881 if (mode == Mode.PostDecrement)
882 ig.Emit (OpCodes.Sub_Ovf_Un);
884 ig.Emit (OpCodes.Add_Ovf_Un);
886 if (mode == Mode.PostDecrement)
887 ig.Emit (OpCodes.Sub_Ovf);
889 ig.Emit (OpCodes.Add_Ovf);
892 if (mode == Mode.PostDecrement)
893 ig.Emit (OpCodes.Sub);
895 ig.Emit (OpCodes.Add);
901 temp_storage.Store (ec);
902 ia.EmitAssign (ec, temp_storage);
907 public override void Emit (EmitContext ec)
913 public override void EmitStatement (EmitContext ec)
915 EmitCode (ec, false);
921 /// Base class for the `Is' and `As' classes.
925 /// FIXME: Split this in two, and we get to save the `Operator' Oper
928 public abstract class Probe : Expression {
929 public readonly string ProbeType;
930 protected Expression expr;
931 protected Type probe_type;
932 protected Location loc;
934 public Probe (Expression expr, string probe_type, Location l)
936 ProbeType = probe_type;
941 public Expression Expr {
947 public override Expression DoResolve (EmitContext ec)
949 probe_type = RootContext.LookupType (ec.DeclSpace, ProbeType, false, loc);
951 if (probe_type == null)
954 expr = expr.Resolve (ec);
961 /// Implementation of the `is' operator.
963 public class Is : Probe {
964 public Is (Expression expr, string probe_type, Location l)
965 : base (expr, probe_type, l)
970 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
975 public override void Emit (EmitContext ec)
977 ILGenerator ig = ec.ig;
982 case Action.AlwaysFalse:
983 ig.Emit (OpCodes.Pop);
984 IntConstant.EmitInt (ig, 0);
986 case Action.AlwaysTrue:
987 ig.Emit (OpCodes.Pop);
988 ig.Emit (OpCodes.Nop);
989 IntConstant.EmitInt (ig, 1);
991 case Action.LeaveOnStack:
992 // the `e != null' rule.
995 ig.Emit (OpCodes.Isinst, probe_type);
996 ig.Emit (OpCodes.Ldnull);
997 ig.Emit (OpCodes.Cgt_Un);
1000 throw new Exception ("never reached");
1003 public override Expression DoResolve (EmitContext ec)
1005 Expression e = base.DoResolve (ec);
1010 Type etype = expr.Type;
1011 bool warning_always_matches = false;
1012 bool warning_never_matches = false;
1014 type = TypeManager.bool_type;
1015 eclass = ExprClass.Value;
1018 // First case, if at compile time, there is an implicit conversion
1019 // then e != null (objects) or true (value types)
1021 e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1024 if (etype.IsValueType)
1025 action = Action.AlwaysTrue;
1027 action = Action.LeaveOnStack;
1029 warning_always_matches = true;
1030 } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1032 // Second case: explicit reference convresion
1034 if (expr is NullLiteral)
1035 action = Action.AlwaysFalse;
1037 action = Action.Probe;
1039 action = Action.AlwaysFalse;
1040 warning_never_matches = true;
1043 if (RootContext.WarningLevel >= 1){
1044 if (warning_always_matches)
1047 "The expression is always of type `" +
1048 TypeManager.CSharpName (probe_type) + "'");
1049 else if (warning_never_matches){
1050 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1053 "The expression is never of type `" +
1054 TypeManager.CSharpName (probe_type) + "'");
1063 /// Implementation of the `as' operator.
1065 public class As : Probe {
1066 public As (Expression expr, string probe_type, Location l)
1067 : base (expr, probe_type, l)
1071 bool do_isinst = false;
1073 public override void Emit (EmitContext ec)
1075 ILGenerator ig = ec.ig;
1080 ig.Emit (OpCodes.Isinst, probe_type);
1083 static void Error_CannotConvertType (Type source, Type target, Location loc)
1086 39, loc, "as operator can not convert from `" +
1087 TypeManager.CSharpName (source) + "' to `" +
1088 TypeManager.CSharpName (target) + "'");
1091 public override Expression DoResolve (EmitContext ec)
1093 Expression e = base.DoResolve (ec);
1099 eclass = ExprClass.Value;
1100 Type etype = expr.Type;
1102 e = ConvertImplicit (ec, expr, probe_type, loc);
1109 if (ExplicitReferenceConversionExists (etype, probe_type)){
1114 Error_CannotConvertType (etype, probe_type, loc);
1120 /// This represents a typecast in the source language.
1122 /// FIXME: Cast expressions have an unusual set of parsing
1123 /// rules, we need to figure those out.
1125 public class Cast : Expression {
1126 Expression target_type;
1130 public Cast (Expression cast_type, Expression expr, Location loc)
1132 this.target_type = cast_type;
1137 public Expression TargetType {
1143 public Expression Expr {
1153 /// Attempts to do a compile-time folding of a constant cast.
1155 Expression TryReduce (EmitContext ec, Type target_type)
1157 if (expr is ByteConstant){
1158 byte v = ((ByteConstant) expr).Value;
1160 if (target_type == TypeManager.sbyte_type)
1161 return new SByteConstant ((sbyte) v);
1162 if (target_type == TypeManager.short_type)
1163 return new ShortConstant ((short) v);
1164 if (target_type == TypeManager.ushort_type)
1165 return new UShortConstant ((ushort) v);
1166 if (target_type == TypeManager.int32_type)
1167 return new IntConstant ((int) v);
1168 if (target_type == TypeManager.uint32_type)
1169 return new UIntConstant ((uint) v);
1170 if (target_type == TypeManager.int64_type)
1171 return new LongConstant ((long) v);
1172 if (target_type == TypeManager.uint64_type)
1173 return new ULongConstant ((ulong) v);
1174 if (target_type == TypeManager.float_type)
1175 return new FloatConstant ((float) v);
1176 if (target_type == TypeManager.double_type)
1177 return new DoubleConstant ((double) v);
1179 if (expr is SByteConstant){
1180 sbyte v = ((SByteConstant) expr).Value;
1182 if (target_type == TypeManager.byte_type)
1183 return new ByteConstant ((byte) v);
1184 if (target_type == TypeManager.short_type)
1185 return new ShortConstant ((short) v);
1186 if (target_type == TypeManager.ushort_type)
1187 return new UShortConstant ((ushort) v);
1188 if (target_type == TypeManager.int32_type)
1189 return new IntConstant ((int) v);
1190 if (target_type == TypeManager.uint32_type)
1191 return new UIntConstant ((uint) v);
1192 if (target_type == TypeManager.int64_type)
1193 return new LongConstant ((long) v);
1194 if (target_type == TypeManager.uint64_type)
1195 return new ULongConstant ((ulong) v);
1196 if (target_type == TypeManager.float_type)
1197 return new FloatConstant ((float) v);
1198 if (target_type == TypeManager.double_type)
1199 return new DoubleConstant ((double) v);
1201 if (expr is ShortConstant){
1202 short v = ((ShortConstant) expr).Value;
1204 if (target_type == TypeManager.byte_type)
1205 return new ByteConstant ((byte) v);
1206 if (target_type == TypeManager.sbyte_type)
1207 return new SByteConstant ((sbyte) v);
1208 if (target_type == TypeManager.ushort_type)
1209 return new UShortConstant ((ushort) v);
1210 if (target_type == TypeManager.int32_type)
1211 return new IntConstant ((int) v);
1212 if (target_type == TypeManager.uint32_type)
1213 return new UIntConstant ((uint) v);
1214 if (target_type == TypeManager.int64_type)
1215 return new LongConstant ((long) v);
1216 if (target_type == TypeManager.uint64_type)
1217 return new ULongConstant ((ulong) v);
1218 if (target_type == TypeManager.float_type)
1219 return new FloatConstant ((float) v);
1220 if (target_type == TypeManager.double_type)
1221 return new DoubleConstant ((double) v);
1223 if (expr is UShortConstant){
1224 ushort v = ((UShortConstant) expr).Value;
1226 if (target_type == TypeManager.byte_type)
1227 return new ByteConstant ((byte) v);
1228 if (target_type == TypeManager.sbyte_type)
1229 return new SByteConstant ((sbyte) v);
1230 if (target_type == TypeManager.short_type)
1231 return new ShortConstant ((short) v);
1232 if (target_type == TypeManager.int32_type)
1233 return new IntConstant ((int) v);
1234 if (target_type == TypeManager.uint32_type)
1235 return new UIntConstant ((uint) v);
1236 if (target_type == TypeManager.int64_type)
1237 return new LongConstant ((long) v);
1238 if (target_type == TypeManager.uint64_type)
1239 return new ULongConstant ((ulong) v);
1240 if (target_type == TypeManager.float_type)
1241 return new FloatConstant ((float) v);
1242 if (target_type == TypeManager.double_type)
1243 return new DoubleConstant ((double) v);
1245 if (expr is IntConstant){
1246 int v = ((IntConstant) expr).Value;
1248 if (target_type == TypeManager.byte_type)
1249 return new ByteConstant ((byte) v);
1250 if (target_type == TypeManager.sbyte_type)
1251 return new SByteConstant ((sbyte) v);
1252 if (target_type == TypeManager.short_type)
1253 return new ShortConstant ((short) v);
1254 if (target_type == TypeManager.ushort_type)
1255 return new UShortConstant ((ushort) v);
1256 if (target_type == TypeManager.uint32_type)
1257 return new UIntConstant ((uint) v);
1258 if (target_type == TypeManager.int64_type)
1259 return new LongConstant ((long) v);
1260 if (target_type == TypeManager.uint64_type)
1261 return new ULongConstant ((ulong) v);
1262 if (target_type == TypeManager.float_type)
1263 return new FloatConstant ((float) v);
1264 if (target_type == TypeManager.double_type)
1265 return new DoubleConstant ((double) v);
1267 if (expr is UIntConstant){
1268 uint v = ((UIntConstant) expr).Value;
1270 if (target_type == TypeManager.byte_type)
1271 return new ByteConstant ((byte) v);
1272 if (target_type == TypeManager.sbyte_type)
1273 return new SByteConstant ((sbyte) v);
1274 if (target_type == TypeManager.short_type)
1275 return new ShortConstant ((short) v);
1276 if (target_type == TypeManager.ushort_type)
1277 return new UShortConstant ((ushort) v);
1278 if (target_type == TypeManager.int32_type)
1279 return new IntConstant ((int) v);
1280 if (target_type == TypeManager.int64_type)
1281 return new LongConstant ((long) v);
1282 if (target_type == TypeManager.uint64_type)
1283 return new ULongConstant ((ulong) v);
1284 if (target_type == TypeManager.float_type)
1285 return new FloatConstant ((float) v);
1286 if (target_type == TypeManager.double_type)
1287 return new DoubleConstant ((double) v);
1289 if (expr is LongConstant){
1290 long v = ((LongConstant) expr).Value;
1292 if (target_type == TypeManager.byte_type)
1293 return new ByteConstant ((byte) v);
1294 if (target_type == TypeManager.sbyte_type)
1295 return new SByteConstant ((sbyte) v);
1296 if (target_type == TypeManager.short_type)
1297 return new ShortConstant ((short) v);
1298 if (target_type == TypeManager.ushort_type)
1299 return new UShortConstant ((ushort) v);
1300 if (target_type == TypeManager.int32_type)
1301 return new IntConstant ((int) v);
1302 if (target_type == TypeManager.uint32_type)
1303 return new UIntConstant ((uint) v);
1304 if (target_type == TypeManager.uint64_type)
1305 return new ULongConstant ((ulong) v);
1306 if (target_type == TypeManager.float_type)
1307 return new FloatConstant ((float) v);
1308 if (target_type == TypeManager.double_type)
1309 return new DoubleConstant ((double) v);
1311 if (expr is ULongConstant){
1312 ulong v = ((ULongConstant) expr).Value;
1314 if (target_type == TypeManager.byte_type)
1315 return new ByteConstant ((byte) v);
1316 if (target_type == TypeManager.sbyte_type)
1317 return new SByteConstant ((sbyte) v);
1318 if (target_type == TypeManager.short_type)
1319 return new ShortConstant ((short) v);
1320 if (target_type == TypeManager.ushort_type)
1321 return new UShortConstant ((ushort) v);
1322 if (target_type == TypeManager.int32_type)
1323 return new IntConstant ((int) v);
1324 if (target_type == TypeManager.uint32_type)
1325 return new UIntConstant ((uint) v);
1326 if (target_type == TypeManager.int64_type)
1327 return new LongConstant ((long) v);
1328 if (target_type == TypeManager.float_type)
1329 return new FloatConstant ((float) v);
1330 if (target_type == TypeManager.double_type)
1331 return new DoubleConstant ((double) v);
1333 if (expr is FloatConstant){
1334 float v = ((FloatConstant) expr).Value;
1336 if (target_type == TypeManager.byte_type)
1337 return new ByteConstant ((byte) v);
1338 if (target_type == TypeManager.sbyte_type)
1339 return new SByteConstant ((sbyte) v);
1340 if (target_type == TypeManager.short_type)
1341 return new ShortConstant ((short) v);
1342 if (target_type == TypeManager.ushort_type)
1343 return new UShortConstant ((ushort) v);
1344 if (target_type == TypeManager.int32_type)
1345 return new IntConstant ((int) v);
1346 if (target_type == TypeManager.uint32_type)
1347 return new UIntConstant ((uint) v);
1348 if (target_type == TypeManager.int64_type)
1349 return new LongConstant ((long) v);
1350 if (target_type == TypeManager.uint64_type)
1351 return new ULongConstant ((ulong) v);
1352 if (target_type == TypeManager.double_type)
1353 return new DoubleConstant ((double) v);
1355 if (expr is DoubleConstant){
1356 double v = ((DoubleConstant) expr).Value;
1358 if (target_type == TypeManager.byte_type)
1359 return new ByteConstant ((byte) v);
1360 if (target_type == TypeManager.sbyte_type)
1361 return new SByteConstant ((sbyte) v);
1362 if (target_type == TypeManager.short_type)
1363 return new ShortConstant ((short) v);
1364 if (target_type == TypeManager.ushort_type)
1365 return new UShortConstant ((ushort) v);
1366 if (target_type == TypeManager.int32_type)
1367 return new IntConstant ((int) v);
1368 if (target_type == TypeManager.uint32_type)
1369 return new UIntConstant ((uint) v);
1370 if (target_type == TypeManager.int64_type)
1371 return new LongConstant ((long) v);
1372 if (target_type == TypeManager.uint64_type)
1373 return new ULongConstant ((ulong) v);
1374 if (target_type == TypeManager.float_type)
1375 return new FloatConstant ((float) v);
1381 public override Expression DoResolve (EmitContext ec)
1383 expr = expr.Resolve (ec);
1387 bool old_state = ec.OnlyLookupTypes;
1388 ec.OnlyLookupTypes = true;
1389 target_type = target_type.Resolve (ec);
1390 ec.OnlyLookupTypes = old_state;
1392 if (target_type == null){
1393 Report.Error (-10, loc, "Can not resolve type");
1397 if (target_type.eclass != ExprClass.Type){
1398 report118 (loc, target_type, "class");
1402 type = target_type.Type;
1403 eclass = ExprClass.Value;
1408 if (expr is Constant){
1409 Expression e = TryReduce (ec, type);
1415 expr = ConvertExplicit (ec, expr, type, loc);
1419 public override void Emit (EmitContext ec)
1422 // This one will never happen
1424 throw new Exception ("Should not happen");
1429 /// Binary operators
1431 public class Binary : Expression {
1432 public enum Operator : byte {
1433 Multiply, Division, Modulus,
1434 Addition, Subtraction,
1435 LeftShift, RightShift,
1436 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1437 Equality, Inequality,
1447 Expression left, right;
1450 // After resolution, method might contain the operator overload
1453 protected MethodBase method;
1454 ArrayList Arguments;
1458 bool DelegateOperation;
1460 // This must be kept in sync with Operator!!!
1461 static string [] oper_names;
1465 oper_names = new string [(int) Operator.TOP];
1467 oper_names [(int) Operator.Multiply] = "op_Multiply";
1468 oper_names [(int) Operator.Division] = "op_Division";
1469 oper_names [(int) Operator.Modulus] = "op_Modulus";
1470 oper_names [(int) Operator.Addition] = "op_Addition";
1471 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1472 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1473 oper_names [(int) Operator.RightShift] = "op_RightShift";
1474 oper_names [(int) Operator.LessThan] = "op_LessThan";
1475 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1476 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1477 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1478 oper_names [(int) Operator.Equality] = "op_Equality";
1479 oper_names [(int) Operator.Inequality] = "op_Inequality";
1480 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1481 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1482 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1483 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1484 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1487 public Binary (Operator oper, Expression left, Expression right, Location loc)
1495 public Operator Oper {
1504 public Expression Left {
1513 public Expression Right {
1524 /// Returns a stringified representation of the Operator
1526 static string OperName (Operator oper)
1529 case Operator.Multiply:
1531 case Operator.Division:
1533 case Operator.Modulus:
1535 case Operator.Addition:
1537 case Operator.Subtraction:
1539 case Operator.LeftShift:
1541 case Operator.RightShift:
1543 case Operator.LessThan:
1545 case Operator.GreaterThan:
1547 case Operator.LessThanOrEqual:
1549 case Operator.GreaterThanOrEqual:
1551 case Operator.Equality:
1553 case Operator.Inequality:
1555 case Operator.BitwiseAnd:
1557 case Operator.BitwiseOr:
1559 case Operator.ExclusiveOr:
1561 case Operator.LogicalOr:
1563 case Operator.LogicalAnd:
1567 return oper.ToString ();
1570 public override string ToString ()
1572 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1573 right.ToString () + ")";
1576 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1578 if (expr.Type == target_type)
1581 return ConvertImplicit (ec, expr, target_type, new Location (-1));
1584 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1587 34, loc, "Operator `" + OperName (oper)
1588 + "' is ambiguous on operands of type `"
1589 + TypeManager.CSharpName (l) + "' "
1590 + "and `" + TypeManager.CSharpName (r)
1595 // Note that handling the case l == Decimal || r == Decimal
1596 // is taken care of by the Step 1 Operator Overload resolution.
1598 bool DoNumericPromotions (EmitContext ec, Type l, Type r)
1600 if (l == TypeManager.double_type || r == TypeManager.double_type){
1602 // If either operand is of type double, the other operand is
1603 // conveted to type double.
1605 if (r != TypeManager.double_type)
1606 right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
1607 if (l != TypeManager.double_type)
1608 left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
1610 type = TypeManager.double_type;
1611 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1613 // if either operand is of type float, the other operand is
1614 // converted to type float.
1616 if (r != TypeManager.double_type)
1617 right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
1618 if (l != TypeManager.double_type)
1619 left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
1620 type = TypeManager.float_type;
1621 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
1625 // If either operand is of type ulong, the other operand is
1626 // converted to type ulong. or an error ocurrs if the other
1627 // operand is of type sbyte, short, int or long
1629 if (l == TypeManager.uint64_type){
1630 if (r != TypeManager.uint64_type){
1631 if (right is IntConstant){
1632 IntConstant ic = (IntConstant) right;
1634 e = TryImplicitIntConversion (l, ic);
1637 } else if (right is LongConstant){
1638 long ll = ((LongConstant) right).Value;
1641 right = new ULongConstant ((ulong) ll);
1643 e = ImplicitNumericConversion (ec, right, l, loc);
1650 if (left is IntConstant){
1651 e = TryImplicitIntConversion (r, (IntConstant) left);
1654 } else if (left is LongConstant){
1655 long ll = ((LongConstant) left).Value;
1658 left = new ULongConstant ((ulong) ll);
1660 e = ImplicitNumericConversion (ec, left, r, loc);
1667 if ((other == TypeManager.sbyte_type) ||
1668 (other == TypeManager.short_type) ||
1669 (other == TypeManager.int32_type) ||
1670 (other == TypeManager.int64_type))
1671 Error_OperatorAmbiguous (loc, oper, l, r);
1672 type = TypeManager.uint64_type;
1673 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1675 // If either operand is of type long, the other operand is converted
1678 if (l != TypeManager.int64_type)
1679 left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
1680 if (r != TypeManager.int64_type)
1681 right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
1683 type = TypeManager.int64_type;
1684 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1686 // If either operand is of type uint, and the other
1687 // operand is of type sbyte, short or int, othe operands are
1688 // converted to type long.
1692 if (l == TypeManager.uint32_type){
1693 if (right is IntConstant){
1694 IntConstant ic = (IntConstant) right;
1698 right = new UIntConstant ((uint) val);
1705 else if (r == TypeManager.uint32_type){
1706 if (left is IntConstant){
1707 IntConstant ic = (IntConstant) left;
1711 left = new UIntConstant ((uint) val);
1720 if ((other == TypeManager.sbyte_type) ||
1721 (other == TypeManager.short_type) ||
1722 (other == TypeManager.int32_type)){
1723 left = ForceConversion (ec, left, TypeManager.int64_type);
1724 right = ForceConversion (ec, right, TypeManager.int64_type);
1725 type = TypeManager.int64_type;
1728 // if either operand is of type uint, the other
1729 // operand is converd to type uint
1731 left = ForceConversion (ec, left, TypeManager.uint32_type);
1732 right = ForceConversion (ec, right, TypeManager.uint32_type);
1733 type = TypeManager.uint32_type;
1735 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1736 if (l != TypeManager.decimal_type)
1737 left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
1738 if (r != TypeManager.decimal_type)
1739 right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
1741 type = TypeManager.decimal_type;
1743 Expression l_tmp, r_tmp;
1745 l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
1749 r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
1756 type = TypeManager.int32_type;
1762 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1765 "Operator " + name + " cannot be applied to operands of type `" +
1766 TypeManager.CSharpName (l) + "' and `" +
1767 TypeManager.CSharpName (r) + "'");
1770 void Error_OperatorCannotBeApplied ()
1772 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1775 static bool is_32_or_64 (Type t)
1777 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1778 t == TypeManager.int64_type || t == TypeManager.uint64_type);
1781 Expression CheckShiftArguments (EmitContext ec)
1785 Type r = right.Type;
1787 e = ForceConversion (ec, right, TypeManager.int32_type);
1789 Error_OperatorCannotBeApplied ();
1794 if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
1795 ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
1796 ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
1797 ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
1803 Error_OperatorCannotBeApplied ();
1807 Expression ResolveOperator (EmitContext ec)
1810 Type r = right.Type;
1812 bool overload_failed = false;
1815 // Step 1: Perform Operator Overload location
1817 Expression left_expr, right_expr;
1819 string op = oper_names [(int) oper];
1821 MethodGroupExpr union;
1822 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
1824 right_expr = MemberLookup (
1825 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
1826 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
1828 union = (MethodGroupExpr) left_expr;
1830 if (union != null) {
1831 Arguments = new ArrayList ();
1832 Arguments.Add (new Argument (left, Argument.AType.Expression));
1833 Arguments.Add (new Argument (right, Argument.AType.Expression));
1835 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
1836 if (method != null) {
1837 MethodInfo mi = (MethodInfo) method;
1839 type = mi.ReturnType;
1842 overload_failed = true;
1847 // Step 2: Default operations on CLI native types.
1851 // Step 0: String concatenation (because overloading will get this wrong)
1853 if (oper == Operator.Addition){
1855 // If any of the arguments is a string, cast to string
1858 if (l == TypeManager.string_type){
1860 if (r == TypeManager.void_type) {
1861 Error_OperatorCannotBeApplied ();
1865 if (r == TypeManager.string_type){
1866 if (left is Constant && right is Constant){
1867 StringConstant ls = (StringConstant) left;
1868 StringConstant rs = (StringConstant) right;
1870 return new StringConstant (
1871 ls.Value + rs.Value);
1875 method = TypeManager.string_concat_string_string;
1878 method = TypeManager.string_concat_object_object;
1879 right = ConvertImplicit (ec, right,
1880 TypeManager.object_type, loc);
1882 type = TypeManager.string_type;
1884 Arguments = new ArrayList ();
1885 Arguments.Add (new Argument (left, Argument.AType.Expression));
1886 Arguments.Add (new Argument (right, Argument.AType.Expression));
1890 } else if (r == TypeManager.string_type){
1893 if (l == TypeManager.void_type) {
1894 Error_OperatorCannotBeApplied ();
1898 method = TypeManager.string_concat_object_object;
1899 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
1900 Arguments = new ArrayList ();
1901 Arguments.Add (new Argument (left, Argument.AType.Expression));
1902 Arguments.Add (new Argument (right, Argument.AType.Expression));
1904 type = TypeManager.string_type;
1910 // Transform a + ( - b) into a - b
1912 if (right is Unary){
1913 Unary right_unary = (Unary) right;
1915 if (right_unary.Oper == Unary.Operator.UnaryNegation){
1916 oper = Operator.Subtraction;
1917 right = right_unary.Expr;
1923 if (oper == Operator.Equality || oper == Operator.Inequality){
1924 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
1925 if (r != TypeManager.bool_type || l != TypeManager.bool_type){
1926 Error_OperatorCannotBeApplied ();
1930 type = TypeManager.bool_type;
1935 // operator != (object a, object b)
1936 // operator == (object a, object b)
1938 // For this to be used, both arguments have to be reference-types.
1939 // Read the rationale on the spec (14.9.6)
1941 // Also, if at compile time we know that the classes do not inherit
1942 // one from the other, then we catch the error there.
1944 if (!(l.IsValueType || r.IsValueType)){
1945 type = TypeManager.bool_type;
1950 if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
1954 // Also, a standard conversion must exist from either one
1956 if (!(StandardConversionExists (left, r) ||
1957 StandardConversionExists (right, l))){
1958 Error_OperatorCannotBeApplied ();
1962 // We are going to have to convert to an object to compare
1964 if (l != TypeManager.object_type)
1965 left = new EmptyCast (left, TypeManager.object_type);
1966 if (r != TypeManager.object_type)
1967 right = new EmptyCast (right, TypeManager.object_type);
1970 // FIXME: CSC here catches errors cs254 and cs252
1976 // Only perform numeric promotions on:
1977 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1979 if (oper == Operator.Addition || oper == Operator.Subtraction) {
1980 if (l.IsSubclassOf (TypeManager.delegate_type) &&
1981 r.IsSubclassOf (TypeManager.delegate_type)) {
1983 Arguments = new ArrayList ();
1984 Arguments.Add (new Argument (left, Argument.AType.Expression));
1985 Arguments.Add (new Argument (right, Argument.AType.Expression));
1987 if (oper == Operator.Addition)
1988 method = TypeManager.delegate_combine_delegate_delegate;
1990 method = TypeManager.delegate_remove_delegate_delegate;
1992 DelegateOperation = true;
1998 // Pointer arithmetic:
2000 // T* operator + (T* x, int y);
2001 // T* operator + (T* x, uint y);
2002 // T* operator + (T* x, long y);
2003 // T* operator + (T* x, ulong y);
2005 // T* operator + (int y, T* x);
2006 // T* operator + (uint y, T *x);
2007 // T* operator + (long y, T *x);
2008 // T* operator + (ulong y, T *x);
2010 // T* operator - (T* x, int y);
2011 // T* operator - (T* x, uint y);
2012 // T* operator - (T* x, long y);
2013 // T* operator - (T* x, ulong y);
2015 // long operator - (T* x, T *y)
2018 if (r.IsPointer && oper == Operator.Subtraction){
2020 return new PointerArithmetic (
2021 false, left, right, TypeManager.int64_type);
2022 } else if (is_32_or_64 (r))
2023 return new PointerArithmetic (
2024 oper == Operator.Addition, left, right, l);
2025 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2026 return new PointerArithmetic (
2027 true, right, left, r);
2031 // Enumeration operators
2033 bool lie = TypeManager.IsEnumType (l);
2034 bool rie = TypeManager.IsEnumType (r);
2039 // operator + (E e, U x)
2041 if (oper == Operator.Addition){
2043 Error_OperatorCannotBeApplied ();
2047 Type enum_type = lie ? l : r;
2048 Type other_type = lie ? r : l;
2049 Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2052 if (underlying_type != other_type){
2053 Error_OperatorCannotBeApplied ();
2062 temp = ConvertImplicit (ec, right, l, loc);
2066 temp = ConvertImplicit (ec, left, r, loc);
2073 if (oper == Operator.Equality || oper == Operator.Inequality ||
2074 oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2075 oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2076 type = TypeManager.bool_type;
2080 if (oper == Operator.BitwiseAnd ||
2081 oper == Operator.BitwiseOr ||
2082 oper == Operator.ExclusiveOr){
2089 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2090 return CheckShiftArguments (ec);
2092 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2093 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
2094 Error_OperatorCannotBeApplied ();
2098 type = TypeManager.bool_type;
2103 // operator & (bool x, bool y)
2104 // operator | (bool x, bool y)
2105 // operator ^ (bool x, bool y)
2107 if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2108 if (oper == Operator.BitwiseAnd ||
2109 oper == Operator.BitwiseOr ||
2110 oper == Operator.ExclusiveOr){
2117 // Pointer comparison
2119 if (l.IsPointer && r.IsPointer){
2120 if (oper == Operator.Equality || oper == Operator.Inequality ||
2121 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2122 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2123 type = TypeManager.bool_type;
2129 // We are dealing with numbers
2131 if (overload_failed){
2132 Error_OperatorCannotBeApplied ();
2136 if (!DoNumericPromotions (ec, l, r)){
2137 Error_OperatorCannotBeApplied ();
2141 if (left == null || right == null)
2145 // reload our cached types if required
2150 if (oper == Operator.BitwiseAnd ||
2151 oper == Operator.BitwiseOr ||
2152 oper == Operator.ExclusiveOr){
2154 if (!((l == TypeManager.int32_type) ||
2155 (l == TypeManager.uint32_type) ||
2156 (l == TypeManager.int64_type) ||
2157 (l == TypeManager.uint64_type)))
2160 Error_OperatorCannotBeApplied ();
2165 if (oper == Operator.Equality ||
2166 oper == Operator.Inequality ||
2167 oper == Operator.LessThanOrEqual ||
2168 oper == Operator.LessThan ||
2169 oper == Operator.GreaterThanOrEqual ||
2170 oper == Operator.GreaterThan){
2171 type = TypeManager.bool_type;
2177 public override Expression DoResolve (EmitContext ec)
2179 left = left.Resolve (ec);
2180 right = right.Resolve (ec);
2182 if (left == null || right == null)
2185 if (left.Type == null)
2186 throw new Exception (
2187 "Resolve returned non null, but did not set the type! (" +
2188 left + ") at Line: " + loc.Row);
2189 if (right.Type == null)
2190 throw new Exception (
2191 "Resolve returned non null, but did not set the type! (" +
2192 right + ") at Line: "+ loc.Row);
2194 eclass = ExprClass.Value;
2196 if (left is Constant && right is Constant){
2197 Expression e = ConstantFold.BinaryFold (
2198 ec, oper, (Constant) left, (Constant) right, loc);
2203 return ResolveOperator (ec);
2206 public bool IsBranchable ()
2208 if (oper == Operator.Equality ||
2209 oper == Operator.Inequality ||
2210 oper == Operator.LessThan ||
2211 oper == Operator.GreaterThan ||
2212 oper == Operator.LessThanOrEqual ||
2213 oper == Operator.GreaterThanOrEqual){
2220 /// This entry point is used by routines that might want
2221 /// to emit a brfalse/brtrue after an expression, and instead
2222 /// they could use a more compact notation.
2224 /// Typically the code would generate l.emit/r.emit, followed
2225 /// by the comparission and then a brtrue/brfalse. The comparissions
2226 /// are sometimes inneficient (there are not as complete as the branches
2227 /// look for the hacks in Emit using double ceqs).
2229 /// So for those cases we provide EmitBranchable that can emit the
2230 /// branch with the test
2232 public void EmitBranchable (EmitContext ec, int target)
2235 bool close_target = false;
2236 ILGenerator ig = ec.ig;
2239 // short-circuit operators
2241 if (oper == Operator.LogicalAnd){
2243 ig.Emit (OpCodes.Brfalse, target);
2245 ig.Emit (OpCodes.Brfalse, target);
2246 } else if (oper == Operator.LogicalOr){
2248 ig.Emit (OpCodes.Brtrue, target);
2250 ig.Emit (OpCodes.Brfalse, target);
2257 case Operator.Equality:
2259 opcode = OpCodes.Beq_S;
2261 opcode = OpCodes.Beq;
2264 case Operator.Inequality:
2266 opcode = OpCodes.Bne_Un_S;
2268 opcode = OpCodes.Bne_Un;
2271 case Operator.LessThan:
2273 opcode = OpCodes.Blt_S;
2275 opcode = OpCodes.Blt;
2278 case Operator.GreaterThan:
2280 opcode = OpCodes.Bgt_S;
2282 opcode = OpCodes.Bgt;
2285 case Operator.LessThanOrEqual:
2287 opcode = OpCodes.Ble_S;
2289 opcode = OpCodes.Ble;
2292 case Operator.GreaterThanOrEqual:
2294 opcode = OpCodes.Bge_S;
2296 opcode = OpCodes.Ble;
2300 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
2301 + oper.ToString ());
2304 ig.Emit (opcode, target);
2307 public override void Emit (EmitContext ec)
2309 ILGenerator ig = ec.ig;
2311 Type r = right.Type;
2314 if (method != null) {
2316 // Note that operators are static anyway
2318 if (Arguments != null)
2319 Invocation.EmitArguments (ec, method, Arguments);
2321 if (method is MethodInfo)
2322 ig.Emit (OpCodes.Call, (MethodInfo) method);
2324 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2326 if (DelegateOperation)
2327 ig.Emit (OpCodes.Castclass, type);
2333 // Handle short-circuit operators differently
2336 if (oper == Operator.LogicalAnd){
2337 Label load_zero = ig.DefineLabel ();
2338 Label end = ig.DefineLabel ();
2341 ig.Emit (OpCodes.Brfalse, load_zero);
2343 ig.Emit (OpCodes.Br, end);
2344 ig.MarkLabel (load_zero);
2345 ig.Emit (OpCodes.Ldc_I4_0);
2348 } else if (oper == Operator.LogicalOr){
2349 Label load_one = ig.DefineLabel ();
2350 Label end = ig.DefineLabel ();
2353 ig.Emit (OpCodes.Brtrue, load_one);
2355 ig.Emit (OpCodes.Br, end);
2356 ig.MarkLabel (load_one);
2357 ig.Emit (OpCodes.Ldc_I4_1);
2366 case Operator.Multiply:
2368 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2369 opcode = OpCodes.Mul_Ovf;
2370 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2371 opcode = OpCodes.Mul_Ovf_Un;
2373 opcode = OpCodes.Mul;
2375 opcode = OpCodes.Mul;
2379 case Operator.Division:
2380 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2381 opcode = OpCodes.Div_Un;
2383 opcode = OpCodes.Div;
2386 case Operator.Modulus:
2387 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2388 opcode = OpCodes.Rem_Un;
2390 opcode = OpCodes.Rem;
2393 case Operator.Addition:
2395 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2396 opcode = OpCodes.Add_Ovf;
2397 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2398 opcode = OpCodes.Add_Ovf_Un;
2400 opcode = OpCodes.Add;
2402 opcode = OpCodes.Add;
2405 case Operator.Subtraction:
2407 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2408 opcode = OpCodes.Sub_Ovf;
2409 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2410 opcode = OpCodes.Sub_Ovf_Un;
2412 opcode = OpCodes.Sub;
2414 opcode = OpCodes.Sub;
2417 case Operator.RightShift:
2418 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2419 opcode = OpCodes.Shr_Un;
2421 opcode = OpCodes.Shr;
2424 case Operator.LeftShift:
2425 opcode = OpCodes.Shl;
2428 case Operator.Equality:
2429 opcode = OpCodes.Ceq;
2432 case Operator.Inequality:
2433 ec.ig.Emit (OpCodes.Ceq);
2434 ec.ig.Emit (OpCodes.Ldc_I4_0);
2436 opcode = OpCodes.Ceq;
2439 case Operator.LessThan:
2440 opcode = OpCodes.Clt;
2443 case Operator.GreaterThan:
2444 opcode = OpCodes.Cgt;
2447 case Operator.LessThanOrEqual:
2448 ec.ig.Emit (OpCodes.Cgt);
2449 ec.ig.Emit (OpCodes.Ldc_I4_0);
2451 opcode = OpCodes.Ceq;
2454 case Operator.GreaterThanOrEqual:
2455 ec.ig.Emit (OpCodes.Clt);
2456 ec.ig.Emit (OpCodes.Ldc_I4_1);
2458 opcode = OpCodes.Sub;
2461 case Operator.BitwiseOr:
2462 opcode = OpCodes.Or;
2465 case Operator.BitwiseAnd:
2466 opcode = OpCodes.And;
2469 case Operator.ExclusiveOr:
2470 opcode = OpCodes.Xor;
2474 throw new Exception ("This should not happen: Operator = "
2475 + oper.ToString ());
2481 public bool IsBuiltinOperator {
2483 return method == null;
2488 public class PointerArithmetic : Expression {
2489 Expression left, right;
2493 // We assume that `l' is always a pointer
2495 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t)
2498 eclass = ExprClass.Variable;
2501 is_add = is_addition;
2504 public override Expression DoResolve (EmitContext ec)
2507 // We are born fully resolved
2512 public override void Emit (EmitContext ec)
2514 Type op_type = left.Type;
2515 ILGenerator ig = ec.ig;
2516 int size = GetTypeSize (op_type.GetElementType ());
2518 if (right.Type.IsPointer){
2520 // handle (pointer - pointer)
2524 ig.Emit (OpCodes.Sub);
2528 ig.Emit (OpCodes.Sizeof, op_type);
2530 IntLiteral.EmitInt (ig, size);
2531 ig.Emit (OpCodes.Div);
2533 ig.Emit (OpCodes.Conv_I8);
2536 // handle + and - on (pointer op int)
2539 ig.Emit (OpCodes.Conv_I);
2543 ig.Emit (OpCodes.Sizeof, op_type);
2545 IntLiteral.EmitInt (ig, size);
2546 ig.Emit (OpCodes.Mul);
2549 ig.Emit (OpCodes.Add);
2551 ig.Emit (OpCodes.Sub);
2557 /// Implements the ternary conditiona operator (?:)
2559 public class Conditional : Expression {
2560 Expression expr, trueExpr, falseExpr;
2563 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2566 this.trueExpr = trueExpr;
2567 this.falseExpr = falseExpr;
2571 public Expression Expr {
2577 public Expression TrueExpr {
2583 public Expression FalseExpr {
2589 public override Expression DoResolve (EmitContext ec)
2591 expr = expr.Resolve (ec);
2593 if (expr.Type != TypeManager.bool_type)
2594 expr = Expression.ConvertImplicitRequired (
2595 ec, expr, TypeManager.bool_type, loc);
2597 trueExpr = trueExpr.Resolve (ec);
2598 falseExpr = falseExpr.Resolve (ec);
2600 if (expr == null || trueExpr == null || falseExpr == null)
2603 eclass = ExprClass.Value;
2604 if (trueExpr.Type == falseExpr.Type)
2605 type = trueExpr.Type;
2608 Type true_type = trueExpr.Type;
2609 Type false_type = falseExpr.Type;
2611 if (trueExpr is NullLiteral){
2614 } else if (falseExpr is NullLiteral){
2620 // First, if an implicit conversion exists from trueExpr
2621 // to falseExpr, then the result type is of type falseExpr.Type
2623 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
2626 // Check if both can convert implicitl to each other's type
2628 if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
2631 "Can not compute type of conditional expression " +
2632 "as `" + TypeManager.CSharpName (trueExpr.Type) +
2633 "' and `" + TypeManager.CSharpName (falseExpr.Type) +
2634 "' convert implicitly to each other");
2639 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
2643 Error (173, loc, "The type of the conditional expression can " +
2644 "not be computed because there is no implicit conversion" +
2645 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2646 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2651 if (expr is BoolConstant){
2652 BoolConstant bc = (BoolConstant) expr;
2663 public override void Emit (EmitContext ec)
2665 ILGenerator ig = ec.ig;
2666 Label false_target = ig.DefineLabel ();
2667 Label end_target = ig.DefineLabel ();
2670 ig.Emit (OpCodes.Brfalse, false_target);
2672 ig.Emit (OpCodes.Br, end_target);
2673 ig.MarkLabel (false_target);
2674 falseExpr.Emit (ec);
2675 ig.MarkLabel (end_target);
2683 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation {
2684 public readonly string Name;
2685 public readonly Block Block;
2687 VariableInfo variable_info;
2689 public LocalVariableReference (Block block, string name, Location l)
2694 eclass = ExprClass.Variable;
2697 public VariableInfo VariableInfo {
2699 if (variable_info == null)
2700 variable_info = Block.GetVariableInfo (Name);
2701 return variable_info;
2705 public override Expression DoResolve (EmitContext ec)
2707 VariableInfo vi = VariableInfo;
2709 if (Block.IsConstant (Name)) {
2710 Expression e = Block.GetConstantExpression (Name);
2716 type = vi.VariableType;
2720 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
2722 Expression e = DoResolve (ec);
2727 VariableInfo vi = VariableInfo;
2731 // Sigh: this breaks `using' and `fixed'. Need to review that
2736 "cannot assign to `" + Name + "' because it is readonly");
2744 public override void Emit (EmitContext ec)
2746 VariableInfo vi = VariableInfo;
2747 ILGenerator ig = ec.ig;
2749 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
2753 public void EmitAssign (EmitContext ec, Expression source)
2755 ILGenerator ig = ec.ig;
2756 VariableInfo vi = VariableInfo;
2762 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
2765 public void AddressOf (EmitContext ec, AddressOp mode)
2767 VariableInfo vi = VariableInfo;
2769 if ((mode & AddressOp.Load) != 0)
2771 if ((mode & AddressOp.Store) != 0)
2774 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
2779 /// This represents a reference to a parameter in the intermediate
2782 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation {
2788 public ParameterReference (Parameters pars, int idx, string name)
2793 eclass = ExprClass.Variable;
2797 // Notice that for ref/out parameters, the type exposed is not the
2798 // same type exposed externally.
2801 // externally we expose "int&"
2802 // here we expose "int".
2804 // We record this in "is_ref". This means that the type system can treat
2805 // the type as it is expected, but when we generate the code, we generate
2806 // the alternate kind of code.
2808 public override Expression DoResolve (EmitContext ec)
2810 type = pars.GetParameterInfo (ec.DeclSpace, idx, out is_ref);
2811 eclass = ExprClass.Variable;
2817 // This method is used by parameters that are references, that are
2818 // being passed as references: we only want to pass the pointer (that
2819 // is already stored in the parameter, not the address of the pointer,
2820 // and not the value of the variable).
2822 public void EmitLoad (EmitContext ec)
2824 ILGenerator ig = ec.ig;
2831 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2833 ig.Emit (OpCodes.Ldarg, arg_idx);
2836 public override void Emit (EmitContext ec)
2838 ILGenerator ig = ec.ig;
2845 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2847 ig.Emit (OpCodes.Ldarg, arg_idx);
2853 // If we are a reference, we loaded on the stack a pointer
2854 // Now lets load the real value
2856 LoadFromPtr (ig, type);
2859 public void EmitAssign (EmitContext ec, Expression source)
2861 ILGenerator ig = ec.ig;
2870 ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
2872 ig.Emit (OpCodes.Ldarg, arg_idx);
2878 StoreFromPtr (ig, type);
2881 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
2883 ig.Emit (OpCodes.Starg, arg_idx);
2888 public void AddressOf (EmitContext ec, AddressOp mode)
2896 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
2898 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
2903 /// Used for arguments to New(), Invocation()
2905 public class Argument {
2906 public enum AType : byte {
2912 public readonly AType ArgType;
2913 public Expression expr;
2915 public Argument (Expression expr, AType type)
2918 this.ArgType = type;
2921 public Expression Expr {
2933 if (ArgType == AType.Ref || ArgType == AType.Out)
2934 return TypeManager.LookupType (expr.Type.ToString () + "&");
2940 public Parameter.Modifier GetParameterModifier ()
2942 if (ArgType == AType.Ref || ArgType == AType.Out)
2943 return Parameter.Modifier.OUT;
2945 return Parameter.Modifier.NONE;
2948 public static string FullDesc (Argument a)
2950 return (a.ArgType == AType.Ref ? "ref " :
2951 (a.ArgType == AType.Out ? "out " : "")) +
2952 TypeManager.CSharpName (a.Expr.Type);
2955 public bool Resolve (EmitContext ec, Location loc)
2957 expr = expr.Resolve (ec);
2959 if (ArgType == AType.Expression)
2960 return expr != null;
2962 if (expr.eclass != ExprClass.Variable){
2964 // We just probe to match the CSC output
2966 if (expr.eclass == ExprClass.PropertyAccess ||
2967 expr.eclass == ExprClass.IndexerAccess){
2970 "A property or indexer can not be passed as an out or ref " +
2975 "An lvalue is required as an argument to out or ref");
2980 return expr != null;
2983 public void Emit (EmitContext ec)
2986 // Ref and Out parameters need to have their addresses taken.
2988 // ParameterReferences might already be references, so we want
2989 // to pass just the value
2991 if (ArgType == AType.Ref || ArgType == AType.Out){
2992 AddressOp mode = AddressOp.Store;
2994 if (ArgType == AType.Ref)
2995 mode |= AddressOp.Load;
2997 if (expr is ParameterReference){
2998 ParameterReference pr = (ParameterReference) expr;
3004 pr.AddressOf (ec, mode);
3007 ((IMemoryLocation)expr).AddressOf (ec, mode);
3014 /// Invocation of methods or delegates.
3016 public class Invocation : ExpressionStatement {
3017 public readonly ArrayList Arguments;
3021 MethodBase method = null;
3024 static Hashtable method_parameter_cache;
3026 static Invocation ()
3028 method_parameter_cache = new PtrHashtable ();
3032 // arguments is an ArrayList, but we do not want to typecast,
3033 // as it might be null.
3035 // FIXME: only allow expr to be a method invocation or a
3036 // delegate invocation (7.5.5)
3038 public Invocation (Expression expr, ArrayList arguments, Location l)
3041 Arguments = arguments;
3045 public Expression Expr {
3052 /// Returns the Parameters (a ParameterData interface) for the
3055 public static ParameterData GetParameterData (MethodBase mb)
3057 object pd = method_parameter_cache [mb];
3061 return (ParameterData) pd;
3064 ip = TypeManager.LookupParametersByBuilder (mb);
3066 method_parameter_cache [mb] = ip;
3068 return (ParameterData) ip;
3070 ParameterInfo [] pi = mb.GetParameters ();
3071 ReflectionParameters rp = new ReflectionParameters (pi);
3072 method_parameter_cache [mb] = rp;
3074 return (ParameterData) rp;
3079 /// Determines "better conversion" as specified in 7.4.2.3
3080 /// Returns : 1 if a->p is better
3081 /// 0 if a->q or neither is better
3083 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
3085 Type argument_type = a.Type;
3086 Expression argument_expr = a.Expr;
3088 if (argument_type == null)
3089 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3094 if (argument_type == p)
3097 if (argument_type == q)
3101 // Now probe whether an implicit constant expression conversion
3104 // An implicit constant expression conversion permits the following
3107 // * A constant-expression of type `int' can be converted to type
3108 // sbyte, byute, short, ushort, uint, ulong provided the value of
3109 // of the expression is withing the range of the destination type.
3111 // * A constant-expression of type long can be converted to type
3112 // ulong, provided the value of the constant expression is not negative
3114 // FIXME: Note that this assumes that constant folding has
3115 // taken place. We dont do constant folding yet.
3118 if (argument_expr is IntConstant){
3119 IntConstant ei = (IntConstant) argument_expr;
3120 int value = ei.Value;
3122 if (p == TypeManager.sbyte_type){
3123 if (value >= SByte.MinValue && value <= SByte.MaxValue)
3125 } else if (p == TypeManager.byte_type){
3126 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3128 } else if (p == TypeManager.short_type){
3129 if (value >= Int16.MinValue && value <= Int16.MaxValue)
3131 } else if (p == TypeManager.ushort_type){
3132 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3134 } else if (p == TypeManager.uint32_type){
3136 // we can optimize this case: a positive int32
3137 // always fits on a uint32
3141 } else if (p == TypeManager.uint64_type){
3143 // we can optimize this case: a positive int32
3144 // always fits on a uint64
3149 } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
3150 LongConstant lc = (LongConstant) argument_expr;
3152 if (p == TypeManager.uint64_type){
3159 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
3167 Expression p_tmp = new EmptyExpression (p);
3168 Expression q_tmp = new EmptyExpression (q);
3170 if (StandardConversionExists (p_tmp, q) == true &&
3171 StandardConversionExists (q_tmp, p) == false)
3174 if (p == TypeManager.sbyte_type)
3175 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3176 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3179 if (p == TypeManager.short_type)
3180 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3181 q == TypeManager.uint64_type)
3184 if (p == TypeManager.int32_type)
3185 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3188 if (p == TypeManager.int64_type)
3189 if (q == TypeManager.uint64_type)
3196 /// Determines "Better function"
3199 /// and returns an integer indicating :
3200 /// 0 if candidate ain't better
3201 /// 1 if candidate is better than the current best match
3203 static int BetterFunction (EmitContext ec, ArrayList args,
3204 MethodBase candidate, MethodBase best,
3205 bool expanded_form, Location loc)
3207 ParameterData candidate_pd = GetParameterData (candidate);
3208 ParameterData best_pd;
3214 argument_count = args.Count;
3216 int cand_count = candidate_pd.Count;
3218 if (cand_count == 0 && argument_count == 0)
3221 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3222 if (cand_count != argument_count)
3228 if (argument_count == 0 && cand_count == 1 &&
3229 candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
3232 for (int j = argument_count; j > 0;) {
3235 Argument a = (Argument) args [j];
3236 Type t = candidate_pd.ParameterType (j);
3238 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3240 t = t.GetElementType ();
3242 x = BetterConversion (ec, a, t, null, loc);
3254 best_pd = GetParameterData (best);
3256 int rating1 = 0, rating2 = 0;
3258 for (int j = 0; j < argument_count; ++j) {
3261 Argument a = (Argument) args [j];
3263 Type ct = candidate_pd.ParameterType (j);
3264 Type bt = best_pd.ParameterType (j);
3266 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3268 ct = ct.GetElementType ();
3270 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3272 bt = bt.GetElementType ();
3274 x = BetterConversion (ec, a, ct, bt, loc);
3275 y = BetterConversion (ec, a, bt, ct, loc);
3284 if (rating1 > rating2)
3290 public static string FullMethodDesc (MethodBase mb)
3292 string ret_type = "";
3294 if (mb is MethodInfo)
3295 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
3297 StringBuilder sb = new StringBuilder (ret_type + " " + mb.Name);
3298 ParameterData pd = GetParameterData (mb);
3300 int count = pd.Count;
3303 for (int i = count; i > 0; ) {
3306 sb.Append (pd.ParameterDesc (count - i - 1));
3312 return sb.ToString ();
3315 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3317 MemberInfo [] miset;
3318 MethodGroupExpr union;
3323 return (MethodGroupExpr) mg2;
3326 return (MethodGroupExpr) mg1;
3329 MethodGroupExpr left_set = null, right_set = null;
3330 int length1 = 0, length2 = 0;
3332 left_set = (MethodGroupExpr) mg1;
3333 length1 = left_set.Methods.Length;
3335 right_set = (MethodGroupExpr) mg2;
3336 length2 = right_set.Methods.Length;
3338 ArrayList common = new ArrayList ();
3340 foreach (MethodBase l in left_set.Methods){
3341 foreach (MethodBase r in right_set.Methods){
3349 miset = new MemberInfo [length1 + length2 - common.Count];
3350 left_set.Methods.CopyTo (miset, 0);
3354 foreach (MemberInfo mi in right_set.Methods){
3355 if (!common.Contains (mi))
3359 union = new MethodGroupExpr (miset, loc);
3365 /// Determines is the candidate method, if a params method, is applicable
3366 /// in its expanded form to the given set of arguments
3368 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3372 if (arguments == null)
3375 arg_count = arguments.Count;
3377 ParameterData pd = GetParameterData (candidate);
3379 int pd_count = pd.Count;
3384 if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
3387 if (pd_count - 1 > arg_count)
3390 if (pd_count == 1 && arg_count == 0)
3394 // If we have come this far, the case which remains is when the number of parameters
3395 // is less than or equal to the argument count.
3397 for (int i = 0; i < pd_count - 1; ++i) {
3399 Argument a = (Argument) arguments [i];
3401 Parameter.Modifier a_mod = a.GetParameterModifier ();
3402 Parameter.Modifier p_mod = pd.ParameterModifier (i);
3404 if (a_mod == p_mod) {
3406 if (a_mod == Parameter.Modifier.NONE)
3407 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3410 if (a_mod == Parameter.Modifier.REF ||
3411 a_mod == Parameter.Modifier.OUT) {
3412 Type pt = pd.ParameterType (i);
3415 pt = TypeManager.LookupType (pt.FullName + "&");
3425 Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
3427 for (int i = pd_count - 1; i < arg_count; i++) {
3428 Argument a = (Argument) arguments [i];
3430 if (!StandardConversionExists (a.Expr, element_type))
3438 /// Determines if the candidate method is applicable (section 14.4.2.1)
3439 /// to the given set of arguments
3441 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3445 if (arguments == null)
3448 arg_count = arguments.Count;
3450 ParameterData pd = GetParameterData (candidate);
3452 int pd_count = pd.Count;
3454 if (arg_count != pd.Count)
3457 for (int i = arg_count; i > 0; ) {
3460 Argument a = (Argument) arguments [i];
3462 Parameter.Modifier a_mod = a.GetParameterModifier ();
3463 Parameter.Modifier p_mod = pd.ParameterModifier (i);
3465 if (a_mod == p_mod ||
3466 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3467 if (a_mod == Parameter.Modifier.NONE)
3468 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3471 if (a_mod == Parameter.Modifier.REF ||
3472 a_mod == Parameter.Modifier.OUT) {
3473 Type pt = pd.ParameterType (i);
3476 pt = TypeManager.LookupType (pt.FullName + "&");
3491 /// Find the Applicable Function Members (7.4.2.1)
3493 /// me: Method Group expression with the members to select.
3494 /// it might contain constructors or methods (or anything
3495 /// that maps to a method).
3497 /// Arguments: ArrayList containing resolved Argument objects.
3499 /// loc: The location if we want an error to be reported, or a Null
3500 /// location for "probing" purposes.
3502 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3503 /// that is the best match of me on Arguments.
3506 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3507 ArrayList Arguments, Location loc)
3509 ArrayList afm = new ArrayList ();
3510 MethodBase method = null;
3512 ArrayList candidates = new ArrayList ();
3515 foreach (MethodBase candidate in me.Methods){
3518 // Check if candidate is applicable (section 14.4.2.1)
3519 if (!IsApplicable (ec, Arguments, candidate))
3522 candidates.Add (candidate);
3523 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
3531 if (Arguments == null)
3534 argument_count = Arguments.Count;
3537 // Now we see if we can find params functions, applicable in their expanded form
3538 // since if they were applicable in their normal form, they would have been selected
3541 bool chose_params_expanded = false;
3543 if (method == null) {
3544 candidates = new ArrayList ();
3545 foreach (MethodBase candidate in me.Methods){
3546 if (!IsParamsMethodApplicable (ec, Arguments, candidate))
3549 candidates.Add (candidate);
3551 int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
3556 chose_params_expanded = true;
3564 // Now check that there are no ambiguities i.e the selected method
3565 // should be better than all the others
3568 foreach (MethodBase candidate in candidates){
3569 if (candidate == method)
3573 // If a normal method is applicable in the sense that it has the same
3574 // number of arguments, then the expanded params method is never applicable
3575 // so we debar the params method.
3577 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
3578 IsApplicable (ec, Arguments, method))
3581 int x = BetterFunction (ec, Arguments, method, candidate,
3582 chose_params_expanded, loc);
3587 "Ambiguous call when selecting function due to implicit casts");
3593 // And now check if the arguments are all compatible, perform conversions
3594 // if necessary etc. and return if everything is all right
3597 if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
3598 chose_params_expanded, null, loc))
3604 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
3607 bool chose_params_expanded,
3611 ParameterData pd = GetParameterData (method);
3612 int pd_count = pd.Count;
3614 for (int j = 0; j < argument_count; j++) {
3615 Argument a = (Argument) Arguments [j];
3616 Expression a_expr = a.Expr;
3617 Type parameter_type = pd.ParameterType (j);
3619 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
3620 chose_params_expanded)
3621 parameter_type = parameter_type.GetElementType ();
3623 if (a.Type != parameter_type){
3626 conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
3629 if (!Location.IsNull (loc)) {
3630 if (delegate_type == null)
3632 "The best overloaded match for method '" +
3633 FullMethodDesc (method) +
3634 "' has some invalid arguments");
3636 Report.Error (1594, loc,
3637 "Delegate '" + delegate_type.ToString () +
3638 "' has some invalid arguments.");
3640 "Argument " + (j+1) +
3641 ": Cannot convert from '" + Argument.FullDesc (a)
3642 + "' to '" + pd.ParameterDesc (j) + "'");
3649 // Update the argument with the implicit conversion
3655 if (a.GetParameterModifier () != pd.ParameterModifier (j) &&
3656 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
3657 if (!Location.IsNull (loc)) {
3658 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
3659 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
3660 Console.WriteLine ("PT: " + parameter_type.IsByRef);
3662 "The best overloaded match for method '" + FullMethodDesc (method)+
3663 "' has some invalid arguments");
3665 "Argument " + (j+1) +
3666 ": Cannot convert from '" + Argument.FullDesc (a)
3667 + "' to '" + pd.ParameterDesc (j) + "'");
3677 public override Expression DoResolve (EmitContext ec)
3680 // First, resolve the expression that is used to
3681 // trigger the invocation
3683 if (expr is BaseAccess)
3686 expr = expr.Resolve (ec);
3690 if (!(expr is MethodGroupExpr)) {
3691 Type expr_type = expr.Type;
3693 if (expr_type != null){
3694 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
3696 return (new DelegateInvocation (
3697 this.expr, Arguments, loc)).Resolve (ec);
3701 if (!(expr is MethodGroupExpr)){
3702 report118 (loc, this.expr, "method group");
3707 // Next, evaluate all the expressions in the argument list
3709 if (Arguments != null){
3710 foreach (Argument a in Arguments){
3711 if (!a.Resolve (ec, loc))
3716 method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);
3718 if (method == null){
3720 "Could not find any applicable function for this argument list");
3724 if (method is MethodInfo)
3725 type = ((MethodInfo)method).ReturnType;
3727 if (type.IsPointer){
3734 eclass = ExprClass.Value;
3739 // Emits the list of arguments as an array
3741 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
3743 ILGenerator ig = ec.ig;
3744 int count = arguments.Count - idx;
3745 Argument a = (Argument) arguments [idx];
3746 Type t = a.expr.Type;
3747 string array_type = t.FullName + "[]";
3750 array = ig.DeclareLocal (Type.GetType (array_type));
3751 IntConstant.EmitInt (ig, count);
3752 ig.Emit (OpCodes.Newarr, t);
3753 ig.Emit (OpCodes.Stloc, array);
3755 int top = arguments.Count;
3756 for (int j = idx; j < top; j++){
3757 a = (Argument) arguments [j];
3759 ig.Emit (OpCodes.Ldloc, array);
3760 IntConstant.EmitInt (ig, j - idx);
3763 ArrayAccess.EmitStoreOpcode (ig, t);
3765 ig.Emit (OpCodes.Ldloc, array);
3769 /// Emits a list of resolved Arguments that are in the arguments
3772 /// The MethodBase argument might be null if the
3773 /// emission of the arguments is known not to contain
3774 /// a `params' field (for example in constructors or other routines
3775 /// that keep their arguments in this structure
3777 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
3781 pd = GetParameterData (mb);
3786 // If we are calling a params method with no arguments, special case it
3788 if (arguments == null){
3789 if (pd != null && pd.Count > 0 &&
3790 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
3791 ILGenerator ig = ec.ig;
3793 IntConstant.EmitInt (ig, 0);
3794 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
3800 int top = arguments.Count;
3802 for (int i = 0; i < top; i++){
3803 Argument a = (Argument) arguments [i];
3806 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
3808 // Special case if we are passing the same data as the
3809 // params argument, do not put it in an array.
3811 if (pd.ParameterType (i) == a.Type)
3814 EmitParams (ec, i, arguments);
3824 /// is_base tells whether we want to force the use of the `call'
3825 /// opcode instead of using callvirt. Call is required to call
3826 /// a specific method, while callvirt will always use the most
3827 /// recent method in the vtable.
3829 /// is_static tells whether this is an invocation on a static method
3831 /// instance_expr is an expression that represents the instance
3832 /// it must be non-null if is_static is false.
3834 /// method is the method to invoke.
3836 /// Arguments is the list of arguments to pass to the method or constructor.
3838 public static void EmitCall (EmitContext ec, bool is_base,
3839 bool is_static, Expression instance_expr,
3840 MethodBase method, ArrayList Arguments)
3842 ILGenerator ig = ec.ig;
3843 bool struct_call = false;
3845 Type decl_type = method.DeclaringType;
3847 if (RootContext.DisableTrace && decl_type == TypeManager.trace_type)
3849 if (RootContext.DisableDebug && decl_type == TypeManager.debug_type)
3853 if (decl_type.IsValueType)
3856 // If this is ourselves, push "this"
3858 if (instance_expr == null){
3859 ig.Emit (OpCodes.Ldarg_0);
3862 // Push the instance expression
3864 if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
3866 // Special case: calls to a function declared in a
3867 // reference-type with a value-type argument need
3868 // to have their value boxed.
3871 if (decl_type.IsValueType){
3873 // If the expression implements IMemoryLocation, then
3874 // we can optimize and use AddressOf on the
3877 // If not we have to use some temporary storage for
3879 if (instance_expr is IMemoryLocation){
3880 ((IMemoryLocation)instance_expr).
3881 AddressOf (ec, AddressOp.LoadStore);
3884 Type t = instance_expr.Type;
3886 instance_expr.Emit (ec);
3887 LocalBuilder temp = ig.DeclareLocal (t);
3888 ig.Emit (OpCodes.Stloc, temp);
3889 ig.Emit (OpCodes.Ldloca, temp);
3892 instance_expr.Emit (ec);
3893 ig.Emit (OpCodes.Box, instance_expr.Type);
3896 instance_expr.Emit (ec);
3900 EmitArguments (ec, method, Arguments);
3902 if (is_static || struct_call || is_base){
3903 if (method is MethodInfo)
3904 ig.Emit (OpCodes.Call, (MethodInfo) method);
3906 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3908 if (method is MethodInfo)
3909 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3911 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3915 public override void Emit (EmitContext ec)
3917 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3919 EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments);
3922 public override void EmitStatement (EmitContext ec)
3927 // Pop the return value if there is one
3929 if (method is MethodInfo){
3930 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3931 ec.ig.Emit (OpCodes.Pop);
3937 // This class is used to "disable" the code generation for the
3938 // temporary variable when initializing value types.
3940 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
3941 public void AddressOf (EmitContext ec, AddressOp Mode)
3948 /// Implements the new expression
3950 public class New : ExpressionStatement {
3951 public readonly ArrayList Arguments;
3952 public readonly string RequestedType;
3955 MethodBase method = null;
3958 // If set, the new expression is for a value_target, and
3959 // we will not leave anything on the stack.
3961 Expression value_target;
3963 public New (string requested_type, ArrayList arguments, Location l)
3965 RequestedType = requested_type;
3966 Arguments = arguments;
3970 public Expression ValueTypeVariable {
3972 return value_target;
3976 value_target = value;
3981 // This function is used to disable the following code sequence for
3982 // value type initialization:
3984 // AddressOf (temporary)
3988 // Instead the provide will have provided us with the address on the
3989 // stack to store the results.
3991 static Expression MyEmptyExpression;
3993 public void DisableTemporaryValueType ()
3995 if (MyEmptyExpression == null)
3996 MyEmptyExpression = new EmptyAddressOf ();
3999 // To enable this, look into:
4000 // test-34 and test-89 and self bootstrapping.
4002 // For instance, we can avoid a copy by using `newobj'
4003 // instead of Call + Push-temp on value types.
4004 // value_target = MyEmptyExpression;
4007 public override Expression DoResolve (EmitContext ec)
4009 type = RootContext.LookupType (ec.DeclSpace, RequestedType, false, loc);
4014 bool IsDelegate = TypeManager.IsDelegateType (type);
4017 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4019 if (type.IsInterface || type.IsAbstract){
4021 144, loc, "It is not possible to create instances of interfaces " +
4022 "or abstract classes");
4026 bool is_struct = false;
4027 is_struct = type.IsSubclassOf (TypeManager.value_type);
4028 eclass = ExprClass.Value;
4031 // SRE returns a match for .ctor () on structs (the object constructor),
4032 // so we have to manually ignore it.
4034 if (is_struct && Arguments == null)
4038 ml = MemberLookupFinal (ec, type, ".ctor",
4039 MemberTypes.Constructor,
4040 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4045 if (! (ml is MethodGroupExpr)){
4047 report118 (loc, ml, "method group");
4053 if (Arguments != null){
4054 foreach (Argument a in Arguments){
4055 if (!a.Resolve (ec, loc))
4060 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
4065 if (method == null && !is_struct) {
4067 "New invocation: Can not find a constructor for " +
4068 "this argument list");
4075 // This DoEmit can be invoked in two contexts:
4076 // * As a mechanism that will leave a value on the stack (new object)
4077 // * As one that wont (init struct)
4079 // You can control whether a value is required on the stack by passing
4080 // need_value_on_stack. The code *might* leave a value on the stack
4081 // so it must be popped manually
4083 // If we are dealing with a ValueType, we have a few
4084 // situations to deal with:
4086 // * The target is a ValueType, and we have been provided
4087 // the instance (this is easy, we are being assigned).
4089 // * The target of New is being passed as an argument,
4090 // to a boxing operation or a function that takes a
4093 // In this case, we need to create a temporary variable
4094 // that is the argument of New.
4096 // Returns whether a value is left on the stack
4098 bool DoEmit (EmitContext ec, bool need_value_on_stack)
4100 bool is_value_type = type.IsSubclassOf (TypeManager.value_type);
4101 ILGenerator ig = ec.ig;
4106 if (value_target == null)
4107 value_target = new LocalTemporary (ec, type);
4109 ml = (IMemoryLocation) value_target;
4110 ml.AddressOf (ec, AddressOp.Store);
4114 Invocation.EmitArguments (ec, method, Arguments);
4118 ig.Emit (OpCodes.Initobj, type);
4120 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4121 if (need_value_on_stack){
4122 value_target.Emit (ec);
4127 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4132 public override void Emit (EmitContext ec)
4137 public override void EmitStatement (EmitContext ec)
4139 if (DoEmit (ec, false))
4140 ec.ig.Emit (OpCodes.Pop);
4145 /// Represents an array creation expression.
4149 /// There are two possible scenarios here: one is an array creation
4150 /// expression that specifies the dimensions and optionally the
4151 /// initialization data and the other which does not need dimensions
4152 /// specified but where initialization data is mandatory.
4154 public class ArrayCreation : ExpressionStatement {
4155 string RequestedType;
4157 ArrayList Initializers;
4161 // The list of Argument types.
4162 // This is used to constrcut the `newarray' or constructor signature
4164 ArrayList Arguments;
4166 MethodBase method = null;
4167 Type array_element_type;
4168 bool IsOneDimensional = false;
4169 bool IsBuiltinType = false;
4170 bool ExpectInitializers = false;
4173 Type underlying_type;
4175 ArrayList ArrayData;
4180 // The number of array initializers that we can handle
4181 // via the InitializeArray method - through EmitStaticInitializers
4183 int num_automatic_initializers;
4185 public ArrayCreation (string requested_type, ArrayList exprs,
4186 string rank, ArrayList initializers, Location l)
4188 RequestedType = requested_type;
4190 Initializers = initializers;
4193 Arguments = new ArrayList ();
4195 foreach (Expression e in exprs)
4196 Arguments.Add (new Argument (e, Argument.AType.Expression));
4199 public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)
4201 RequestedType = requested_type;
4202 Initializers = initializers;
4205 Rank = rank.Substring (0, rank.LastIndexOf ("["));
4207 string tmp = rank.Substring (rank.LastIndexOf ("["));
4209 dimensions = tmp.Length - 1;
4210 ExpectInitializers = true;
4213 public static string FormArrayType (string base_type, int idx_count, string rank)
4215 StringBuilder sb = new StringBuilder (base_type);
4220 for (int i = 1; i < idx_count; i++)
4225 return sb.ToString ();
4228 public static string FormElementType (string base_type, int idx_count, string rank)
4230 StringBuilder sb = new StringBuilder (base_type);
4233 for (int i = 1; i < idx_count; i++)
4240 string val = sb.ToString ();
4242 return val.Substring (0, val.LastIndexOf ("["));
4247 Report.Error (178, loc, "Incorrectly structured array initializer");
4250 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
4252 if (specified_dims) {
4253 Argument a = (Argument) Arguments [idx];
4255 if (!a.Resolve (ec, loc))
4258 if (!(a.Expr is Constant)) {
4259 Report.Error (150, loc, "A constant value is expected");
4263 int value = (int) ((Constant) a.Expr).GetValue ();
4265 if (value != probe.Count) {
4270 Bounds [idx] = value;
4273 foreach (object o in probe) {
4274 if (o is ArrayList) {
4275 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
4279 Expression tmp = (Expression) o;
4280 tmp = tmp.Resolve (ec);
4284 // Handle initialization from vars, fields etc.
4286 Expression conv = ConvertImplicitRequired (
4287 ec, tmp, underlying_type, loc);
4292 if (conv is StringConstant)
4293 ArrayData.Add (conv);
4294 else if (conv is Constant) {
4295 ArrayData.Add (conv);
4296 num_automatic_initializers++;
4298 ArrayData.Add (conv);
4305 public void UpdateIndices (EmitContext ec)
4308 for (ArrayList probe = Initializers; probe != null;) {
4309 if (probe.Count > 0 && probe [0] is ArrayList) {
4310 Expression e = new IntConstant (probe.Count);
4311 Arguments.Add (new Argument (e, Argument.AType.Expression));
4313 Bounds [i++] = probe.Count;
4315 probe = (ArrayList) probe [0];
4318 Expression e = new IntConstant (probe.Count);
4319 Arguments.Add (new Argument (e, Argument.AType.Expression));
4321 Bounds [i++] = probe.Count;
4328 public bool ValidateInitializers (EmitContext ec)
4330 if (Initializers == null) {
4331 if (ExpectInitializers)
4337 underlying_type = RootContext.LookupType (
4338 ec.DeclSpace, RequestedType, false, loc);
4341 // We use this to store all the date values in the order in which we
4342 // will need to store them in the byte blob later
4344 ArrayData = new ArrayList ();
4345 Bounds = new Hashtable ();
4349 if (Arguments != null) {
4350 ret = CheckIndices (ec, Initializers, 0, true);
4354 Arguments = new ArrayList ();
4356 ret = CheckIndices (ec, Initializers, 0, false);
4363 if (Arguments.Count != dimensions) {
4372 public override Expression DoResolve (EmitContext ec)
4377 // First step is to validate the initializers and fill
4378 // in any missing bits
4380 if (!ValidateInitializers (ec))
4383 if (Arguments == null)
4386 arg_count = Arguments.Count;
4387 foreach (Argument a in Arguments){
4388 if (!a.Resolve (ec, loc))
4392 // Now, convert that to an integer
4394 Expression real_arg;
4395 bool old_checked = ec.CheckState;
4396 ec.CheckState = true;
4398 real_arg = ConvertExplicit (
4399 ec, a.expr, TypeManager.uint32_type, loc);
4400 ec.CheckState = old_checked;
4401 if (real_arg == null)
4408 string array_type = FormArrayType (RequestedType, arg_count, Rank);
4409 string element_type = FormElementType (RequestedType, arg_count, Rank);
4411 type = RootContext.LookupType (ec.DeclSpace, array_type, false, loc);
4413 array_element_type = RootContext.LookupType (
4414 ec.DeclSpace, element_type, false, loc);
4419 if (arg_count == 1) {
4420 IsOneDimensional = true;
4421 eclass = ExprClass.Value;
4425 IsBuiltinType = TypeManager.IsBuiltinType (type);
4427 if (IsBuiltinType) {
4431 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
4432 AllBindingFlags, loc);
4434 if (!(ml is MethodGroupExpr)){
4435 report118 (loc, ml, "method group");
4440 Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4441 "this argument list");
4445 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
4447 if (method == null) {
4448 Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4449 "this argument list");
4453 eclass = ExprClass.Value;
4458 ModuleBuilder mb = CodeGen.ModuleBuilder;
4460 ArrayList args = new ArrayList ();
4461 if (Arguments != null){
4462 for (int i = 0; i < arg_count; i++)
4463 args.Add (TypeManager.int32_type);
4466 Type [] arg_types = null;
4469 arg_types = new Type [args.Count];
4471 args.CopyTo (arg_types, 0);
4473 method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
4476 if (method == null) {
4477 Report.Error (-6, loc, "New invocation: Can not find a constructor for " +
4478 "this argument list");
4482 eclass = ExprClass.Value;
4488 public static byte [] MakeByteBlob (ArrayList ArrayData, Type underlying_type, Location loc)
4493 int count = ArrayData.Count;
4495 factor = GetTypeSize (underlying_type);
4499 data = new byte [(count * factor + 4) & ~3];
4502 for (int i = 0; i < count; ++i) {
4503 object v = ArrayData [i];
4505 if (v is EnumConstant)
4506 v = ((EnumConstant) v).Child;
4508 if (v is Constant && !(v is StringConstant))
4509 v = ((Constant) v).GetValue ();
4515 if (underlying_type == TypeManager.int64_type){
4516 if (!(v is Expression)){
4517 long val = (long) v;
4519 for (int j = 0; j < factor; ++j) {
4520 data [idx + j] = (byte) (val & 0xFF);
4524 } else if (underlying_type == TypeManager.uint64_type){
4525 if (!(v is Expression)){
4526 ulong val = (ulong) v;
4528 for (int j = 0; j < factor; ++j) {
4529 data [idx + j] = (byte) (val & 0xFF);
4533 } else if (underlying_type == TypeManager.float_type) {
4534 if (!(v is Expression)){
4535 element = BitConverter.GetBytes ((float) v);
4537 for (int j = 0; j < factor; ++j)
4538 data [idx + j] = element [j];
4540 } else if (underlying_type == TypeManager.double_type) {
4541 if (!(v is Expression)){
4542 element = BitConverter.GetBytes ((double) v);
4544 for (int j = 0; j < factor; ++j)
4545 data [idx + j] = element [j];
4547 } else if (underlying_type == TypeManager.char_type){
4548 if (!(v is Expression)){
4549 int val = (int) ((char) v);
4551 data [idx] = (byte) (val & 0xff);
4552 data [idx+1] = (byte) (val >> 8);
4554 } else if (underlying_type == TypeManager.short_type){
4555 if (!(v is Expression)){
4556 int val = (int) ((short) v);
4558 data [idx] = (byte) (val & 0xff);
4559 data [idx+1] = (byte) (val >> 8);
4561 } else if (underlying_type == TypeManager.ushort_type){
4562 if (!(v is Expression)){
4563 int val = (int) ((ushort) v);
4565 data [idx] = (byte) (val & 0xff);
4566 data [idx+1] = (byte) (val >> 8);
4568 } else if (underlying_type == TypeManager.int32_type) {
4569 if (!(v is Expression)){
4572 data [idx] = (byte) (val & 0xff);
4573 data [idx+1] = (byte) ((val >> 8) & 0xff);
4574 data [idx+2] = (byte) ((val >> 16) & 0xff);
4575 data [idx+3] = (byte) (val >> 24);
4577 } else if (underlying_type == TypeManager.uint32_type) {
4578 if (!(v is Expression)){
4579 uint val = (uint) v;
4581 data [idx] = (byte) (val & 0xff);
4582 data [idx+1] = (byte) ((val >> 8) & 0xff);
4583 data [idx+2] = (byte) ((val >> 16) & 0xff);
4584 data [idx+3] = (byte) (val >> 24);
4586 } else if (underlying_type == TypeManager.sbyte_type) {
4587 if (!(v is Expression)){
4588 sbyte val = (sbyte) v;
4589 data [idx] = (byte) val;
4591 } else if (underlying_type == TypeManager.byte_type) {
4592 if (!(v is Expression)){
4593 byte val = (byte) v;
4594 data [idx] = (byte) val;
4596 } else if (underlying_type == TypeManager.bool_type) {
4597 if (!(v is Expression)){
4598 bool val = (bool) v;
4599 data [idx] = (byte) (val ? 1 : 0);
4602 throw new Exception ("Unrecognized type in MakeByteBlob");
4611 // Emits the initializers for the array
4613 void EmitStaticInitializers (EmitContext ec, bool is_expression)
4616 // First, the static data
4619 ILGenerator ig = ec.ig;
4621 byte [] data = MakeByteBlob (ArrayData, underlying_type, loc);
4624 fb = RootContext.MakeStaticData (data);
4627 ig.Emit (OpCodes.Dup);
4628 ig.Emit (OpCodes.Ldtoken, fb);
4629 ig.Emit (OpCodes.Call,
4630 TypeManager.void_initializearray_array_fieldhandle);
4635 // Emits pieces of the array that can not be computed at compile
4636 // time (variables and string locations).
4638 // This always expect the top value on the stack to be the array
4640 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
4642 ILGenerator ig = ec.ig;
4643 int dims = Bounds.Count;
4644 int [] current_pos = new int [dims];
4645 int top = ArrayData.Count;
4646 LocalBuilder temp = ig.DeclareLocal (type);
4648 ig.Emit (OpCodes.Stloc, temp);
4650 MethodInfo set = null;
4654 ModuleBuilder mb = null;
4655 mb = CodeGen.ModuleBuilder;
4656 args = new Type [dims + 1];
4659 for (j = 0; j < dims; j++)
4660 args [j] = TypeManager.int32_type;
4662 args [j] = array_element_type;
4664 set = mb.GetArrayMethod (
4666 CallingConventions.HasThis | CallingConventions.Standard,
4667 TypeManager.void_type, args);
4670 for (int i = 0; i < top; i++){
4672 Expression e = null;
4674 if (ArrayData [i] is Expression)
4675 e = (Expression) ArrayData [i];
4679 // Basically we do this for string literals and
4680 // other non-literal expressions
4682 if (e is StringConstant || !(e is Constant) ||
4683 num_automatic_initializers <= 2) {
4684 Type etype = e.Type;
4686 ig.Emit (OpCodes.Ldloc, temp);
4688 for (int idx = dims; idx > 0; ) {
4690 IntConstant.EmitInt (ig, current_pos [idx]);
4694 // If we are dealing with a struct, get the
4695 // address of it, so we can store it.
4697 if (etype.IsSubclassOf (TypeManager.value_type) &&
4698 !TypeManager.IsBuiltinType (etype)){
4703 // Let new know that we are providing
4704 // the address where to store the results
4706 n.DisableTemporaryValueType ();
4709 ig.Emit (OpCodes.Ldelema, etype);
4715 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
4717 ig.Emit (OpCodes.Call, set);
4724 for (int j = 0; j < dims; j++){
4726 if (current_pos [j] < (int) Bounds [j])
4728 current_pos [j] = 0;
4733 ig.Emit (OpCodes.Ldloc, temp);
4736 void EmitArrayArguments (EmitContext ec)
4738 foreach (Argument a in Arguments)
4742 void DoEmit (EmitContext ec, bool is_statement)
4744 ILGenerator ig = ec.ig;
4746 EmitArrayArguments (ec);
4747 if (IsOneDimensional)
4748 ig.Emit (OpCodes.Newarr, array_element_type);
4751 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4753 ig.Emit (OpCodes.Newobj, (MethodInfo) method);
4756 if (Initializers != null){
4758 // FIXME: Set this variable correctly.
4760 bool dynamic_initializers = true;
4762 if (underlying_type != TypeManager.string_type &&
4763 underlying_type != TypeManager.object_type) {
4764 if (num_automatic_initializers > 2)
4765 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
4768 if (dynamic_initializers)
4769 EmitDynamicInitializers (ec, !is_statement);
4773 public override void Emit (EmitContext ec)
4778 public override void EmitStatement (EmitContext ec)
4786 /// Represents the `this' construct
4788 public class This : Expression, IAssignMethod, IMemoryLocation {
4791 public This (Location loc)
4796 public override Expression DoResolve (EmitContext ec)
4798 eclass = ExprClass.Variable;
4799 type = ec.ContainerType;
4802 Report.Error (26, loc,
4803 "Keyword this not valid in static code");
4810 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4814 if (ec.TypeContainer is Class){
4815 Report.Error (1604, loc, "Cannot assign to `this'");
4822 public override void Emit (EmitContext ec)
4824 ec.ig.Emit (OpCodes.Ldarg_0);
4827 public void EmitAssign (EmitContext ec, Expression source)
4830 ec.ig.Emit (OpCodes.Starg, 0);
4833 public void AddressOf (EmitContext ec, AddressOp mode)
4835 ec.ig.Emit (OpCodes.Ldarg_0);
4838 // FIGURE OUT WHY LDARG_S does not work
4840 // consider: struct X { int val; int P { set { val = value; }}}
4842 // Yes, this looks very bad. Look at `NOTAS' for
4844 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4849 /// Implements the typeof operator
4851 public class TypeOf : Expression {
4852 public readonly string QueriedType;
4856 public TypeOf (string queried_type, Location l)
4858 QueriedType = queried_type;
4862 public override Expression DoResolve (EmitContext ec)
4864 typearg = RootContext.LookupType (
4865 ec.DeclSpace, QueriedType, false, loc);
4867 if (typearg == null)
4870 type = TypeManager.type_type;
4871 eclass = ExprClass.Type;
4875 public override void Emit (EmitContext ec)
4877 ec.ig.Emit (OpCodes.Ldtoken, typearg);
4878 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4881 public Type TypeArg {
4882 get { return typearg; }
4887 /// Implements the sizeof expression
4889 public class SizeOf : Expression {
4890 public readonly string QueriedType;
4894 public SizeOf (string queried_type, Location l)
4896 this.QueriedType = queried_type;
4900 public override Expression DoResolve (EmitContext ec)
4902 type_queried = RootContext.LookupType (
4903 ec.DeclSpace, QueriedType, false, loc);
4904 if (type_queried == null)
4907 type = TypeManager.int32_type;
4908 eclass = ExprClass.Value;
4912 public override void Emit (EmitContext ec)
4914 int size = GetTypeSize (type_queried);
4917 ec.ig.Emit (OpCodes.Sizeof, type_queried);
4919 IntConstant.EmitInt (ec.ig, size);
4924 /// Implements the member access expression
4926 public class MemberAccess : Expression {
4927 public readonly string Identifier;
4929 Expression member_lookup;
4932 public MemberAccess (Expression expr, string id, Location l)
4939 public Expression Expr {
4945 static void error176 (Location loc, string name)
4947 Report.Error (176, loc, "Static member `" +
4948 name + "' cannot be accessed " +
4949 "with an instance reference, qualify with a " +
4950 "type name instead");
4953 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
4955 if (left_original == null)
4958 if (!(left_original is SimpleName))
4961 SimpleName sn = (SimpleName) left_original;
4963 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
4970 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
4971 Expression left, Location loc,
4972 Expression left_original)
4977 if (member_lookup is MethodGroupExpr){
4978 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
4983 if (left is TypeExpr){
4984 if (!mg.RemoveInstanceMethods ()){
4985 SimpleName.Error120 (loc, mg.Methods [0].Name);
4989 return member_lookup;
4993 // Instance.MethodGroup
4995 if (IdenticalNameAndTypeName (ec, left_original, loc)){
4996 if (mg.RemoveInstanceMethods ())
4997 return member_lookup;
5000 if (!mg.RemoveStaticMethods ()){
5001 error176 (loc, mg.Methods [0].Name);
5005 mg.InstanceExpression = left;
5006 return member_lookup;
5008 if (!mg.RemoveStaticMethods ()){
5009 if (IdenticalNameAndTypeName (ec, left_original, loc)){
5010 if (!mg.RemoveInstanceMethods ()){
5011 SimpleName.Error120 (loc, mg.Methods [0].Name);
5014 return member_lookup;
5017 error176 (loc, mg.Methods [0].Name);
5021 mg.InstanceExpression = left;
5023 return member_lookup;
5027 if (member_lookup is FieldExpr){
5028 FieldExpr fe = (FieldExpr) member_lookup;
5029 FieldInfo fi = fe.FieldInfo;
5030 Type decl_type = fi.DeclaringType;
5032 if (fi is FieldBuilder) {
5033 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
5036 object o = c.LookupConstantValue (ec);
5037 object real_value = ((Constant) c.Expr).GetValue ();
5039 return Constantify (real_value, fi.FieldType);
5044 Type t = fi.FieldType;
5048 if (fi is FieldBuilder)
5049 o = TypeManager.GetValue ((FieldBuilder) fi);
5051 o = fi.GetValue (fi);
5053 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
5054 Expression enum_member = MemberLookup (
5055 ec, decl_type, "value__", MemberTypes.Field,
5056 AllBindingFlags, loc);
5058 Enum en = TypeManager.LookupEnum (decl_type);
5062 c = Constantify (o, en.UnderlyingType);
5064 c = Constantify (o, enum_member.Type);
5066 return new EnumConstant (c, decl_type);
5069 Expression exp = Constantify (o, t);
5071 if (!(left is TypeExpr)) {
5072 error176 (loc, fe.FieldInfo.Name);
5079 if (fi.FieldType.IsPointer && !ec.InUnsafe){
5084 if (left is TypeExpr){
5085 // and refers to a type name or an
5086 if (!fe.FieldInfo.IsStatic){
5087 error176 (loc, fe.FieldInfo.Name);
5090 return member_lookup;
5092 if (fe.FieldInfo.IsStatic){
5093 if (IdenticalNameAndTypeName (ec, left_original, loc))
5094 return member_lookup;
5096 error176 (loc, fe.FieldInfo.Name);
5099 fe.InstanceExpression = left;
5105 if (member_lookup is PropertyExpr){
5106 PropertyExpr pe = (PropertyExpr) member_lookup;
5108 if (left is TypeExpr){
5110 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
5116 if (IdenticalNameAndTypeName (ec, left_original, loc))
5117 return member_lookup;
5118 error176 (loc, pe.PropertyInfo.Name);
5121 pe.InstanceExpression = left;
5127 if (member_lookup is EventExpr) {
5129 EventExpr ee = (EventExpr) member_lookup;
5132 // If the event is local to this class, we transform ourselves into
5136 Expression ml = MemberLookup (
5137 ec, ec.ContainerType,
5138 ee.EventInfo.Name, MemberTypes.Event, AllBindingFlags, loc);
5141 MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);
5145 // If this happens, then we have an event with its own
5146 // accessors and private field etc so there's no need
5147 // to transform ourselves : we should instead flag an error
5149 Assign.error70 (ee.EventInfo, loc);
5153 ml = ExprClassFromMemberInfo (ec, mi, loc);
5156 Report.Error (-200, loc, "Internal error!!");
5159 return ResolveMemberAccess (ec, ml, left, loc, left_original);
5162 if (left is TypeExpr) {
5164 SimpleName.Error120 (loc, ee.EventInfo.Name);
5172 if (IdenticalNameAndTypeName (ec, left_original, loc))
5175 error176 (loc, ee.EventInfo.Name);
5179 ee.InstanceExpression = left;
5185 if (member_lookup is TypeExpr){
5186 member_lookup.Resolve (ec);
5187 return member_lookup;
5190 Console.WriteLine ("Left is: " + left);
5191 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
5192 Environment.Exit (0);
5196 public override Expression DoResolve (EmitContext ec)
5199 // We are the sole users of ResolveWithSimpleName (ie, the only
5200 // ones that can cope with it
5202 Expression original = expr;
5203 expr = expr.ResolveWithSimpleName (ec);
5208 if (expr is SimpleName){
5209 SimpleName child_expr = (SimpleName) expr;
5211 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
5213 return expr.ResolveWithSimpleName (ec);
5217 // TODO: I mailed Ravi about this, and apparently we can get rid
5218 // of this and put it in the right place.
5220 // Handle enums here when they are in transit.
5221 // Note that we cannot afford to hit MemberLookup in this case because
5222 // it will fail to find any members at all
5225 Type expr_type = expr.Type;
5226 if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){
5228 Enum en = TypeManager.LookupEnum (expr_type);
5231 object value = en.LookupEnumValue (ec, Identifier, loc);
5234 Constant c = Constantify (value, en.UnderlyingType);
5235 return new EnumConstant (c, expr_type);
5240 if (expr_type.IsPointer){
5241 Report.Error (23, loc,
5242 "The `.' operator can not be applied to pointer operands (" +
5243 TypeManager.CSharpName (expr_type) + ")");
5247 member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
5249 if (member_lookup == null){
5251 // Try looking the member up from the same type, if we find
5252 // it, we know that the error was due to limited visibility
5254 object lookup = TypeManager.MemberLookup (
5255 expr_type, expr_type, AllMemberTypes, AllBindingFlags, Identifier);
5257 Report.Error (117, loc, "`" + expr_type + "' does not contain a " +
5258 "definition for `" + Identifier + "'");
5260 Report.Error (122, loc, "`" + expr_type + "." + Identifier + "' " +
5261 "is inaccessible because of its protection level");
5266 return ResolveMemberAccess (ec, member_lookup, expr, loc, original);
5269 public override void Emit (EmitContext ec)
5271 throw new Exception ("Should not happen");
5276 /// Implements checked expressions
5278 public class CheckedExpr : Expression {
5280 public Expression Expr;
5282 public CheckedExpr (Expression e)
5287 public override Expression DoResolve (EmitContext ec)
5289 bool last_const_check = ec.ConstantCheckState;
5291 ec.ConstantCheckState = true;
5292 Expr = Expr.Resolve (ec);
5293 ec.ConstantCheckState = last_const_check;
5298 eclass = Expr.eclass;
5303 public override void Emit (EmitContext ec)
5305 bool last_check = ec.CheckState;
5306 bool last_const_check = ec.ConstantCheckState;
5308 ec.CheckState = true;
5309 ec.ConstantCheckState = true;
5311 ec.CheckState = last_check;
5312 ec.ConstantCheckState = last_const_check;
5318 /// Implements the unchecked expression
5320 public class UnCheckedExpr : Expression {
5322 public Expression Expr;
5324 public UnCheckedExpr (Expression e)
5329 public override Expression DoResolve (EmitContext ec)
5331 bool last_const_check = ec.ConstantCheckState;
5333 ec.ConstantCheckState = false;
5334 Expr = Expr.Resolve (ec);
5335 ec.ConstantCheckState = last_const_check;
5340 eclass = Expr.eclass;
5345 public override void Emit (EmitContext ec)
5347 bool last_check = ec.CheckState;
5348 bool last_const_check = ec.ConstantCheckState;
5350 ec.CheckState = false;
5351 ec.ConstantCheckState = false;
5353 ec.CheckState = last_check;
5354 ec.ConstantCheckState = last_const_check;
5360 /// An Element Access expression.
5362 /// During semantic analysis these are transformed into
5363 /// IndexerAccess or ArrayAccess
5365 public class ElementAccess : Expression {
5366 public ArrayList Arguments;
5367 public Expression Expr;
5368 public Location loc;
5370 public ElementAccess (Expression e, ArrayList e_list, Location l)
5379 Arguments = new ArrayList ();
5380 foreach (Expression tmp in e_list)
5381 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
5385 bool CommonResolve (EmitContext ec)
5387 Expr = Expr.Resolve (ec);
5392 if (Arguments == null)
5395 foreach (Argument a in Arguments){
5396 if (!a.Resolve (ec, loc))
5403 Expression MakePointerAccess ()
5407 if (t == TypeManager.void_ptr_type){
5410 "The array index operation is not valid for void pointers");
5413 if (Arguments.Count != 1){
5416 "A pointer must be indexed by a single value");
5419 Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t);
5420 return new Indirection (p);
5423 public override Expression DoResolve (EmitContext ec)
5425 if (!CommonResolve (ec))
5429 // We perform some simple tests, and then to "split" the emit and store
5430 // code we create an instance of a different class, and return that.
5432 // I am experimenting with this pattern.
5436 if (t.IsSubclassOf (TypeManager.array_type))
5437 return (new ArrayAccess (this)).Resolve (ec);
5438 else if (t.IsPointer)
5439 return MakePointerAccess ();
5441 return (new IndexerAccess (this)).Resolve (ec);
5444 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5446 if (!CommonResolve (ec))
5450 if (t.IsSubclassOf (TypeManager.array_type))
5451 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
5452 else if (t.IsPointer)
5453 return MakePointerAccess ();
5455 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
5458 public override void Emit (EmitContext ec)
5460 throw new Exception ("Should never be reached");
5465 /// Implements array access
5467 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
5469 // Points to our "data" repository
5473 LocalTemporary [] cached_locations;
5475 public ArrayAccess (ElementAccess ea_data)
5478 eclass = ExprClass.Variable;
5481 public override Expression DoResolve (EmitContext ec)
5483 ExprClass eclass = ea.Expr.eclass;
5486 // As long as the type is valid
5487 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
5488 eclass == ExprClass.Value)) {
5489 report118 (ea.loc, ea.Expr, "variable or value");
5494 Type t = ea.Expr.Type;
5495 if (t.GetArrayRank () != ea.Arguments.Count){
5496 Report.Error (22, ea.loc,
5497 "Incorrect number of indexes for array " +
5498 " expected: " + t.GetArrayRank () + " got: " +
5499 ea.Arguments.Count);
5502 type = t.GetElementType ();
5503 if (type.IsPointer && !ec.InUnsafe){
5504 UnsafeError (ea.loc);
5508 eclass = ExprClass.Variable;
5514 /// Emits the right opcode to load an object of Type `t'
5515 /// from an array of T
5517 static public void EmitLoadOpcode (ILGenerator ig, Type type)
5519 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
5520 ig.Emit (OpCodes.Ldelem_I1);
5521 else if (type == TypeManager.sbyte_type)
5522 ig.Emit (OpCodes.Ldelem_U1);
5523 else if (type == TypeManager.short_type)
5524 ig.Emit (OpCodes.Ldelem_I2);
5525 else if (type == TypeManager.ushort_type)
5526 ig.Emit (OpCodes.Ldelem_U2);
5527 else if (type == TypeManager.int32_type)
5528 ig.Emit (OpCodes.Ldelem_I4);
5529 else if (type == TypeManager.uint32_type)
5530 ig.Emit (OpCodes.Ldelem_U4);
5531 else if (type == TypeManager.uint64_type)
5532 ig.Emit (OpCodes.Ldelem_I8);
5533 else if (type == TypeManager.int64_type)
5534 ig.Emit (OpCodes.Ldelem_I8);
5535 else if (type == TypeManager.float_type)
5536 ig.Emit (OpCodes.Ldelem_R4);
5537 else if (type == TypeManager.double_type)
5538 ig.Emit (OpCodes.Ldelem_R8);
5539 else if (type == TypeManager.intptr_type)
5540 ig.Emit (OpCodes.Ldelem_I);
5541 else if (type.IsValueType){
5542 ig.Emit (OpCodes.Ldelema, type);
5543 ig.Emit (OpCodes.Ldobj, type);
5545 ig.Emit (OpCodes.Ldelem_Ref);
5549 /// Emits the right opcode to store an object of Type `t'
5550 /// from an array of T.
5552 static public void EmitStoreOpcode (ILGenerator ig, Type t)
5554 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
5555 t == TypeManager.bool_type)
5556 ig.Emit (OpCodes.Stelem_I1);
5557 else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
5558 ig.Emit (OpCodes.Stelem_I2);
5559 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
5560 ig.Emit (OpCodes.Stelem_I4);
5561 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
5562 ig.Emit (OpCodes.Stelem_I8);
5563 else if (t == TypeManager.float_type)
5564 ig.Emit (OpCodes.Stelem_R4);
5565 else if (t == TypeManager.double_type)
5566 ig.Emit (OpCodes.Stelem_R8);
5567 else if (t == TypeManager.intptr_type)
5568 ig.Emit (OpCodes.Stelem_I);
5569 else if (t.IsValueType)
5570 ig.Emit (OpCodes.Stobj, t);
5572 ig.Emit (OpCodes.Stelem_Ref);
5575 MethodInfo FetchGetMethod ()
5577 ModuleBuilder mb = CodeGen.ModuleBuilder;
5578 int arg_count = ea.Arguments.Count;
5579 Type [] args = new Type [arg_count];
5582 for (int i = 0; i < arg_count; i++){
5583 //args [i++] = a.Type;
5584 args [i] = TypeManager.int32_type;
5587 get = mb.GetArrayMethod (
5588 ea.Expr.Type, "Get",
5589 CallingConventions.HasThis |
5590 CallingConventions.Standard,
5596 MethodInfo FetchAddressMethod ()
5598 ModuleBuilder mb = CodeGen.ModuleBuilder;
5599 int arg_count = ea.Arguments.Count;
5600 Type [] args = new Type [arg_count];
5602 string ptr_type_name;
5605 ptr_type_name = type.FullName + "&";
5606 ret_type = Type.GetType (ptr_type_name);
5609 // It is a type defined by the source code we are compiling
5611 if (ret_type == null){
5612 ret_type = mb.GetType (ptr_type_name);
5615 for (int i = 0; i < arg_count; i++){
5616 //args [i++] = a.Type;
5617 args [i] = TypeManager.int32_type;
5620 address = mb.GetArrayMethod (
5621 ea.Expr.Type, "Address",
5622 CallingConventions.HasThis |
5623 CallingConventions.Standard,
5630 // Load the array arguments into the stack.
5632 // If we have been requested to cache the values (cached_locations array
5633 // initialized), then load the arguments the first time and store them
5634 // in locals. otherwise load from local variables.
5636 void LoadArrayAndArguments (EmitContext ec)
5638 if (cached_locations == null){
5640 foreach (Argument a in ea.Arguments)
5645 ILGenerator ig = ec.ig;
5647 if (cached_locations [0] == null){
5648 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
5650 ig.Emit (OpCodes.Dup);
5651 cached_locations [0].Store (ec);
5655 foreach (Argument a in ea.Arguments){
5656 cached_locations [j] = new LocalTemporary (ec, a.Expr.Type);
5658 ig.Emit (OpCodes.Dup);
5659 cached_locations [j].Store (ec);
5665 foreach (LocalTemporary lt in cached_locations)
5669 public new void CacheTemporaries (EmitContext ec)
5671 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
5674 public override void Emit (EmitContext ec)
5676 int rank = ea.Expr.Type.GetArrayRank ();
5677 ILGenerator ig = ec.ig;
5679 LoadArrayAndArguments (ec);
5682 EmitLoadOpcode (ig, type);
5686 method = FetchGetMethod ();
5687 ig.Emit (OpCodes.Call, method);
5691 public void EmitAssign (EmitContext ec, Expression source)
5693 int rank = ea.Expr.Type.GetArrayRank ();
5694 ILGenerator ig = ec.ig;
5695 Type t = source.Type;
5697 LoadArrayAndArguments (ec);
5700 // The stobj opcode used by value types will need
5701 // an address on the stack, not really an array/array
5705 if (t.IsValueType && !TypeManager.IsBuiltinType (t))
5706 ig.Emit (OpCodes.Ldelema, t);
5712 EmitStoreOpcode (ig, t);
5714 ModuleBuilder mb = CodeGen.ModuleBuilder;
5715 int arg_count = ea.Arguments.Count;
5716 Type [] args = new Type [arg_count + 1];
5719 for (int i = 0; i < arg_count; i++){
5720 //args [i++] = a.Type;
5721 args [i] = TypeManager.int32_type;
5724 args [arg_count] = type;
5726 set = mb.GetArrayMethod (
5727 ea.Expr.Type, "Set",
5728 CallingConventions.HasThis |
5729 CallingConventions.Standard,
5730 TypeManager.void_type, args);
5732 ig.Emit (OpCodes.Call, set);
5736 public void AddressOf (EmitContext ec, AddressOp mode)
5738 int rank = ea.Expr.Type.GetArrayRank ();
5739 ILGenerator ig = ec.ig;
5741 LoadArrayAndArguments (ec);
5744 ig.Emit (OpCodes.Ldelema, type);
5746 MethodInfo address = FetchAddressMethod ();
5747 ig.Emit (OpCodes.Call, address);
5754 public ArrayList getters, setters;
5755 static Hashtable map;
5759 map = new Hashtable ();
5762 Indexers (MemberInfo [] mi)
5764 foreach (PropertyInfo property in mi){
5765 MethodInfo get, set;
5767 get = property.GetGetMethod (true);
5769 if (getters == null)
5770 getters = new ArrayList ();
5775 set = property.GetSetMethod (true);
5777 if (setters == null)
5778 setters = new ArrayList ();
5784 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
5786 Indexers ix = (Indexers) map [lookup_type];
5791 string p_name = TypeManager.IndexerPropertyName (lookup_type);
5793 MemberInfo [] mi = TypeManager.MemberLookup (
5794 caller_type, lookup_type, MemberTypes.Property,
5795 BindingFlags.Public | BindingFlags.Instance, p_name);
5797 if (mi == null || mi.Length == 0){
5798 Report.Error (21, loc,
5799 "Type `" + TypeManager.CSharpName (lookup_type) +
5800 "' does not have any indexers defined");
5804 ix = new Indexers (mi);
5805 map [lookup_type] = ix;
5812 /// Expressions that represent an indexer call.
5814 public class IndexerAccess : Expression, IAssignMethod {
5816 // Points to our "data" repository
5819 MethodInfo get, set;
5821 ArrayList set_arguments;
5823 public IndexerAccess (ElementAccess ea_data)
5826 eclass = ExprClass.Value;
5829 public override Expression DoResolve (EmitContext ec)
5831 Type indexer_type = ea.Expr.Type;
5834 // Step 1: Query for all `Item' *properties*. Notice
5835 // that the actual methods are pointed from here.
5837 // This is a group of properties, piles of them.
5840 ilist = Indexers.GetIndexersForType (
5841 ec.ContainerType, indexer_type, ea.loc);
5845 // Step 2: find the proper match
5847 if (ilist != null && ilist.getters != null && ilist.getters.Count > 0){
5848 Location loc = ea.loc;
5850 get = (MethodInfo) Invocation.OverloadResolve (
5851 ec, new MethodGroupExpr (ilist.getters, loc), ea.Arguments, loc);
5855 Report.Error (154, ea.loc,
5856 "indexer can not be used in this context, because " +
5857 "it lacks a `get' accessor");
5861 type = get.ReturnType;
5862 if (type.IsPointer && !ec.InUnsafe){
5863 UnsafeError (ea.loc);
5867 eclass = ExprClass.IndexerAccess;
5871 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5873 Type indexer_type = ea.Expr.Type;
5874 Type right_type = right_side.Type;
5877 ilist = Indexers.GetIndexersForType (
5878 ec.ContainerType, indexer_type, ea.loc);
5880 if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
5881 Location loc = ea.loc;
5883 set_arguments = (ArrayList) ea.Arguments.Clone ();
5884 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
5886 set = (MethodInfo) Invocation.OverloadResolve (
5887 ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
5891 Report.Error (200, ea.loc,
5892 "indexer X.this [" + TypeManager.CSharpName (right_type) +
5893 "] lacks a `set' accessor");
5897 type = TypeManager.void_type;
5898 eclass = ExprClass.IndexerAccess;
5902 public override void Emit (EmitContext ec)
5904 Invocation.EmitCall (ec, false, false, ea.Expr, get, ea.Arguments);
5908 // source is ignored, because we already have a copy of it from the
5909 // LValue resolution and we have already constructed a pre-cached
5910 // version of the arguments (ea.set_arguments);
5912 public void EmitAssign (EmitContext ec, Expression source)
5914 Invocation.EmitCall (ec, false, false, ea.Expr, set, set_arguments);
5919 /// The base operator for method names
5921 public class BaseAccess : Expression {
5925 public BaseAccess (string member, Location l)
5927 this.member = member;
5931 public override Expression DoResolve (EmitContext ec)
5933 Expression member_lookup;
5934 Type current_type = ec.ContainerType;
5935 Type base_type = current_type.BaseType;
5939 Report.Error (1511, loc,
5940 "Keyword base is not allowed in static method");
5944 member_lookup = MemberLookup (ec, base_type, member, loc);
5945 if (member_lookup == null)
5951 left = new TypeExpr (base_type);
5955 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
5956 if (e is PropertyExpr){
5957 PropertyExpr pe = (PropertyExpr) e;
5965 public override void Emit (EmitContext ec)
5967 throw new Exception ("Should never be called");
5972 /// The base indexer operator
5974 public class BaseIndexerAccess : Expression {
5975 ArrayList Arguments;
5978 public BaseIndexerAccess (ArrayList args, Location l)
5984 public override Expression DoResolve (EmitContext ec)
5986 Type current_type = ec.ContainerType;
5987 Type base_type = current_type.BaseType;
5988 Expression member_lookup;
5991 Report.Error (1511, loc,
5992 "Keyword base is not allowed in static method");
5996 member_lookup = MemberLookup (ec, base_type, "get_Item", MemberTypes.Method, AllBindingFlags, loc);
5997 if (member_lookup == null)
6000 return MemberAccess.ResolveMemberAccess (ec, member_lookup, ec.This, loc, null);
6003 public override void Emit (EmitContext ec)
6005 throw new Exception ("Should never be called");
6010 /// This class exists solely to pass the Type around and to be a dummy
6011 /// that can be passed to the conversion functions (this is used by
6012 /// foreach implementation to typecast the object return value from
6013 /// get_Current into the proper type. All code has been generated and
6014 /// we only care about the side effect conversions to be performed
6016 /// This is also now used as a placeholder where a no-action expression
6017 /// is needed (the `New' class).
6019 public class EmptyExpression : Expression {
6020 public EmptyExpression ()
6022 type = TypeManager.object_type;
6023 eclass = ExprClass.Value;
6026 public EmptyExpression (Type t)
6029 eclass = ExprClass.Value;
6032 public override Expression DoResolve (EmitContext ec)
6037 public override void Emit (EmitContext ec)
6039 // nothing, as we only exist to not do anything.
6043 // This is just because we might want to reuse this bad boy
6044 // instead of creating gazillions of EmptyExpressions.
6045 // (CanConvertImplicit uses it)
6047 public void SetType (Type t)
6053 public class UserCast : Expression {
6057 public UserCast (MethodInfo method, Expression source)
6059 this.method = method;
6060 this.source = source;
6061 type = method.ReturnType;
6062 eclass = ExprClass.Value;
6065 public override Expression DoResolve (EmitContext ec)
6068 // We are born fully resolved
6073 public override void Emit (EmitContext ec)
6075 ILGenerator ig = ec.ig;
6079 if (method is MethodInfo)
6080 ig.Emit (OpCodes.Call, (MethodInfo) method);
6082 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6088 // This class is used to "construct" the type during a typecast
6089 // operation. Since the Type.GetType class in .NET can parse
6090 // the type specification, we just use this to construct the type
6091 // one bit at a time.
6093 public class ComposedCast : Expression {
6098 public ComposedCast (Expression left, string dim, Location l)
6105 public override Expression DoResolve (EmitContext ec)
6107 left = left.Resolve (ec);
6111 if (left.eclass != ExprClass.Type){
6112 report118 (loc, left, "type");
6116 type = RootContext.LookupType (
6117 ec.DeclSpace, left.Type.FullName + dim, false, loc);
6121 if (!ec.InUnsafe && type.IsPointer){
6126 eclass = ExprClass.Type;
6130 public override void Emit (EmitContext ec)
6132 throw new Exception ("This should never be called");
6137 // This class is used to represent the address of an array, used
6138 // only by the Fixed statement, this is like the C "&a [0]" construct.
6140 public class ArrayPtr : Expression {
6143 public ArrayPtr (Expression array)
6145 Type array_type = array.Type.GetElementType ();
6149 string array_ptr_type_name = array_type.FullName + "*";
6151 type = Type.GetType (array_ptr_type_name);
6153 ModuleBuilder mb = CodeGen.ModuleBuilder;
6155 type = mb.GetType (array_ptr_type_name);
6158 eclass = ExprClass.Value;
6161 public override void Emit (EmitContext ec)
6163 ILGenerator ig = ec.ig;
6166 IntLiteral.EmitInt (ig, 0);
6167 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
6170 public override Expression DoResolve (EmitContext ec)
6173 // We are born fully resolved
6180 // Used by the fixed statement
6182 public class StringPtr : Expression {
6185 public StringPtr (LocalBuilder b)
6188 eclass = ExprClass.Value;
6189 type = TypeManager.char_ptr_type;
6192 public override Expression DoResolve (EmitContext ec)
6194 // This should never be invoked, we are born in fully
6195 // initialized state.
6200 public override void Emit (EmitContext ec)
6202 ILGenerator ig = ec.ig;
6204 ig.Emit (OpCodes.Ldloc, b);
6205 ig.Emit (OpCodes.Conv_I);
6206 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
6207 ig.Emit (OpCodes.Add);
6212 // Implements the `stackalloc' keyword
6214 public class StackAlloc : Expression {
6220 public StackAlloc (string type, Expression count, Location l)
6227 public override Expression DoResolve (EmitContext ec)
6229 count = count.Resolve (ec);
6233 if (count.Type != TypeManager.int32_type){
6234 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
6239 if (ec.InCatch || ec.InFinally){
6240 Report.Error (255, loc,
6241 "stackalloc can not be used in a catch or finally block");
6245 otype = RootContext.LookupType (ec.DeclSpace, t, false, loc);
6250 if (!TypeManager.VerifyUnManaged (otype, loc))
6253 string ptr_name = otype.FullName + "*";
6254 type = Type.GetType (ptr_name);
6256 ModuleBuilder mb = CodeGen.ModuleBuilder;
6258 type = mb.GetType (ptr_name);
6260 eclass = ExprClass.Value;
6265 public override void Emit (EmitContext ec)
6267 int size = GetTypeSize (otype);
6268 ILGenerator ig = ec.ig;
6271 ig.Emit (OpCodes.Sizeof, otype);
6273 IntConstant.EmitInt (ig, size);
6275 ig.Emit (OpCodes.Mul);
6276 ig.Emit (OpCodes.Localloc);