2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Manjula GHM (mmanjula@novell.com)
7 // Satya Sudha K (ksathyasudha@novell.com)
9 // (C) 2001 Ximian, Inc.
14 namespace Mono.MonoBASIC {
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// This is just a helper class, it is generated by Unary, UnaryMutator
23 /// when an overloaded method has been found. It just emits the code for a
26 public class StaticCallExpr : ExpressionStatement {
30 StaticCallExpr (MethodInfo m, ArrayList a, Location l)
36 eclass = ExprClass.Value;
40 public override Expression DoResolve (EmitContext ec)
43 // We are born fully resolved
48 public override void Emit (EmitContext ec)
51 Invocation.EmitArguments (ec, mi, args);
53 ec.ig.Emit (OpCodes.Call, mi);
57 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
58 Expression e, Location loc)
63 args = new ArrayList (1);
64 args.Add (new Argument (e, Argument.AType.Expression));
65 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
70 return new StaticCallExpr ((MethodInfo) method, args, loc);
73 public override void EmitStatement (EmitContext ec)
76 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
77 ec.ig.Emit (OpCodes.Pop);
82 /// Unary expressions.
86 /// Unary implements unary expressions. It derives from
87 /// ExpressionStatement becuase the pre/post increment/decrement
88 /// operators can be used in a statement context.
90 public class Unary : Expression {
91 public enum Operator : byte {
92 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
93 Indirection, AddressOf, TOP
97 public Expression Expr;
99 public Unary (Operator op, Expression expr, Location loc)
107 /// Returns a stringified representation of the Operator
109 static public string OperName (Operator oper)
112 case Operator.UnaryPlus:
114 case Operator.UnaryNegation:
116 case Operator.LogicalNot:
118 case Operator.OnesComplement:
120 case Operator.AddressOf:
122 case Operator.Indirection:
126 return oper.ToString ();
129 static string [] oper_names;
133 oper_names = new string [(int)Operator.TOP];
135 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
136 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
137 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
138 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
139 oper_names [(int) Operator.Indirection] = "op_Indirection";
140 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
143 void Error23 (Type t)
146 30311, "Operator " + OperName (Oper) +
147 " cannot be applied to operand of type '" +
148 TypeManager.MonoBASIC_Name (t) + "'");
152 /// The result has been already resolved:
154 /// FIXME: a minus constant -128 sbyte cant be turned into a
157 static Expression TryReduceNegative (Constant expr)
161 if (expr is IntConstant)
162 e = new IntConstant (-((IntConstant) expr).Value);
163 else if (expr is UIntConstant){
164 uint value = ((UIntConstant) expr).Value;
166 if (value < 2147483649)
167 return new IntConstant (-(int)value);
169 e = new LongConstant (value);
171 else if (expr is LongConstant)
172 e = new LongConstant (-((LongConstant) expr).Value);
173 else if (expr is ULongConstant){
174 ulong value = ((ULongConstant) expr).Value;
176 if (value < 9223372036854775809)
177 return new LongConstant(-(long)value);
179 else if (expr is FloatConstant)
180 e = new FloatConstant (-((FloatConstant) expr).Value);
181 else if (expr is DoubleConstant)
182 e = new DoubleConstant (-((DoubleConstant) expr).Value);
183 else if (expr is DecimalConstant)
184 e = new DecimalConstant (-((DecimalConstant) expr).Value);
185 else if (expr is ShortConstant)
186 e = new IntConstant (-((ShortConstant) expr).Value);
187 else if (expr is UShortConstant)
188 e = new IntConstant (-((UShortConstant) expr).Value);
193 // This routine will attempt to simplify the unary expression when the
194 // argument is a constant. The result is returned in 'result' and the
195 // function returns true or false depending on whether a reduction
196 // was performed or not
198 bool Reduce (EmitContext ec, Constant e, out Expression result)
200 Type expr_type = e.Type;
203 case Operator.UnaryPlus:
207 case Operator.UnaryNegation:
208 result = TryReduceNegative (e);
211 case Operator.LogicalNot:
212 if (expr_type != TypeManager.bool_type) {
218 BoolConstant b = (BoolConstant) e;
219 result = new BoolConstant (!(b.Value));
222 case Operator.OnesComplement:
223 if (!((expr_type == TypeManager.int32_type) ||
224 (expr_type == TypeManager.uint32_type) ||
225 (expr_type == TypeManager.int64_type) ||
226 (expr_type == TypeManager.uint64_type) ||
227 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
233 if (e is EnumConstant){
234 EnumConstant enum_constant = (EnumConstant) e;
237 if (Reduce (ec, enum_constant.Child, out reduced)){
238 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
246 if (expr_type == TypeManager.int32_type){
247 result = new IntConstant (~ ((IntConstant) e).Value);
248 } else if (expr_type == TypeManager.uint32_type){
249 result = new UIntConstant (~ ((UIntConstant) e).Value);
250 } else if (expr_type == TypeManager.int64_type){
251 result = new LongConstant (~ ((LongConstant) e).Value);
252 } else if (expr_type == TypeManager.uint64_type){
253 result = new ULongConstant (~ ((ULongConstant) e).Value);
261 case Operator.AddressOf:
265 case Operator.Indirection:
269 throw new Exception ("Can not constant fold: " + Oper.ToString());
272 Expression ResolveOperator (EmitContext ec)
274 Type expr_type = Expr.Type;
278 if (Oper == Operator.LogicalNot && expr_type != TypeManager.bool_type)
279 Oper = Operator.OnesComplement;
282 if ((expr_type == TypeManager.string_type) &&
283 (Oper == Operator.UnaryPlus ||
284 Oper == Operator.UnaryNegation)) {
286 Expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
291 expr_type = Expr.Type;
295 // Step 1: Perform Operator Overload location
297 op_name = oper_names [(int) Oper];
299 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
302 Expression e = StaticCallExpr.MakeSimpleCall (
303 ec, (MethodGroupExpr) mg, Expr, loc);
313 // Only perform numeric promotions on:
316 if (expr_type == null)
320 // Step 2: Default operations on CLI native types.
323 // Attempt to use a constant folding operation.
324 if (Expr is Constant){
327 if (Reduce (ec, (Constant) Expr, out result))
332 case Operator.LogicalNot:
333 if (expr_type != TypeManager.bool_type) {
338 type = TypeManager.bool_type;
341 case Operator.OnesComplement:
342 if (expr_type == TypeManager.string_type ||
343 expr_type == TypeManager.decimal_type ||
344 expr_type == TypeManager.double_type ||
345 expr_type == TypeManager.float_type) {
346 if ((Expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc)) == null) {
350 expr_type = Expr.Type;
353 if (expr_type == TypeManager.int64_type) {
357 if (expr_type == TypeManager.byte_type ||
358 expr_type == TypeManager.short_type ||
359 expr_type == TypeManager.int32_type) {
360 type = TypeManager.int32_type;
364 if (expr_type == TypeManager.object_type) {
365 Expression etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.ObjectType.NotObj", Location.Null);
366 ArrayList arguments = new ArrayList ();
367 arguments.Add (new Argument (Expr, Argument.AType.Expression));
368 Expression e = new Invocation (etmp, arguments, loc);
369 return e.Resolve (ec);
373 case Operator.AddressOf:
374 // Not required in VB ??
375 if (Expr.eclass != ExprClass.Variable){
376 Error (211, "Cannot take the address of non-variables");
385 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
389 string ptr_type_name = Expr.Type.FullName + "*";
390 type = TypeManager.LookupType (ptr_type_name);
394 case Operator.Indirection:
400 if (!expr_type.IsPointer){
403 "The * or -> operator can only be applied to pointers");
408 // We create an Indirection expression, because
409 // it can implement the IMemoryLocation.
411 return new Indirection (Expr, loc);
413 case Operator.UnaryPlus:
415 // A plus in front of something is just a no-op, so return the child.
417 if (expr_type == TypeManager.string_type) {
418 Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
420 type = TypeManager.double_type;
425 if (expr_type == TypeManager.bool_type) {
426 Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
428 type = TypeManager.int32_type;
435 case Operator.UnaryNegation:
437 // Deals with -literals
438 // int operator- (int x)
439 // long operator- (long x)
440 // float operator- (float f)
441 // double operator- (double d)
442 // decimal operator- (decimal d)
446 // transform - - expr into expr
449 Unary unary = (Unary) Expr;
451 if (unary.Oper == Operator.UnaryNegation)
456 // perform numeric promotions to int,
460 // The following is inneficient, because we call
461 // ConvertImplicit too many times.
463 // It is also not clear if we should convert to Float
464 // or Double initially.
466 if (expr_type == TypeManager.string_type) {
467 Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
470 type = TypeManager.double_type;
475 if (expr_type == TypeManager.bool_type) {
476 Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
479 type = TypeManager.int32_type;
484 if (expr_type == TypeManager.float_type ||
485 expr_type == TypeManager.double_type) {
490 if (expr_type == TypeManager.short_type ||
491 expr_type == TypeManager.byte_type) {
492 type = TypeManager.int32_type;
496 if (expr_type == TypeManager.int32_type ||
497 expr_type == TypeManager.int64_type) {
498 Expression e = new Binary (Binary.Operator.Subtraction, new IntLiteral (0), Expr, loc);
499 return e.Resolve (ec);
506 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
507 TypeManager.MonoBASIC_Name (expr_type) + "'");
511 public override Expression DoResolve (EmitContext ec)
513 if (Oper == Operator.AddressOf)
514 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
516 Expr = Expr.Resolve (ec);
521 Type init_type = Expr.Type;
523 eclass = ExprClass.Value;
524 Expression etmp = ResolveOperator (ec);
525 // Convert the result to byte/short if operands are of type byte/short/boolean
526 if (etmp.Type != init_type &&
527 (init_type == TypeManager.byte_type ||
528 init_type == TypeManager.short_type ||
529 init_type == TypeManager.bool_type)) {
530 Expression conv_exp = null;
531 if (init_type == TypeManager.byte_type && Oper != Operator.UnaryNegation) {
532 return new OpcodeCast (etmp, TypeManager.byte_type, OpCodes.Conv_U1);
535 conv_exp = ConvertImplicit (ec, etmp, TypeManager.short_type, loc);
537 if (conv_exp != null)
543 public override void Emit (EmitContext ec)
545 ILGenerator ig = ec.ig;
548 case Operator.UnaryPlus:
549 throw new Exception ("This should be caught by Resolve");
551 case Operator.UnaryNegation:
553 ig.Emit (OpCodes.Neg);
556 case Operator.LogicalNot:
558 ig.Emit (OpCodes.Ldc_I4_0);
559 ig.Emit (OpCodes.Ceq);
562 case Operator.OnesComplement:
564 ig.Emit (OpCodes.Not);
567 case Operator.AddressOf:
568 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
572 throw new Exception ("This should not happen: Operator = "
578 /// This will emit the child expression for 'ec' avoiding the logical
579 /// not. The parent will take care of changing brfalse/brtrue
581 public void EmitLogicalNot (EmitContext ec)
583 if (Oper != Operator.LogicalNot)
584 throw new Exception ("EmitLogicalNot can only be called with !expr");
589 public override string ToString ()
591 return "Unary (" + Oper + ", " + Expr + ")";
597 // Unary operators are turned into Indirection expressions
598 // after semantic analysis (this is so we can take the address
599 // of an indirection).
601 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
603 LocalTemporary temporary;
606 public Indirection (Expression expr, Location l)
609 this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
610 eclass = ExprClass.Variable;
614 void LoadExprValue (EmitContext ec)
618 public override void Emit (EmitContext ec)
620 ILGenerator ig = ec.ig;
622 if (temporary != null){
628 ec.ig.Emit (OpCodes.Dup);
629 temporary.Store (ec);
630 have_temporary = true;
634 LoadFromPtr (ig, Type);
637 public void EmitAssign (EmitContext ec, Expression source)
639 if (temporary != null){
645 ec.ig.Emit (OpCodes.Dup);
646 temporary.Store (ec);
647 have_temporary = true;
652 StoreFromPtr (ec.ig, type);
655 public void AddressOf (EmitContext ec, AddressOp Mode)
657 if (temporary != null){
663 ec.ig.Emit (OpCodes.Dup);
664 temporary.Store (ec);
665 have_temporary = true;
670 public override Expression DoResolve (EmitContext ec)
673 // Born fully resolved
678 public new void CacheTemporaries (EmitContext ec)
680 temporary = new LocalTemporary (ec, type);
685 /// Unary Mutator expressions (pre and post ++ and --)
689 /// UnaryMutator implements ++ and -- expressions. It derives from
690 /// ExpressionStatement becuase the pre/post increment/decrement
691 /// operators can be used in a statement context.
693 /// FIXME: Idea, we could split this up in two classes, one simpler
694 /// for the common case, and one with the extra fields for more complex
695 /// classes (indexers require temporary access; overloaded require method)
697 /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
698 /// PostDecrement, that way we could save the 'Mode' byte as well.
700 public class UnaryMutator : ExpressionStatement {
701 public enum Mode : byte {
702 PreIncrement, PreDecrement, PostIncrement, PostDecrement
707 LocalTemporary temp_storage;
710 // This is expensive for the simplest case.
714 public UnaryMutator (Mode m, Expression e, Location l)
721 static string OperName (Mode mode)
723 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
727 void Error23 (Type t)
730 30311, "Operator " + OperName (mode) +
731 " cannot be applied to operand of type '" +
732 TypeManager.MonoBASIC_Name (t) + "'");
736 /// Returns whether an object of type 't' can be incremented
737 /// or decremented with add/sub (ie, basically whether we can
738 /// use pre-post incr-decr operations on it, but it is not a
739 /// System.Decimal, which we require operator overloading to catch)
741 static bool IsIncrementableNumber (Type t)
743 return (t == TypeManager.sbyte_type) ||
744 (t == TypeManager.byte_type) ||
745 (t == TypeManager.short_type) ||
746 (t == TypeManager.ushort_type) ||
747 (t == TypeManager.int32_type) ||
748 (t == TypeManager.uint32_type) ||
749 (t == TypeManager.int64_type) ||
750 (t == TypeManager.uint64_type) ||
751 (t == TypeManager.char_type) ||
752 (t.IsSubclassOf (TypeManager.enum_type)) ||
753 (t == TypeManager.float_type) ||
754 (t == TypeManager.double_type) ||
755 (t.IsPointer && t != TypeManager.void_ptr_type);
758 Expression ResolveOperator (EmitContext ec)
760 Type expr_type = expr.Type;
763 // Step 1: Perform Operator Overload location
768 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
769 op_name = "op_Increment";
771 op_name = "op_Decrement";
773 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
775 if (mg == null && expr_type.BaseType != null)
776 mg = MemberLookup (ec, expr_type.BaseType, op_name,
777 MemberTypes.Method, AllBindingFlags, loc);
780 method = StaticCallExpr.MakeSimpleCall (
781 ec, (MethodGroupExpr) mg, expr, loc);
788 // The operand of the prefix/postfix increment decrement operators
789 // should be an expression that is classified as a variable,
790 // a property access or an indexer access
793 if (expr.eclass == ExprClass.Variable){
794 if (IsIncrementableNumber (expr_type) ||
795 expr_type == TypeManager.decimal_type){
798 } else if (expr.eclass == ExprClass.IndexerAccess){
799 IndexerAccess ia = (IndexerAccess) expr;
801 temp_storage = new LocalTemporary (ec, expr.Type);
803 expr = ia.ResolveLValue (ec, temp_storage);
808 } else if (expr.eclass == ExprClass.PropertyAccess){
809 PropertyExpr pe = (PropertyExpr) expr;
811 if (pe.VerifyAssignable ())
816 expr.Error118 ("variable, indexer or property access");
820 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
821 TypeManager.MonoBASIC_Name (expr_type) + "'");
825 public override Expression DoResolve (EmitContext ec)
827 expr = expr.Resolve (ec);
832 eclass = ExprClass.Value;
833 return ResolveOperator (ec);
836 static int PtrTypeSize (Type t)
838 return GetTypeSize (t.GetElementType ());
842 // Loads the proper "1" into the stack based on the type
844 static void LoadOne (ILGenerator ig, Type t)
846 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
847 ig.Emit (OpCodes.Ldc_I8, 1L);
848 else if (t == TypeManager.double_type)
849 ig.Emit (OpCodes.Ldc_R8, 1.0);
850 else if (t == TypeManager.float_type)
851 ig.Emit (OpCodes.Ldc_R4, 1.0F);
852 else if (t.IsPointer){
853 int n = PtrTypeSize (t);
856 ig.Emit (OpCodes.Sizeof, t);
858 IntConstant.EmitInt (ig, n);
860 ig.Emit (OpCodes.Ldc_I4_1);
865 // FIXME: We need some way of avoiding the use of temp_storage
866 // for some types of storage (parameters, local variables,
867 // static fields) and single-dimension array access.
869 void EmitCode (EmitContext ec, bool is_expr)
871 ILGenerator ig = ec.ig;
872 IAssignMethod ia = (IAssignMethod) expr;
873 Type expr_type = expr.Type;
875 if (temp_storage == null)
876 temp_storage = new LocalTemporary (ec, expr_type);
878 ia.CacheTemporaries (ec);
879 ig.Emit (OpCodes.Nop);
881 case Mode.PreIncrement:
882 case Mode.PreDecrement:
886 LoadOne (ig, expr_type);
889 // Select the opcode based on the check state (then the type)
890 // and the actual operation
893 if (expr_type == TypeManager.int32_type ||
894 expr_type == TypeManager.int64_type){
895 if (mode == Mode.PreDecrement)
896 ig.Emit (OpCodes.Sub_Ovf);
898 ig.Emit (OpCodes.Add_Ovf);
899 } else if (expr_type == TypeManager.uint32_type ||
900 expr_type == TypeManager.uint64_type){
901 if (mode == Mode.PreDecrement)
902 ig.Emit (OpCodes.Sub_Ovf_Un);
904 ig.Emit (OpCodes.Add_Ovf_Un);
906 if (mode == Mode.PreDecrement)
907 ig.Emit (OpCodes.Sub_Ovf);
909 ig.Emit (OpCodes.Add_Ovf);
912 if (mode == Mode.PreDecrement)
913 ig.Emit (OpCodes.Sub);
915 ig.Emit (OpCodes.Add);
920 temp_storage.Store (ec);
921 ia.EmitAssign (ec, temp_storage);
923 temp_storage.Emit (ec);
926 case Mode.PostIncrement:
927 case Mode.PostDecrement:
935 ig.Emit (OpCodes.Dup);
937 LoadOne (ig, expr_type);
940 if (expr_type == TypeManager.int32_type ||
941 expr_type == TypeManager.int64_type){
942 if (mode == Mode.PostDecrement)
943 ig.Emit (OpCodes.Sub_Ovf);
945 ig.Emit (OpCodes.Add_Ovf);
946 } else if (expr_type == TypeManager.uint32_type ||
947 expr_type == TypeManager.uint64_type){
948 if (mode == Mode.PostDecrement)
949 ig.Emit (OpCodes.Sub_Ovf_Un);
951 ig.Emit (OpCodes.Add_Ovf_Un);
953 if (mode == Mode.PostDecrement)
954 ig.Emit (OpCodes.Sub_Ovf);
956 ig.Emit (OpCodes.Add_Ovf);
959 if (mode == Mode.PostDecrement)
960 ig.Emit (OpCodes.Sub);
962 ig.Emit (OpCodes.Add);
968 temp_storage.Store (ec);
969 ia.EmitAssign (ec, temp_storage);
974 public override void Emit (EmitContext ec)
980 public override void EmitStatement (EmitContext ec)
982 EmitCode (ec, false);
988 /// Base class for the 'Is' and 'As' classes.
992 /// FIXME: Split this in two, and we get to save the 'Operator' Oper
995 public abstract class Probe : Expression {
996 public readonly Expression ProbeType;
997 protected Expression expr;
998 protected Type probe_type;
1000 public Probe (Expression expr, Expression probe_type, Location l)
1002 ProbeType = probe_type;
1007 public Expression Expr {
1013 public override Expression DoResolve (EmitContext ec)
1015 probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1017 if (probe_type == null)
1020 expr = expr.Resolve (ec);
1027 /// Implementation of the 'is' operator.
1029 public class Is : Probe {
1030 public Is (Expression expr, Expression probe_type, Location l)
1031 : base (expr, probe_type, l)
1036 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1041 public override void Emit (EmitContext ec)
1043 ILGenerator ig = ec.ig;
1048 case Action.AlwaysFalse:
1049 ig.Emit (OpCodes.Pop);
1050 IntConstant.EmitInt (ig, 0);
1052 case Action.AlwaysTrue:
1053 ig.Emit (OpCodes.Pop);
1054 ig.Emit (OpCodes.Nop);
1055 IntConstant.EmitInt (ig, 1);
1057 case Action.LeaveOnStack:
1058 // the 'e != null' rule.
1061 ig.Emit (OpCodes.Isinst, probe_type);
1062 ig.Emit (OpCodes.Ldnull);
1063 ig.Emit (OpCodes.Cgt_Un);
1066 throw new Exception ("never reached");
1069 public override Expression DoResolve (EmitContext ec)
1071 Expression e = base.DoResolve (ec);
1073 if ((e == null) || (expr == null))
1076 Type etype = expr.Type;
1077 bool warning_always_matches = false;
1078 bool warning_never_matches = false;
1080 type = TypeManager.bool_type;
1081 eclass = ExprClass.Value;
1084 // First case, if at compile time, there is an implicit conversion
1085 // then e != null (objects) or true (value types)
1087 e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1090 if (etype.IsValueType)
1091 action = Action.AlwaysTrue;
1093 action = Action.LeaveOnStack;
1095 warning_always_matches = true;
1096 } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1098 // Second case: explicit reference convresion
1100 if (expr is NullLiteral)
1101 action = Action.AlwaysFalse;
1103 action = Action.Probe;
1105 action = Action.AlwaysFalse;
1106 warning_never_matches = true;
1109 if (RootContext.WarningLevel >= 1){
1110 if (warning_always_matches)
1113 "The expression is always of type '" +
1114 TypeManager.MonoBASIC_Name (probe_type) + "'");
1115 else if (warning_never_matches){
1116 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1119 "The expression is never of type '" +
1120 TypeManager.MonoBASIC_Name (probe_type) + "'");
1129 /// Implementation of the 'as' operator.
1131 public class As : Probe {
1132 public As (Expression expr, Expression probe_type, Location l)
1133 : base (expr, probe_type, l)
1137 bool do_isinst = false;
1139 public override void Emit (EmitContext ec)
1141 ILGenerator ig = ec.ig;
1146 ig.Emit (OpCodes.Isinst, probe_type);
1149 static void Error_CannotConvertType (Type source, Type target, Location loc)
1152 39, loc, "as operator can not convert from '" +
1153 TypeManager.MonoBASIC_Name (source) + "' to '" +
1154 TypeManager.MonoBASIC_Name (target) + "'");
1157 public override Expression DoResolve (EmitContext ec)
1159 Expression e = base.DoResolve (ec);
1165 eclass = ExprClass.Value;
1166 Type etype = expr.Type;
1168 if (TypeManager.IsValueType (probe_type)){
1169 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1170 TypeManager.MonoBASIC_Name (probe_type) + " is a value type)");
1175 e = ConvertImplicit (ec, expr, probe_type, loc);
1182 if (ExplicitReferenceConversionExists (etype, probe_type)){
1187 Error_CannotConvertType (etype, probe_type, loc);
1193 /// This represents a typecast in the source language.
1195 /// FIXME: Cast expressions have an unusual set of parsing
1196 /// rules, we need to figure those out.
1198 public class Cast : Expression {
1199 Expression target_type;
1203 public Cast (Expression cast_type, Expression expr, Location loc)
1205 this.target_type = cast_type;
1208 runtime_cast = false;
1211 public Expression TargetType {
1217 public Expression Expr {
1226 public bool IsRuntimeCast
1229 return runtime_cast;
1232 runtime_cast = value;
1237 /// Attempts to do a compile-time folding of a constant cast.
1239 Expression TryReduce (EmitContext ec, Type target_type)
1241 if (expr is ByteConstant){
1242 byte v = ((ByteConstant) expr).Value;
1244 if (target_type == TypeManager.sbyte_type)
1245 return new SByteConstant ((sbyte) v);
1246 if (target_type == TypeManager.short_type)
1247 return new ShortConstant ((short) v);
1248 if (target_type == TypeManager.ushort_type)
1249 return new UShortConstant ((ushort) v);
1250 if (target_type == TypeManager.int32_type)
1251 return new IntConstant ((int) v);
1252 if (target_type == TypeManager.uint32_type)
1253 return new UIntConstant ((uint) v);
1254 if (target_type == TypeManager.int64_type)
1255 return new LongConstant ((long) v);
1256 if (target_type == TypeManager.uint64_type)
1257 return new ULongConstant ((ulong) v);
1258 if (target_type == TypeManager.float_type)
1259 return new FloatConstant ((float) v);
1260 if (target_type == TypeManager.double_type)
1261 return new DoubleConstant ((double) v);
1262 if (target_type == TypeManager.char_type)
1263 return new CharConstant ((char) v);
1264 if (target_type == TypeManager.decimal_type)
1265 return new DecimalConstant ((decimal) v);
1267 if (expr is SByteConstant){
1268 sbyte v = ((SByteConstant) expr).Value;
1270 if (target_type == TypeManager.byte_type)
1271 return new ByteConstant ((byte) v);
1272 if (target_type == TypeManager.short_type)
1273 return new ShortConstant ((short) v);
1274 if (target_type == TypeManager.ushort_type)
1275 return new UShortConstant ((ushort) v);
1276 if (target_type == TypeManager.int32_type)
1277 return new IntConstant ((int) v);
1278 if (target_type == TypeManager.uint32_type)
1279 return new UIntConstant ((uint) 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);
1288 if (target_type == TypeManager.char_type)
1289 return new CharConstant ((char) v);
1290 if (target_type == TypeManager.decimal_type)
1291 return new DecimalConstant ((decimal) v);
1293 if (expr is ShortConstant){
1294 short v = ((ShortConstant) expr).Value;
1296 if (target_type == TypeManager.byte_type)
1297 return new ByteConstant ((byte) v);
1298 if (target_type == TypeManager.sbyte_type)
1299 return new SByteConstant ((sbyte) v);
1300 if (target_type == TypeManager.ushort_type)
1301 return new UShortConstant ((ushort) v);
1302 if (target_type == TypeManager.int32_type)
1303 return new IntConstant ((int) v);
1304 if (target_type == TypeManager.uint32_type)
1305 return new UIntConstant ((uint) v);
1306 if (target_type == TypeManager.int64_type)
1307 return new LongConstant ((long) v);
1308 if (target_type == TypeManager.uint64_type)
1309 return new ULongConstant ((ulong) v);
1310 if (target_type == TypeManager.float_type)
1311 return new FloatConstant ((float) v);
1312 if (target_type == TypeManager.double_type)
1313 return new DoubleConstant ((double) v);
1314 if (target_type == TypeManager.char_type)
1315 return new CharConstant ((char) v);
1316 if (target_type == TypeManager.decimal_type)
1317 return new DecimalConstant ((decimal) v);
1319 if (expr is UShortConstant){
1320 ushort v = ((UShortConstant) expr).Value;
1322 if (target_type == TypeManager.byte_type)
1323 return new ByteConstant ((byte) v);
1324 if (target_type == TypeManager.sbyte_type)
1325 return new SByteConstant ((sbyte) v);
1326 if (target_type == TypeManager.short_type)
1327 return new ShortConstant ((short) v);
1328 if (target_type == TypeManager.int32_type)
1329 return new IntConstant ((int) v);
1330 if (target_type == TypeManager.uint32_type)
1331 return new UIntConstant ((uint) v);
1332 if (target_type == TypeManager.int64_type)
1333 return new LongConstant ((long) v);
1334 if (target_type == TypeManager.uint64_type)
1335 return new ULongConstant ((ulong) v);
1336 if (target_type == TypeManager.float_type)
1337 return new FloatConstant ((float) v);
1338 if (target_type == TypeManager.double_type)
1339 return new DoubleConstant ((double) v);
1340 if (target_type == TypeManager.char_type)
1341 return new CharConstant ((char) v);
1342 if (target_type == TypeManager.decimal_type)
1343 return new DecimalConstant ((decimal) v);
1345 if (expr is IntConstant){
1346 int v = ((IntConstant) expr).Value;
1348 if (target_type == TypeManager.byte_type)
1349 return new ByteConstant ((byte) v);
1350 if (target_type == TypeManager.sbyte_type)
1351 return new SByteConstant ((sbyte) v);
1352 if (target_type == TypeManager.short_type)
1353 return new ShortConstant ((short) v);
1354 if (target_type == TypeManager.ushort_type)
1355 return new UShortConstant ((ushort) v);
1356 if (target_type == TypeManager.uint32_type)
1357 return new UIntConstant ((uint) v);
1358 if (target_type == TypeManager.int64_type)
1359 return new LongConstant ((long) v);
1360 if (target_type == TypeManager.uint64_type)
1361 return new ULongConstant ((ulong) v);
1362 if (target_type == TypeManager.float_type)
1363 return new FloatConstant ((float) v);
1364 if (target_type == TypeManager.double_type)
1365 return new DoubleConstant ((double) v);
1366 if (target_type == TypeManager.char_type)
1367 return new CharConstant ((char) v);
1368 if (target_type == TypeManager.decimal_type)
1369 return new DecimalConstant ((decimal) v);
1371 if (expr is UIntConstant){
1372 uint v = ((UIntConstant) expr).Value;
1374 if (target_type == TypeManager.byte_type)
1375 return new ByteConstant ((byte) v);
1376 if (target_type == TypeManager.sbyte_type)
1377 return new SByteConstant ((sbyte) v);
1378 if (target_type == TypeManager.short_type)
1379 return new ShortConstant ((short) v);
1380 if (target_type == TypeManager.ushort_type)
1381 return new UShortConstant ((ushort) v);
1382 if (target_type == TypeManager.int32_type)
1383 return new IntConstant ((int) v);
1384 if (target_type == TypeManager.int64_type)
1385 return new LongConstant ((long) v);
1386 if (target_type == TypeManager.uint64_type)
1387 return new ULongConstant ((ulong) v);
1388 if (target_type == TypeManager.float_type)
1389 return new FloatConstant ((float) v);
1390 if (target_type == TypeManager.double_type)
1391 return new DoubleConstant ((double) v);
1392 if (target_type == TypeManager.char_type)
1393 return new CharConstant ((char) v);
1394 if (target_type == TypeManager.decimal_type)
1395 return new DecimalConstant ((decimal) v);
1397 if (expr is LongConstant){
1398 long v = ((LongConstant) expr).Value;
1400 if (target_type == TypeManager.byte_type)
1401 return new ByteConstant ((byte) v);
1402 if (target_type == TypeManager.sbyte_type)
1403 return new SByteConstant ((sbyte) v);
1404 if (target_type == TypeManager.short_type)
1405 return new ShortConstant ((short) v);
1406 if (target_type == TypeManager.ushort_type)
1407 return new UShortConstant ((ushort) v);
1408 if (target_type == TypeManager.int32_type)
1409 return new IntConstant ((int) v);
1410 if (target_type == TypeManager.uint32_type)
1411 return new UIntConstant ((uint) v);
1412 if (target_type == TypeManager.uint64_type)
1413 return new ULongConstant ((ulong) v);
1414 if (target_type == TypeManager.float_type)
1415 return new FloatConstant ((float) v);
1416 if (target_type == TypeManager.double_type)
1417 return new DoubleConstant ((double) v);
1418 if (target_type == TypeManager.char_type)
1419 return new CharConstant ((char) v);
1420 if (target_type == TypeManager.decimal_type)
1421 return new DecimalConstant ((decimal) v);
1423 if (expr is ULongConstant){
1424 ulong v = ((ULongConstant) expr).Value;
1426 if (target_type == TypeManager.byte_type)
1427 return new ByteConstant ((byte) v);
1428 if (target_type == TypeManager.sbyte_type)
1429 return new SByteConstant ((sbyte) v);
1430 if (target_type == TypeManager.short_type)
1431 return new ShortConstant ((short) v);
1432 if (target_type == TypeManager.ushort_type)
1433 return new UShortConstant ((ushort) v);
1434 if (target_type == TypeManager.int32_type)
1435 return new IntConstant ((int) v);
1436 if (target_type == TypeManager.uint32_type)
1437 return new UIntConstant ((uint) v);
1438 if (target_type == TypeManager.int64_type)
1439 return new LongConstant ((long) v);
1440 if (target_type == TypeManager.float_type)
1441 return new FloatConstant ((float) v);
1442 if (target_type == TypeManager.double_type)
1443 return new DoubleConstant ((double) v);
1444 if (target_type == TypeManager.char_type)
1445 return new CharConstant ((char) v);
1446 if (target_type == TypeManager.decimal_type)
1447 return new DecimalConstant ((decimal) v);
1449 if (expr is FloatConstant){
1450 float v = ((FloatConstant) expr).Value;
1452 if (target_type == TypeManager.byte_type)
1453 return new ByteConstant ((byte) v);
1454 if (target_type == TypeManager.sbyte_type)
1455 return new SByteConstant ((sbyte) v);
1456 if (target_type == TypeManager.short_type)
1457 return new ShortConstant ((short) v);
1458 if (target_type == TypeManager.ushort_type)
1459 return new UShortConstant ((ushort) v);
1460 if (target_type == TypeManager.int32_type)
1461 return new IntConstant ((int) v);
1462 if (target_type == TypeManager.uint32_type)
1463 return new UIntConstant ((uint) v);
1464 if (target_type == TypeManager.int64_type)
1465 return new LongConstant ((long) v);
1466 if (target_type == TypeManager.uint64_type)
1467 return new ULongConstant ((ulong) v);
1468 if (target_type == TypeManager.double_type)
1469 return new DoubleConstant ((double) v);
1470 if (target_type == TypeManager.char_type)
1471 return new CharConstant ((char) v);
1472 if (target_type == TypeManager.decimal_type)
1473 return new DecimalConstant ((decimal) v);
1475 if (expr is DoubleConstant){
1476 double v = ((DoubleConstant) expr).Value;
1478 if (target_type == TypeManager.byte_type)
1479 return new ByteConstant ((byte) v);
1480 if (target_type == TypeManager.sbyte_type)
1481 return new SByteConstant ((sbyte) v);
1482 if (target_type == TypeManager.short_type)
1483 return new ShortConstant ((short) v);
1484 if (target_type == TypeManager.ushort_type)
1485 return new UShortConstant ((ushort) v);
1486 if (target_type == TypeManager.int32_type)
1487 return new IntConstant ((int) v);
1488 if (target_type == TypeManager.uint32_type)
1489 return new UIntConstant ((uint) v);
1490 if (target_type == TypeManager.int64_type)
1491 return new LongConstant ((long) v);
1492 if (target_type == TypeManager.uint64_type)
1493 return new ULongConstant ((ulong) v);
1494 if (target_type == TypeManager.float_type)
1495 return new FloatConstant ((float) v);
1496 if (target_type == TypeManager.char_type)
1497 return new CharConstant ((char) v);
1498 if (target_type == TypeManager.decimal_type)
1499 return new DecimalConstant ((decimal) v);
1505 public override Expression DoResolve (EmitContext ec)
1507 expr = expr.Resolve (ec);
1511 type = ec.DeclSpace.ResolveType (target_type, false, Location);
1516 eclass = ExprClass.Value;
1518 if (expr is Constant){
1519 Expression e = TryReduce (ec, type);
1525 expr = ConvertExplicit (ec, expr, type, runtime_cast, loc);
1529 public override void Emit (EmitContext ec)
1532 // This one will never happen
1534 throw new Exception ("Should not happen");
1538 public class StringConcat : Expression {
1540 Expression left, right;
1541 ArrayList Arguments;
1542 protected MethodBase method;
1544 public StringConcat(Location loc, Expression left, Expression right) {
1550 public override Expression DoResolve (EmitContext ec)
1552 left = left.Resolve (ec);
1553 right = right.Resolve (ec);
1555 if (left == null || right == null)
1558 if (left.Type == null)
1559 throw new Exception (
1560 "Resolve returned non null, but did not set the type! (" +
1561 left + ") at Line: " + loc.Row);
1562 if (right.Type == null)
1563 throw new Exception (
1564 "Resolve returned non null, but did not set the type! (" +
1565 right + ") at Line: "+ loc.Row);
1567 eclass = ExprClass.Value;
1568 if (left is StringConstant && right is StringConstant){
1569 return new StringConstant (
1570 ((StringConstant) left).Value +
1571 ((StringConstant) right).Value);
1575 Type r = right.Type;
1577 if (l == TypeManager.string_type && r == TypeManager.string_type) {
1578 type = TypeManager.string_type;
1579 method = TypeManager.string_concat_string_string;
1580 Arguments = new ArrayList ();
1581 Arguments.Add (new Argument (left, Argument.AType.Expression));
1582 Arguments.Add (new Argument (right, Argument.AType.Expression));
1586 if (l != TypeManager.string_type) {
1587 method = TypeManager.string_concat_object_object;
1588 left = ConvertImplicit (ec, left, TypeManager.string_type, loc);
1590 Error_OperatorCannotBeApplied (loc, "&", l, r);
1594 type = TypeManager.string_type;
1595 Arguments = new ArrayList ();
1596 Arguments.Add (new Argument (left, Argument.AType.Expression));
1597 Arguments.Add (new Argument (right, Argument.AType.Expression));
1601 if (r != TypeManager.string_type) {
1602 method = TypeManager.string_concat_object_object;
1603 right = ConvertImplicit (ec, right, TypeManager.string_type, loc);
1605 Error_OperatorCannotBeApplied (loc, "&", l, r);
1609 type = TypeManager.string_type;
1610 Arguments = new ArrayList ();
1611 Arguments.Add (new Argument (left, Argument.AType.Expression));
1612 Arguments.Add (new Argument (right, Argument.AType.Expression));
1618 public override void Emit (EmitContext ec)
1620 ILGenerator ig = ec.ig;
1621 if (method != null) {
1622 // Note that operators are static anyway
1623 if (Arguments != null)
1624 Invocation.EmitArguments (ec, method, Arguments);
1625 if (method is MethodInfo)
1626 ig.Emit (OpCodes.Call, (MethodInfo) method);
1628 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1634 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1636 Report.Error (19, loc,
1637 "Operator " + name + " cannot be applied to operands of type '" +
1638 TypeManager.MonoBASIC_Name (l) + "' and '" +
1639 TypeManager.MonoBASIC_Name (r) + "'");
1646 /// Binary operators
1648 public class Binary : Expression {
1649 public enum Operator : byte {
1651 Multiply, Division, IntDivision, Modulus,
1652 Addition, Subtraction,
1653 LeftShift, RightShift,
1654 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1655 Equality, Inequality,
1667 Expression left, right;
1670 // After resolution, method might contain the operator overload
1673 protected MethodBase method;
1674 ArrayList Arguments;
1676 bool DelegateOperation;
1678 // This must be kept in sync with Operator!!!
1679 static string [] oper_names;
1683 oper_names = new string [(int) Operator.TOP];
1685 oper_names [(int) Operator.Multiply] = "op_Multiply";
1686 oper_names [(int) Operator.Division] = "op_Division";
1687 oper_names [(int) Operator.IntDivision] = "op_Division";
1688 oper_names [(int) Operator.Modulus] = "op_Modulus";
1689 oper_names [(int) Operator.Addition] = "op_Addition";
1690 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1691 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1692 oper_names [(int) Operator.RightShift] = "op_RightShift";
1693 oper_names [(int) Operator.LessThan] = "op_LessThan";
1694 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1695 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1696 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1697 oper_names [(int) Operator.Equality] = "op_Equality";
1698 oper_names [(int) Operator.Inequality] = "op_Inequality";
1699 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1700 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1701 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1702 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1703 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1704 oper_names [(int) Operator.Is] = "op_Is";
1707 public Binary (Operator oper, Expression left, Expression right, Location loc)
1709 left = Parser.SetValueRequiredFlag (left);
1710 right = Parser.SetValueRequiredFlag (right);
1717 public Operator Oper {
1726 public Expression Left {
1735 public Expression Right {
1746 /// Returns a stringified representation of the Operator
1748 static string OperName (Operator oper)
1751 case Operator.Exponentiation:
1753 case Operator.Multiply:
1755 case Operator.Division:
1757 case Operator.IntDivision:
1759 case Operator.Modulus:
1761 case Operator.Addition:
1763 case Operator.Subtraction:
1765 case Operator.LeftShift:
1767 case Operator.RightShift:
1769 case Operator.LessThan:
1771 case Operator.GreaterThan:
1773 case Operator.LessThanOrEqual:
1775 case Operator.GreaterThanOrEqual:
1777 case Operator.Equality:
1779 case Operator.Inequality:
1781 case Operator.BitwiseAnd:
1783 case Operator.BitwiseOr:
1785 case Operator.ExclusiveOr:
1787 case Operator.LogicalOr:
1789 case Operator.LogicalAnd:
1795 return oper.ToString ();
1798 public override string ToString ()
1800 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1801 right.ToString () + ")";
1804 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1806 if (expr.Type == target_type)
1809 return ConvertImplicit (ec, expr, target_type, Location.Null);
1812 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1815 34, loc, "Operator '" + OperName (oper)
1816 + "' is ambiguous on operands of type '"
1817 + TypeManager.MonoBASIC_Name (l) + "' "
1818 + "and '" + TypeManager.MonoBASIC_Name (r)
1823 // Handles boolean types also
1825 bool DoNumericPromotions (EmitContext ec, Type l, Type r, Operator oper)
1828 Type conv_left_as = null;
1829 Type conv_right_as = null;
1830 if (left is NullLiteral)
1832 if (right is NullLiteral)
1835 // Need not do anything for shift operators, as this will be handled by the
1836 // 'CheckShiftArguments' method
1837 if (oper == Operator.LeftShift || oper == Operator.RightShift)
1839 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
1840 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
1841 type = TypeManager.int32_type;
1842 conv_left_as = conv_right_as = TypeManager.short_type;
1846 if (IsBitwiseOperator (oper)) {
1848 if (l == TypeManager.decimal_type ||
1849 l == TypeManager.double_type ||
1850 l == TypeManager.float_type) {
1851 conv_left_as = type = TypeManager.int64_type;
1854 if (r == TypeManager.decimal_type ||
1855 r == TypeManager.double_type ||
1856 r == TypeManager.float_type) {
1857 conv_right_as = type = TypeManager.int64_type;
1862 if (oper == Operator.IntDivision) {
1863 if (l == TypeManager.decimal_type || r == TypeManager.decimal_type ||
1864 l == TypeManager.float_type || r == TypeManager.float_type ||
1865 l == TypeManager.double_type || r == TypeManager.double_type)
1866 conv_left_as = conv_right_as = TypeManager.int64_type;
1867 l = r = TypeManager.int64_type;
1870 if (IsLogicalOperator (oper)) {
1871 if (l == TypeManager.decimal_type)
1872 conv_left_as = TypeManager.bool_type;
1873 else if (r == TypeManager.decimal_type)
1874 conv_right_as = TypeManager.bool_type;
1875 } else if ((l == TypeManager.double_type || r == TypeManager.double_type) ||
1876 (oper == Operator.Exponentiation) ||
1877 (oper == Operator.Division &&
1878 !(l == TypeManager.decimal_type || r == TypeManager.decimal_type))) {
1880 // If either operand is of type double, the other operand is
1881 // conveted to type double.
1883 type = conv_left_as = conv_right_as = TypeManager.double_type;
1885 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1887 // if either operand is of type float, the other operand is
1888 // converted to type float.
1890 type = conv_left_as = conv_right_as = TypeManager.float_type;
1891 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1892 type = conv_left_as = conv_right_as = TypeManager.decimal_type;
1893 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1895 // If either operand is of type long, the other operand is converted
1898 type = conv_left_as = conv_right_as = TypeManager.int64_type;
1899 } else if (l == TypeManager.int32_type || r == TypeManager.int32_type){
1900 type = conv_left_as = conv_right_as = TypeManager.int32_type;
1901 } else if (l == TypeManager.short_type || r == TypeManager.short_type){
1902 conv_left_as = conv_right_as = TypeManager.short_type;
1903 type = TypeManager.int32_type;
1905 type = TypeManager.int32_type;
1908 if (conv_left_as != null)
1909 left = ConvertImplicit (ec, left, conv_left_as, loc);
1910 if (conv_right_as != null)
1911 right = ConvertImplicit (ec, right, conv_right_as, loc);
1913 return (left != null) && (right != null);
1916 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1918 Report.Error (19, loc,
1919 "Operator '" + name + "' cannot be applied to operands of type '" +
1920 TypeManager.MonoBASIC_Name (l) + "' and '" +
1921 TypeManager.MonoBASIC_Name (r) + "'");
1924 void Error_OperatorCannotBeApplied ()
1926 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1929 static bool is_32_or_64 (Type t)
1931 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1932 t == TypeManager.int64_type || t == TypeManager.uint64_type);
1935 static bool is_unsigned (Type t)
1937 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1938 t == TypeManager.short_type || t == TypeManager.byte_type);
1941 Expression CheckShiftArguments (EmitContext ec)
1945 e = ForceConversion (ec, right, TypeManager.int32_type);
1947 Error_OperatorCannotBeApplied ();
1952 if (left is NullLiteral) {
1954 if (right.Type != TypeManager.bool_type) {
1955 left = ConvertImplicit (ec, left, right.Type, loc);
1957 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1964 if (type == TypeManager.bool_type) {
1965 left = ConvertImplicit (ec, left, TypeManager.short_type, loc);
1967 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1974 if ( type == TypeManager.byte_type)
1976 else if (type == TypeManager.short_type || type == TypeManager.bool_type)
1978 else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1983 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (mask), loc);
1984 right = right.DoResolve (ec);
1987 if (type == TypeManager.byte_type ||
1988 type == TypeManager.short_type ||
1989 type == TypeManager.int32_type) {
1990 type = TypeManager.int32_type;
1994 if (type == TypeManager.int64_type)
1996 if ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) {
1998 type = TypeManager.int64_type;
2002 Error_OperatorCannotBeApplied ();
2006 bool IsRelationalOperator (Binary.Operator oper) {
2007 return (oper == Operator.Equality ||
2008 oper == Operator.Inequality ||
2009 oper == Operator.LessThan ||
2010 oper == Operator.LessThanOrEqual ||
2011 oper == Operator.GreaterThan ||
2012 oper == Operator.GreaterThanOrEqual);
2015 bool IsArithmaticOperator (Binary.Operator oper) {
2016 return (oper == Operator.Addition ||
2017 oper == Operator.Subtraction ||
2018 oper == Operator.Multiply ||
2019 oper == Operator.Division ||
2020 oper == Operator.IntDivision ||
2021 oper == Operator.Exponentiation ||
2022 oper == Operator.Modulus);
2025 bool IsShiftOperator (Binary.Operator oper) {
2026 return (oper == Operator.LeftShift ||
2027 oper == Operator.RightShift);
2030 bool IsLogicalOperator (Binary.Operator oper) {
2031 return (oper == Operator.LogicalOr ||
2032 oper == Operator.LogicalAnd);
2035 bool IsBitwiseOperator (Binary.Operator oper) {
2036 return (oper == Operator.BitwiseOr ||
2037 oper == Operator.BitwiseAnd ||
2038 oper == Operator.ExclusiveOr);
2041 bool IsNumericType (Type type) {
2042 return (type == TypeManager.byte_type ||
2043 type == TypeManager.sbyte_type ||
2044 type == TypeManager.short_type ||
2045 type == TypeManager.int32_type ||
2046 type == TypeManager.int64_type ||
2047 type == TypeManager.decimal_type ||
2048 type == TypeManager.double_type ||
2049 type == TypeManager.float_type);
2052 Expression ResolveOperator (EmitContext ec)
2055 Type r = right.Type;
2057 Expression left_expr, right_expr;
2058 left_expr = right_expr = null;
2060 if (oper == Operator.Addition && right is Unary) {
2061 Unary unary_right = (Unary) right;
2062 if (unary_right.Oper == Unary.Operator.UnaryNegation) {
2063 oper = Operator.Subtraction;
2064 right = unary_right.Expr;
2069 if (TypeManager.IsEnumType (l))
2070 l = TypeManager.EnumToUnderlying (l);
2071 if (TypeManager.IsEnumType (r))
2072 r = TypeManager.EnumToUnderlying (r);
2074 Type conv_left_as = null;
2075 Type conv_right_as = null;
2077 if (left is NullLiteral && (r.IsValueType || r == TypeManager.string_type)) {
2078 // Just treat nothing as the other type, implicit conversion
2079 // will return the default value
2084 if (right is NullLiteral && (l.IsValueType || l == TypeManager.string_type)) {
2085 // Just treat nothing as the other type, implicit conversion
2086 // will return the default value
2091 // deal with objects and reference types first
2092 if (l == TypeManager.object_type || r == TypeManager.object_type) {
2095 // operator != (object a, object b)
2096 // operator == (object a, object b)
2098 // For this to be used, both arguments have to be reference-types.
2099 // Read the rationale on the spec (14.9.6)
2101 // Also, if at compile time we know that the classes do not inherit
2102 // one from the other, then we catch the error there.
2104 // If other type is a value type, convert it to object
2105 if (r == TypeManager.object_type &&
2106 (l.IsValueType || l == TypeManager.string_type))
2107 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2108 if (l == TypeManager.object_type &&
2109 (r.IsValueType || r == TypeManager.string_type))
2110 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2111 if (left == null || right == null) {
2112 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2119 if (l == TypeManager.object_type && r == TypeManager.object_type) {
2122 case Operator.Addition :
2123 fqn = "ObjectType.AddObj";
2125 case Operator.Subtraction :
2126 fqn = "ObjectType.SubObj";
2128 case Operator.Multiply :
2129 fqn = "ObjectType.MulObj";
2131 case Operator.Division :
2132 fqn = "ObjectType.DivObj";
2134 case Operator.IntDivision :
2135 fqn = "ObjectType.IDivObj";
2137 case Operator.Modulus :
2138 fqn = "ObjectType.ModObj";
2140 case Operator.Exponentiation :
2141 fqn = "ObjectType.PowObj";
2143 case Operator.Like :
2144 fqn = "ObjectType.LikeObj";
2146 case Operator.Equality :
2147 case Operator.Inequality :
2148 case Operator.LessThan :
2149 case Operator.LessThanOrEqual :
2150 case Operator.GreaterThan :
2151 case Operator.GreaterThanOrEqual :
2152 fqn = "ObjectType.ObjTst";
2154 case Operator.BitwiseAnd:
2155 fqn = "ObjectType.BitAndObj";
2157 case Operator.BitwiseOr:
2158 fqn = "ObjectType.BitOrObj";
2160 case Operator.ExclusiveOr:
2161 fqn = "ObjectType.BitXorObj";
2163 case Operator.LeftShift:
2164 fqn = "ObjectType.ShiftLeftObj";
2166 case Operator.RightShift:
2167 fqn = "ObjectType.ShiftRightObj";
2170 eclass = ExprClass.Value;
2171 type = TypeManager.bool_type;
2176 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2180 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2181 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2182 if (right == null) {
2183 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2188 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (
2189 "Microsoft.VisualBasic.CompilerServices." + fqn,
2192 ArrayList args = new ArrayList ();
2193 args.Add (new Argument (left, Argument.AType.Expression));
2194 args.Add (new Argument (right, Argument.AType.Expression));
2195 if (IsRelationalOperator (oper))
2196 args.Add (new Argument (new BoolConstant (false), Argument.AType.Expression));
2197 if (oper == Operator.Like)
2198 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2199 Expression e = new Invocation (etmp, args, loc);
2200 if (IsRelationalOperator (oper)) {
2201 e = new Binary (oper, e.Resolve(ec), new IntConstant (0), loc);
2203 return e.Resolve (ec);
2204 } else if (!l.IsValueType || !r.IsValueType) {
2206 // If one of the operands are reference types and other is object, support for 'Is' operator
2207 if (oper == Operator.Is) {
2208 eclass = ExprClass.Value;
2209 type = TypeManager.bool_type;
2215 } else if (!l.IsValueType || !r.IsValueType) {
2217 if (!l.IsValueType && !r.IsValueType) {
2218 // If both the operands are reference types, support for 'Is' operator
2219 if (oper == Operator.Is) {
2220 eclass = ExprClass.Value;
2221 type = TypeManager.bool_type;
2225 // Either of the operands are reference types
2226 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2227 r.IsSubclassOf (TypeManager.delegate_type)) {
2228 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2229 Arguments = new ArrayList ();
2230 Arguments.Add (new Argument (left, Argument.AType.Expression));
2231 Arguments.Add (new Argument (right, Argument.AType.Expression));
2233 if (oper == Operator.Addition)
2234 method = TypeManager.delegate_combine_delegate_delegate;
2236 method = TypeManager.delegate_remove_delegate_delegate;
2239 Error_OperatorCannotBeApplied ();
2243 DelegateOperation = true;
2248 if (oper != Operator.Equality) {
2249 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2254 bool left_is_string = (left.Type == TypeManager.string_type);
2255 bool right_is_string = (right.Type == TypeManager.string_type);
2257 if (left_is_string || right_is_string) {
2259 if (left is NullLiteral) {
2260 left_is_string = true;
2263 if (right is NullLiteral) {
2264 right_is_string = true;
2267 if (left_is_string && right_is_string) {
2268 if (oper == Operator.Addition) {
2269 // Both operands are string
2270 Expression e = new StringConcat (loc, left, right);
2271 return e.Resolve(ec);
2274 if (IsRelationalOperator (oper)) {
2276 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrCmp", Location.Null);
2277 eclass = ExprClass.Value;
2278 type = TypeManager.bool_type;
2279 ArrayList args = new ArrayList ();
2280 args.Add (new Argument(left, Argument.AType.Expression));
2281 args.Add (new Argument(right, Argument.AType.Expression));
2282 args.Add (new Argument(new BoolConstant(false), Argument.AType.Expression));
2283 Expression e = (Expression) new Invocation (etmp, args, loc);
2284 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2285 return e.Resolve(ec);
2288 if (oper == Operator.Like) {
2289 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrLike", Location.Null);
2290 type = TypeManager.bool_type;
2291 ArrayList args = new ArrayList ();
2292 args.Add (new Argument(left, Argument.AType.Expression));
2293 args.Add (new Argument(right, Argument.AType.Expression));
2294 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2295 Expression e = (Expression) new Invocation (etmp, args, loc);
2296 return e.Resolve (ec);
2300 Expression other = right_is_string ? left: right;
2301 Type other_type = other.Type;
2304 // Disallow arithmatic / shift / logical operators on dates and characters
2306 if (other_type == TypeManager.date_type || other_type == TypeManager.char_type) {
2307 if (!(oper == Operator.Addition || IsRelationalOperator (oper) || oper == Operator.Like)) {
2308 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2313 if (oper == Operator.Addition) {
2314 if (other_type == TypeManager.void_type) {
2315 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2318 if (other_type == TypeManager.date_type ||
2319 other_type == TypeManager.char_type ||
2320 other_type == typeof (System.Char[])) {
2321 conv_left_as = conv_right_as = TypeManager.string_type;
2322 type = TypeManager.string_type;
2325 conv_right_as = conv_left_as = TypeManager.double_type;
2326 type = TypeManager.double_type;
2328 } else if (IsRelationalOperator (oper)) {
2329 if (other_type == TypeManager.char_type || other_type == typeof (System.Char[])) {
2330 conv_left_as = conv_right_as = TypeManager.string_type;
2331 } else if (other_type == TypeManager.date_type) {
2332 conv_right_as = conv_left_as = other_type;
2333 } else if (other_type == TypeManager.bool_type) {
2334 conv_right_as = conv_left_as = other_type;
2335 } else if (! other_type.IsValueType) {
2336 // Do Nothing, just return
2337 type = TypeManager.bool_type;
2340 conv_right_as = conv_left_as = TypeManager.double_type;
2342 type = TypeManager.bool_type;
2344 } else if (oper == Operator.Like) {
2345 conv_left_as = conv_right_as = TypeManager.string_type;
2346 } else if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2348 conv_left_as = TypeManager.int64_type;
2349 conv_right_as = TypeManager.int32_type;
2350 type = TypeManager.int64_type;
2352 } else if ( IsLogicalOperator (oper)) {
2353 type = conv_right_as = conv_left_as = TypeManager.bool_type;
2354 } else if ( IsBitwiseOperator (oper)) {
2356 if (other_type == TypeManager.bool_type) {
2357 conv_right_as = conv_left_as = TypeManager.bool_type;
2358 type = TypeManager.bool_type;
2360 conv_left_as = conv_right_as = TypeManager.int64_type;
2361 type = TypeManager.int64_type;
2363 } else if (oper == Operator.Exponentiation) {
2364 conv_left_as = conv_right_as = TypeManager.double_type;
2365 } else if (oper == Operator.IntDivision) {
2366 conv_left_as = conv_right_as = TypeManager.int64_type;
2368 // Arithmatic operators
2369 conv_right_as = conv_left_as = TypeManager.double_type;
2370 type = TypeManager.double_type;
2373 // Both are not of type string
2374 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is) {
2375 if (l.IsValueType || r.IsValueType) {
2376 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2379 type = TypeManager.bool_type;
2382 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2386 } else if (l == TypeManager.date_type || r == TypeManager.date_type) {
2387 // Date with string operations handled above
2388 // Only other possiblity is date with date
2389 if (oper == Operator.Like) {
2390 conv_right_as = conv_left_as = TypeManager.string_type;
2391 type = TypeManager.bool_type;
2392 } else if (l == TypeManager.date_type && r == TypeManager.date_type) {
2393 if (oper == Operator.Addition) {
2394 conv_left_as = conv_right_as = TypeManager.string_type;
2395 } else if (IsRelationalOperator (oper)) {
2396 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.DateTime.Compare", Location.Null);
2397 eclass = ExprClass.Value;
2398 type = TypeManager.bool_type;
2399 ArrayList args = new ArrayList ();
2400 args.Add (new Argument(left, Argument.AType.Expression));
2401 args.Add (new Argument(right, Argument.AType.Expression));
2402 Expression e = (Expression) new Invocation (etmp, args, loc);
2403 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2404 return e.Resolve(ec);
2406 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2410 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2413 } else if (l == TypeManager.char_type || r == TypeManager.char_type) {
2414 // char op string handled above
2415 if (oper == Operator.Like) {
2416 conv_right_as = conv_left_as = TypeManager.string_type;
2417 type = TypeManager.bool_type;
2418 } else if (l == TypeManager.char_type && r == TypeManager.char_type) {
2419 if (oper == Operator.Addition)
2420 conv_left_as = conv_right_as = TypeManager.string_type;
2421 else if (IsRelationalOperator (oper)) {
2422 type = TypeManager.bool_type;
2424 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2428 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2431 } else if (l.IsPointer || r.IsPointer) {
2432 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2434 if (r.IsPointer && oper == Operator.Subtraction){
2436 return new PointerArithmetic (
2437 false, left, right, TypeManager.int64_type,
2439 } else if (is_32_or_64 (r))
2440 return new PointerArithmetic (
2441 oper == Operator.Addition, left, right, l, loc);
2442 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2443 return new PointerArithmetic (
2444 true, right, left, r, loc);
2448 // Pointer comparison
2450 if (l.IsPointer && r.IsPointer){
2451 if (oper == Operator.Equality || oper == Operator.Inequality ||
2452 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2453 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2454 type = TypeManager.bool_type;
2458 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2461 } else if (oper == Operator.Like) {
2462 conv_left_as = conv_right_as = TypeManager.string_type;
2466 DoNumericPromotions (ec, l, r, oper);
2467 if (left == null || right == null) {
2468 Error_OperatorCannotBeApplied (loc, OperName(oper), l, r);
2474 // Required conversions done by 'DoNumericPromotions' method
2475 // So Reset 'conv_left_as', 'conv_right_as'
2476 conv_left_as = conv_right_as = null;
2478 if (l == TypeManager.decimal_type && r == TypeManager.decimal_type) {
2479 if (IsRelationalOperator (oper)) {
2480 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.Decimal.Compare", Location.Null);
2481 eclass = ExprClass.Value;
2482 type = TypeManager.bool_type;
2483 ArrayList args = new ArrayList ();
2484 args.Add (new Argument(left, Argument.AType.Expression));
2485 args.Add (new Argument(right, Argument.AType.Expression));
2486 Expression e = (Expression) new Invocation (etmp, args, loc);
2487 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2488 return e.Resolve(ec);
2489 } else if (IsArithmaticOperator (oper)) {
2491 if (oper == Operator.Addition)
2492 fqn = "System.Decimal.Add";
2493 else if (oper == Operator.Subtraction)
2494 fqn = "System.Decimal.Subtract";
2495 else if (oper == Operator.Multiply)
2496 fqn = "System.Decimal.Multiply";
2497 else if (oper == Operator.Division)
2498 fqn = "System.Decimal.Divide";
2499 else if (oper == Operator.Modulus)
2500 fqn = "System.Decimal.Remainder";
2503 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (fqn, Location.Null);
2504 eclass = ExprClass.Value;
2505 type = TypeManager.decimal_type;
2506 ArrayList args = new ArrayList ();
2507 args.Add (new Argument(left, Argument.AType.Expression));
2508 args.Add (new Argument(right, Argument.AType.Expression));
2509 Expression e = (Expression) new Invocation (etmp, args, loc);
2510 return e.Resolve (ec);
2516 bool conv_done = false;
2517 if (conv_left_as != null && conv_left_as != l) {
2519 left = ConvertImplicit (ec, left, conv_left_as, loc);
2521 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2527 if (conv_right_as != null && conv_right_as != r) {
2529 right = ConvertImplicit (ec, right, conv_right_as, loc);
2530 if (right == null) {
2531 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2538 return ResolveOperator (ec);
2541 if (oper == Operator.Exponentiation) {
2542 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI("System.Math.Pow", loc);
2543 ArrayList args = new ArrayList();
2544 args.Add (new Argument (left, Argument.AType.Expression));
2545 args.Add (new Argument (right, Argument.AType.Expression));
2546 Expression e = (Expression) new Invocation (etmp, args, loc);
2547 return e.Resolve(ec);
2550 bool overload_failed = false;
2551 string op = oper_names [(int) oper];
2552 MethodGroupExpr union = null;
2553 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2555 right_expr = MemberLookup (
2556 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2557 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2559 union = (MethodGroupExpr) left_expr;
2561 if (union != null) {
2562 Arguments = new ArrayList ();
2563 Arguments.Add (new Argument (left, Argument.AType.Expression));
2564 Arguments.Add (new Argument (right, Argument.AType.Expression));
2566 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
2567 if (method != null) {
2568 MethodInfo mi = (MethodInfo) method;
2570 type = mi.ReturnType;
2573 overload_failed = true;
2577 if (overload_failed) {
2578 Error_OperatorCannotBeApplied ();
2582 if (IsRelationalOperator (oper)) {
2583 type = TypeManager.bool_type;
2584 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2585 // Reverse the operator - to make it consistent with vbc
2586 if (oper == Operator.LessThan)
2587 oper = Operator.GreaterThan;
2588 else if (oper == Operator.GreaterThan)
2589 oper = Operator.LessThan;
2590 else if (oper == Operator.LessThanOrEqual)
2591 oper = Operator.GreaterThanOrEqual;
2592 else if (oper == Operator.GreaterThanOrEqual)
2593 oper = Operator.LessThanOrEqual;
2597 if (IsLogicalOperator (oper))
2598 type = TypeManager.bool_type;
2599 if (IsBitwiseOperator (oper)) {
2601 if (l == TypeManager.byte_type ||
2602 l == TypeManager.short_type ||
2603 l == TypeManager.bool_type ||
2604 l == TypeManager.int32_type ||
2605 l == TypeManager.int64_type)
2608 Error_OperatorCannotBeApplied();
2612 Error_OperatorCannotBeApplied();
2617 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2618 return CheckShiftArguments (ec);
2625 public override Expression DoResolve (EmitContext ec)
2627 left = left.Resolve (ec);
2628 right = right.Resolve (ec);
2630 if (left == null || right == null)
2633 if (left.Type == null)
2634 throw new Exception (
2635 "Resolve returned non null, but did not set the type! (" +
2636 left + ") at Line: " + loc.Row);
2637 if (right.Type == null)
2638 throw new Exception (
2639 "Resolve returned non null, but did not set the type! (" +
2640 right + ") at Line: "+ loc.Row);
2642 eclass = ExprClass.Value;
2644 // To support 'Or' argument of AttributeTargets in AttributeUsage
2646 if (left is EnumConstant && oper != Operator.BitwiseOr) {
2647 left = ((EnumConstant) left).WidenToCompilerConstant();
2650 if (right is EnumConstant && oper != Operator.BitwiseOr) {
2651 right = ((EnumConstant) right).WidenToCompilerConstant();
2654 if (left is Constant && right is Constant){
2655 Expression e = ConstantFold.BinaryFold (
2656 ec, oper, (Constant) left, (Constant) right, loc);
2661 Expression etmp = ResolveOperator (ec);
2664 // if the operands are of type byte/short, convert the result back to short/byte
2665 if (l == TypeManager.bool_type || l == TypeManager.short_type || l == TypeManager.byte_type) {
2666 if (l == TypeManager.bool_type)
2667 l = TypeManager.short_type;
2668 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
2669 Expression conv_exp = ConvertImplicit (ec, etmp, l, loc);
2670 if (conv_exp != null)
2673 if (IsShiftOperator (oper)) {
2674 // No overflow checks are needed
2675 if (l == TypeManager.byte_type)
2676 return new OpcodeCast (etmp, l, OpCodes.Conv_U1);
2678 return new OpcodeCast (etmp, l, OpCodes.Conv_I2);
2686 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2687 /// context of a conditional bool expression. This function will return
2688 /// false if it is was possible to use EmitBranchable, or true if it was.
2690 /// The expression's code is generated, and we will generate a branch to 'target'
2691 /// if the resulting expression value is equal to isTrue
2693 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2698 ILGenerator ig = ec.ig;
2701 // This is more complicated than it looks, but its just to avoid
2702 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2703 // but on top of that we want for == and != to use a special path
2704 // if we are comparing against null
2706 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is){
2707 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2709 if (left is NullLiteral){
2712 ig.Emit (OpCodes.Brtrue, target);
2714 ig.Emit (OpCodes.Brfalse, target);
2716 } else if (right is NullLiteral){
2719 ig.Emit (OpCodes.Brtrue, target);
2721 ig.Emit (OpCodes.Brfalse, target);
2724 } else if (!(oper == Operator.LessThan ||
2725 oper == Operator.GreaterThan ||
2726 oper == Operator.LessThanOrEqual ||
2727 oper == Operator.GreaterThanOrEqual ||
2728 oper == Operator.Is))
2736 bool isUnsigned = is_unsigned (left.Type);
2739 case Operator.Equality:
2741 ig.Emit (OpCodes.Beq, target);
2743 ig.Emit (OpCodes.Bne_Un, target);
2746 case Operator.Inequality:
2748 ig.Emit (OpCodes.Bne_Un, target);
2750 ig.Emit (OpCodes.Beq, target);
2753 case Operator.LessThan:
2756 ig.Emit (OpCodes.Blt_Un, target);
2758 ig.Emit (OpCodes.Blt, target);
2761 ig.Emit (OpCodes.Bge_Un, target);
2763 ig.Emit (OpCodes.Bge, target);
2766 case Operator.GreaterThan:
2769 ig.Emit (OpCodes.Bgt_Un, target);
2771 ig.Emit (OpCodes.Bgt, target);
2774 ig.Emit (OpCodes.Ble_Un, target);
2776 ig.Emit (OpCodes.Ble, target);
2779 case Operator.LessThanOrEqual:
2782 ig.Emit (OpCodes.Ble_Un, target);
2784 ig.Emit (OpCodes.Ble, target);
2787 ig.Emit (OpCodes.Bgt_Un, target);
2789 ig.Emit (OpCodes.Bgt, target);
2793 case Operator.GreaterThanOrEqual:
2796 ig.Emit (OpCodes.Bge_Un, target);
2798 ig.Emit (OpCodes.Bge, target);
2801 ig.Emit (OpCodes.Blt_Un, target);
2803 ig.Emit (OpCodes.Blt, target);
2808 ig.Emit (OpCodes.Beq, target); //Check this
2810 ig.Emit (OpCodes.Bne_Un_S, target);
2820 public override void Emit (EmitContext ec)
2822 ILGenerator ig = ec.ig;
2824 Type r = right.Type;
2825 //Type r = right.Type;
2828 if (method != null) {
2830 // Note that operators are static anyway
2832 if (Arguments != null)
2833 Invocation.EmitArguments (ec, method, Arguments);
2835 if (method is MethodInfo)
2836 ig.Emit (OpCodes.Call, (MethodInfo) method);
2838 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2840 if (DelegateOperation)
2841 ig.Emit (OpCodes.Castclass, type);
2847 // Handle short-circuit operators differently
2850 if (IsLogicalOperator (oper)) {
2851 Label load_zero = ig.DefineLabel ();
2852 Label load_one = ig.DefineLabel ();
2853 Label end = ig.DefineLabel ();
2856 if (l != TypeManager.bool_type) {
2857 if (l == TypeManager.int64_type) {
2858 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2859 ec.ig.Emit (OpCodes.Cgt_Un);
2860 } else if (l == TypeManager.float_type) {
2861 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2862 ec.ig.Emit (OpCodes.Ceq);
2863 ec.ig.Emit (OpCodes.Ldc_I4_0);
2864 ec.ig.Emit (OpCodes.Ceq);
2865 } else if (l == TypeManager.double_type) {
2866 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2867 ec.ig.Emit (OpCodes.Ceq);
2868 ec.ig.Emit (OpCodes.Ldc_I4_0);
2869 ec.ig.Emit (OpCodes.Ceq);
2871 ec.ig.Emit (OpCodes.Ldc_I4_0);
2872 ec.ig.Emit (OpCodes.Cgt_Un);
2875 if (oper == Operator.LogicalAnd)
2876 ig.Emit (OpCodes.Brfalse, load_zero);
2878 ig.Emit (OpCodes.Brtrue, load_one);
2881 if (r != TypeManager.bool_type) {
2882 if (r == TypeManager.int64_type) {
2883 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2884 ec.ig.Emit (OpCodes.Cgt_Un);
2885 } else if (r == TypeManager.float_type) {
2886 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2887 ec.ig.Emit (OpCodes.Ceq);
2888 ec.ig.Emit (OpCodes.Ldc_I4_0);
2889 ec.ig.Emit (OpCodes.Ceq);
2890 } else if (r == TypeManager.double_type) {
2891 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2892 ec.ig.Emit (OpCodes.Ceq);
2893 ec.ig.Emit (OpCodes.Ldc_I4_0);
2894 ec.ig.Emit (OpCodes.Ceq);
2896 ec.ig.Emit (OpCodes.Ldc_I4_0);
2897 ec.ig.Emit (OpCodes.Cgt_Un);
2900 ig.Emit (OpCodes.Brtrue, load_one);
2901 ig.MarkLabel (load_zero);
2902 ig.Emit (OpCodes.Ldc_I4_0);
2903 ig.Emit (OpCodes.Br, end);
2904 ig.MarkLabel (load_one);
2905 ig.Emit (OpCodes.Ldc_I4_1);
2914 case Operator.Multiply:
2916 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2917 opcode = OpCodes.Mul_Ovf;
2918 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2919 opcode = OpCodes.Mul_Ovf_Un;
2921 opcode = OpCodes.Mul;
2923 opcode = OpCodes.Mul;
2927 case Operator.Division:
2928 case Operator.IntDivision:
2929 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2930 opcode = OpCodes.Div_Un;
2932 opcode = OpCodes.Div;
2935 case Operator.Modulus:
2936 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2937 opcode = OpCodes.Rem_Un;
2939 opcode = OpCodes.Rem;
2942 case Operator.Addition:
2944 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2945 opcode = OpCodes.Add_Ovf;
2946 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2947 opcode = OpCodes.Add_Ovf_Un;
2949 opcode = OpCodes.Add;
2951 opcode = OpCodes.Add;
2954 case Operator.Subtraction:
2956 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2957 opcode = OpCodes.Sub_Ovf;
2958 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2959 opcode = OpCodes.Sub_Ovf_Un;
2961 opcode = OpCodes.Sub;
2963 opcode = OpCodes.Sub;
2966 case Operator.RightShift:
2967 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2968 opcode = OpCodes.Shr_Un;
2970 opcode = OpCodes.Shr;
2973 case Operator.LeftShift:
2974 opcode = OpCodes.Shl;
2977 case Operator.Equality:
2979 opcode = OpCodes.Ceq;
2982 case Operator.Inequality:
2983 ec.ig.Emit (OpCodes.Ceq);
2984 ec.ig.Emit (OpCodes.Ldc_I4_0);
2986 opcode = OpCodes.Ceq;
2989 case Operator.LessThan:
2990 opcode = OpCodes.Clt;
2993 case Operator.GreaterThan:
2994 opcode = OpCodes.Cgt;
2997 case Operator.LessThanOrEqual:
2998 ec.ig.Emit (OpCodes.Cgt);
2999 ec.ig.Emit (OpCodes.Ldc_I4_0);
3001 opcode = OpCodes.Ceq;
3004 case Operator.GreaterThanOrEqual:
3005 ec.ig.Emit (OpCodes.Clt);
3006 ec.ig.Emit (OpCodes.Ldc_I4_1);
3008 opcode = OpCodes.Sub;
3011 case Operator.BitwiseOr:
3012 opcode = OpCodes.Or;
3015 case Operator.BitwiseAnd:
3016 opcode = OpCodes.And;
3019 case Operator.ExclusiveOr:
3020 opcode = OpCodes.Xor;
3024 throw new Exception ("This should not happen: Operator = "
3025 + oper.ToString ());
3031 public bool IsBuiltinOperator {
3033 return method == null;
3038 public class PointerArithmetic : Expression {
3039 Expression left, right;
3043 // We assume that 'l' is always a pointer
3045 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
3049 eclass = ExprClass.Variable;
3053 is_add = is_addition;
3056 public override Expression DoResolve (EmitContext ec)
3059 // We are born fully resolved
3064 public override void Emit (EmitContext ec)
3066 Type op_type = left.Type;
3067 ILGenerator ig = ec.ig;
3068 int size = GetTypeSize (op_type.GetElementType ());
3070 if (right.Type.IsPointer){
3072 // handle (pointer - pointer)
3076 ig.Emit (OpCodes.Sub);
3080 ig.Emit (OpCodes.Sizeof, op_type);
3082 IntLiteral.EmitInt (ig, size);
3083 ig.Emit (OpCodes.Div);
3085 ig.Emit (OpCodes.Conv_I8);
3088 // handle + and - on (pointer op int)
3091 ig.Emit (OpCodes.Conv_I);
3095 ig.Emit (OpCodes.Sizeof, op_type);
3097 IntLiteral.EmitInt (ig, size);
3098 ig.Emit (OpCodes.Mul);
3101 ig.Emit (OpCodes.Add);
3103 ig.Emit (OpCodes.Sub);
3109 /// Implements the ternary conditional operator (?:)
3111 public class Conditional : Expression {
3112 Expression expr, trueExpr, falseExpr;
3114 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3117 this.trueExpr = trueExpr;
3118 this.falseExpr = falseExpr;
3122 public Expression Expr {
3128 public Expression TrueExpr {
3134 public Expression FalseExpr {
3140 public override Expression DoResolve (EmitContext ec)
3142 expr = expr.Resolve (ec);
3147 if (expr.Type != TypeManager.bool_type)
3148 expr = Expression.ConvertImplicitRequired (
3149 ec, expr, TypeManager.bool_type, loc);
3151 trueExpr = trueExpr.Resolve (ec);
3152 falseExpr = falseExpr.Resolve (ec);
3154 if (trueExpr == null || falseExpr == null)
3157 eclass = ExprClass.Value;
3158 if (trueExpr.Type == falseExpr.Type)
3159 type = trueExpr.Type;
3162 Type true_type = trueExpr.Type;
3163 Type false_type = falseExpr.Type;
3165 if (trueExpr is NullLiteral){
3168 } else if (falseExpr is NullLiteral){
3174 // First, if an implicit conversion exists from trueExpr
3175 // to falseExpr, then the result type is of type falseExpr.Type
3177 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
3180 // Check if both can convert implicitl to each other's type
3182 if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
3184 "Can not compute type of conditional expression " +
3185 "as '" + TypeManager.MonoBASIC_Name (trueExpr.Type) +
3186 "' and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) +
3187 "' convert implicitly to each other");
3192 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
3196 Error (173, "The type of the conditional expression can " +
3197 "not be computed because there is no implicit conversion" +
3198 " from '" + TypeManager.MonoBASIC_Name (trueExpr.Type) + "'" +
3199 " and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) + "'");
3204 if (expr is BoolConstant){
3205 BoolConstant bc = (BoolConstant) expr;
3216 public override void Emit (EmitContext ec)
3218 ILGenerator ig = ec.ig;
3219 Label false_target = ig.DefineLabel ();
3220 Label end_target = ig.DefineLabel ();
3222 Statement.EmitBoolExpression (ec, expr, false_target, false);
3224 ig.Emit (OpCodes.Br, end_target);
3225 ig.MarkLabel (false_target);
3226 falseExpr.Emit (ec);
3227 ig.MarkLabel (end_target);
3235 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3236 public readonly string Name;
3237 public readonly Block Block;
3238 VariableInfo variable_info;
3241 public LocalVariableReference (Block block, string name, Location l)
3246 eclass = ExprClass.Variable;
3249 // Setting 'is_readonly' to false will allow you to create a writable
3250 // reference to a read-only variable. This is used by foreach and using.
3251 public LocalVariableReference (Block block, string name, Location l,
3252 VariableInfo variable_info, bool is_readonly)
3253 : this (block, name, l)
3255 this.variable_info = variable_info;
3256 this.is_readonly = is_readonly;
3259 public VariableInfo VariableInfo {
3261 if (variable_info == null) {
3262 variable_info = Block.GetVariableInfo (Name);
3263 is_readonly = variable_info.ReadOnly;
3265 return variable_info;
3269 public bool IsAssigned (EmitContext ec, Location loc)
3271 return VariableInfo.IsAssigned (ec, loc);
3274 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
3276 return VariableInfo.IsFieldAssigned (ec, name, loc);
3279 public void SetAssigned (EmitContext ec)
3281 VariableInfo.SetAssigned (ec);
3284 public void SetFieldAssigned (EmitContext ec, string name)
3286 VariableInfo.SetFieldAssigned (ec, name);
3289 public bool IsReadOnly {
3291 if (variable_info == null) {
3292 variable_info = Block.GetVariableInfo (Name);
3293 is_readonly = variable_info.ReadOnly;
3299 public override Expression DoResolve (EmitContext ec)
3301 VariableInfo vi = VariableInfo;
3303 if (Block.IsConstant (Name)) {
3304 Expression e = Block.GetConstantExpression (Name);
3310 if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3313 type = vi.VariableType;
3317 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3319 VariableInfo vi = VariableInfo;
3321 if (ec.DoFlowAnalysis)
3322 ec.SetVariableAssigned (vi);
3324 Expression e = DoResolve (ec);
3330 Error (1604, "cannot assign to '" + Name + "' because it is readonly");
3337 public override void Emit (EmitContext ec)
3339 VariableInfo vi = VariableInfo;
3340 ILGenerator ig = ec.ig;
3342 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
3346 public void EmitAssign (EmitContext ec, Expression source)
3348 ILGenerator ig = ec.ig;
3349 VariableInfo vi = VariableInfo;
3355 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3358 public void AddressOf (EmitContext ec, AddressOp mode)
3360 VariableInfo vi = VariableInfo;
3362 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
3367 /// This represents a reference to a parameter in the intermediate
3370 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3374 public Parameter.Modifier mod;
3375 public bool is_ref, is_out;
3377 public ParameterReference (Parameters pars, int idx, string name, Location loc)
3383 eclass = ExprClass.Variable;
3386 public bool IsAssigned (EmitContext ec, Location loc)
3388 if (!is_out || !ec.DoFlowAnalysis)
3391 if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
3392 Report.Error (165, loc,
3393 "Use of unassigned local variable '" + name + "'");
3400 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3402 if (!is_out || !ec.DoFlowAnalysis)
3405 if (ec.CurrentBranching.IsParameterAssigned (idx))
3408 if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
3409 Report.Error (170, loc,
3410 "Use of possibly unassigned field '" + field_name + "'");
3417 public void SetAssigned (EmitContext ec)
3419 if (is_out && ec.DoFlowAnalysis)
3420 ec.CurrentBranching.SetParameterAssigned (idx);
3423 public void SetFieldAssigned (EmitContext ec, string field_name)
3425 if (is_out && ec.DoFlowAnalysis)
3426 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
3430 // Notice that for ref/out parameters, the type exposed is not the
3431 // same type exposed externally.
3434 // externally we expose "int&"
3435 // here we expose "int".
3437 // We record this in "is_ref". This means that the type system can treat
3438 // the type as it is expected, but when we generate the code, we generate
3439 // the alternate kind of code.
3441 public override Expression DoResolve (EmitContext ec)
3443 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3444 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3445 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3446 eclass = ExprClass.Variable;
3448 /* if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3454 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3456 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3457 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3458 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3459 eclass = ExprClass.Variable;
3461 if (is_out && ec.DoFlowAnalysis)
3462 ec.SetParameterAssigned (idx);
3467 static void EmitLdArg (ILGenerator ig, int x)
3471 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3472 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3473 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3474 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3475 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3478 ig.Emit (OpCodes.Ldarg, x);
3482 // This method is used by parameters that are references, that are
3483 // being passed as references: we only want to pass the pointer (that
3484 // is already stored in the parameter, not the address of the pointer,
3485 // and not the value of the variable).
3487 public void EmitLoad (EmitContext ec)
3489 ILGenerator ig = ec.ig;
3495 EmitLdArg (ig, arg_idx);
3498 public override void Emit (EmitContext ec)
3500 ILGenerator ig = ec.ig;
3506 EmitLdArg (ig, arg_idx);
3512 // If we are a reference, we loaded on the stack a pointer
3513 // Now lets load the real value
3515 LoadFromPtr (ig, type);
3518 public void EmitAssign (EmitContext ec, Expression source)
3520 ILGenerator ig = ec.ig;
3527 EmitLdArg (ig, arg_idx);
3532 StoreFromPtr (ig, type);
3535 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3537 ig.Emit (OpCodes.Starg, arg_idx);
3541 public void AddressOf (EmitContext ec, AddressOp mode)
3550 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3552 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3555 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3557 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3564 /// Invocation of methods or delegates.
3566 public class Invocation : ExpressionStatement {
3567 public ArrayList Arguments;
3569 public Expression expr;
3570 MethodBase method = null;
3572 bool is_latebinding;
3573 bool is_left_hand; // Needed for late bound calls
3574 bool is_retval_required; // Needed for late bound calls
3575 static Hashtable method_parameter_cache;
3576 static MemberFilter CompareName;
3578 static Invocation ()
3580 method_parameter_cache = new PtrHashtable ();
3584 // arguments is an ArrayList, but we do not want to typecast,
3585 // as it might be null.
3587 // FIXME: only allow expr to be a method invocation or a
3588 // delegate invocation (7.5.5)
3590 public Invocation (Expression expr, ArrayList arguments, Location l)
3593 if (this.expr is MemberAccess) {
3594 ((MemberAccess) this.expr).IsInvocation = true;
3596 this.is_retval_required = false;
3597 this.is_left_hand = false;
3598 Arguments = arguments;
3600 CompareName = new MemberFilter (compare_name_filter);
3603 public Expression Expr {
3609 public bool IsLeftHand {
3611 return is_left_hand;
3614 is_left_hand = value;
3618 public bool IsRetvalRequired {
3620 return is_retval_required;
3623 is_retval_required = value;
3627 public bool IsLateBinding {
3629 return is_latebinding;
3632 is_latebinding = value;
3637 /// Returns the Parameters (a ParameterData interface) for the
3640 public static ParameterData GetParameterData (MethodBase mb)
3642 object pd = method_parameter_cache [mb];
3646 return (ParameterData) pd;
3649 ip = TypeManager.LookupParametersByBuilder (mb);
3651 method_parameter_cache [mb] = ip;
3653 return (ParameterData) ip;
3655 ParameterInfo [] pi = mb.GetParameters ();
3657 ReflectionParameters rp = new ReflectionParameters (pi);
3658 method_parameter_cache [mb] = rp;
3660 return (ParameterData) rp;
3664 enum Applicability { Same, Better, Worse };
3667 /// Determines "Better function"
3670 /// and returns an integer indicating :
3671 /// 0 if candidate ain't better
3672 /// 1 if candidate is better than the current best match
3674 static Applicability BetterFunction (EmitContext ec, ArrayList args,
3675 MethodBase candidate, MethodBase best,
3676 bool expanded_form, Location loc)
3678 ParameterData candidate_pd = GetParameterData (candidate);
3679 ParameterData best_pd;
3685 argument_count = args.Count;
3687 int cand_count = candidate_pd.Count;
3689 if (cand_count == 0 && argument_count == 0)
3690 return Applicability.Same;
3692 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3693 if (cand_count != argument_count)
3694 return Applicability.Worse;
3696 best_pd = GetParameterData (best);
3698 Applicability res = Applicability.Same;
3700 for (int j = 0; j < argument_count; ++j) {
3702 //Argument a = (Argument) args [j];
3704 Type ct = candidate_pd.ParameterType (j);
3705 Type bt = best_pd.ParameterType (j);
3707 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3709 ct = ct.GetElementType ();
3711 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3713 bt = bt.GetElementType ();
3716 if (!WideningConversionExists (ct, bt))
3717 return Applicability.Worse;
3718 res = Applicability.Better;
3722 if (res == Applicability.Same)
3723 if (candidate_pd.Count < best_pd.Count)
3724 res = Applicability.Better;
3725 else if (candidate_pd.Count > best_pd.Count)
3726 res = Applicability.Worse;
3731 public static string FullMethodDesc (MethodBase mb)
3733 string ret_type = "";
3735 if (mb is MethodInfo)
3736 ret_type = TypeManager.MonoBASIC_Name (((MethodInfo) mb).ReturnType) + " ";
3738 StringBuilder sb = new StringBuilder (ret_type + mb.Name);
3739 ParameterData pd = GetParameterData (mb);
3741 int count = pd.Count;
3744 for (int i = count; i > 0; ) {
3747 sb.Append (pd.ParameterDesc (count - i - 1));
3753 return sb.ToString ();
3756 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3758 MemberInfo [] miset;
3759 MethodGroupExpr union;
3764 return (MethodGroupExpr) mg2;
3767 return (MethodGroupExpr) mg1;
3770 MethodGroupExpr left_set = null, right_set = null;
3771 int length1 = 0, length2 = 0;
3773 left_set = (MethodGroupExpr) mg1;
3774 length1 = left_set.Methods.Length;
3776 right_set = (MethodGroupExpr) mg2;
3777 length2 = right_set.Methods.Length;
3779 ArrayList common = new ArrayList ();
3781 foreach (MethodBase l in left_set.Methods){
3782 foreach (MethodBase r in right_set.Methods){
3790 miset = new MemberInfo [length1 + length2 - common.Count];
3791 left_set.Methods.CopyTo (miset, 0);
3795 foreach (MemberInfo mi in right_set.Methods){
3796 if (!common.Contains (mi))
3800 union = new MethodGroupExpr (miset, loc);
3806 /// Determines is the candidate method, if a params method, is applicable
3807 /// in its expanded form to the given set of arguments
3809 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
3813 if (arguments == null)
3816 arg_count = arguments.Count;
3818 ParameterData pd = GetParameterData (candidate);
3820 int pd_count = pd.Count;
3825 if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
3828 if (pd_count - 1 > arg_count)
3831 if (pd_count == 1 && arg_count == 0)
3835 // If we have come this far, the case which remains is when the number of parameters
3836 // is less than or equal to the argument count.
3838 for (int i = 0; i < pd_count - 1; ++i) {
3840 Argument a = (Argument) arguments [i];
3842 Parameter.Modifier a_mod = a.GetParameterModifier () &
3843 ~(Parameter.Modifier.REF);
3844 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3845 ~(Parameter.Modifier.REF);
3847 if (a_mod == p_mod) {
3849 if (a_mod == Parameter.Modifier.NONE)
3850 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
3853 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3854 Type pt = pd.ParameterType (i);
3857 pt = TypeManager.LookupType (pt.FullName + "&");
3867 Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
3869 for (int i = pd_count - 1; i < arg_count; i++) {
3870 Argument a = (Argument) arguments [i];
3872 if (!StandardConversionExists (a.Expr, element_type))
3880 protected enum ConversionType { None, Widening, Narrowing };
3882 static ConversionType CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
3884 Parameter.Modifier a_mod = a.GetParameterModifier () &
3885 ~(Parameter.Modifier.REF);
3886 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3887 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
3889 if (a_mod == p_mod ||
3890 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3891 if (a_mod == Parameter.Modifier.NONE) {
3892 if (! WideningConversionExists (a.Expr, ptype) ) {
3894 if (! NarrowingConversionExists (ec, a.Expr, ptype) )
3895 return ConversionType.None;
3897 return ConversionType.Narrowing;
3899 return ConversionType.Widening;
3902 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3903 Type pt = pd.ParameterType (i);
3906 pt = TypeManager.LookupType (pt.FullName + "&");
3909 return ConversionType.None;
3911 return ConversionType.Widening;
3913 return ConversionType.None;
3916 static bool HasArrayParameter (ParameterData pd)
3919 return c > 0 && (pd.ParameterModifier (c - 1) & Parameter.Modifier.PARAMS) != 0;
3922 static int CountStandardParams (ParameterData pd)
3924 int count = pd.Count;
3925 for (int i = 0; i < count; i++) {
3926 Parameter.Modifier pm = pd.ParameterModifier (i);
3927 if ((pm & (Parameter.Modifier.OPTIONAL | Parameter.Modifier.PARAMS)) != 0)
3934 /// Determines if the candidate method is applicable (section 14.4.2.1)
3935 /// to the given set of arguments
3937 static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate, out bool expanded)
3944 if (arguments == null)
3947 arg_count = arguments.Count;
3949 ParameterData pd = GetParameterData (candidate);
3950 int ps_count = CountStandardParams (pd);
3951 int pd_count = pd.Count;
3953 // Validate argument count
3954 if (ps_count == pd_count) {
3955 if (arg_count != pd_count)
3956 return ConversionType.None;
3959 if (arg_count < ps_count)
3960 return ConversionType.None;
3961 if (!HasArrayParameter (pd) && arg_count > pd_count)
3962 return ConversionType.None;
3964 ConversionType result = ConversionType.Widening;
3965 ArrayList newarglist = new ArrayList();
3966 if (arg_count > 0) {
3967 result = ConversionType.None;
3968 int array_param_index = -1;
3969 for (int i = 0; i < arg_count; ++i) {
3970 Argument a = (Argument) arguments [i];
3971 param_type = pd.ParameterType (i);
3972 Parameter.Modifier mod = pd.ParameterModifier (i);
3973 if (array_param_index < 0 && (mod & Parameter.Modifier.PARAMS) != 0)
3974 array_param_index = i;
3976 bool IsDelegate = TypeManager.IsDelegateType (param_type);
3979 if (a.ArgType == Argument.AType.AddressOf) {
3980 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
3981 ArrayList args = new ArrayList();
3983 string param_name = pd.ParameterDesc(i).Replace('+', '.');
3984 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
3986 New temp_new = new New ((Expression)pname, args, Location.Null);
3987 Expression del_temp = temp_new.DoResolve(ec);
3989 if (del_temp == null)
3990 return ConversionType.None;
3992 a = new Argument (del_temp, Argument.AType.Expression);
3993 if (!a.Resolve(ec, Location.Null))
3994 return ConversionType.None;
3998 if (a.ArgType == Argument.AType.AddressOf)
3999 return ConversionType.None;
4002 if ((mod & Parameter.Modifier.REF) != 0) {
4003 a = new Argument (a.Expr, Argument.AType.Ref);
4004 if (!a.Resolve(ec,Location.Null))
4005 return ConversionType.None;
4008 ConversionType match = ConversionType.None;
4009 if (i == array_param_index)
4010 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
4011 if (match == ConversionType.None && array_param_index >= 0 && i >= array_param_index) {
4013 param_type = param_type.GetElementType ();
4015 if (match == ConversionType.None)
4016 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
4018 if (match == ConversionType.None)
4019 return ConversionType.None;
4020 if (result == ConversionType.None)
4022 else if (match == ConversionType.Narrowing)
4023 result = ConversionType.Narrowing;
4028 // We've found a candidate, so we exchange the dummy NoArg arguments
4029 // with new arguments containing the default value for that parameter
4031 ArrayList newarglist = new ArrayList();
4032 for (int i = 0; i < arg_count; i++) {
4033 Argument a = (Argument) arguments [i];
4037 p = (Parameter) ps.FixedParameters[i];
4039 if (a.ArgType == Argument.AType.NoArg){
4040 a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
4041 a.Resolve(ec, Location.Null);
4044 // ToDo - This part is getting resolved second time within this function
4045 // This is a costly operation
4046 // The earlier resoved result should be used here.
4047 // Has to be done during compiler optimization.
4048 if (a.ArgType == Argument.AType.AddressOf) {
4049 param_type = pd.ParameterType (i);
4050 bool IsDelegate = TypeManager.IsDelegateType (param_type);
4052 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
4053 ArrayList args = new ArrayList();
4055 string param_name = pd.ParameterDesc(i).Replace('+', '.');
4056 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
4058 New temp_new = new New ((Expression)pname, args, Location.Null);
4059 Expression del_temp = temp_new.DoResolve(ec);
4061 if (del_temp == null)
4062 return ConversionType.None;
4064 a = new Argument (del_temp, Argument.AType.Expression);
4065 if (!a.Resolve(ec, Location.Null))
4066 return ConversionType.None;
4069 if ((p != null) && ((p.ModFlags & Parameter.Modifier.REF) != 0)) {
4070 a.ArgType = Argument.AType.Ref;
4071 a.Resolve(ec, Location.Null);
4072 } else if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0) {
4073 a.ArgType = Argument.AType.Ref;
4074 a.Resolve(ec, Location.Null);
4077 int n = pd_count - arg_count;
4079 for (int x = 0; x < n; x++) {
4080 Parameter op = (Parameter) ps.FixedParameters[x + arg_count];
4081 Argument b = new Argument (op.ParameterInitializer, Argument.AType.Expression);
4082 b.Resolve(ec, Location.Null);
4091 static bool compare_name_filter (MemberInfo m, object filterCriteria)
4093 return (m.Name == ((string) filterCriteria));
4096 // We need an overload for OverloadResolve because Invocation.DoResolve
4097 // must pass Arguments by reference, since a later call to IsApplicable
4098 // can change the argument list if optional parameters are defined
4099 // in the method declaration
4100 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4101 ArrayList Arguments, Location loc)
4103 ArrayList a = Arguments;
4104 return OverloadResolve (ec, me, ref a, loc);
4107 static string ToString(MethodBase mbase)
4112 if (mbase is MethodBuilder)
4114 MethodBuilder mb = (MethodBuilder) mbase;
4115 String res = mb.ReturnType + " (";
4116 ParameterInfo [] parms = mb.GetParameters();
4117 for (int i = 0; i < parms.Length; i++) {
4120 res += parms[i].ParameterType;
4126 return mbase.ToString();
4130 /// Find the Applicable Function Members (7.4.2.1)
4132 /// me: Method Group expression with the members to select.
4133 /// it might contain constructors or methods (or anything
4134 /// that maps to a method).
4136 /// Arguments: ArrayList containing resolved Argument objects.
4138 /// loc: The location if we want an error to be reported, or a Null
4139 /// location for "probing" purposes.
4141 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4142 /// that is the best match of me on Arguments.
4145 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4146 ref ArrayList Arguments, Location loc)
4148 MethodBase method = null;
4150 ArrayList candidates = new ArrayList ();
4151 Hashtable expanded_candidates = new Hashtable();
4152 int narrow_count = 0;
4153 bool narrowing_candidate = false;
4155 foreach (MethodBase candidate in me.Methods){
4156 bool candidate_expanded;
4157 ConversionType m = IsApplicable (ec, Arguments, candidate, out candidate_expanded);
4158 if (candidate_expanded)
4159 expanded_candidates [candidate] = candidate;
4160 if (m == ConversionType.None)
4162 else if (m == ConversionType.Narrowing) {
4163 if (method == null) {
4165 narrowing_candidate = true;
4168 } else if (m == ConversionType.Widening) {
4169 if (method == null || narrowing_candidate) {
4171 narrowing_candidate = false;
4173 Applicability res = BetterFunction (ec, Arguments, candidate, method, true, loc);
4174 if (res == Applicability.Same)
4175 continue; // should check it overrides?
4176 if (res == Applicability.Better)
4179 candidates.Add (candidate);
4183 if (candidates.Count == 0) {
4184 if (narrow_count > 1)
4186 else if (narrow_count == 1)
4188 } else if (candidates.Count == 1) {
4189 method = (MethodBase)candidates [0];
4194 if (Arguments == null)
4197 argument_count = Arguments.Count;
4200 if (method == null) {
4202 // Okay so we have failed to find anything so we
4203 // return by providing info about the closest match
4205 for (int i = 0; i < me.Methods.Length; ++i) {
4207 MethodBase c = (MethodBase) me.Methods [i];
4208 ParameterData pd = GetParameterData (c);
4210 if (pd.Count != argument_count)
4214 if (narrow_count != 0) {
4215 if (IsApplicable (ec, Arguments, c, out dummy) == ConversionType.None)
4217 Report.Error (1502, loc,
4218 "Overloaded match for method '" +
4219 FullMethodDesc (c) +
4220 "' requires narrowing conversionss");
4223 VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4231 // Now check that there are no ambiguities i.e the selected method
4232 // should be better than all the others
4235 if (candidates != null) {
4236 foreach (MethodBase candidate in candidates){
4237 if (candidate == method)
4240 if (BetterFunction (ec, Arguments, candidate, method,
4241 false, loc) == Applicability.Better) {
4244 "Ambiguous call of '" + me.Name + "' when selecting function due to implicit casts");
4251 // And now check if the arguments are all compatible, perform conversions
4252 // if necessary etc. and return if everything is all right
4257 bool chose_params_expanded = expanded_candidates.Contains (method);
4259 Arguments = ConstructArgumentList(ec, Arguments, method);
4260 if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4261 chose_params_expanded, null, loc))
4269 public static ArrayList ConstructArgumentList (EmitContext ec, ArrayList Arguments, MethodBase method)
4271 ArrayList newarglist = new ArrayList();
4272 int arg_count = Arguments == null ? 0 : Arguments.Count;
4274 ParameterData pd = GetParameterData (method);
4277 for (int i = 0; i < arg_count; i++) {
4278 Argument a = (Argument) Arguments [i];
4279 Type param_type = pd.ParameterType (i);
4281 bool IsDelegate = TypeManager.IsDelegateType (param_type);
4283 if (a.ArgType == Argument.AType.AddressOf) {
4284 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
4285 ArrayList args = new ArrayList();
4287 string param_name = pd.ParameterDesc(i).Replace('+', '.');
4288 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
4290 New temp_new = new New ((Expression)pname, args, Location.Null);
4291 Expression del_temp = temp_new.DoResolve(ec);
4292 a = new Argument (del_temp, Argument.AType.Expression);
4293 a.Resolve(ec, Location.Null);
4296 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0) {
4297 a.ArgType = Argument.AType.Ref;
4298 a.Resolve(ec, Location.Null);
4304 if (HasArrayParameter (pd) && arg_count == pd.Count - 1)
4307 for (int i = arg_count; i < pd.Count; i++) {
4308 Expression e = pd.DefaultValue (i);
4309 Argument a = new Argument (e, Argument.AType.Expression);
4310 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0)
4311 a.ArgType = Argument.AType.Ref;
4313 a.Resolve (ec, Location.Null);
4320 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4323 bool chose_params_expanded,
4327 return (VerifyArgumentsCompat (ec, Arguments, argument_count,
4328 method, chose_params_expanded, delegate_type, loc, null));
4331 public static bool VerifyArgumentsCompat (EmitContext ec,
4332 ArrayList Arguments,
4335 bool chose_params_expanded,
4338 string InvokingProperty)
4340 ParameterData pd = GetParameterData (method);
4341 int pd_count = pd.Count;
4343 for (int j = 0; j < argument_count; j++) {
4344 Argument a = (Argument) Arguments [j];
4345 Expression a_expr = a.Expr;
4346 Type parameter_type = pd.ParameterType(j);
4348 if (parameter_type == null)
4350 Error_WrongNumArguments(loc, (InvokingProperty == null)?((delegate_type == null)?FullMethodDesc (method):delegate_type.ToString ()):InvokingProperty, argument_count);
4353 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
4354 chose_params_expanded)
4355 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
4356 if (a.Type != parameter_type){
4359 conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
4362 if (!Location.IsNull (loc)) {
4363 if (delegate_type == null)
4364 if (InvokingProperty == null)
4365 Report.Error (1502, loc,
4366 "The best overloaded match for method '" +
4367 FullMethodDesc (method) +
4368 "' has some invalid arguments");
4370 Report.Error (1502, loc,
4373 "' has some invalid arguments");
4375 Report.Error (1594, loc,
4376 "Delegate '" + delegate_type.ToString () +
4377 "' has some invalid arguments.");
4378 Report.Error (1503, loc,
4379 "Argument " + (j+1) +
4380 ": Cannot convert from '" + Argument.FullDesc (a)
4381 + "' to '" + pd.ParameterDesc (j) + "'");
4388 // Update the argument with the implicit conversion
4394 Parameter.Modifier a_mod = a.GetParameterModifier () &
4395 ~(Parameter.Modifier.REF);
4396 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4397 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
4399 if (a_mod != p_mod &&
4400 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4401 if (!Location.IsNull (loc)) {
4402 Report.Error (1502, loc,
4403 "The best overloaded match for method '" + FullMethodDesc (method)+
4404 "' has some invalid arguments");
4405 Report.Error (1503, loc,
4406 "Argument " + (j+1) +
4407 ": Cannot convert from '" + Argument.FullDesc (a)
4408 + "' to '" + pd.ParameterDesc (j) + "'");
4418 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4420 this.is_left_hand = true;
4421 Expression expr_to_return = DoResolve (ec);
4423 if (expr_to_return is IndexerAccess) {
4424 IndexerAccess ia = expr_to_return as IndexerAccess;
4425 expr_to_return = ia.DoResolveLValue (ec, right_side);
4428 return expr_to_return;
4431 public override Expression DoResolve (EmitContext ec)
4434 // First, resolve the expression that is used to
4435 // trigger the invocation
4437 Expression expr_to_return = null;
4438 Expression temp = null;
4440 if (expr is BaseAccess)
4444 if ((ec.ReturnType != null) && (expr.ToString() == ec.BlockName)) {
4445 ec.InvokingOwnOverload = true;
4446 flags = ResolveFlags.MethodGroup;
4447 temp = expr.Resolve (ec, flags);
4448 ec.InvokingOwnOverload = false;
4452 ec.InvokingOwnOverload = false;
4453 flags = ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup;
4454 temp = expr.Resolve (ec, flags);
4460 if (expr is MemberAccess) {
4461 MemberAccess m = expr as MemberAccess;
4462 if (m.Expr.Type == TypeManager.object_type) {
4463 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4464 loc, expr, Arguments,
4465 is_retval_required, is_left_hand);
4466 etmp.GenerateLateBindingStatements();
4467 this.is_latebinding = true;
4468 return etmp.Resolve (ec);
4476 if (expr is Invocation) {
4477 // FIXME Calls which return an Array are not resolved (here or in the grammar)
4478 expr = expr.Resolve(ec);
4481 if (!(expr is MethodGroupExpr))
4483 Type expr_type = expr.Type;
4485 if (expr_type != null)
4487 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4489 return (new DelegateInvocation (
4490 this.expr, Arguments, loc)).Resolve (ec);
4495 // Next, evaluate all the expressions in the argument list
4497 if (Arguments != null)
4499 foreach (Argument a in Arguments)
4501 if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
4502 Report.Error (999, "This item cannot have empty arguments");
4504 if (!a.Resolve (ec, loc))
4509 if (expr is MethodGroupExpr)
4511 MethodGroupExpr mg = (MethodGroupExpr) expr;
4512 method = OverloadResolve (ec, mg, ref Arguments, loc);
4517 "Could not find any applicable function to invoke for this argument list");
4521 if ((method as MethodInfo) != null)
4523 MethodInfo mi = method as MethodInfo;
4524 type = TypeManager.TypeToCoreType (mi.ReturnType);
4525 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4526 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4529 if ((method as ConstructorInfo) != null)
4531 ConstructorInfo ci = method as ConstructorInfo;
4532 type = TypeManager.void_type;
4533 if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4534 SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);
4545 eclass = ExprClass.Value;
4546 expr_to_return = this;
4547 return expr_to_return;
4550 if (expr is PropertyExpr)
4552 PropertyExpr pe = ((PropertyExpr) expr);
4553 if (pe.PropertyArgs != null)
4554 goto skip_already_resolved_property;
4555 pe.PropertyArgs = (ArrayList) Arguments;
4556 MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
4558 bool expanded = false;
4559 if (IsApplicable(ec, pe.PropertyArgs, mi, out expanded) != ConversionType.None) {
4560 if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
4561 pe.PropertyArgs.Count, mi, expanded, null, loc, pe.Name))
4563 expr_to_return = pe.DoResolve (ec);
4564 expr_to_return.eclass = ExprClass.PropertyAccess;
4565 Arguments = new ArrayList ();
4566 return expr_to_return;
4570 throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
4573 pe.PropertyArgs = new ArrayList ();
4574 if (VerifyArgumentsCompat (ec, pe.PropertyArgs,
4575 0, mi, false, null, loc, pe.Name)) {
4576 expr = pe.DoResolve (ec);
4577 expr.eclass = ExprClass.PropertyAccess;
4579 throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
4584 skip_already_resolved_property:
4585 if (expr.Type.IsArray) {
4586 // If we are here, expr must be an ArrayAccess
4587 ArrayList idxs = new ArrayList();
4588 foreach (Argument a in Arguments)
4592 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4593 ArrayAccess aa = new ArrayAccess (ea, expr.Location);
4594 expr_to_return = aa.DoResolve(ec);
4595 expr_to_return.eclass = ExprClass.Variable;
4598 // check whether this is a indexer
4600 ArrayList idxs = new ArrayList();
4601 foreach (Argument a in Arguments) {
4604 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4605 IndexerAccess ia = new IndexerAccess (ea, expr.Location);
4607 expr_to_return = ia.DoResolve(ec);
4609 expr_to_return = ia.DoResolve(ec);
4611 // Since all the above are failed we need to do
4614 if (expr_to_return == null) {
4616 // We can't resolve now, but we
4617 // have to try to access the array with a call
4618 // to LateIndexGet/Set in the runtime
4619 if (! is_left_hand) {
4620 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4623 etmp.GenerateLateBindingStatements();
4624 return etmp.Resolve (ec);
4630 return expr_to_return;
4633 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4635 Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
4636 arg_count + "' arguments");
4640 // Emits the list of arguments as an array
4642 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4644 ILGenerator ig = ec.ig;
4645 int count = arguments.Count - idx;
4646 Argument a = (Argument) arguments [idx];
4647 Type t = a.Expr.Type;
4648 string array_type = t.FullName + "[]";
4651 array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4652 IntConstant.EmitInt (ig, count);
4653 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4654 ig.Emit (OpCodes.Stloc, array);
4656 int top = arguments.Count;
4657 for (int j = idx; j < top; j++){
4658 a = (Argument) arguments [j];
4660 ig.Emit (OpCodes.Ldloc, array);
4661 IntConstant.EmitInt (ig, j - idx);
4664 ArrayAccess.EmitStoreOpcode (ig, t);
4666 ig.Emit (OpCodes.Ldloc, array);
4670 /// Emits a list of resolved Arguments that are in the arguments
4673 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4675 ParameterData pd = GetParameterData (mb);
4678 // If we are calling a params method with no arguments, special case it
4680 if (arguments == null){
4682 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4683 ILGenerator ig = ec.ig;
4685 IntConstant.EmitInt (ig, 0);
4686 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4691 int top = arguments.Count;
4693 for (int i = 0; i < top; i++){
4694 Argument a = (Argument) arguments [i];
4696 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4698 // Special case if we are passing the same data as the
4699 // params argument, do not put it in an array.
4701 if (pd.ParameterType (i) == a.Type)
4704 EmitParams (ec, i, arguments);
4708 if ((a.ArgType == Argument.AType.Ref ) &&
4709 !(a.Expr is IMemoryLocation)) {
4710 LocalTemporary tmp = new LocalTemporary (ec, pd.ParameterType (i));
4714 a = new Argument (tmp, a.ArgType);
4720 if (pd.Count > top &&
4721 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4722 ILGenerator ig = ec.ig;
4724 IntConstant.EmitInt (ig, 0);
4725 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4730 /// is_base tells whether we want to force the use of the 'call'
4731 /// opcode instead of using callvirt. Call is required to call
4732 /// a specific method, while callvirt will always use the most
4733 /// recent method in the vtable.
4735 /// is_static tells whether this is an invocation on a static method
4737 /// instance_expr is an expression that represents the instance
4738 /// it must be non-null if is_static is false.
4740 /// method is the method to invoke.
4742 /// Arguments is the list of arguments to pass to the method or constructor.
4744 public static void EmitCall (EmitContext ec, bool is_base,
4745 bool is_static, Expression instance_expr,
4746 MethodBase method, ArrayList Arguments, Location loc)
4748 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
4751 public static void EmitCall (EmitContext ec, bool is_base,
4752 bool is_static, Expression instance_expr,
4753 MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)
4755 ILGenerator ig = ec.ig;
4756 bool struct_call = false;
4757 bool is_myclass = false;
4759 if (instance_expr is This && ((This) instance_expr).AccessType == This.TypeOfAccess.MyClass)
4762 Type decl_type = method.DeclaringType;
4764 if (!RootContext.StdLib)
4766 // Replace any calls to the system's System.Array type with calls to
4767 // the newly created one.
4768 if (method == TypeManager.system_int_array_get_length)
4769 method = TypeManager.int_array_get_length;
4770 else if (method == TypeManager.system_int_array_get_rank)
4771 method = TypeManager.int_array_get_rank;
4772 else if (method == TypeManager.system_object_array_clone)
4773 method = TypeManager.object_array_clone;
4774 else if (method == TypeManager.system_int_array_get_length_int)
4775 method = TypeManager.int_array_get_length_int;
4776 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4777 method = TypeManager.int_array_get_lower_bound_int;
4778 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4779 method = TypeManager.int_array_get_upper_bound_int;
4780 else if (method == TypeManager.system_void_array_copyto_array_int)
4781 method = TypeManager.void_array_copyto_array_int;
4785 // This checks the 'ConditionalAttribute' on the method, and the
4786 // ObsoleteAttribute
4788 TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4789 if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4791 if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4796 if (decl_type.IsValueType)
4799 // If this is ourselves, push "this"
4801 if (instance_expr == null)
4803 ig.Emit (OpCodes.Ldarg_0);
4808 // Push the instance expression
4810 if (instance_expr.Type.IsValueType)
4813 // Special case: calls to a function declared in a
4814 // reference-type with a value-type argument need
4815 // to have their value boxed.
4818 if (decl_type.IsValueType)
4821 // If the expression implements IMemoryLocation, then
4822 // we can optimize and use AddressOf on the
4825 // If not we have to use some temporary storage for
4827 if (instance_expr is IMemoryLocation)
4829 ((IMemoryLocation)instance_expr).
4830 AddressOf (ec, AddressOp.LoadStore);
4834 Type t = instance_expr.Type;
4836 instance_expr.Emit (ec);
4837 LocalBuilder temp = ig.DeclareLocal (t);
4838 ig.Emit (OpCodes.Stloc, temp);
4839 ig.Emit (OpCodes.Ldloca, temp);
4844 instance_expr.Emit (ec);
4845 ig.Emit (OpCodes.Box, instance_expr.Type);
4849 instance_expr.Emit (ec);
4853 if (prop_args != null && prop_args.Count > 0)
4855 if (Arguments == null)
4856 Arguments = new ArrayList();
4858 for (int i = prop_args.Count-1; i >=0 ; i--)
4860 Arguments.Insert (0,prop_args[i]);
4865 EmitArguments (ec, method, Arguments);
4867 if (is_static || struct_call || is_base || is_myclass)
4869 if (method is MethodInfo)
4871 ig.Emit (OpCodes.Call, (MethodInfo) method);
4874 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4878 if (method is MethodInfo)
4879 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4881 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4885 static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
4887 int top = prop_args.Count;
4889 for (int i = 0; i < top; i++)
4891 Argument a = (Argument) prop_args [i];
4896 public override void Emit (EmitContext ec)
4898 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4901 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4904 public override void EmitStatement (EmitContext ec)
4909 // Pop the return value if there is one
4911 if (method is MethodInfo){
4912 Type ret = ((MethodInfo)method).ReturnType;
4913 if ((TypeManager.TypeToCoreType (ret) != TypeManager.void_type) && !this.is_latebinding) {
4914 ec.ig.Emit (OpCodes.Pop);
4921 // This class is used to "disable" the code generation for the
4922 // temporary variable when initializing value types.
4924 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4925 public void AddressOf (EmitContext ec, AddressOp Mode)
4932 /// Implements the new expression
4934 public class New : ExpressionStatement {
4935 public readonly ArrayList Arguments;
4936 public readonly Expression RequestedType;
4938 MethodBase method = null;
4941 // If set, the new expression is for a value_target, and
4942 // we will not leave anything on the stack.
4944 Expression value_target;
4945 bool value_target_set = false;
4946 public bool isDelegate = false;
4948 public New (Expression requested_type, ArrayList arguments, Location l)
4950 RequestedType = requested_type;
4951 Arguments = arguments;
4955 public Expression ValueTypeVariable {
4957 return value_target;
4961 value_target = value;
4962 value_target_set = true;
4967 // This function is used to disable the following code sequence for
4968 // value type initialization:
4970 // AddressOf (temporary)
4974 // Instead the provide will have provided us with the address on the
4975 // stack to store the results.
4977 static Expression MyEmptyExpression;
4979 public void DisableTemporaryValueType ()
4981 if (MyEmptyExpression == null)
4982 MyEmptyExpression = new EmptyAddressOf ();
4985 // To enable this, look into:
4986 // test-34 and test-89 and self bootstrapping.
4988 // For instance, we can avoid a copy by using 'newobj'
4989 // instead of Call + Push-temp on value types.
4990 // value_target = MyEmptyExpression;
4993 public override Expression DoResolve (EmitContext ec)
4995 if (this.isDelegate) {
4996 // if its a delegate resolve the type of RequestedType first
4997 Expression dtype = RequestedType.Resolve(ec);
4998 string ts = (dtype.Type.ToString()).Replace ('+','.');
4999 dtype = Mono.MonoBASIC.Parser.DecomposeQI (ts, Location.Null);
5001 type = ec.DeclSpace.ResolveType (dtype, false, loc);
5004 type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5009 bool IsDelegate = TypeManager.IsDelegateType (type);
5012 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5014 if (type.IsInterface || type.IsAbstract){
5016 30376, "It is not possible to create instances of Interfaces " +
5017 "or classes marked as MustInherit");
5021 bool is_struct = false;
5022 is_struct = type.IsValueType;
5023 eclass = ExprClass.Value;
5026 // SRE returns a match for .ctor () on structs (the object constructor),
5027 // so we have to manually ignore it.
5029 if (is_struct && Arguments == null)
5033 ml = MemberLookupFinal (ec, type, ".ctor",
5034 MemberTypes.Constructor,
5035 AllBindingFlags | BindingFlags.Public, loc);
5040 if (! (ml is MethodGroupExpr)){
5042 ml.Error118 ("method group");
5048 if (Arguments != null){
5049 foreach (Argument a in Arguments){
5050 if (!a.Resolve (ec, loc))
5055 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
5060 if (method == null) {
5061 if (!is_struct || Arguments.Count > 0) {
5063 "New invocation: Can not find a constructor for " +
5064 "this argument list");
5072 // This DoEmit can be invoked in two contexts:
5073 // * As a mechanism that will leave a value on the stack (new object)
5074 // * As one that wont (init struct)
5076 // You can control whether a value is required on the stack by passing
5077 // need_value_on_stack. The code *might* leave a value on the stack
5078 // so it must be popped manually
5080 // If we are dealing with a ValueType, we have a few
5081 // situations to deal with:
5083 // * The target is a ValueType, and we have been provided
5084 // the instance (this is easy, we are being assigned).
5086 // * The target of New is being passed as an argument,
5087 // to a boxing operation or a function that takes a
5090 // In this case, we need to create a temporary variable
5091 // that is the argument of New.
5093 // Returns whether a value is left on the stack
5095 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5097 bool is_value_type = type.IsValueType;
5098 ILGenerator ig = ec.ig;
5103 // Allow DoEmit() to be called multiple times.
5104 // We need to create a new LocalTemporary each time since
5105 // you can't share LocalBuilders among ILGeneators.
5106 if (!value_target_set)
5107 value_target = new LocalTemporary (ec, type);
5109 ml = (IMemoryLocation) value_target;
5110 ml.AddressOf (ec, AddressOp.Store);
5114 Invocation.EmitArguments (ec, method, Arguments);
5118 ig.Emit (OpCodes.Initobj, type);
5120 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5121 if (need_value_on_stack){
5122 value_target.Emit (ec);
5127 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5132 public override void Emit (EmitContext ec)
5137 public override void EmitStatement (EmitContext ec)
5139 if (DoEmit (ec, false))
5140 ec.ig.Emit (OpCodes.Pop);
5145 /// 14.5.10.2: Represents an array creation expression.
5149 /// There are two possible scenarios here: one is an array creation
5150 /// expression that specifies the dimensions and optionally the
5151 /// initialization data and the other which does not need dimensions
5152 /// specified but where initialization data is mandatory.
5154 public class ArrayCreation : ExpressionStatement {
5155 Expression requested_base_type;
5156 ArrayList initializers;
5159 // The list of Argument types.
5160 // This is used to construct the 'newarray' or constructor signature
5162 ArrayList arguments;
5165 // Method used to create the array object.
5167 MethodBase new_method = null;
5169 Type array_element_type;
5170 Type underlying_type;
5171 bool is_one_dimensional = false;
5172 bool is_builtin_type = false;
5173 bool expect_initializers = false;
5174 int num_arguments = 0;
5178 ArrayList array_data;
5183 // The number of array initializers that we can handle
5184 // via the InitializeArray method - through EmitStaticInitializers
5186 int num_automatic_initializers;
5188 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5190 this.requested_base_type = requested_base_type;
5191 this.initializers = initializers;
5195 arguments = new ArrayList ();
5197 foreach (Expression e in exprs) {
5198 arguments.Add (new Argument (e, Argument.AType.Expression));
5203 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5205 this.requested_base_type = requested_base_type;
5206 this.initializers = initializers;
5210 //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
5212 //string tmp = rank.Substring (rank.LastIndexOf ("["));
5214 //dimensions = tmp.Length - 1;
5215 expect_initializers = true;
5218 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5220 StringBuilder sb = new StringBuilder (rank);
5223 for (int i = 1; i < idx_count; i++)
5228 return new ComposedCast (base_type, sb.ToString (), loc);
5231 void Error_IncorrectArrayInitializer ()
5233 Error (30567, "Incorrectly structured array initializer");
5236 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5238 if (specified_dims) {
5239 Argument a = (Argument) arguments [idx];
5241 if (!a.Resolve (ec, loc))
5244 if (!(a.Expr is Constant)) {
5245 Error (150, "A constant value is expected");
5249 int value = (int) ((Constant) a.Expr).GetValue ();
5251 if (value != probe.Count) {
5252 Error_IncorrectArrayInitializer ();
5256 bounds [idx] = value;
5259 int child_bounds = -1;
5260 foreach (object o in probe) {
5261 if (o is ArrayList) {
5262 int current_bounds = ((ArrayList) o).Count;
5264 if (child_bounds == -1)
5265 child_bounds = current_bounds;
5267 else if (child_bounds != current_bounds){
5268 Error_IncorrectArrayInitializer ();
5271 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5275 if (child_bounds != -1){
5276 Error_IncorrectArrayInitializer ();
5280 Expression tmp = (Expression) o;
5281 tmp = tmp.Resolve (ec);
5285 // Console.WriteLine ("I got: " + tmp);
5286 // Handle initialization from vars, fields etc.
5288 Expression conv = ConvertImplicitRequired (
5289 ec, tmp, underlying_type, loc);
5294 if (conv is StringConstant)
5295 array_data.Add (conv);
5296 else if (conv is Constant) {
5297 array_data.Add (conv);
5298 num_automatic_initializers++;
5300 array_data.Add (conv);
5307 public void UpdateIndices (EmitContext ec)
5310 for (ArrayList probe = initializers; probe != null;) {
5311 if (probe.Count > 0 && probe [0] is ArrayList) {
5312 Expression e = new IntConstant (probe.Count);
5313 arguments.Add (new Argument (e, Argument.AType.Expression));
5315 bounds [i++] = probe.Count;
5317 probe = (ArrayList) probe [0];
5320 Expression e = new IntConstant (probe.Count);
5321 arguments.Add (new Argument (e, Argument.AType.Expression));
5323 bounds [i++] = probe.Count;
5330 public bool ValidateInitializers (EmitContext ec, Type array_type)
5332 if (initializers == null) {
5333 if (expect_initializers)
5339 if (underlying_type == null)
5343 // We use this to store all the date values in the order in which we
5344 // will need to store them in the byte blob later
5346 array_data = new ArrayList ();
5347 bounds = new Hashtable ();
5351 if (arguments != null) {
5352 ret = CheckIndices (ec, initializers, 0, true);
5355 arguments = new ArrayList ();
5357 ret = CheckIndices (ec, initializers, 0, false);
5364 if (arguments.Count != dimensions) {
5365 Error_IncorrectArrayInitializer ();
5373 void Error_NegativeArrayIndex ()
5375 Error (284, "Can not create array with a negative size");
5379 // Converts 'source' to an int, uint, long or ulong.
5381 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5385 bool old_checked = ec.CheckState;
5386 ec.CheckState = true;
5388 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
5389 if (target == null){
5390 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
5391 if (target == null){
5392 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
5393 if (target == null){
5394 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
5396 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
5400 ec.CheckState = old_checked;
5403 // Only positive constants are allowed at compile time
5405 if (target is Constant){
5406 if (target is IntConstant){
5407 if (((IntConstant) target).Value < 0){
5408 Error_NegativeArrayIndex ();
5413 if (target is LongConstant){
5414 if (((LongConstant) target).Value < 0){
5415 Error_NegativeArrayIndex ();
5426 // Creates the type of the array
5428 bool LookupType (EmitContext ec)
5430 StringBuilder array_qualifier = new StringBuilder (rank);
5433 // 'In the first form allocates an array instace of the type that results
5434 // from deleting each of the individual expression from the expression list'
5436 if (num_arguments > 0) {
5437 array_qualifier.Append ("[");
5438 for (int i = num_arguments-1; i > 0; i--)
5439 array_qualifier.Append (",");
5440 array_qualifier.Append ("]");
5446 Expression array_type_expr;
5447 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5448 type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5453 underlying_type = type;
5454 if (underlying_type.IsArray)
5455 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
5456 dimensions = type.GetArrayRank ();
5461 public override Expression DoResolve (EmitContext ec)
5465 if (!LookupType (ec))
5469 // First step is to validate the initializers and fill
5470 // in any missing bits
5472 if (!ValidateInitializers (ec, type))
5475 if (arguments == null)
5478 arg_count = arguments.Count;
5479 foreach (Argument a in arguments){
5480 if (!a.Resolve (ec, loc))
5483 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5484 if (real_arg == null)
5491 array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
5493 if (arg_count == 1) {
5494 is_one_dimensional = true;
5495 eclass = ExprClass.Value;
5499 is_builtin_type = TypeManager.IsBuiltinType (type);
5501 if (is_builtin_type) {
5504 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5505 AllBindingFlags, loc);
5507 if (!(ml is MethodGroupExpr)) {
5508 ml.Error118 ("method group");
5513 Error (-6, "New invocation: Can not find a constructor for " +
5514 "this argument list");
5518 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5520 if (new_method == null) {
5521 Error (-6, "New invocation: Can not find a constructor for " +
5522 "this argument list");
5526 eclass = ExprClass.Value;
5529 ModuleBuilder mb = CodeGen.ModuleBuilder;
5530 ArrayList args = new ArrayList ();
5532 if (arguments != null) {
5533 for (int i = 0; i < arg_count; i++)
5534 args.Add (TypeManager.int32_type);
5537 Type [] arg_types = null;
5540 arg_types = new Type [args.Count];
5542 args.CopyTo (arg_types, 0);
5544 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5547 if (new_method == null) {
5548 Error (-6, "New invocation: Can not find a constructor for " +
5549 "this argument list");
5553 eclass = ExprClass.Value;
5558 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5563 int count = array_data.Count;
5565 if (underlying_type.IsEnum)
5566 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5568 factor = GetTypeSize (underlying_type);
5570 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5572 data = new byte [(count * factor + 4) & ~3];
5575 for (int i = 0; i < count; ++i) {
5576 object v = array_data [i];
5578 if (v is EnumConstant)
5579 v = ((EnumConstant) v).Child;
5581 if (v is Constant && !(v is StringConstant))
5582 v = ((Constant) v).GetValue ();
5588 if (underlying_type == TypeManager.int64_type){
5589 if (!(v is Expression)){
5590 long val = (long) v;
5592 for (int j = 0; j < factor; ++j) {
5593 data [idx + j] = (byte) (val & 0xFF);
5597 } else if (underlying_type == TypeManager.uint64_type){
5598 if (!(v is Expression)){
5599 ulong val = (ulong) v;
5601 for (int j = 0; j < factor; ++j) {
5602 data [idx + j] = (byte) (val & 0xFF);
5606 } else if (underlying_type == TypeManager.float_type) {
5607 if (!(v is Expression)){
5608 element = BitConverter.GetBytes ((float) v);
5610 for (int j = 0; j < factor; ++j)
5611 data [idx + j] = element [j];
5613 } else if (underlying_type == TypeManager.double_type) {
5614 if (!(v is Expression)){
5615 element = BitConverter.GetBytes ((double) v);
5617 for (int j = 0; j < factor; ++j)
5618 data [idx + j] = element [j];
5620 } else if (underlying_type == TypeManager.char_type){
5621 if (!(v is Expression)){
5622 int val = (int) ((char) v);
5624 data [idx] = (byte) (val & 0xff);
5625 data [idx+1] = (byte) (val >> 8);
5627 } else if (underlying_type == TypeManager.short_type){
5628 if (!(v is Expression)){
5629 int val = (int) ((short) v);
5631 data [idx] = (byte) (val & 0xff);
5632 data [idx+1] = (byte) (val >> 8);
5634 } else if (underlying_type == TypeManager.ushort_type){
5635 if (!(v is Expression)){
5636 int val = (int) ((ushort) v);
5638 data [idx] = (byte) (val & 0xff);
5639 data [idx+1] = (byte) (val >> 8);
5641 } else if (underlying_type == TypeManager.int32_type) {
5642 if (!(v is Expression)){
5645 data [idx] = (byte) (val & 0xff);
5646 data [idx+1] = (byte) ((val >> 8) & 0xff);
5647 data [idx+2] = (byte) ((val >> 16) & 0xff);
5648 data [idx+3] = (byte) (val >> 24);
5650 } else if (underlying_type == TypeManager.uint32_type) {
5651 if (!(v is Expression)){
5652 uint val = (uint) v;
5654 data [idx] = (byte) (val & 0xff);
5655 data [idx+1] = (byte) ((val >> 8) & 0xff);
5656 data [idx+2] = (byte) ((val >> 16) & 0xff);
5657 data [idx+3] = (byte) (val >> 24);
5659 } else if (underlying_type == TypeManager.sbyte_type) {
5660 if (!(v is Expression)){
5661 sbyte val = (sbyte) v;
5662 data [idx] = (byte) val;
5664 } else if (underlying_type == TypeManager.byte_type) {
5665 if (!(v is Expression)){
5666 byte val = (byte) v;
5667 data [idx] = (byte) val;
5669 } else if (underlying_type == TypeManager.bool_type) {
5670 if (!(v is Expression)){
5671 bool val = (bool) v;
5672 data [idx] = (byte) (val ? 1 : 0);
5674 } else if (underlying_type == TypeManager.decimal_type){
5675 if (!(v is Expression)){
5676 int [] bits = Decimal.GetBits ((decimal) v);
5679 for (int j = 0; j < 4; j++){
5680 data [p++] = (byte) (bits [j] & 0xff);
5681 data [p++] = (byte) ((bits [j] >> 8) & 0xff);
5682 data [p++] = (byte) ((bits [j] >> 16) & 0xff);
5683 data [p++] = (byte) (bits [j] >> 24);
5687 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5696 // Emits the initializers for the array
5698 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5701 // First, the static data
5704 ILGenerator ig = ec.ig;
5706 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5708 fb = RootContext.MakeStaticData (data);
5711 ig.Emit (OpCodes.Dup);
5712 ig.Emit (OpCodes.Ldtoken, fb);
5713 ig.Emit (OpCodes.Call,
5714 TypeManager.void_initializearray_array_fieldhandle);
5718 // Emits pieces of the array that can not be computed at compile
5719 // time (variables and string locations).
5721 // This always expect the top value on the stack to be the array
5723 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5725 ILGenerator ig = ec.ig;
5726 int dims = bounds.Count;
5727 int [] current_pos = new int [dims];
5728 int top = array_data.Count;
5729 LocalBuilder temp = ig.DeclareLocal (type);
5731 ig.Emit (OpCodes.Stloc, temp);
5733 MethodInfo set = null;
5737 ModuleBuilder mb = null;
5738 mb = CodeGen.ModuleBuilder;
5739 args = new Type [dims + 1];
5742 for (j = 0; j < dims; j++)
5743 args [j] = TypeManager.int32_type;
5745 args [j] = array_element_type;
5747 set = mb.GetArrayMethod (
5749 CallingConventions.HasThis | CallingConventions.Standard,
5750 TypeManager.void_type, args);
5753 for (int i = 0; i < top; i++){
5755 Expression e = null;
5757 if (array_data [i] is Expression)
5758 e = (Expression) array_data [i];
5762 // Basically we do this for string literals and
5763 // other non-literal expressions
5765 if (e is StringConstant || !(e is Constant) ||
5766 num_automatic_initializers <= 2) {
5767 Type etype = e.Type;
5769 ig.Emit (OpCodes.Ldloc, temp);
5771 for (int idx = 0; idx < dims; idx++)
5772 IntConstant.EmitInt (ig, current_pos [idx]);
5775 // If we are dealing with a struct, get the
5776 // address of it, so we can store it.
5779 etype.IsSubclassOf (TypeManager.value_type) &&
5780 (!TypeManager.IsBuiltinType (etype) ||
5781 etype == TypeManager.decimal_type)) {
5786 // Let new know that we are providing
5787 // the address where to store the results
5789 n.DisableTemporaryValueType ();
5792 ig.Emit (OpCodes.Ldelema, etype);
5798 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
5800 ig.Emit (OpCodes.Call, set);
5807 for (int j = dims - 1; j >= 0; j--){
5809 if (current_pos [j] < (int) bounds [j])
5811 current_pos [j] = 0;
5816 ig.Emit (OpCodes.Ldloc, temp);
5819 void EmitArrayArguments (EmitContext ec)
5821 ILGenerator ig = ec.ig;
5823 foreach (Argument a in arguments) {
5824 Type atype = a.Type;
5827 if (atype == TypeManager.uint64_type)
5828 ig.Emit (OpCodes.Conv_Ovf_U4);
5829 else if (atype == TypeManager.int64_type)
5830 ig.Emit (OpCodes.Conv_Ovf_I4);
5834 void DoEmit (EmitContext ec, bool is_statement)
5836 ILGenerator ig = ec.ig;
5838 EmitArrayArguments (ec);
5839 if (is_one_dimensional)
5840 ig.Emit (OpCodes.Newarr, array_element_type);
5842 if (is_builtin_type)
5843 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
5845 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
5848 if (initializers != null){
5850 // FIXME: Set this variable correctly.
5852 bool dynamic_initializers = true;
5854 if (underlying_type != TypeManager.string_type &&
5855 underlying_type != TypeManager.object_type) {
5856 if (num_automatic_initializers > 2)
5857 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
5860 if (dynamic_initializers)
5861 EmitDynamicInitializers (ec, !is_statement);
5865 public override void Emit (EmitContext ec)
5870 public override void EmitStatement (EmitContext ec)
5878 /// Represents the 'this' construct
5880 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
5882 public enum TypeOfAccess : byte {
5888 TypeOfAccess access_type;
5890 public This (TypeOfAccess access_type, Block block, Location loc)
5894 this.access_type = access_type;
5897 public This (Block block, Location loc)
5901 this.access_type = TypeOfAccess.Me;
5904 public This (Location loc)
5907 this.access_type = TypeOfAccess.Me;
5910 public TypeOfAccess AccessType {
5911 get { return access_type; }
5914 public bool IsAssigned (EmitContext ec, Location loc)
5919 return vi.IsAssigned (ec, loc);
5922 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
5927 return vi.IsFieldAssigned (ec, field_name, loc);
5930 public void SetAssigned (EmitContext ec)
5933 vi.SetAssigned (ec);
5936 public void SetFieldAssigned (EmitContext ec, string field_name)
5939 vi.SetFieldAssigned (ec, field_name);
5942 public override Expression DoResolve (EmitContext ec)
5944 eclass = ExprClass.Variable;
5945 type = ec.ContainerType;
5948 Error (26, "Keyword this not valid in static code");
5953 vi = block.ThisVariable;
5958 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5962 VariableInfo vi = ec.CurrentBlock.ThisVariable;
5964 vi.SetAssigned (ec);
5966 if (ec.TypeContainer is Class){
5967 Error (1604, "Cannot assign to 'this'");
5974 public override void Emit (EmitContext ec)
5976 ILGenerator ig = ec.ig;
5978 ig.Emit (OpCodes.Ldarg_0);
5979 if (ec.TypeContainer is Struct)
5980 ig.Emit (OpCodes.Ldobj, type);
5983 public void EmitAssign (EmitContext ec, Expression source)
5985 ILGenerator ig = ec.ig;
5987 if (ec.TypeContainer is Struct){
5988 ig.Emit (OpCodes.Ldarg_0);
5990 ig.Emit (OpCodes.Stobj, type);
5993 ig.Emit (OpCodes.Starg, 0);
5997 public void AddressOf (EmitContext ec, AddressOp mode)
5999 ec.ig.Emit (OpCodes.Ldarg_0);
6002 // FIGURE OUT WHY LDARG_S does not work
6004 // consider: struct X { int val; int P { set { val = value; }}}
6006 // Yes, this looks very bad. Look at 'NOTAS' for
6008 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6013 /// Implements the typeof operator
6015 public class TypeOf : Expression {
6016 public readonly Expression QueriedType;
6019 public TypeOf (Expression queried_type, Location l)
6021 QueriedType = queried_type;
6025 public override Expression DoResolve (EmitContext ec)
6027 typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6029 if (typearg == null)
6032 type = TypeManager.type_type;
6033 eclass = ExprClass.Type;
6037 public override void Emit (EmitContext ec)
6039 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6040 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6043 public Type TypeArg {
6044 get { return typearg; }
6049 /// Implements the sizeof expression
6051 public class SizeOf : Expression {
6052 public readonly Expression QueriedType;
6055 public SizeOf (Expression queried_type, Location l)
6057 this.QueriedType = queried_type;
6061 public override Expression DoResolve (EmitContext ec)
6064 Error (233, "Sizeof may only be used in an unsafe context " +
6065 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6069 type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6070 if (type_queried == null)
6073 if (!TypeManager.IsUnmanagedType (type_queried)){
6074 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.MonoBASIC_Name (type_queried) + ")");
6078 type = TypeManager.int32_type;
6079 eclass = ExprClass.Value;
6083 public override void Emit (EmitContext ec)
6085 int size = GetTypeSize (type_queried);
6088 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6090 IntConstant.EmitInt (ec.ig, size);
6095 /// Implements the member access expression
6097 public class MemberAccess : Expression, ITypeExpression {
6098 public readonly string Identifier;
6100 Expression member_lookup;
6104 public MemberAccess (Expression expr, string id, Location l)
6111 public MemberAccess (Expression expr, string id, Location l, bool isInvocation)
6116 is_invocation = isInvocation;
6119 public bool IsInvocation {
6121 return is_invocation;
6124 is_invocation = value;
6128 public bool IsLeftHand {
6130 return is_left_hand;
6133 is_left_hand = value;
6137 public Expression Expr {
6143 static void error176 (Location loc, string name)
6145 Report.Error (176, loc, "Static member '" +
6146 name + "' cannot be accessed " +
6147 "with an instance reference, qualify with a " +
6148 "type name instead");
6151 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6153 if (left_original == null)
6156 if (!(left_original is SimpleName))
6159 SimpleName sn = (SimpleName) left_original;
6161 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6168 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6169 Expression left, Location loc,
6170 Expression left_original)
6172 bool left_is_type, left_is_explicit;
6174 // If 'left' is null, then we're called from SimpleNameResolve and this is
6175 // a member in the currently defining class.
6177 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6178 left_is_explicit = false;
6180 // Implicitly default to 'this' unless we're static.
6181 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6184 left_is_type = left is TypeExpr;
6185 left_is_explicit = true;
6188 if (member_lookup is FieldExpr){
6189 FieldExpr fe = (FieldExpr) member_lookup;
6190 FieldInfo fi = fe.FieldInfo;
6191 Type decl_type = fi.DeclaringType;
6193 if (fi is FieldBuilder) {
6194 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6197 //object o = c.LookupConstantValue (ec);
6198 object real_value = ((Constant) c.Expr).GetValue ();
6200 return Constantify (real_value, fi.FieldType);
6205 Type t = fi.FieldType;
6209 if (fi is FieldBuilder)
6210 o = TypeManager.GetValue ((FieldBuilder) fi);
6212 o = fi.GetValue (fi);
6214 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6215 if (left_is_explicit && !left_is_type &&
6216 !IdenticalNameAndTypeName (ec, left_original, loc)) {
6217 error176 (loc, fe.FieldInfo.Name);
6221 Expression enum_member = MemberLookup (
6222 ec, decl_type, "value__", MemberTypes.Field,
6223 AllBindingFlags, loc);
6225 Enum en = TypeManager.LookupEnum (decl_type);
6229 c = Constantify (o, en.UnderlyingType);
6231 c = Constantify (o, enum_member.Type);
6233 return new EnumConstant (c, decl_type);
6236 Expression exp = Constantify (o, t);
6238 if (left_is_explicit && !left_is_type) {
6239 error176 (loc, fe.FieldInfo.Name);
6246 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6253 if (member_lookup is IMemberExpr) {
6254 IMemberExpr me = (IMemberExpr) member_lookup;
6257 MethodGroupExpr mg = me as MethodGroupExpr;
6258 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6259 mg.IsExplicitImpl = left_is_explicit;
6262 if (IdenticalNameAndTypeName (ec, left_original, loc))
6263 return member_lookup;
6265 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6270 if (!me.IsInstance){
6271 if (IdenticalNameAndTypeName (ec, left_original, loc))
6272 return member_lookup;
6274 /*if (left_is_explicit) {
6275 error176 (loc, me.Name);
6281 // Since we can not check for instance objects in SimpleName,
6282 // becaue of the rule that allows types and variables to share
6283 // the name (as long as they can be de-ambiguated later, see
6284 // IdenticalNameAndTypeName), we have to check whether left
6285 // is an instance variable in a static context
6287 // However, if the left-hand value is explicitly given, then
6288 // it is already our instance expression, so we aren't in
6292 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6293 IMemberExpr mexp = (IMemberExpr) left;
6295 if (!mexp.IsStatic){
6296 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6301 me.InstanceExpression = left;
6304 return member_lookup;
6307 if (member_lookup is TypeExpr){
6308 member_lookup.Resolve (ec, ResolveFlags.Type);
6309 return member_lookup;
6312 Console.WriteLine ("Left is: " + left);
6313 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6314 Environment.Exit (0);
6318 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6321 throw new Exception ();
6323 // Resolve the expression with flow analysis turned off, we'll do the definite
6324 // assignment checks later. This is because we don't know yet what the expression
6325 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6326 // definite assignment check on the actual field and not on the whole struct.
6329 Expression original = expr;
6330 expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6335 if (expr is SimpleName){
6336 SimpleName child_expr = (SimpleName) expr;
6338 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
6340 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6341 return new_expr.Resolve (ec, flags);
6343 return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup | ResolveFlags.VariableOrValue);
6346 int errors = Report.Errors;
6348 Type expr_type = expr.Type;
6350 if (expr is TypeExpr){
6351 //FIXME: add access level check
6352 //if (!ec.DeclSpace.CheckAccessLevel (expr_type)) {
6353 // Error (30390, "'" + TypeManager.MonoBASIC_Name (expr_type) + "' " +
6354 // "is inaccessible because of its protection level");
6358 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6359 Enum en = TypeManager.LookupEnum (expr_type);
6362 object value = en.LookupEnumValue (Identifier);
6365 Constant c = Constantify (value, en.UnderlyingType);
6366 return new EnumConstant (c, expr_type);
6368 Report.Error (30456, loc,
6369 Identifier + " is not found in member list of enum " + en.Name);
6375 if (expr_type.IsPointer){
6376 Error (30311, "The '.' operator can not be applied to pointer operands (" +
6377 TypeManager.MonoBASIC_Name (expr_type) + ")");
6381 member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
6383 if (member_lookup == null)
6385 // Error has already been reported.
6386 if (errors < Report.Errors)
6390 // Try looking the member up from the same type, if we find
6391 // it, we know that the error was due to limited visibility
6393 object lookup = TypeManager.MemberLookup (
6394 expr_type, expr_type, AllMemberTypes, AllBindingFlags |
6395 BindingFlags.NonPublic, Identifier);
6397 if (lookup == null) {
6398 if (expr_type != TypeManager.object_type)
6399 Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
6400 // If this came as a part of Invocation,
6401 // Since argumets are not known, return null,
6402 // let Invocation's Resolve take care
6406 else if (! is_left_hand) {
6407 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
6409 true, is_left_hand);
6410 etmp.GenerateLateBindingStatements();
6411 return etmp.Resolve (ec);
6414 // if the expression is a left hand side of an assignment,
6415 // return null, as we dont know the RHS
6416 // Let assign take care of Late Binding
6421 if ((expr_type != ec.ContainerType) &&
6422 ec.ContainerType.IsSubclassOf (expr_type))
6425 // Although a derived class can access protected members of
6426 // its base class it cannot do so through an instance of the
6427 // base class (CS1540). If the expr_type is a parent of the
6428 // ec.ContainerType and the lookup succeeds with the latter one,
6429 // then we are in this situation.
6431 lookup = TypeManager.MemberLookup(
6432 ec.ContainerType, ec.ContainerType, AllMemberTypes,
6433 AllBindingFlags, Identifier);
6436 Error (1540, "Cannot access protected member '" +
6437 expr_type + "." + Identifier + "' " +
6438 "via a qualifier of type '" + TypeManager.MonoBASIC_Name (expr_type) + "'; the " +
6439 "qualifier must be of type '" + TypeManager.MonoBASIC_Name (ec.ContainerType) + "' " +
6440 "(or derived from it)");
6442 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6443 "is inaccessible because of its protection level");
6445 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6446 "is inaccessible because of its protection level");
6451 if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))) {
6452 Enum en = TypeManager.LookupEnum (expr_type);
6455 object value = en.LookupEnumValue (Identifier);
6456 expr_type = TypeManager.int32_type;
6457 if (value != null) {
6458 Constant c = Constantify (value, en.UnderlyingType);
6459 return new EnumConstant (c, en.UnderlyingType);
6461 Report.Error (30456, loc,
6462 Identifier + " is not found in member list of enum " + en.Name);
6467 if (member_lookup is TypeExpr){
6468 member_lookup.Resolve (ec, ResolveFlags.Type);
6470 return member_lookup;
6471 } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6474 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6475 if (member_lookup == null)
6478 // The following DoResolve/DoResolveLValue will do the definite assignment
6480 if (right_side != null)
6481 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6483 member_lookup = member_lookup.DoResolve (ec);
6485 return member_lookup;
6488 public override Expression DoResolve (EmitContext ec)
6490 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6491 ResolveFlags.SimpleName | ResolveFlags.Type);
6494 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6496 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6497 ResolveFlags.SimpleName | ResolveFlags.Type);
6500 public Expression DoResolveType (EmitContext ec)
6502 return DoResolve (ec, null, ResolveFlags.Type);
6505 public override void Emit (EmitContext ec)
6507 throw new Exception ("Should not happen");
6510 public override string ToString ()
6512 return expr + "." + Identifier;
6519 /// Implements checked expressions
6521 public class CheckedExpr : Expression {
6523 public Expression Expr;
6525 public CheckedExpr (Expression e, Location l)
6531 public override Expression DoResolve (EmitContext ec)
6533 bool last_const_check = ec.ConstantCheckState;
6535 ec.ConstantCheckState = true;
6536 Expr = Expr.Resolve (ec);
6537 ec.ConstantCheckState = last_const_check;
6542 if (Expr is Constant)
6545 eclass = Expr.eclass;
6550 public override void Emit (EmitContext ec)
6552 bool last_check = ec.CheckState;
6553 bool last_const_check = ec.ConstantCheckState;
6555 ec.CheckState = true;
6556 ec.ConstantCheckState = true;
6558 ec.CheckState = last_check;
6559 ec.ConstantCheckState = last_const_check;
6565 /// Implements the unchecked expression
6567 public class UnCheckedExpr : Expression {
6569 public Expression Expr;
6571 public UnCheckedExpr (Expression e, Location l)
6577 public override Expression DoResolve (EmitContext ec)
6579 bool last_const_check = ec.ConstantCheckState;
6581 ec.ConstantCheckState = false;
6582 Expr = Expr.Resolve (ec);
6583 ec.ConstantCheckState = last_const_check;
6588 if (Expr is Constant)
6591 eclass = Expr.eclass;
6596 public override void Emit (EmitContext ec)
6598 bool last_check = ec.CheckState;
6599 bool last_const_check = ec.ConstantCheckState;
6601 ec.CheckState = false;
6602 ec.ConstantCheckState = false;
6604 ec.CheckState = last_check;
6605 ec.ConstantCheckState = last_const_check;
6611 /// An Element Access expression.
6613 /// During semantic analysis these are transformed into
6614 /// IndexerAccess or ArrayAccess
6616 public class ElementAccess : Expression {
6617 public ArrayList Arguments;
6618 public Expression Expr;
6620 public ElementAccess (Expression e, ArrayList e_list, Location l)
6629 Arguments = new ArrayList ();
6630 foreach (Expression tmp in e_list)
6631 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6635 bool CommonResolve (EmitContext ec)
6637 Expr = Expr.Resolve (ec);
6642 if (Arguments == null)
6645 foreach (Argument a in Arguments){
6646 if (!a.Resolve (ec, loc))
6653 Expression MakePointerAccess ()
6657 if (t == TypeManager.void_ptr_type){
6660 "The array index operation is not valid for void pointers");
6663 if (Arguments.Count != 1){
6666 "A pointer must be indexed by a single value");
6669 Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
6671 return new Indirection (p, loc);
6674 public override Expression DoResolve (EmitContext ec)
6676 if (!CommonResolve (ec))
6680 // We perform some simple tests, and then to "split" the emit and store
6681 // code we create an instance of a different class, and return that.
6683 // I am experimenting with this pattern.
6688 return (new ArrayAccess (this, loc)).Resolve (ec);
6689 else if (t.IsPointer)
6690 return MakePointerAccess ();
6692 return (new IndexerAccess (this, loc)).Resolve (ec);
6695 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6697 if (!CommonResolve (ec))
6702 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
6703 else if (t.IsPointer)
6704 return MakePointerAccess ();
6706 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
6709 public override void Emit (EmitContext ec)
6711 throw new Exception ("Should never be reached");
6716 /// Implements array access
6718 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
6720 // Points to our "data" repository
6724 LocalTemporary [] cached_locations;
6726 public ArrayAccess (ElementAccess ea_data, Location l)
6729 eclass = ExprClass.Variable;
6733 public override Expression DoResolve (EmitContext ec)
6735 //ExprClass eclass = ea.Expr.eclass;
6738 // As long as the type is valid
6739 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
6740 eclass == ExprClass.Value)) {
6741 ea.Expr.Error118 ("variable or value");
6746 Type t = ea.Expr.Type;
6748 if (t == typeof (System.Object))
6750 // We can't resolve now, but we
6751 // have to try to access the array with a call
6752 // to LateIndexGet in the runtime
6754 Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
6755 Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
6756 ArrayList adims = new ArrayList();
6758 ArrayList ainit = new ArrayList();
6759 foreach (Argument a in ea.Arguments)
6760 ainit.Add ((Expression) a.Expr);
6762 adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));
6764 Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
6766 ArrayList args = new ArrayList();
6767 args.Add (new Argument(ea.Expr, Argument.AType.Expression));
6768 args.Add (new Argument(oace, Argument.AType.Expression));
6769 args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
6771 Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
6772 lig_call = lig_call.Resolve(ec);
6776 if (t.GetArrayRank () != ea.Arguments.Count){
6778 "Incorrect number of indexes for array " +
6779 " expected: " + t.GetArrayRank () + " got: " +
6780 ea.Arguments.Count);
6783 type = TypeManager.TypeToCoreType (t.GetElementType ());
6784 if (type.IsPointer && !ec.InUnsafe){
6785 UnsafeError (ea.Location);
6789 foreach (Argument a in ea.Arguments){
6790 Type argtype = a.Type;
6792 if (argtype == TypeManager.int32_type ||
6793 argtype == TypeManager.uint32_type ||
6794 argtype == TypeManager.int64_type ||
6795 argtype == TypeManager.uint64_type)
6799 // Mhm. This is strage, because the Argument.Type is not the same as
6800 // Argument.Expr.Type: the value changes depending on the ref/out setting.
6802 // Wonder if I will run into trouble for this.
6804 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
6809 eclass = ExprClass.Variable;
6815 /// Emits the right opcode to load an object of Type 't'
6816 /// from an array of T
6818 static public void EmitLoadOpcode (ILGenerator ig, Type type)
6820 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
6821 ig.Emit (OpCodes.Ldelem_U1);
6822 else if (type == TypeManager.sbyte_type)
6823 ig.Emit (OpCodes.Ldelem_I1);
6824 else if (type == TypeManager.short_type)
6825 ig.Emit (OpCodes.Ldelem_I2);
6826 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
6827 ig.Emit (OpCodes.Ldelem_U2);
6828 else if (type == TypeManager.int32_type)
6829 ig.Emit (OpCodes.Ldelem_I4);
6830 else if (type == TypeManager.uint32_type)
6831 ig.Emit (OpCodes.Ldelem_U4);
6832 else if (type == TypeManager.uint64_type)
6833 ig.Emit (OpCodes.Ldelem_I8);
6834 else if (type == TypeManager.int64_type)
6835 ig.Emit (OpCodes.Ldelem_I8);
6836 else if (type == TypeManager.float_type)
6837 ig.Emit (OpCodes.Ldelem_R4);
6838 else if (type == TypeManager.double_type)
6839 ig.Emit (OpCodes.Ldelem_R8);
6840 else if (type == TypeManager.intptr_type)
6841 ig.Emit (OpCodes.Ldelem_I);
6842 else if (type.IsValueType){
6843 ig.Emit (OpCodes.Ldelema, type);
6844 ig.Emit (OpCodes.Ldobj, type);
6846 ig.Emit (OpCodes.Ldelem_Ref);
6850 /// Emits the right opcode to store an object of Type 't'
6851 /// from an array of T.
6853 static public void EmitStoreOpcode (ILGenerator ig, Type t)
6855 t = TypeManager.TypeToCoreType (t);
6856 if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
6857 t = TypeManager.EnumToUnderlying (t);
6858 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
6859 t == TypeManager.bool_type)
6860 ig.Emit (OpCodes.Stelem_I1);
6861 else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
6862 ig.Emit (OpCodes.Stelem_I2);
6863 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
6864 ig.Emit (OpCodes.Stelem_I4);
6865 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
6866 ig.Emit (OpCodes.Stelem_I8);
6867 else if (t == TypeManager.float_type)
6868 ig.Emit (OpCodes.Stelem_R4);
6869 else if (t == TypeManager.double_type)
6870 ig.Emit (OpCodes.Stelem_R8);
6871 else if (t == TypeManager.intptr_type)
6872 ig.Emit (OpCodes.Stelem_I);
6873 else if (t.IsValueType){
6874 ig.Emit (OpCodes.Stobj, t);
6876 ig.Emit (OpCodes.Stelem_Ref);
6879 MethodInfo FetchGetMethod ()
6881 ModuleBuilder mb = CodeGen.ModuleBuilder;
6882 int arg_count = ea.Arguments.Count;
6883 Type [] args = new Type [arg_count];
6886 for (int i = 0; i < arg_count; i++){
6887 //args [i++] = a.Type;
6888 args [i] = TypeManager.int32_type;
6891 get = mb.GetArrayMethod (
6892 ea.Expr.Type, "Get",
6893 CallingConventions.HasThis |
6894 CallingConventions.Standard,
6900 MethodInfo FetchAddressMethod ()
6902 ModuleBuilder mb = CodeGen.ModuleBuilder;
6903 int arg_count = ea.Arguments.Count;
6904 Type [] args = new Type [arg_count];
6906 string ptr_type_name;
6909 ptr_type_name = type.FullName + "&";
6910 ret_type = Type.GetType (ptr_type_name);
6913 // It is a type defined by the source code we are compiling
6915 if (ret_type == null){
6916 ret_type = mb.GetType (ptr_type_name);
6919 for (int i = 0; i < arg_count; i++){
6920 //args [i++] = a.Type;
6921 args [i] = TypeManager.int32_type;
6924 address = mb.GetArrayMethod (
6925 ea.Expr.Type, "Address",
6926 CallingConventions.HasThis |
6927 CallingConventions.Standard,
6934 // Load the array arguments into the stack.
6936 // If we have been requested to cache the values (cached_locations array
6937 // initialized), then load the arguments the first time and store them
6938 // in locals. otherwise load from local variables.
6940 void LoadArrayAndArguments (EmitContext ec)
6942 ILGenerator ig = ec.ig;
6944 if (cached_locations == null){
6946 foreach (Argument a in ea.Arguments){
6947 Type argtype = a.Expr.Type;
6951 if (argtype == TypeManager.int64_type)
6952 ig.Emit (OpCodes.Conv_Ovf_I);
6953 else if (argtype == TypeManager.uint64_type)
6954 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6959 if (cached_locations [0] == null){
6960 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
6962 ig.Emit (OpCodes.Dup);
6963 cached_locations [0].Store (ec);
6967 foreach (Argument a in ea.Arguments){
6968 Type argtype = a.Expr.Type;
6970 cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
6972 if (argtype == TypeManager.int64_type)
6973 ig.Emit (OpCodes.Conv_Ovf_I);
6974 else if (argtype == TypeManager.uint64_type)
6975 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6977 ig.Emit (OpCodes.Dup);
6978 cached_locations [j].Store (ec);
6984 foreach (LocalTemporary lt in cached_locations)
6988 public new void CacheTemporaries (EmitContext ec)
6990 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
6993 public override void Emit (EmitContext ec)
6995 int rank = ea.Expr.Type.GetArrayRank ();
6996 ILGenerator ig = ec.ig;
6998 LoadArrayAndArguments (ec);
7001 EmitLoadOpcode (ig, type);
7005 method = FetchGetMethod ();
7006 ig.Emit (OpCodes.Call, method);
7010 public void EmitAssign (EmitContext ec, Expression source)
7012 int rank = ea.Expr.Type.GetArrayRank ();
7013 ILGenerator ig = ec.ig;
7014 Type t = source.Type;
7016 LoadArrayAndArguments (ec);
7019 // The stobj opcode used by value types will need
7020 // an address on the stack, not really an array/array
7024 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
7025 (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
7026 ig.Emit (OpCodes.Ldelema, t);
7032 EmitStoreOpcode (ig, t);
7034 ModuleBuilder mb = CodeGen.ModuleBuilder;
7035 int arg_count = ea.Arguments.Count;
7036 Type [] args = new Type [arg_count + 1];
7039 for (int i = 0; i < arg_count; i++){
7040 //args [i++] = a.Type;
7041 args [i] = TypeManager.int32_type;
7044 args [arg_count] = type;
7046 set = mb.GetArrayMethod (
7047 ea.Expr.Type, "Set",
7048 CallingConventions.HasThis |
7049 CallingConventions.Standard,
7050 TypeManager.void_type, args);
7052 ig.Emit (OpCodes.Call, set);
7056 public void AddressOf (EmitContext ec, AddressOp mode)
7058 int rank = ea.Expr.Type.GetArrayRank ();
7059 ILGenerator ig = ec.ig;
7061 LoadArrayAndArguments (ec);
7064 ig.Emit (OpCodes.Ldelema, type);
7066 MethodInfo address = FetchAddressMethod ();
7067 ig.Emit (OpCodes.Call, address);
7074 public ArrayList getters, setters;
7075 static Hashtable map;
7079 map = new Hashtable ();
7082 Indexers (MemberInfo [] mi)
7084 foreach (PropertyInfo property in mi){
7085 MethodInfo get, set;
7087 get = property.GetGetMethod (true);
7089 if (getters == null)
7090 getters = new ArrayList ();
7095 set = property.GetSetMethod (true);
7097 if (setters == null)
7098 setters = new ArrayList ();
7104 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7106 Indexers ix = (Indexers) map [lookup_type];
7111 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7113 MemberInfo [] mi = TypeManager.MemberLookup (
7114 caller_type, lookup_type, MemberTypes.Property,
7115 BindingFlags.Public | BindingFlags.Instance, p_name);
7117 if (mi == null || mi.Length == 0)
7120 ix = new Indexers (mi);
7121 map [lookup_type] = ix;
7126 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
7128 Indexers ix = (Indexers) map [lookup_type];
7133 ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
7137 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7138 if (ifaces != null) {
7139 foreach (Type itype in ifaces) {
7140 ix = GetIndexersForTypeOrInterface (caller_type, itype);
7146 if (lookup_type != TypeManager.object_type)
7147 Report.Error (21, loc,
7148 "Type '" + TypeManager.MonoBASIC_Name (lookup_type) +
7149 "' does not have any indexers defined");
7155 /// Expressions that represent an indexer call.
7157 public class IndexerAccess : Expression, IAssignMethod {
7159 // Points to our "data" repository
7161 MethodInfo get, set;
7163 ArrayList set_arguments;
7164 bool is_base_indexer;
7166 protected Type indexer_type;
7167 protected Type current_type;
7168 protected Expression instance_expr;
7169 protected ArrayList arguments;
7171 public IndexerAccess (ElementAccess ea, Location loc)
7172 : this (ea.Expr, false, loc)
7174 this.arguments = ea.Arguments;
7177 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7180 this.instance_expr = instance_expr;
7181 this.is_base_indexer = is_base_indexer;
7182 this.eclass = ExprClass.Value;
7186 public Expression Instance {
7188 return instance_expr;
7192 public ArrayList Arguments {
7198 protected virtual bool CommonResolve (EmitContext ec)
7200 indexer_type = instance_expr.Type;
7201 current_type = ec.ContainerType;
7206 public override Expression DoResolve (EmitContext ec)
7208 if (!CommonResolve (ec))
7212 // Step 1: Query for all 'Item' *properties*. Notice
7213 // that the actual methods are pointed from here.
7215 // This is a group of properties, piles of them.
7218 ilist = Indexers.GetIndexersForType (
7219 current_type, indexer_type, loc);
7222 // Step 2: find the proper match
7224 if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
7225 get = (MethodInfo) Invocation.OverloadResolve (
7226 ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
7229 if (instance_expr.Type != TypeManager.object_type)
7230 Error (30524, "indexer can not be used in this context, because " +
7231 "it lacks a 'get' accessor");
7235 type = get.ReturnType;
7236 if (type.IsPointer && !ec.InUnsafe){
7241 eclass = ExprClass.IndexerAccess;
7245 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7247 if (!CommonResolve (ec))
7250 Type right_type = right_side.Type;
7253 ilist = Indexers.GetIndexersForType (
7254 current_type, indexer_type, loc);
7256 if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
7257 set_arguments = (ArrayList) arguments.Clone ();
7258 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7260 set = (MethodInfo) Invocation.OverloadResolve (
7261 ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
7265 Error (30526, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
7266 "] lacks a 'set' accessor");
7270 type = TypeManager.void_type;
7271 eclass = ExprClass.IndexerAccess;
7275 public override void Emit (EmitContext ec)
7277 Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
7281 // source is ignored, because we already have a copy of it from the
7282 // LValue resolution and we have already constructed a pre-cached
7283 // version of the arguments (ea.set_arguments);
7285 public void EmitAssign (EmitContext ec, Expression source)
7287 Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
7292 /// The base operator for method names
7294 public class BaseAccess : Expression {
7295 public string member;
7297 public BaseAccess (string member, Location l)
7299 this.member = member;
7303 public override Expression DoResolve (EmitContext ec)
7305 Expression member_lookup;
7306 Type current_type = ec.ContainerType;
7307 Type base_type = current_type.BaseType;
7311 Error (1511, "Keyword MyBase is not allowed in static method");
7315 if (member == "New")
7318 member_lookup = MemberLookup (ec, current_type, base_type, member,
7319 AllMemberTypes, AllBindingFlags, loc);
7321 if (member_lookup == null) {
7323 TypeManager.MonoBASIC_Name (base_type) + " does not " +
7324 "contain a definition for '" + member + "'");
7331 left = new TypeExpr (base_type, loc);
7335 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7337 if (e is PropertyExpr) {
7338 PropertyExpr pe = (PropertyExpr) e;
7346 public override void Emit (EmitContext ec)
7348 throw new Exception ("Should never be called");
7353 /// The base indexer operator
7355 public class BaseIndexerAccess : IndexerAccess {
7356 public BaseIndexerAccess (ArrayList args, Location loc)
7357 : base (null, true, loc)
7359 arguments = new ArrayList ();
7360 foreach (Expression tmp in args)
7361 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7364 protected override bool CommonResolve (EmitContext ec)
7366 instance_expr = ec.This;
7368 current_type = ec.ContainerType.BaseType;
7369 indexer_type = current_type;
7371 foreach (Argument a in arguments){
7372 if (!a.Resolve (ec, loc))
7381 /// This class exists solely to pass the Type around and to be a dummy
7382 /// that can be passed to the conversion functions (this is used by
7383 /// foreach implementation to typecast the object return value from
7384 /// get_Current into the proper type. All code has been generated and
7385 /// we only care about the side effect conversions to be performed
7387 /// This is also now used as a placeholder where a no-action expression
7388 /// is needed (the 'New' class).
7390 public class EmptyExpression : Expression {
7391 public EmptyExpression ()
7393 type = TypeManager.object_type;
7394 eclass = ExprClass.Value;
7395 loc = Location.Null;
7398 public EmptyExpression (Type t)
7401 eclass = ExprClass.Value;
7402 loc = Location.Null;
7405 public override Expression DoResolve (EmitContext ec)
7410 public override void Emit (EmitContext ec)
7412 // nothing, as we only exist to not do anything.
7416 // This is just because we might want to reuse this bad boy
7417 // instead of creating gazillions of EmptyExpressions.
7418 // (CanConvertImplicit uses it)
7420 public void SetType (Type t)
7426 public class UserCast : Expression {
7430 public UserCast (MethodInfo method, Expression source, Location l)
7432 this.method = method;
7433 this.source = source;
7434 type = method.ReturnType;
7435 eclass = ExprClass.Value;
7439 public override Expression DoResolve (EmitContext ec)
7442 // We are born fully resolved
7447 public override void Emit (EmitContext ec)
7449 ILGenerator ig = ec.ig;
7453 if (method is MethodInfo)
7454 ig.Emit (OpCodes.Call, (MethodInfo) method);
7456 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7462 // This class is used to "construct" the type during a typecast
7463 // operation. Since the Type.GetType class in .NET can parse
7464 // the type specification, we just use this to construct the type
7465 // one bit at a time.
7467 public class ComposedCast : Expression, ITypeExpression {
7471 public ComposedCast (Expression left, string dim, Location l)
7478 public Expression DoResolveType (EmitContext ec)
7480 Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7485 // ltype.Fullname is already fully qualified, so we can skip
7486 // a lot of probes, and go directly to TypeManager.LookupType
7488 string cname = ltype.FullName + dim;
7489 type = TypeManager.LookupTypeDirect (cname);
7492 // For arrays of enumerations we are having a problem
7493 // with the direct lookup. Need to investigate.
7495 // For now, fall back to the full lookup in that case.
7497 type = RootContext.LookupType (
7498 ec.DeclSpace, cname, false, loc);
7504 if (!ec.ResolvingTypeTree){
7506 // If the above flag is set, this is being invoked from the ResolveType function.
7507 // Upper layers take care of the type validity in this context.
7509 if (!ec.InUnsafe && type.IsPointer){
7515 eclass = ExprClass.Type;
7519 public override Expression DoResolve (EmitContext ec)
7521 return DoResolveType (ec);
7524 public override void Emit (EmitContext ec)
7526 throw new Exception ("This should never be called");
7529 public override string ToString ()
7536 // This class is used to represent the address of an array, used
7537 // only by the Fixed statement, this is like the C "&a [0]" construct.
7539 public class ArrayPtr : Expression {
7542 public ArrayPtr (Expression array, Location l)
7544 Type array_type = array.Type.GetElementType ();
7548 string array_ptr_type_name = array_type.FullName + "*";
7550 type = Type.GetType (array_ptr_type_name);
7552 ModuleBuilder mb = CodeGen.ModuleBuilder;
7554 type = mb.GetType (array_ptr_type_name);
7557 eclass = ExprClass.Value;
7561 public override void Emit (EmitContext ec)
7563 ILGenerator ig = ec.ig;
7566 IntLiteral.EmitInt (ig, 0);
7567 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
7570 public override Expression DoResolve (EmitContext ec)
7573 // We are born fully resolved
7580 // Used by the fixed statement
7582 public class StringPtr : Expression {
7585 public StringPtr (LocalBuilder b, Location l)
7588 eclass = ExprClass.Value;
7589 type = TypeManager.char_ptr_type;
7593 public override Expression DoResolve (EmitContext ec)
7595 // This should never be invoked, we are born in fully
7596 // initialized state.
7601 public override void Emit (EmitContext ec)
7603 ILGenerator ig = ec.ig;
7605 ig.Emit (OpCodes.Ldloc, b);
7606 ig.Emit (OpCodes.Conv_I);
7607 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
7608 ig.Emit (OpCodes.Add);
7613 // Implements the 'stackalloc' keyword
7615 public class StackAlloc : Expression {
7620 public StackAlloc (Expression type, Expression count, Location l)
7627 public override Expression DoResolve (EmitContext ec)
7629 count = count.Resolve (ec);
7633 if (count.Type != TypeManager.int32_type){
7634 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
7639 if (ec.InCatch || ec.InFinally){
7641 "stackalloc can not be used in a catch or finally block");
7645 otype = ec.DeclSpace.ResolveType (t, false, loc);
7650 if (!TypeManager.VerifyUnManaged (otype, loc))
7653 string ptr_name = otype.FullName + "*";
7654 type = Type.GetType (ptr_name);
7656 ModuleBuilder mb = CodeGen.ModuleBuilder;
7658 type = mb.GetType (ptr_name);
7660 eclass = ExprClass.Value;
7665 public override void Emit (EmitContext ec)
7667 int size = GetTypeSize (otype);
7668 ILGenerator ig = ec.ig;
7671 ig.Emit (OpCodes.Sizeof, otype);
7673 IntConstant.EmitInt (ig, size);
7675 ig.Emit (OpCodes.Mul);
7676 ig.Emit (OpCodes.Localloc);
7679 public class Preserve : ExpressionStatement {
7680 ArrayList args = null;
7681 MethodInfo mi = null;
7682 Expression target = null;
7683 ExpressionStatement source = null;
7686 public Preserve (Expression RedimTarget, ExpressionStatement acExpr, Location l)
7688 Type type = typeof(Microsoft.VisualBasic.CompilerServices.Utils);
7689 mi = type.GetMethod("CopyArray");
7691 target = RedimTarget;
7694 eclass = ExprClass.Value;
7698 public override Expression DoResolve (EmitContext ec)
7701 // We are born fully resolved
7703 type = mi.ReturnType;
7705 source.Resolve (ec);
7710 public override void Emit (EmitContext ec)
7712 args = new ArrayList (2);
7714 args.Add (new Argument (target, Argument.AType.Expression));
7715 args.Add (new Argument (source, Argument.AType.Expression));
7717 Invocation.EmitArguments (ec, mi, args);
7719 ec.ig.Emit (OpCodes.Call, mi);
7723 public override void EmitStatement (EmitContext ec)