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;
615 void LoadExprValue (EmitContext ec)
620 public override void Emit (EmitContext ec)
622 ILGenerator ig = ec.ig;
624 if (temporary != null){
630 ec.ig.Emit (OpCodes.Dup);
631 temporary.Store (ec);
632 have_temporary = true;
636 LoadFromPtr (ig, Type);
639 public void EmitAssign (EmitContext ec, Expression source)
641 if (temporary != null){
647 ec.ig.Emit (OpCodes.Dup);
648 temporary.Store (ec);
649 have_temporary = true;
654 StoreFromPtr (ec.ig, type);
657 public void AddressOf (EmitContext ec, AddressOp Mode)
659 if (temporary != null){
665 ec.ig.Emit (OpCodes.Dup);
666 temporary.Store (ec);
667 have_temporary = true;
672 public override Expression DoResolve (EmitContext ec)
675 // Born fully resolved
680 public new void CacheTemporaries (EmitContext ec)
682 temporary = new LocalTemporary (ec, type);
687 /// Unary Mutator expressions (pre and post ++ and --)
691 /// UnaryMutator implements ++ and -- expressions. It derives from
692 /// ExpressionStatement becuase the pre/post increment/decrement
693 /// operators can be used in a statement context.
695 /// FIXME: Idea, we could split this up in two classes, one simpler
696 /// for the common case, and one with the extra fields for more complex
697 /// classes (indexers require temporary access; overloaded require method)
699 /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
700 /// PostDecrement, that way we could save the 'Mode' byte as well.
702 public class UnaryMutator : ExpressionStatement {
703 public enum Mode : byte {
704 PreIncrement, PreDecrement, PostIncrement, PostDecrement
709 LocalTemporary temp_storage;
712 // This is expensive for the simplest case.
716 public UnaryMutator (Mode m, Expression e, Location l)
723 static string OperName (Mode mode)
725 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
730 /// Returns whether an object of type 't' can be incremented
731 /// or decremented with add/sub (ie, basically whether we can
732 /// use pre-post incr-decr operations on it, but it is not a
733 /// System.Decimal, which we require operator overloading to catch)
735 static bool IsIncrementableNumber (Type t)
737 return (t == TypeManager.sbyte_type) ||
738 (t == TypeManager.byte_type) ||
739 (t == TypeManager.short_type) ||
740 (t == TypeManager.ushort_type) ||
741 (t == TypeManager.int32_type) ||
742 (t == TypeManager.uint32_type) ||
743 (t == TypeManager.int64_type) ||
744 (t == TypeManager.uint64_type) ||
745 (t == TypeManager.char_type) ||
746 (t.IsSubclassOf (TypeManager.enum_type)) ||
747 (t == TypeManager.float_type) ||
748 (t == TypeManager.double_type) ||
749 (t.IsPointer && t != TypeManager.void_ptr_type);
752 Expression ResolveOperator (EmitContext ec)
754 Type expr_type = expr.Type;
757 // Step 1: Perform Operator Overload location
762 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
763 op_name = "op_Increment";
765 op_name = "op_Decrement";
767 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
769 if (mg == null && expr_type.BaseType != null)
770 mg = MemberLookup (ec, expr_type.BaseType, op_name,
771 MemberTypes.Method, AllBindingFlags, loc);
774 method = StaticCallExpr.MakeSimpleCall (
775 ec, (MethodGroupExpr) mg, expr, loc);
782 // The operand of the prefix/postfix increment decrement operators
783 // should be an expression that is classified as a variable,
784 // a property access or an indexer access
787 if (expr.eclass == ExprClass.Variable){
788 if (IsIncrementableNumber (expr_type) ||
789 expr_type == TypeManager.decimal_type){
792 } else if (expr.eclass == ExprClass.IndexerAccess){
793 IndexerAccess ia = (IndexerAccess) expr;
795 temp_storage = new LocalTemporary (ec, expr.Type);
797 expr = ia.ResolveLValue (ec, temp_storage);
802 } else if (expr.eclass == ExprClass.PropertyAccess){
803 PropertyExpr pe = (PropertyExpr) expr;
805 if (pe.VerifyAssignable ())
810 expr.Error118 ("variable, indexer or property access");
814 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
815 TypeManager.MonoBASIC_Name (expr_type) + "'");
819 public override Expression DoResolve (EmitContext ec)
821 expr = expr.Resolve (ec);
826 eclass = ExprClass.Value;
827 return ResolveOperator (ec);
830 static int PtrTypeSize (Type t)
832 return GetTypeSize (t.GetElementType ());
836 // Loads the proper "1" into the stack based on the type
838 static void LoadOne (ILGenerator ig, Type t)
840 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
841 ig.Emit (OpCodes.Ldc_I8, 1L);
842 else if (t == TypeManager.double_type)
843 ig.Emit (OpCodes.Ldc_R8, 1.0);
844 else if (t == TypeManager.float_type)
845 ig.Emit (OpCodes.Ldc_R4, 1.0F);
846 else if (t.IsPointer){
847 int n = PtrTypeSize (t);
850 ig.Emit (OpCodes.Sizeof, t);
852 IntConstant.EmitInt (ig, n);
854 ig.Emit (OpCodes.Ldc_I4_1);
859 // FIXME: We need some way of avoiding the use of temp_storage
860 // for some types of storage (parameters, local variables,
861 // static fields) and single-dimension array access.
863 void EmitCode (EmitContext ec, bool is_expr)
865 ILGenerator ig = ec.ig;
866 IAssignMethod ia = (IAssignMethod) expr;
867 Type expr_type = expr.Type;
869 if (temp_storage == null)
870 temp_storage = new LocalTemporary (ec, expr_type);
872 ia.CacheTemporaries (ec);
873 ig.Emit (OpCodes.Nop);
875 case Mode.PreIncrement:
876 case Mode.PreDecrement:
880 LoadOne (ig, expr_type);
883 // Select the opcode based on the check state (then the type)
884 // and the actual operation
887 if (expr_type == TypeManager.int32_type ||
888 expr_type == TypeManager.int64_type){
889 if (mode == Mode.PreDecrement)
890 ig.Emit (OpCodes.Sub_Ovf);
892 ig.Emit (OpCodes.Add_Ovf);
893 } else if (expr_type == TypeManager.uint32_type ||
894 expr_type == TypeManager.uint64_type){
895 if (mode == Mode.PreDecrement)
896 ig.Emit (OpCodes.Sub_Ovf_Un);
898 ig.Emit (OpCodes.Add_Ovf_Un);
900 if (mode == Mode.PreDecrement)
901 ig.Emit (OpCodes.Sub_Ovf);
903 ig.Emit (OpCodes.Add_Ovf);
906 if (mode == Mode.PreDecrement)
907 ig.Emit (OpCodes.Sub);
909 ig.Emit (OpCodes.Add);
914 temp_storage.Store (ec);
915 ia.EmitAssign (ec, temp_storage);
917 temp_storage.Emit (ec);
920 case Mode.PostIncrement:
921 case Mode.PostDecrement:
929 ig.Emit (OpCodes.Dup);
931 LoadOne (ig, expr_type);
934 if (expr_type == TypeManager.int32_type ||
935 expr_type == TypeManager.int64_type){
936 if (mode == Mode.PostDecrement)
937 ig.Emit (OpCodes.Sub_Ovf);
939 ig.Emit (OpCodes.Add_Ovf);
940 } else if (expr_type == TypeManager.uint32_type ||
941 expr_type == TypeManager.uint64_type){
942 if (mode == Mode.PostDecrement)
943 ig.Emit (OpCodes.Sub_Ovf_Un);
945 ig.Emit (OpCodes.Add_Ovf_Un);
947 if (mode == Mode.PostDecrement)
948 ig.Emit (OpCodes.Sub_Ovf);
950 ig.Emit (OpCodes.Add_Ovf);
953 if (mode == Mode.PostDecrement)
954 ig.Emit (OpCodes.Sub);
956 ig.Emit (OpCodes.Add);
962 temp_storage.Store (ec);
963 ia.EmitAssign (ec, temp_storage);
968 public override void Emit (EmitContext ec)
974 public override void EmitStatement (EmitContext ec)
976 EmitCode (ec, false);
982 /// Base class for the 'Is' and 'As' classes.
986 /// FIXME: Split this in two, and we get to save the 'Operator' Oper
989 public abstract class Probe : Expression {
990 public readonly Expression ProbeType;
991 protected Expression expr;
992 protected Type probe_type;
994 public Probe (Expression expr, Expression probe_type, Location l)
996 ProbeType = probe_type;
1001 public Expression Expr {
1007 public override Expression DoResolve (EmitContext ec)
1009 probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1011 if (probe_type == null)
1014 expr = expr.Resolve (ec);
1021 /// Implementation of the 'is' operator.
1023 public class Is : Probe {
1024 public Is (Expression expr, Expression probe_type, Location l)
1025 : base (expr, probe_type, l)
1030 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1035 public override void Emit (EmitContext ec)
1037 ILGenerator ig = ec.ig;
1042 case Action.AlwaysFalse:
1043 ig.Emit (OpCodes.Pop);
1044 IntConstant.EmitInt (ig, 0);
1046 case Action.AlwaysTrue:
1047 ig.Emit (OpCodes.Pop);
1048 ig.Emit (OpCodes.Nop);
1049 IntConstant.EmitInt (ig, 1);
1051 case Action.LeaveOnStack:
1052 // the 'e != null' rule.
1055 ig.Emit (OpCodes.Isinst, probe_type);
1056 ig.Emit (OpCodes.Ldnull);
1057 ig.Emit (OpCodes.Cgt_Un);
1060 throw new Exception ("never reached");
1063 public override Expression DoResolve (EmitContext ec)
1065 Expression e = base.DoResolve (ec);
1067 if ((e == null) || (expr == null))
1070 Type etype = expr.Type;
1071 bool warning_always_matches = false;
1072 bool warning_never_matches = false;
1074 type = TypeManager.bool_type;
1075 eclass = ExprClass.Value;
1078 // First case, if at compile time, there is an implicit conversion
1079 // then e != null (objects) or true (value types)
1081 e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1084 if (etype.IsValueType)
1085 action = Action.AlwaysTrue;
1087 action = Action.LeaveOnStack;
1089 warning_always_matches = true;
1090 } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1092 // Second case: explicit reference convresion
1094 if (expr is NullLiteral)
1095 action = Action.AlwaysFalse;
1097 action = Action.Probe;
1099 action = Action.AlwaysFalse;
1100 warning_never_matches = true;
1103 if (RootContext.WarningLevel >= 1){
1104 if (warning_always_matches)
1107 "The expression is always of type '" +
1108 TypeManager.MonoBASIC_Name (probe_type) + "'");
1109 else if (warning_never_matches){
1110 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1113 "The expression is never of type '" +
1114 TypeManager.MonoBASIC_Name (probe_type) + "'");
1123 /// Implementation of the 'as' operator.
1125 public class As : Probe {
1126 public As (Expression expr, Expression probe_type, Location l)
1127 : base (expr, probe_type, l)
1131 bool do_isinst = false;
1133 public override void Emit (EmitContext ec)
1135 ILGenerator ig = ec.ig;
1140 ig.Emit (OpCodes.Isinst, probe_type);
1143 static void Error_CannotConvertType (Type source, Type target, Location loc)
1146 39, loc, "as operator can not convert from '" +
1147 TypeManager.MonoBASIC_Name (source) + "' to '" +
1148 TypeManager.MonoBASIC_Name (target) + "'");
1151 public override Expression DoResolve (EmitContext ec)
1153 Expression e = base.DoResolve (ec);
1159 eclass = ExprClass.Value;
1160 Type etype = expr.Type;
1162 if (TypeManager.IsValueType (probe_type)){
1163 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1164 TypeManager.MonoBASIC_Name (probe_type) + " is a value type)");
1169 e = ConvertImplicit (ec, expr, probe_type, loc);
1176 if (ExplicitReferenceConversionExists (etype, probe_type)){
1181 Error_CannotConvertType (etype, probe_type, loc);
1187 /// This represents a typecast in the source language.
1189 /// FIXME: Cast expressions have an unusual set of parsing
1190 /// rules, we need to figure those out.
1192 public class Cast : Expression {
1193 Expression target_type;
1197 public Cast (Expression cast_type, Expression expr, Location loc)
1199 this.target_type = cast_type;
1202 runtime_cast = false;
1205 public Expression TargetType {
1211 public Expression Expr {
1220 public bool IsRuntimeCast
1223 return runtime_cast;
1226 runtime_cast = value;
1231 /// Attempts to do a compile-time folding of a constant cast.
1233 Expression TryReduce (EmitContext ec, Type target_type)
1235 if (expr is ByteConstant){
1236 byte v = ((ByteConstant) expr).Value;
1238 if (target_type == TypeManager.sbyte_type)
1239 return new SByteConstant ((sbyte) v);
1240 if (target_type == TypeManager.short_type)
1241 return new ShortConstant ((short) v);
1242 if (target_type == TypeManager.ushort_type)
1243 return new UShortConstant ((ushort) v);
1244 if (target_type == TypeManager.int32_type)
1245 return new IntConstant ((int) v);
1246 if (target_type == TypeManager.uint32_type)
1247 return new UIntConstant ((uint) v);
1248 if (target_type == TypeManager.int64_type)
1249 return new LongConstant ((long) v);
1250 if (target_type == TypeManager.uint64_type)
1251 return new ULongConstant ((ulong) v);
1252 if (target_type == TypeManager.float_type)
1253 return new FloatConstant ((float) v);
1254 if (target_type == TypeManager.double_type)
1255 return new DoubleConstant ((double) v);
1256 if (target_type == TypeManager.char_type)
1257 return new CharConstant ((char) v);
1258 if (target_type == TypeManager.decimal_type)
1259 return new DecimalConstant ((decimal) v);
1261 if (expr is SByteConstant){
1262 sbyte v = ((SByteConstant) expr).Value;
1264 if (target_type == TypeManager.byte_type)
1265 return new ByteConstant ((byte) v);
1266 if (target_type == TypeManager.short_type)
1267 return new ShortConstant ((short) v);
1268 if (target_type == TypeManager.ushort_type)
1269 return new UShortConstant ((ushort) v);
1270 if (target_type == TypeManager.int32_type)
1271 return new IntConstant ((int) v);
1272 if (target_type == TypeManager.uint32_type)
1273 return new UIntConstant ((uint) v);
1274 if (target_type == TypeManager.int64_type)
1275 return new LongConstant ((long) v);
1276 if (target_type == TypeManager.uint64_type)
1277 return new ULongConstant ((ulong) v);
1278 if (target_type == TypeManager.float_type)
1279 return new FloatConstant ((float) v);
1280 if (target_type == TypeManager.double_type)
1281 return new DoubleConstant ((double) v);
1282 if (target_type == TypeManager.char_type)
1283 return new CharConstant ((char) v);
1284 if (target_type == TypeManager.decimal_type)
1285 return new DecimalConstant ((decimal) v);
1287 if (expr is ShortConstant){
1288 short v = ((ShortConstant) expr).Value;
1290 if (target_type == TypeManager.byte_type)
1291 return new ByteConstant ((byte) v);
1292 if (target_type == TypeManager.sbyte_type)
1293 return new SByteConstant ((sbyte) v);
1294 if (target_type == TypeManager.ushort_type)
1295 return new UShortConstant ((ushort) v);
1296 if (target_type == TypeManager.int32_type)
1297 return new IntConstant ((int) v);
1298 if (target_type == TypeManager.uint32_type)
1299 return new UIntConstant ((uint) v);
1300 if (target_type == TypeManager.int64_type)
1301 return new LongConstant ((long) v);
1302 if (target_type == TypeManager.uint64_type)
1303 return new ULongConstant ((ulong) v);
1304 if (target_type == TypeManager.float_type)
1305 return new FloatConstant ((float) v);
1306 if (target_type == TypeManager.double_type)
1307 return new DoubleConstant ((double) v);
1308 if (target_type == TypeManager.char_type)
1309 return new CharConstant ((char) v);
1310 if (target_type == TypeManager.decimal_type)
1311 return new DecimalConstant ((decimal) v);
1313 if (expr is UShortConstant){
1314 ushort v = ((UShortConstant) expr).Value;
1316 if (target_type == TypeManager.byte_type)
1317 return new ByteConstant ((byte) v);
1318 if (target_type == TypeManager.sbyte_type)
1319 return new SByteConstant ((sbyte) v);
1320 if (target_type == TypeManager.short_type)
1321 return new ShortConstant ((short) v);
1322 if (target_type == TypeManager.int32_type)
1323 return new IntConstant ((int) v);
1324 if (target_type == TypeManager.uint32_type)
1325 return new UIntConstant ((uint) v);
1326 if (target_type == TypeManager.int64_type)
1327 return new LongConstant ((long) v);
1328 if (target_type == TypeManager.uint64_type)
1329 return new ULongConstant ((ulong) v);
1330 if (target_type == TypeManager.float_type)
1331 return new FloatConstant ((float) v);
1332 if (target_type == TypeManager.double_type)
1333 return new DoubleConstant ((double) v);
1334 if (target_type == TypeManager.char_type)
1335 return new CharConstant ((char) v);
1336 if (target_type == TypeManager.decimal_type)
1337 return new DecimalConstant ((decimal) v);
1339 if (expr is IntConstant){
1340 int v = ((IntConstant) expr).Value;
1342 if (target_type == TypeManager.byte_type)
1343 return new ByteConstant ((byte) v);
1344 if (target_type == TypeManager.sbyte_type)
1345 return new SByteConstant ((sbyte) v);
1346 if (target_type == TypeManager.short_type)
1347 return new ShortConstant ((short) v);
1348 if (target_type == TypeManager.ushort_type)
1349 return new UShortConstant ((ushort) v);
1350 if (target_type == TypeManager.uint32_type)
1351 return new UIntConstant ((uint) v);
1352 if (target_type == TypeManager.int64_type)
1353 return new LongConstant ((long) v);
1354 if (target_type == TypeManager.uint64_type)
1355 return new ULongConstant ((ulong) v);
1356 if (target_type == TypeManager.float_type)
1357 return new FloatConstant ((float) v);
1358 if (target_type == TypeManager.double_type)
1359 return new DoubleConstant ((double) v);
1360 if (target_type == TypeManager.char_type)
1361 return new CharConstant ((char) v);
1362 if (target_type == TypeManager.decimal_type)
1363 return new DecimalConstant ((decimal) v);
1365 if (expr is UIntConstant){
1366 uint v = ((UIntConstant) expr).Value;
1368 if (target_type == TypeManager.byte_type)
1369 return new ByteConstant ((byte) v);
1370 if (target_type == TypeManager.sbyte_type)
1371 return new SByteConstant ((sbyte) v);
1372 if (target_type == TypeManager.short_type)
1373 return new ShortConstant ((short) v);
1374 if (target_type == TypeManager.ushort_type)
1375 return new UShortConstant ((ushort) v);
1376 if (target_type == TypeManager.int32_type)
1377 return new IntConstant ((int) v);
1378 if (target_type == TypeManager.int64_type)
1379 return new LongConstant ((long) v);
1380 if (target_type == TypeManager.uint64_type)
1381 return new ULongConstant ((ulong) v);
1382 if (target_type == TypeManager.float_type)
1383 return new FloatConstant ((float) v);
1384 if (target_type == TypeManager.double_type)
1385 return new DoubleConstant ((double) v);
1386 if (target_type == TypeManager.char_type)
1387 return new CharConstant ((char) v);
1388 if (target_type == TypeManager.decimal_type)
1389 return new DecimalConstant ((decimal) v);
1391 if (expr is LongConstant){
1392 long v = ((LongConstant) expr).Value;
1394 if (target_type == TypeManager.byte_type)
1395 return new ByteConstant ((byte) v);
1396 if (target_type == TypeManager.sbyte_type)
1397 return new SByteConstant ((sbyte) v);
1398 if (target_type == TypeManager.short_type)
1399 return new ShortConstant ((short) v);
1400 if (target_type == TypeManager.ushort_type)
1401 return new UShortConstant ((ushort) v);
1402 if (target_type == TypeManager.int32_type)
1403 return new IntConstant ((int) v);
1404 if (target_type == TypeManager.uint32_type)
1405 return new UIntConstant ((uint) v);
1406 if (target_type == TypeManager.uint64_type)
1407 return new ULongConstant ((ulong) v);
1408 if (target_type == TypeManager.float_type)
1409 return new FloatConstant ((float) v);
1410 if (target_type == TypeManager.double_type)
1411 return new DoubleConstant ((double) v);
1412 if (target_type == TypeManager.char_type)
1413 return new CharConstant ((char) v);
1414 if (target_type == TypeManager.decimal_type)
1415 return new DecimalConstant ((decimal) v);
1417 if (expr is ULongConstant){
1418 ulong v = ((ULongConstant) expr).Value;
1420 if (target_type == TypeManager.byte_type)
1421 return new ByteConstant ((byte) v);
1422 if (target_type == TypeManager.sbyte_type)
1423 return new SByteConstant ((sbyte) v);
1424 if (target_type == TypeManager.short_type)
1425 return new ShortConstant ((short) v);
1426 if (target_type == TypeManager.ushort_type)
1427 return new UShortConstant ((ushort) v);
1428 if (target_type == TypeManager.int32_type)
1429 return new IntConstant ((int) v);
1430 if (target_type == TypeManager.uint32_type)
1431 return new UIntConstant ((uint) v);
1432 if (target_type == TypeManager.int64_type)
1433 return new LongConstant ((long) v);
1434 if (target_type == TypeManager.float_type)
1435 return new FloatConstant ((float) v);
1436 if (target_type == TypeManager.double_type)
1437 return new DoubleConstant ((double) v);
1438 if (target_type == TypeManager.char_type)
1439 return new CharConstant ((char) v);
1440 if (target_type == TypeManager.decimal_type)
1441 return new DecimalConstant ((decimal) v);
1443 if (expr is FloatConstant){
1444 float v = ((FloatConstant) expr).Value;
1446 if (target_type == TypeManager.byte_type)
1447 return new ByteConstant ((byte) v);
1448 if (target_type == TypeManager.sbyte_type)
1449 return new SByteConstant ((sbyte) v);
1450 if (target_type == TypeManager.short_type)
1451 return new ShortConstant ((short) v);
1452 if (target_type == TypeManager.ushort_type)
1453 return new UShortConstant ((ushort) v);
1454 if (target_type == TypeManager.int32_type)
1455 return new IntConstant ((int) v);
1456 if (target_type == TypeManager.uint32_type)
1457 return new UIntConstant ((uint) v);
1458 if (target_type == TypeManager.int64_type)
1459 return new LongConstant ((long) v);
1460 if (target_type == TypeManager.uint64_type)
1461 return new ULongConstant ((ulong) v);
1462 if (target_type == TypeManager.double_type)
1463 return new DoubleConstant ((double) v);
1464 if (target_type == TypeManager.char_type)
1465 return new CharConstant ((char) v);
1466 if (target_type == TypeManager.decimal_type)
1467 return new DecimalConstant ((decimal) v);
1469 if (expr is DoubleConstant){
1470 double v = ((DoubleConstant) expr).Value;
1472 if (target_type == TypeManager.byte_type)
1473 return new ByteConstant ((byte) v);
1474 if (target_type == TypeManager.sbyte_type)
1475 return new SByteConstant ((sbyte) v);
1476 if (target_type == TypeManager.short_type)
1477 return new ShortConstant ((short) v);
1478 if (target_type == TypeManager.ushort_type)
1479 return new UShortConstant ((ushort) v);
1480 if (target_type == TypeManager.int32_type)
1481 return new IntConstant ((int) v);
1482 if (target_type == TypeManager.uint32_type)
1483 return new UIntConstant ((uint) v);
1484 if (target_type == TypeManager.int64_type)
1485 return new LongConstant ((long) v);
1486 if (target_type == TypeManager.uint64_type)
1487 return new ULongConstant ((ulong) v);
1488 if (target_type == TypeManager.float_type)
1489 return new FloatConstant ((float) v);
1490 if (target_type == TypeManager.char_type)
1491 return new CharConstant ((char) v);
1492 if (target_type == TypeManager.decimal_type)
1493 return new DecimalConstant ((decimal) v);
1499 public override Expression DoResolve (EmitContext ec)
1501 expr = expr.Resolve (ec);
1505 type = ec.DeclSpace.ResolveType (target_type, false, Location);
1510 eclass = ExprClass.Value;
1512 if (expr is Constant){
1513 Expression e = TryReduce (ec, type);
1519 expr = ConvertExplicit (ec, expr, type, runtime_cast, loc);
1523 public override void Emit (EmitContext ec)
1526 // This one will never happen
1528 throw new Exception ("Should not happen");
1532 public class StringConcat : Expression {
1534 Expression left, right;
1535 ArrayList Arguments;
1536 protected MethodBase method;
1538 public StringConcat(Location loc, Expression left, Expression right) {
1544 public override Expression DoResolve (EmitContext ec)
1546 left = left.Resolve (ec);
1547 right = right.Resolve (ec);
1549 if (left == null || right == null)
1552 if (left.Type == null)
1553 throw new Exception (
1554 "Resolve returned non null, but did not set the type! (" +
1555 left + ") at Line: " + loc.Row);
1556 if (right.Type == null)
1557 throw new Exception (
1558 "Resolve returned non null, but did not set the type! (" +
1559 right + ") at Line: "+ loc.Row);
1561 eclass = ExprClass.Value;
1562 if (left is StringConstant && right is StringConstant){
1563 return new StringConstant (
1564 ((StringConstant) left).Value +
1565 ((StringConstant) right).Value);
1569 Type r = right.Type;
1571 if (l == TypeManager.string_type && r == TypeManager.string_type) {
1572 type = TypeManager.string_type;
1573 method = TypeManager.string_concat_string_string;
1574 Arguments = new ArrayList ();
1575 Arguments.Add (new Argument (left, Argument.AType.Expression));
1576 Arguments.Add (new Argument (right, Argument.AType.Expression));
1580 if (l != TypeManager.string_type) {
1581 method = TypeManager.string_concat_object_object;
1582 left = ConvertImplicit (ec, left, TypeManager.string_type, loc);
1584 Error_OperatorCannotBeApplied (loc, "&", l, r);
1588 type = TypeManager.string_type;
1589 Arguments = new ArrayList ();
1590 Arguments.Add (new Argument (left, Argument.AType.Expression));
1591 Arguments.Add (new Argument (right, Argument.AType.Expression));
1595 if (r != TypeManager.string_type) {
1596 method = TypeManager.string_concat_object_object;
1597 right = ConvertImplicit (ec, right, TypeManager.string_type, loc);
1599 Error_OperatorCannotBeApplied (loc, "&", l, r);
1603 type = TypeManager.string_type;
1604 Arguments = new ArrayList ();
1605 Arguments.Add (new Argument (left, Argument.AType.Expression));
1606 Arguments.Add (new Argument (right, Argument.AType.Expression));
1612 public override void Emit (EmitContext ec)
1614 ILGenerator ig = ec.ig;
1615 if (method != null) {
1616 // Note that operators are static anyway
1617 if (Arguments != null)
1618 Invocation.EmitArguments (ec, method, Arguments);
1619 if (method is MethodInfo)
1620 ig.Emit (OpCodes.Call, (MethodInfo) method);
1622 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1628 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1630 Report.Error (19, loc,
1631 "Operator " + name + " cannot be applied to operands of type '" +
1632 TypeManager.MonoBASIC_Name (l) + "' and '" +
1633 TypeManager.MonoBASIC_Name (r) + "'");
1640 /// Binary operators
1642 public class Binary : Expression {
1643 public enum Operator : byte {
1645 Multiply, Division, IntDivision, Modulus,
1646 Addition, Subtraction, Concat,
1647 LeftShift, RightShift,
1648 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1649 Equality, Inequality,
1661 Expression left, right;
1664 // After resolution, method might contain the operator overload
1667 protected MethodBase method;
1668 ArrayList Arguments;
1670 bool DelegateOperation;
1672 // This must be kept in sync with Operator!!!
1673 static string [] oper_names;
1677 oper_names = new string [(int) Operator.TOP];
1679 oper_names [(int) Operator.Multiply] = "op_Multiply";
1680 oper_names [(int) Operator.Division] = "op_Division";
1681 oper_names [(int) Operator.IntDivision] = "op_Division";
1682 oper_names [(int) Operator.Modulus] = "op_Modulus";
1683 oper_names [(int) Operator.Addition] = "op_Addition";
1684 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1685 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1686 oper_names [(int) Operator.RightShift] = "op_RightShift";
1687 oper_names [(int) Operator.LessThan] = "op_LessThan";
1688 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1689 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1690 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1691 oper_names [(int) Operator.Equality] = "op_Equality";
1692 oper_names [(int) Operator.Inequality] = "op_Inequality";
1693 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1694 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1695 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1696 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1697 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1698 oper_names [(int) Operator.Is] = "op_Is";
1701 public Binary (Operator oper, Expression left, Expression right, Location loc)
1703 left = Parser.SetValueRequiredFlag (left);
1704 right = Parser.SetValueRequiredFlag (right);
1711 public Operator Oper {
1720 public Expression Left {
1729 public Expression Right {
1740 /// Returns a stringified representation of the Operator
1742 static string OperName (Operator oper)
1745 case Operator.Exponentiation:
1747 case Operator.Multiply:
1749 case Operator.Division:
1751 case Operator.IntDivision:
1753 case Operator.Modulus:
1755 case Operator.Addition:
1757 case Operator.Subtraction:
1759 case Operator.LeftShift:
1761 case Operator.RightShift:
1763 case Operator.LessThan:
1765 case Operator.GreaterThan:
1767 case Operator.LessThanOrEqual:
1769 case Operator.GreaterThanOrEqual:
1771 case Operator.Equality:
1773 case Operator.Inequality:
1775 case Operator.BitwiseAnd:
1777 case Operator.BitwiseOr:
1779 case Operator.ExclusiveOr:
1781 case Operator.LogicalOr:
1783 case Operator.LogicalAnd:
1789 return oper.ToString ();
1792 public override string ToString ()
1794 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1795 right.ToString () + ")";
1798 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1800 if (expr.Type == target_type)
1803 return ConvertImplicit (ec, expr, target_type, Location.Null);
1806 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1809 34, loc, "Operator '" + OperName (oper)
1810 + "' is ambiguous on operands of type '"
1811 + TypeManager.MonoBASIC_Name (l) + "' "
1812 + "and '" + TypeManager.MonoBASIC_Name (r)
1817 // Handles boolean types also
1819 bool DoNumericPromotions (EmitContext ec, Type l, Type r, Operator oper)
1822 Type conv_left_as = null;
1823 Type conv_right_as = null;
1824 if (left is NullLiteral)
1826 if (right is NullLiteral)
1829 // Need not do anything for shift operators, as this will be handled by the
1830 // 'CheckShiftArguments' method
1831 if (oper == Operator.LeftShift || oper == Operator.RightShift)
1833 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
1834 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
1835 type = TypeManager.int32_type;
1836 conv_left_as = conv_right_as = TypeManager.short_type;
1840 if (IsBitwiseOperator (oper)) {
1842 if (l == TypeManager.decimal_type ||
1843 l == TypeManager.double_type ||
1844 l == TypeManager.float_type) {
1845 conv_left_as = type = TypeManager.int64_type;
1848 if (r == TypeManager.decimal_type ||
1849 r == TypeManager.double_type ||
1850 r == TypeManager.float_type) {
1851 conv_right_as = type = TypeManager.int64_type;
1856 if (oper == Operator.IntDivision) {
1857 if (l == TypeManager.decimal_type || r == TypeManager.decimal_type ||
1858 l == TypeManager.float_type || r == TypeManager.float_type ||
1859 l == TypeManager.double_type || r == TypeManager.double_type)
1860 conv_left_as = conv_right_as = TypeManager.int64_type;
1861 l = r = TypeManager.int64_type;
1864 if (IsLogicalOperator (oper)) {
1865 if (l == TypeManager.decimal_type)
1866 conv_left_as = TypeManager.bool_type;
1867 else if (r == TypeManager.decimal_type)
1868 conv_right_as = TypeManager.bool_type;
1869 } else if ((l == TypeManager.double_type || r == TypeManager.double_type) ||
1870 (oper == Operator.Exponentiation) ||
1871 (oper == Operator.Division &&
1872 !(l == TypeManager.decimal_type || r == TypeManager.decimal_type))) {
1874 // If either operand is of type double, the other operand is
1875 // conveted to type double.
1877 type = conv_left_as = conv_right_as = TypeManager.double_type;
1879 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1881 // if either operand is of type float, the other operand is
1882 // converted to type float.
1884 type = conv_left_as = conv_right_as = TypeManager.float_type;
1885 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1886 type = conv_left_as = conv_right_as = TypeManager.decimal_type;
1887 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1889 // If either operand is of type long, the other operand is converted
1892 type = conv_left_as = conv_right_as = TypeManager.int64_type;
1893 } else if (l == TypeManager.int32_type || r == TypeManager.int32_type){
1894 type = conv_left_as = conv_right_as = TypeManager.int32_type;
1895 } else if (l == TypeManager.short_type || r == TypeManager.short_type){
1896 conv_left_as = conv_right_as = TypeManager.short_type;
1897 type = TypeManager.int32_type;
1899 type = TypeManager.int32_type;
1902 if (conv_left_as != null)
1903 left = ConvertImplicit (ec, left, conv_left_as, loc);
1904 if (conv_right_as != null)
1905 right = ConvertImplicit (ec, right, conv_right_as, loc);
1907 return (left != null) && (right != null);
1910 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1912 Report.Error (19, loc,
1913 "Operator '" + name + "' cannot be applied to operands of type '" +
1914 TypeManager.MonoBASIC_Name (l) + "' and '" +
1915 TypeManager.MonoBASIC_Name (r) + "'");
1918 void Error_OperatorCannotBeApplied ()
1920 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1923 static bool is_32_or_64 (Type t)
1925 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1926 t == TypeManager.int64_type || t == TypeManager.uint64_type);
1929 static bool is_unsigned (Type t)
1931 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1932 t == TypeManager.short_type || t == TypeManager.byte_type);
1935 Expression CheckShiftArguments (EmitContext ec)
1939 e = ForceConversion (ec, right, TypeManager.int32_type);
1941 Error_OperatorCannotBeApplied ();
1946 if (left is NullLiteral) {
1948 if (right.Type != TypeManager.bool_type) {
1949 left = ConvertImplicit (ec, left, right.Type, loc);
1951 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1958 if (type == TypeManager.bool_type) {
1959 left = ConvertImplicit (ec, left, TypeManager.short_type, loc);
1961 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1968 if ( type == TypeManager.byte_type)
1970 else if (type == TypeManager.short_type || type == TypeManager.bool_type)
1972 else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1977 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (mask), loc);
1978 right = right.DoResolve (ec);
1981 if (type == TypeManager.byte_type ||
1982 type == TypeManager.short_type ||
1983 type == TypeManager.int32_type) {
1984 type = TypeManager.int32_type;
1988 if (type == TypeManager.int64_type)
1990 if ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) {
1992 type = TypeManager.int64_type;
1996 Error_OperatorCannotBeApplied ();
2000 bool IsRelationalOperator (Binary.Operator oper) {
2001 return (oper == Operator.Equality ||
2002 oper == Operator.Inequality ||
2003 oper == Operator.LessThan ||
2004 oper == Operator.LessThanOrEqual ||
2005 oper == Operator.GreaterThan ||
2006 oper == Operator.GreaterThanOrEqual);
2009 bool IsArithmaticOperator (Binary.Operator oper) {
2010 return (oper == Operator.Addition ||
2011 oper == Operator.Subtraction ||
2012 oper == Operator.Multiply ||
2013 oper == Operator.Division ||
2014 oper == Operator.IntDivision ||
2015 oper == Operator.Exponentiation ||
2016 oper == Operator.Modulus);
2019 bool IsShiftOperator (Binary.Operator oper) {
2020 return (oper == Operator.LeftShift ||
2021 oper == Operator.RightShift);
2024 bool IsLogicalOperator (Binary.Operator oper) {
2025 return (oper == Operator.LogicalOr ||
2026 oper == Operator.LogicalAnd);
2029 bool IsBitwiseOperator (Binary.Operator oper) {
2030 return (oper == Operator.BitwiseOr ||
2031 oper == Operator.BitwiseAnd ||
2032 oper == Operator.ExclusiveOr);
2035 Expression ResolveOperator (EmitContext ec)
2038 Type r = right.Type;
2040 Expression left_expr, right_expr;
2041 left_expr = right_expr = null;
2043 if (oper == Operator.Addition && right is Unary) {
2044 Unary unary_right = (Unary) right;
2045 if (unary_right.Oper == Unary.Operator.UnaryNegation) {
2046 oper = Operator.Subtraction;
2047 right = unary_right.Expr;
2052 if (TypeManager.IsEnumType (l))
2053 l = TypeManager.EnumToUnderlying (l);
2054 if (TypeManager.IsEnumType (r))
2055 r = TypeManager.EnumToUnderlying (r);
2057 Type conv_left_as = null;
2058 Type conv_right_as = null;
2060 if ((left is NullLiteral ||(Type.GetTypeCode(l)==TypeCode.DBNull)) && (r.IsValueType || r == TypeManager.string_type)) {
2061 // Just treat nothing as the other type, implicit conversion
2062 // will return the default value
2065 //incase of DBNull set to NullLiteral
2066 left = NullLiteral.Null;
2069 if ((right is NullLiteral ||(Type.GetTypeCode(r)==TypeCode.DBNull)) && (l.IsValueType || l == TypeManager.string_type)) {
2070 // Just treat nothing as the other type, implicit conversion
2071 // will return the default value
2074 right = NullLiteral.Null;
2077 // deal with objects and reference types first
2078 if (l == TypeManager.object_type || r == TypeManager.object_type) {
2081 // operator != (object a, object b)
2082 // operator == (object a, object b)
2084 // For this to be used, both arguments have to be reference-types.
2085 // Read the rationale on the spec (14.9.6)
2087 // Also, if at compile time we know that the classes do not inherit
2088 // one from the other, then we catch the error there.
2090 // If other type is a value type, convert it to object
2091 if (r == TypeManager.object_type &&
2092 (l.IsValueType || l == TypeManager.string_type))
2093 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2094 if (l == TypeManager.object_type &&
2095 (r.IsValueType || r == TypeManager.string_type))
2096 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2097 if (left == null || right == null) {
2098 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2105 if (l == TypeManager.object_type && r == TypeManager.object_type) {
2108 case Operator.Addition :
2109 fqn = "ObjectType.AddObj";
2111 case Operator.Subtraction :
2112 fqn = "ObjectType.SubObj";
2114 case Operator.Multiply :
2115 fqn = "ObjectType.MulObj";
2117 case Operator.Division :
2118 fqn = "ObjectType.DivObj";
2120 case Operator.IntDivision :
2121 fqn = "ObjectType.IDivObj";
2123 case Operator.Modulus :
2124 fqn = "ObjectType.ModObj";
2126 case Operator.Exponentiation :
2127 fqn = "ObjectType.PowObj";
2129 case Operator.Like :
2130 fqn = "ObjectType.LikeObj";
2132 case Operator.Equality :
2133 case Operator.Inequality :
2134 case Operator.LessThan :
2135 case Operator.LessThanOrEqual :
2136 case Operator.GreaterThan :
2137 case Operator.GreaterThanOrEqual :
2138 fqn = "ObjectType.ObjTst";
2140 case Operator.BitwiseAnd:
2141 fqn = "ObjectType.BitAndObj";
2143 case Operator.BitwiseOr:
2144 fqn = "ObjectType.BitOrObj";
2146 case Operator.ExclusiveOr:
2147 fqn = "ObjectType.BitXorObj";
2149 case Operator.LeftShift:
2150 fqn = "ObjectType.ShiftLeftObj";
2152 case Operator.RightShift:
2153 fqn = "ObjectType.ShiftRightObj";
2156 eclass = ExprClass.Value;
2157 type = TypeManager.bool_type;
2162 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2166 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2167 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2168 if (right == null) {
2169 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2174 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (
2175 "Microsoft.VisualBasic.CompilerServices." + fqn,
2178 ArrayList args = new ArrayList ();
2179 args.Add (new Argument (left, Argument.AType.Expression));
2180 args.Add (new Argument (right, Argument.AType.Expression));
2181 if (IsRelationalOperator (oper))
2182 args.Add (new Argument (new BoolConstant (false), Argument.AType.Expression));
2183 if (oper == Operator.Like)
2184 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2185 Expression e = new Invocation (etmp, args, loc);
2186 if (IsRelationalOperator (oper)) {
2187 e = new Binary (oper, e.Resolve(ec), new IntConstant (0), loc);
2189 return e.Resolve (ec);
2190 } else if (!l.IsValueType || !r.IsValueType) {
2192 // If one of the operands are reference types and other is object, support for 'Is' operator
2193 if (oper == Operator.Is) {
2194 eclass = ExprClass.Value;
2195 type = TypeManager.bool_type;
2201 } else if (!l.IsValueType || !r.IsValueType) {
2203 if (!l.IsValueType && !r.IsValueType) {
2204 // If both the operands are reference types, support for 'Is' operator
2205 if (oper == Operator.Is) {
2206 eclass = ExprClass.Value;
2207 type = TypeManager.bool_type;
2211 // Either of the operands are reference types
2212 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2213 r.IsSubclassOf (TypeManager.delegate_type)) {
2214 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2215 Arguments = new ArrayList ();
2216 Arguments.Add (new Argument (left, Argument.AType.Expression));
2217 Arguments.Add (new Argument (right, Argument.AType.Expression));
2219 if (oper == Operator.Addition)
2220 method = TypeManager.delegate_combine_delegate_delegate;
2222 method = TypeManager.delegate_remove_delegate_delegate;
2225 Error_OperatorCannotBeApplied ();
2229 DelegateOperation = true;
2234 if (oper != Operator.Equality) {
2235 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2240 bool left_is_string = (left.Type == TypeManager.string_type);
2241 bool right_is_string = (right.Type == TypeManager.string_type);
2243 if (left_is_string || right_is_string) {
2245 if (left is NullLiteral) {
2246 left_is_string = true;
2249 if (right is NullLiteral) {
2250 right_is_string = true;
2253 if (left_is_string && right_is_string) {
2254 if (oper == Operator.Addition) {
2255 // Both operands are string
2256 Expression e = new StringConcat (loc, left, right);
2257 return e.Resolve(ec);
2260 if (IsRelationalOperator (oper)) {
2262 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrCmp", Location.Null);
2263 eclass = ExprClass.Value;
2264 type = TypeManager.bool_type;
2265 ArrayList args = new ArrayList ();
2266 args.Add (new Argument(left, Argument.AType.Expression));
2267 args.Add (new Argument(right, Argument.AType.Expression));
2268 args.Add (new Argument(new BoolConstant(false), Argument.AType.Expression));
2269 Expression e = (Expression) new Invocation (etmp, args, loc);
2270 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2271 return e.Resolve(ec);
2274 if (oper == Operator.Like) {
2275 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrLike", Location.Null);
2276 type = TypeManager.bool_type;
2277 ArrayList args = new ArrayList ();
2278 args.Add (new Argument(left, Argument.AType.Expression));
2279 args.Add (new Argument(right, Argument.AType.Expression));
2280 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2281 Expression e = (Expression) new Invocation (etmp, args, loc);
2282 return e.Resolve (ec);
2286 Expression other = right_is_string ? left: right;
2287 Type other_type = other.Type;
2290 // Disallow arithmatic / shift / logical operators on dates and characters
2292 if (other_type == TypeManager.date_type || other_type == TypeManager.char_type) {
2293 if (!(oper == Operator.Addition || IsRelationalOperator (oper) || oper == Operator.Like)) {
2294 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2299 if (oper == Operator.Addition) {
2300 if (other_type == TypeManager.void_type) {
2301 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2304 if (other_type == TypeManager.date_type ||
2305 other_type == TypeManager.char_type ||
2306 other_type == typeof (System.Char[])) {
2307 conv_left_as = conv_right_as = TypeManager.string_type;
2308 type = TypeManager.string_type;
2311 conv_right_as = conv_left_as = TypeManager.double_type;
2312 type = TypeManager.double_type;
2314 } else if (IsRelationalOperator (oper)) {
2315 if (other_type == TypeManager.char_type || other_type == typeof (System.Char[])) {
2316 conv_left_as = conv_right_as = TypeManager.string_type;
2317 } else if (other_type == TypeManager.date_type) {
2318 conv_right_as = conv_left_as = other_type;
2319 } else if (other_type == TypeManager.bool_type) {
2320 conv_right_as = conv_left_as = other_type;
2321 } else if (! other_type.IsValueType) {
2322 // Do Nothing, just return
2323 type = TypeManager.bool_type;
2326 conv_right_as = conv_left_as = TypeManager.double_type;
2328 type = TypeManager.bool_type;
2330 } else if (oper == Operator.Like) {
2331 conv_left_as = conv_right_as = TypeManager.string_type;
2332 } else if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2334 conv_left_as = TypeManager.int64_type;
2335 conv_right_as = TypeManager.int32_type;
2336 type = TypeManager.int64_type;
2338 } else if ( IsLogicalOperator (oper)) {
2339 type = conv_right_as = conv_left_as = TypeManager.bool_type;
2340 } else if ( IsBitwiseOperator (oper)) {
2342 if (other_type == TypeManager.bool_type) {
2343 conv_right_as = conv_left_as = TypeManager.bool_type;
2344 type = TypeManager.bool_type;
2346 conv_left_as = conv_right_as = TypeManager.int64_type;
2347 type = TypeManager.int64_type;
2349 } else if (oper == Operator.Exponentiation) {
2350 conv_left_as = conv_right_as = TypeManager.double_type;
2351 } else if (oper == Operator.IntDivision) {
2352 conv_left_as = conv_right_as = TypeManager.int64_type;
2354 // Arithmatic operators
2355 conv_right_as = conv_left_as = TypeManager.double_type;
2356 type = TypeManager.double_type;
2359 // Both are not of type string
2360 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is) {
2361 if (l.IsValueType || r.IsValueType) {
2362 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2365 type = TypeManager.bool_type;
2368 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2372 } else if (l == TypeManager.date_type || r == TypeManager.date_type) {
2373 // Date with string operations handled above
2374 // Only other possiblity is date with date
2375 if (oper == Operator.Like) {
2376 conv_right_as = conv_left_as = TypeManager.string_type;
2377 type = TypeManager.bool_type;
2378 } else if (l == TypeManager.date_type && r == TypeManager.date_type) {
2379 if (oper == Operator.Addition) {
2380 conv_left_as = conv_right_as = TypeManager.string_type;
2381 } else if (IsRelationalOperator (oper)) {
2382 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.DateTime.Compare", Location.Null);
2383 eclass = ExprClass.Value;
2384 type = TypeManager.bool_type;
2385 ArrayList args = new ArrayList ();
2386 args.Add (new Argument(left, Argument.AType.Expression));
2387 args.Add (new Argument(right, Argument.AType.Expression));
2388 Expression e = (Expression) new Invocation (etmp, args, loc);
2389 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2390 return e.Resolve(ec);
2392 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2396 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2399 } else if (l == TypeManager.char_type || r == TypeManager.char_type) {
2400 // char op string handled above
2401 if (oper == Operator.Like) {
2402 conv_right_as = conv_left_as = TypeManager.string_type;
2403 type = TypeManager.bool_type;
2404 } else if (l == TypeManager.char_type && r == TypeManager.char_type) {
2405 if (oper == Operator.Addition)
2406 conv_left_as = conv_right_as = TypeManager.string_type;
2407 else if (IsRelationalOperator (oper)) {
2408 type = TypeManager.bool_type;
2410 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2414 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2417 } else if (l.IsPointer || r.IsPointer) {
2418 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2420 if (r.IsPointer && oper == Operator.Subtraction){
2422 return new PointerArithmetic (
2423 false, left, right, TypeManager.int64_type,
2425 } else if (is_32_or_64 (r))
2426 return new PointerArithmetic (
2427 oper == Operator.Addition, left, right, l, loc);
2428 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2429 return new PointerArithmetic (
2430 true, right, left, r, loc);
2434 // Pointer comparison
2436 if (l.IsPointer && r.IsPointer){
2437 if (oper == Operator.Equality || oper == Operator.Inequality ||
2438 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2439 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2440 type = TypeManager.bool_type;
2444 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2447 } else if (oper == Operator.Like) {
2448 conv_left_as = conv_right_as = TypeManager.string_type;
2452 DoNumericPromotions (ec, l, r, oper);
2453 if (left == null || right == null) {
2454 Error_OperatorCannotBeApplied (loc, OperName(oper), l, r);
2460 // Required conversions done by 'DoNumericPromotions' method
2461 // So Reset 'conv_left_as', 'conv_right_as'
2462 conv_left_as = conv_right_as = null;
2464 if (l == TypeManager.decimal_type && r == TypeManager.decimal_type) {
2465 if (IsRelationalOperator (oper)) {
2466 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.Decimal.Compare", Location.Null);
2467 eclass = ExprClass.Value;
2468 type = TypeManager.bool_type;
2469 ArrayList args = new ArrayList ();
2470 args.Add (new Argument(left, Argument.AType.Expression));
2471 args.Add (new Argument(right, Argument.AType.Expression));
2472 Expression e = (Expression) new Invocation (etmp, args, loc);
2473 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2474 return e.Resolve(ec);
2475 } else if (IsArithmaticOperator (oper)) {
2477 if (oper == Operator.Addition)
2478 fqn = "System.Decimal.Add";
2479 else if (oper == Operator.Subtraction)
2480 fqn = "System.Decimal.Subtract";
2481 else if (oper == Operator.Multiply)
2482 fqn = "System.Decimal.Multiply";
2483 else if (oper == Operator.Division)
2484 fqn = "System.Decimal.Divide";
2485 else if (oper == Operator.Modulus)
2486 fqn = "System.Decimal.Remainder";
2489 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (fqn, Location.Null);
2490 eclass = ExprClass.Value;
2491 type = TypeManager.decimal_type;
2492 ArrayList args = new ArrayList ();
2493 args.Add (new Argument(left, Argument.AType.Expression));
2494 args.Add (new Argument(right, Argument.AType.Expression));
2495 Expression e = (Expression) new Invocation (etmp, args, loc);
2496 return e.Resolve (ec);
2502 bool conv_done = false;
2503 if (conv_left_as != null && conv_left_as != l) {
2505 left = ConvertImplicit (ec, left, conv_left_as, loc);
2507 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2513 if (conv_right_as != null && conv_right_as != r) {
2515 right = ConvertImplicit (ec, right, conv_right_as, loc);
2516 if (right == null) {
2517 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2524 return ResolveOperator (ec);
2527 if (oper == Operator.Exponentiation) {
2528 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI("System.Math.Pow", loc);
2529 ArrayList args = new ArrayList();
2530 args.Add (new Argument (left, Argument.AType.Expression));
2531 args.Add (new Argument (right, Argument.AType.Expression));
2532 Expression e = (Expression) new Invocation (etmp, args, loc);
2533 return e.Resolve(ec);
2536 bool overload_failed = false;
2537 string op = oper_names [(int) oper];
2538 MethodGroupExpr union = null;
2539 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2541 right_expr = MemberLookup (
2542 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2543 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2545 union = (MethodGroupExpr) left_expr;
2547 if (union != null) {
2548 Arguments = new ArrayList ();
2549 Arguments.Add (new Argument (left, Argument.AType.Expression));
2550 Arguments.Add (new Argument (right, Argument.AType.Expression));
2552 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
2553 if (method != null) {
2554 MethodInfo mi = (MethodInfo) method;
2556 type = mi.ReturnType;
2559 overload_failed = true;
2563 if (overload_failed) {
2564 Error_OperatorCannotBeApplied ();
2568 if (IsRelationalOperator (oper)) {
2569 type = TypeManager.bool_type;
2570 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2571 // Reverse the operator - to make it consistent with vbc
2572 if (oper == Operator.LessThan)
2573 oper = Operator.GreaterThan;
2574 else if (oper == Operator.GreaterThan)
2575 oper = Operator.LessThan;
2576 else if (oper == Operator.LessThanOrEqual)
2577 oper = Operator.GreaterThanOrEqual;
2578 else if (oper == Operator.GreaterThanOrEqual)
2579 oper = Operator.LessThanOrEqual;
2583 if (IsLogicalOperator (oper))
2584 type = TypeManager.bool_type;
2585 if (IsBitwiseOperator (oper)) {
2587 if (l == TypeManager.byte_type ||
2588 l == TypeManager.short_type ||
2589 l == TypeManager.bool_type ||
2590 l == TypeManager.int32_type ||
2591 l == TypeManager.int64_type)
2594 Error_OperatorCannotBeApplied();
2598 Error_OperatorCannotBeApplied();
2603 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2604 return CheckShiftArguments (ec);
2611 public override Expression DoResolve (EmitContext ec)
2613 if (oper == Operator.Concat) {
2614 Expression e = new StringConcat (loc, left, right);
2615 return e.Resolve (ec);
2617 left = left.Resolve (ec);
2618 right = right.Resolve (ec);
2620 if (left == null || right == null)
2623 if (left.Type == null)
2624 throw new Exception (
2625 "Resolve returned non null, but did not set the type! (" +
2626 left + ") at Line: " + loc.Row);
2627 if (right.Type == null)
2628 throw new Exception (
2629 "Resolve returned non null, but did not set the type! (" +
2630 right + ") at Line: "+ loc.Row);
2632 eclass = ExprClass.Value;
2634 // To support 'Or' argument of AttributeTargets in AttributeUsage
2636 if (left is EnumConstant && oper != Operator.BitwiseOr) {
2637 left = ((EnumConstant) left).WidenToCompilerConstant();
2640 if (right is EnumConstant && oper != Operator.BitwiseOr) {
2641 right = ((EnumConstant) right).WidenToCompilerConstant();
2644 if (left is Constant && right is Constant){
2645 Expression e = ConstantFold.BinaryFold (
2646 ec, oper, (Constant) left, (Constant) right, loc);
2651 Expression etmp = ResolveOperator (ec);
2654 // if the operands are of type byte/short, convert the result back to short/byte
2655 if (l == TypeManager.bool_type || l == TypeManager.short_type || l == TypeManager.byte_type) {
2656 if (l == TypeManager.bool_type)
2657 l = TypeManager.short_type;
2658 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
2659 Expression conv_exp = ConvertImplicit (ec, etmp, l, loc);
2660 if (conv_exp != null)
2663 if (IsShiftOperator (oper)) {
2664 // No overflow checks are needed
2665 if (l == TypeManager.byte_type)
2666 return new OpcodeCast (etmp, l, OpCodes.Conv_U1);
2668 return new OpcodeCast (etmp, l, OpCodes.Conv_I2);
2676 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2677 /// context of a conditional bool expression. This function will return
2678 /// false if it is was possible to use EmitBranchable, or true if it was.
2680 /// The expression's code is generated, and we will generate a branch to 'target'
2681 /// if the resulting expression value is equal to isTrue
2683 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2688 ILGenerator ig = ec.ig;
2691 // This is more complicated than it looks, but its just to avoid
2692 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2693 // but on top of that we want for == and != to use a special path
2694 // if we are comparing against null
2696 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is){
2697 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2699 if (left is NullLiteral){
2702 ig.Emit (OpCodes.Brtrue, target);
2704 ig.Emit (OpCodes.Brfalse, target);
2706 } else if (right is NullLiteral){
2709 ig.Emit (OpCodes.Brtrue, target);
2711 ig.Emit (OpCodes.Brfalse, target);
2714 } else if (!(oper == Operator.LessThan ||
2715 oper == Operator.GreaterThan ||
2716 oper == Operator.LessThanOrEqual ||
2717 oper == Operator.GreaterThanOrEqual ||
2718 oper == Operator.Is))
2726 bool isUnsigned = is_unsigned (left.Type);
2729 case Operator.Equality:
2731 ig.Emit (OpCodes.Beq, target);
2733 ig.Emit (OpCodes.Bne_Un, target);
2736 case Operator.Inequality:
2738 ig.Emit (OpCodes.Bne_Un, target);
2740 ig.Emit (OpCodes.Beq, target);
2743 case Operator.LessThan:
2746 ig.Emit (OpCodes.Blt_Un, target);
2748 ig.Emit (OpCodes.Blt, target);
2751 ig.Emit (OpCodes.Bge_Un, target);
2753 ig.Emit (OpCodes.Bge, target);
2756 case Operator.GreaterThan:
2759 ig.Emit (OpCodes.Bgt_Un, target);
2761 ig.Emit (OpCodes.Bgt, target);
2764 ig.Emit (OpCodes.Ble_Un, target);
2766 ig.Emit (OpCodes.Ble, target);
2769 case Operator.LessThanOrEqual:
2772 ig.Emit (OpCodes.Ble_Un, target);
2774 ig.Emit (OpCodes.Ble, target);
2777 ig.Emit (OpCodes.Bgt_Un, target);
2779 ig.Emit (OpCodes.Bgt, target);
2783 case Operator.GreaterThanOrEqual:
2786 ig.Emit (OpCodes.Bge_Un, target);
2788 ig.Emit (OpCodes.Bge, target);
2791 ig.Emit (OpCodes.Blt_Un, target);
2793 ig.Emit (OpCodes.Blt, target);
2798 ig.Emit (OpCodes.Beq, target); //Check this
2800 ig.Emit (OpCodes.Bne_Un_S, target);
2810 public override void Emit (EmitContext ec)
2812 ILGenerator ig = ec.ig;
2814 Type r = right.Type;
2815 //Type r = right.Type;
2818 if (method != null) {
2820 // Note that operators are static anyway
2822 if (Arguments != null)
2823 Invocation.EmitArguments (ec, method, Arguments);
2825 if (method is MethodInfo)
2826 ig.Emit (OpCodes.Call, (MethodInfo) method);
2828 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2830 if (DelegateOperation)
2831 ig.Emit (OpCodes.Castclass, type);
2837 // Handle short-circuit operators differently
2840 if (IsLogicalOperator (oper)) {
2841 Label load_zero = ig.DefineLabel ();
2842 Label load_one = ig.DefineLabel ();
2843 Label end = ig.DefineLabel ();
2846 if (l != TypeManager.bool_type) {
2847 if (l == TypeManager.int64_type) {
2848 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2849 ec.ig.Emit (OpCodes.Cgt_Un);
2850 } else if (l == TypeManager.float_type) {
2851 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2852 ec.ig.Emit (OpCodes.Ceq);
2853 ec.ig.Emit (OpCodes.Ldc_I4_0);
2854 ec.ig.Emit (OpCodes.Ceq);
2855 } else if (l == TypeManager.double_type) {
2856 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2857 ec.ig.Emit (OpCodes.Ceq);
2858 ec.ig.Emit (OpCodes.Ldc_I4_0);
2859 ec.ig.Emit (OpCodes.Ceq);
2861 ec.ig.Emit (OpCodes.Ldc_I4_0);
2862 ec.ig.Emit (OpCodes.Cgt_Un);
2865 if (oper == Operator.LogicalAnd)
2866 ig.Emit (OpCodes.Brfalse, load_zero);
2868 ig.Emit (OpCodes.Brtrue, load_one);
2871 if (r != TypeManager.bool_type) {
2872 if (r == TypeManager.int64_type) {
2873 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2874 ec.ig.Emit (OpCodes.Cgt_Un);
2875 } else if (r == TypeManager.float_type) {
2876 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2877 ec.ig.Emit (OpCodes.Ceq);
2878 ec.ig.Emit (OpCodes.Ldc_I4_0);
2879 ec.ig.Emit (OpCodes.Ceq);
2880 } else if (r == TypeManager.double_type) {
2881 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2882 ec.ig.Emit (OpCodes.Ceq);
2883 ec.ig.Emit (OpCodes.Ldc_I4_0);
2884 ec.ig.Emit (OpCodes.Ceq);
2886 ec.ig.Emit (OpCodes.Ldc_I4_0);
2887 ec.ig.Emit (OpCodes.Cgt_Un);
2890 ig.Emit (OpCodes.Brtrue, load_one);
2891 ig.MarkLabel (load_zero);
2892 ig.Emit (OpCodes.Ldc_I4_0);
2893 ig.Emit (OpCodes.Br, end);
2894 ig.MarkLabel (load_one);
2895 ig.Emit (OpCodes.Ldc_I4_1);
2904 case Operator.Multiply:
2906 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2907 opcode = OpCodes.Mul_Ovf;
2908 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2909 opcode = OpCodes.Mul_Ovf_Un;
2911 opcode = OpCodes.Mul;
2913 opcode = OpCodes.Mul;
2917 case Operator.Division:
2918 case Operator.IntDivision:
2919 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2920 opcode = OpCodes.Div_Un;
2922 opcode = OpCodes.Div;
2925 case Operator.Modulus:
2926 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2927 opcode = OpCodes.Rem_Un;
2929 opcode = OpCodes.Rem;
2932 case Operator.Addition:
2934 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2935 opcode = OpCodes.Add_Ovf;
2936 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2937 opcode = OpCodes.Add_Ovf_Un;
2939 opcode = OpCodes.Add;
2941 opcode = OpCodes.Add;
2944 case Operator.Subtraction:
2946 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2947 opcode = OpCodes.Sub_Ovf;
2948 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2949 opcode = OpCodes.Sub_Ovf_Un;
2951 opcode = OpCodes.Sub;
2953 opcode = OpCodes.Sub;
2956 case Operator.RightShift:
2957 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2958 opcode = OpCodes.Shr_Un;
2960 opcode = OpCodes.Shr;
2963 case Operator.LeftShift:
2964 opcode = OpCodes.Shl;
2967 case Operator.Equality:
2969 opcode = OpCodes.Ceq;
2972 case Operator.Inequality:
2973 ec.ig.Emit (OpCodes.Ceq);
2974 ec.ig.Emit (OpCodes.Ldc_I4_0);
2976 opcode = OpCodes.Ceq;
2979 case Operator.LessThan:
2980 opcode = OpCodes.Clt;
2983 case Operator.GreaterThan:
2984 opcode = OpCodes.Cgt;
2987 case Operator.LessThanOrEqual:
2988 ec.ig.Emit (OpCodes.Cgt);
2989 ec.ig.Emit (OpCodes.Ldc_I4_0);
2991 opcode = OpCodes.Ceq;
2994 case Operator.GreaterThanOrEqual:
2995 ec.ig.Emit (OpCodes.Clt);
2996 ec.ig.Emit (OpCodes.Ldc_I4_1);
2998 opcode = OpCodes.Sub;
3001 case Operator.BitwiseOr:
3002 opcode = OpCodes.Or;
3005 case Operator.BitwiseAnd:
3006 opcode = OpCodes.And;
3009 case Operator.ExclusiveOr:
3010 opcode = OpCodes.Xor;
3014 throw new Exception ("This should not happen: Operator = "
3015 + oper.ToString ());
3021 public bool IsBuiltinOperator {
3023 return method == null;
3028 public class PointerArithmetic : Expression {
3029 Expression left, right;
3033 // We assume that 'l' is always a pointer
3035 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
3039 eclass = ExprClass.Variable;
3043 is_add = is_addition;
3046 public override Expression DoResolve (EmitContext ec)
3049 // We are born fully resolved
3054 public override void Emit (EmitContext ec)
3056 Type op_type = left.Type;
3057 ILGenerator ig = ec.ig;
3058 int size = GetTypeSize (op_type.GetElementType ());
3060 if (right.Type.IsPointer){
3062 // handle (pointer - pointer)
3066 ig.Emit (OpCodes.Sub);
3070 ig.Emit (OpCodes.Sizeof, op_type);
3072 IntLiteral.EmitInt (ig, size);
3073 ig.Emit (OpCodes.Div);
3075 ig.Emit (OpCodes.Conv_I8);
3078 // handle + and - on (pointer op int)
3081 ig.Emit (OpCodes.Conv_I);
3085 ig.Emit (OpCodes.Sizeof, op_type);
3087 IntLiteral.EmitInt (ig, size);
3088 ig.Emit (OpCodes.Mul);
3091 ig.Emit (OpCodes.Add);
3093 ig.Emit (OpCodes.Sub);
3099 /// Implements the ternary conditional operator (?:)
3101 public class Conditional : Expression {
3102 Expression expr, trueExpr, falseExpr;
3104 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3107 this.trueExpr = trueExpr;
3108 this.falseExpr = falseExpr;
3112 public Expression Expr {
3118 public Expression TrueExpr {
3124 public Expression FalseExpr {
3130 public override Expression DoResolve (EmitContext ec)
3132 expr = expr.Resolve (ec);
3137 if (expr.Type != TypeManager.bool_type)
3138 expr = Expression.ConvertImplicitRequired (
3139 ec, expr, TypeManager.bool_type, loc);
3141 trueExpr = trueExpr.Resolve (ec);
3142 falseExpr = falseExpr.Resolve (ec);
3144 if (trueExpr == null || falseExpr == null)
3147 eclass = ExprClass.Value;
3148 if (trueExpr.Type == falseExpr.Type)
3149 type = trueExpr.Type;
3152 Type true_type = trueExpr.Type;
3153 Type false_type = falseExpr.Type;
3155 if (trueExpr is NullLiteral){
3158 } else if (falseExpr is NullLiteral){
3164 // First, if an implicit conversion exists from trueExpr
3165 // to falseExpr, then the result type is of type falseExpr.Type
3167 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
3170 // Check if both can convert implicitl to each other's type
3172 if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
3174 "Can not compute type of conditional expression " +
3175 "as '" + TypeManager.MonoBASIC_Name (trueExpr.Type) +
3176 "' and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) +
3177 "' convert implicitly to each other");
3182 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
3186 Error (173, "The type of the conditional expression can " +
3187 "not be computed because there is no implicit conversion" +
3188 " from '" + TypeManager.MonoBASIC_Name (trueExpr.Type) + "'" +
3189 " and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) + "'");
3194 if (expr is BoolConstant){
3195 BoolConstant bc = (BoolConstant) expr;
3206 public override void Emit (EmitContext ec)
3208 ILGenerator ig = ec.ig;
3209 Label false_target = ig.DefineLabel ();
3210 Label end_target = ig.DefineLabel ();
3212 Statement.EmitBoolExpression (ec, expr, false_target, false);
3214 ig.Emit (OpCodes.Br, end_target);
3215 ig.MarkLabel (false_target);
3216 falseExpr.Emit (ec);
3217 ig.MarkLabel (end_target);
3225 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3226 public readonly string Name;
3227 public readonly Block Block;
3228 VariableInfo variable_info;
3231 public LocalVariableReference (Block block, string name, Location l)
3236 eclass = ExprClass.Variable;
3239 // Setting 'is_readonly' to false will allow you to create a writable
3240 // reference to a read-only variable. This is used by foreach and using.
3241 public LocalVariableReference (Block block, string name, Location l,
3242 VariableInfo variable_info, bool is_readonly)
3243 : this (block, name, l)
3245 this.variable_info = variable_info;
3246 this.is_readonly = is_readonly;
3249 public VariableInfo VariableInfo {
3251 if (variable_info == null) {
3252 variable_info = Block.GetVariableInfo (Name);
3253 is_readonly = variable_info.ReadOnly;
3255 return variable_info;
3259 public bool IsAssigned (EmitContext ec, Location loc)
3261 return VariableInfo.IsAssigned (ec, loc);
3264 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
3266 return VariableInfo.IsFieldAssigned (ec, name, loc);
3269 public void SetAssigned (EmitContext ec)
3271 VariableInfo.SetAssigned (ec);
3274 public void SetFieldAssigned (EmitContext ec, string name)
3276 VariableInfo.SetFieldAssigned (ec, name);
3279 public bool IsReadOnly {
3281 if (variable_info == null) {
3282 variable_info = Block.GetVariableInfo (Name);
3283 is_readonly = variable_info.ReadOnly;
3289 public override Expression DoResolve (EmitContext ec)
3291 VariableInfo vi = VariableInfo;
3293 if (Block.IsConstant (Name)) {
3294 Expression e = Block.GetConstantExpression (Name);
3300 if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3303 type = vi.VariableType;
3307 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3309 VariableInfo vi = VariableInfo;
3311 if (ec.DoFlowAnalysis) {
3312 ec.SetVariableAssigned (vi);
3315 Expression e = DoResolve (ec);
3321 Error (1604, "cannot assign to '" + Name + "' because it is readonly");
3328 public override void Emit (EmitContext ec)
3330 VariableInfo vi = VariableInfo;
3331 ILGenerator ig = ec.ig;
3333 if (vi.Alias != null) {
3334 ArrayList fields = ec.TypeContainer.Fields;
3335 FieldBase fb = null;
3336 for (int i = 0; i < fields.Count; i++) {
3337 if (((Field) fields[i]).Name == vi.Alias) {
3338 fb = (Field) fields[i];
3342 if ((fb.ModFlags & Modifiers.STATIC) != 0)
3343 ig.Emit (OpCodes.Ldsfld, fb.FieldBuilder);
3345 ig.Emit (OpCodes.Ldarg_0);
3346 ig.Emit (OpCodes.Ldfld, fb.FieldBuilder);
3349 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
3354 public void EmitAssign (EmitContext ec, Expression source)
3356 ILGenerator ig = ec.ig;
3357 VariableInfo vi = VariableInfo;
3361 if (vi.Alias != null) {
3362 ArrayList fields = ec.TypeContainer.Fields;
3363 FieldBase fb = null;
3364 for (int i = 0; i < fields.Count; i++) {
3365 if (((Field) fields[i]).Name == vi.Alias) {
3366 fb = (Field) fields[i];
3371 if ((fb.ModFlags & Modifiers.STATIC) != 0) {
3373 ig.Emit (OpCodes.Stsfld, fb.FieldBuilder);
3376 ig.Emit (OpCodes.Ldarg_0);
3378 ig.Emit (OpCodes.Stfld, fb.FieldBuilder);
3383 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3387 public void EmitAssign (EmitContext ec, Expression source, FieldBase fb)
3389 //This is used in specific cases with non Static fields with
3390 //part of source assign emmited before this.
3391 ILGenerator ig = ec.ig;
3392 VariableInfo vi = VariableInfo;
3396 if ((fb.ModFlags & Modifiers.STATIC) != 0)
3397 ig.Emit (OpCodes.Stsfld, fb.FieldBuilder);
3399 ig.Emit (OpCodes.Stfld, fb.FieldBuilder);
3402 public void AddressOf (EmitContext ec, AddressOp mode)
3404 VariableInfo vi = VariableInfo;
3406 if (vi.Alias != null) {
3407 ArrayList fields = ec.TypeContainer.Fields;
3408 FieldBase fb = null;
3409 for (int i = 0; i < fields.Count; i++) {
3410 if (((Field) fields[i]).Name == vi.Alias) {
3411 fb = (Field) fields[i];
3415 if ((fb.ModFlags & Modifiers.STATIC) != 0)
3416 ec.ig.Emit (OpCodes.Ldsflda, fb.FieldBuilder);
3418 ec.ig.Emit (OpCodes.Ldarg_0);
3419 ec.ig.Emit (OpCodes.Ldflda, fb.FieldBuilder);
3422 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
3427 /// This represents a reference to a parameter in the intermediate
3430 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3434 public Parameter.Modifier mod;
3435 public bool is_ref, is_out;
3437 public ParameterReference (Parameters pars, int idx, string name, Location loc)
3443 eclass = ExprClass.Variable;
3446 public bool IsAssigned (EmitContext ec, Location loc)
3448 if (!is_out || !ec.DoFlowAnalysis)
3451 if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
3452 Report.Error (165, loc,
3453 "Use of unassigned local variable '" + name + "'");
3460 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3462 if (!is_out || !ec.DoFlowAnalysis)
3465 if (ec.CurrentBranching.IsParameterAssigned (idx))
3468 if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
3469 Report.Error (170, loc,
3470 "Use of possibly unassigned field '" + field_name + "'");
3477 public void SetAssigned (EmitContext ec)
3479 if (is_out && ec.DoFlowAnalysis)
3480 ec.CurrentBranching.SetParameterAssigned (idx);
3483 public void SetFieldAssigned (EmitContext ec, string field_name)
3485 if (is_out && ec.DoFlowAnalysis)
3486 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
3490 // Notice that for ref/out parameters, the type exposed is not the
3491 // same type exposed externally.
3494 // externally we expose "int&"
3495 // here we expose "int".
3497 // We record this in "is_ref". This means that the type system can treat
3498 // the type as it is expected, but when we generate the code, we generate
3499 // the alternate kind of code.
3501 public override Expression DoResolve (EmitContext ec)
3503 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3504 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3505 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3506 eclass = ExprClass.Variable;
3508 /* if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3514 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3516 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3517 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3518 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3519 eclass = ExprClass.Variable;
3521 if (is_out && ec.DoFlowAnalysis)
3522 ec.SetParameterAssigned (idx);
3527 static void EmitLdArg (ILGenerator ig, int x)
3531 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3532 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3533 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3534 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3535 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3538 ig.Emit (OpCodes.Ldarg, x);
3542 // This method is used by parameters that are references, that are
3543 // being passed as references: we only want to pass the pointer (that
3544 // is already stored in the parameter, not the address of the pointer,
3545 // and not the value of the variable).
3547 public void EmitLoad (EmitContext ec)
3549 ILGenerator ig = ec.ig;
3555 EmitLdArg (ig, arg_idx);
3558 public override void Emit (EmitContext ec)
3560 ILGenerator ig = ec.ig;
3566 EmitLdArg (ig, arg_idx);
3572 // If we are a reference, we loaded on the stack a pointer
3573 // Now lets load the real value
3575 LoadFromPtr (ig, type);
3578 public void EmitAssign (EmitContext ec, Expression source)
3580 ILGenerator ig = ec.ig;
3587 EmitLdArg (ig, arg_idx);
3592 StoreFromPtr (ig, type);
3595 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3597 ig.Emit (OpCodes.Starg, arg_idx);
3601 public void AddressOf (EmitContext ec, AddressOp mode)
3610 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3612 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3615 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3617 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3624 /// Invocation of methods or delegates.
3626 public class Invocation : ExpressionStatement {
3627 public ArrayList Arguments;
3629 public Expression expr;
3630 MethodBase method = null;
3632 bool is_latebinding;
3633 bool is_left_hand; // Needed for late bound calls
3634 bool is_retval_required; // Needed for late bound calls
3635 static Hashtable method_parameter_cache;
3636 //static MemberFilter CompareName;
3638 static ArrayList tempvars; // For ByRef - different parameter and argument type
3639 static bool is_byref_conversion = false; //For ByRef when it is converted
3640 static string errorMsg = "";
3642 static Invocation ()
3644 method_parameter_cache = new PtrHashtable ();
3648 // arguments is an ArrayList, but we do not want to typecast,
3649 // as it might be null.
3651 // FIXME: only allow expr to be a method invocation or a
3652 // delegate invocation (7.5.5)
3654 public Invocation (Expression expr, ArrayList arguments, Location l)
3657 if (this.expr is MemberAccess)
3658 ((MemberAccess) this.expr).IsInvocation = true;
3659 if (this.expr is SimpleName)
3660 ((SimpleName) this.expr).IsInvocation = true;
3661 this.is_retval_required = false;
3662 this.is_left_hand = false;
3663 Arguments = arguments;
3665 //CompareName = new MemberFilter (compare_name_filter);
3668 public Expression Expr {
3674 public bool IsLeftHand {
3676 return is_left_hand;
3679 is_left_hand = value;
3683 public bool IsRetvalRequired {
3685 return is_retval_required;
3688 is_retval_required = value;
3692 public bool IsLateBinding {
3694 return is_latebinding;
3697 is_latebinding = value;
3702 /// Returns the Parameters (a ParameterData interface) for the
3705 public static ParameterData GetParameterData (MethodBase mb)
3707 object pd = method_parameter_cache [mb];
3711 return (ParameterData) pd;
3714 ip = TypeManager.LookupParametersByBuilder (mb);
3716 method_parameter_cache [mb] = ip;
3718 return (ParameterData) ip;
3720 ParameterInfo [] pi = mb.GetParameters ();
3722 ReflectionParameters rp = new ReflectionParameters (pi);
3723 method_parameter_cache [mb] = rp;
3725 return (ParameterData) rp;
3729 enum Applicability { Same, Better, Worse };
3732 /// Determines "Better function"
3735 /// and returns an integer indicating :
3736 /// 0 if candidate ain't better
3737 /// 1 if candidate is better than the current best match
3739 static Applicability BetterFunction (EmitContext ec, ArrayList args,
3740 MethodBase candidate, MethodBase best,
3741 bool expanded_form, Location loc)
3743 ParameterData candidate_pd = GetParameterData (candidate);
3744 ParameterData best_pd;
3750 argument_count = args.Count;
3752 int cand_count = candidate_pd.Count;
3754 if (cand_count == 0 && argument_count == 0)
3755 return Applicability.Same;
3757 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3758 if (cand_count != argument_count)
3759 return Applicability.Worse;
3761 best_pd = GetParameterData (best);
3763 Applicability res = Applicability.Same;
3765 for (int j = 0; j < argument_count; ++j) {
3767 //Argument a = (Argument) args [j];
3769 Type ct = candidate_pd.ParameterType (j);
3770 Type bt = best_pd.ParameterType (j);
3772 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3774 ct = ct.GetElementType ();
3776 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3778 bt = bt.GetElementType ();
3781 if (!WideningConversionExists (ct, bt))
3782 return Applicability.Worse;
3783 res = Applicability.Better;
3787 if (res == Applicability.Same)
3788 if (candidate_pd.Count < best_pd.Count)
3789 res = Applicability.Better;
3790 else if (candidate_pd.Count > best_pd.Count)
3791 res = Applicability.Worse;
3796 public static string FullMethodDesc (MethodBase mb)
3798 string ret_type = "";
3800 if (mb is MethodInfo)
3801 ret_type = TypeManager.MonoBASIC_Name (((MethodInfo) mb).ReturnType) + " ";
3803 StringBuilder sb = new StringBuilder (ret_type + mb.Name);
3804 ParameterData pd = GetParameterData (mb);
3806 int count = pd.Count;
3809 for (int i = count; i > 0; ) {
3812 sb.Append (pd.ParameterDesc (count - i - 1));
3818 return sb.ToString ();
3821 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3823 MemberInfo [] miset;
3824 MethodGroupExpr union;
3829 return (MethodGroupExpr) mg2;
3832 return (MethodGroupExpr) mg1;
3835 MethodGroupExpr left_set = null, right_set = null;
3836 int length1 = 0, length2 = 0;
3838 left_set = (MethodGroupExpr) mg1;
3839 length1 = left_set.Methods.Length;
3841 right_set = (MethodGroupExpr) mg2;
3842 length2 = right_set.Methods.Length;
3844 ArrayList common = new ArrayList ();
3846 foreach (MethodBase l in left_set.Methods){
3847 foreach (MethodBase r in right_set.Methods){
3855 miset = new MemberInfo [length1 + length2 - common.Count];
3856 left_set.Methods.CopyTo (miset, 0);
3860 foreach (MemberInfo mi in right_set.Methods){
3861 if (!common.Contains (mi))
3865 union = new MethodGroupExpr (miset, loc);
3871 protected enum ConversionType { None, Widening, Narrowing };
3873 static ConversionType CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
3875 if (a.ArgType == Argument.AType.NoArg) {
3876 return ConversionType.Widening;
3879 Parameter.Modifier a_mod = a.GetParameterModifier () &
3880 ~(Parameter.Modifier.REF);
3881 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3882 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
3884 if (a_mod == p_mod ||
3885 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3886 // if (a_mod == Parameter.Modifier.NONE) {
3887 if (p_mod == Parameter.Modifier.PARAMS) {
3888 if (!(a.Expr is NullLiteral))
3889 if (ptype.IsArray && !a.Expr.Type.IsArray)
3890 return ConversionType.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;
3903 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3904 Type pt = pd.ParameterType (i);
3907 pt = TypeManager.LookupType (pt.FullName + "&");
3910 return ConversionType.None;
3912 return ConversionType.Widening;
3915 return ConversionType.None;
3918 static bool HasArrayParameter (ParameterData pd)
3921 return c > 0 && (pd.ParameterModifier (c - 1) & Parameter.Modifier.PARAMS) != 0;
3924 static int CountStandardParams (ParameterData pd)
3926 int count = pd.Count;
3927 for (int i = 0; i < count; i++) {
3928 Parameter.Modifier pm = pd.ParameterModifier (i);
3929 if ((pm & (Parameter.Modifier.OPTIONAL | Parameter.Modifier.PARAMS)) != 0)
3935 static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate,
3938 bool objectArgsPresent;
3939 return IsApplicable (ec, arguments, candidate, out expanded, out objectArgsPresent);
3943 /// Determines if the candidate method is applicable (section 14.4.2.1)
3944 /// to the given set of arguments
3946 static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate,
3947 out bool expanded, out bool objectArgsPresent)
3952 expanded = objectArgsPresent = false;
3953 int num_narr_conv = 0; // Count the narrowing conversion not involving object
3956 if (arguments == null)
3959 arg_count = arguments.Count;
3961 ParameterData pd = GetParameterData (candidate);
3962 int ps_count = CountStandardParams (pd);
3963 int pd_count = pd.Count;
3965 // Validate argument count
3966 if (ps_count == pd_count) {
3967 if (arg_count != pd_count)
3968 return ConversionType.None;
3971 if (arg_count < ps_count)
3972 return ConversionType.None;
3973 if (!HasArrayParameter (pd) && arg_count > pd_count)
3974 return ConversionType.None;
3977 ConversionType result = ConversionType.Widening;
3978 if (arg_count > 0) {
3979 result = ConversionType.None;
3980 int array_param_index = -1;
3981 for (int i = 0; i < arg_count; ++i) {
3982 Argument a = (Argument) arguments [i];
3983 param_type = pd.ParameterType (i);
3984 Parameter.Modifier mod = pd.ParameterModifier (i);
3985 if (array_param_index < 0 && (mod & Parameter.Modifier.PARAMS) != 0)
3986 array_param_index = i;
3988 bool IsDelegate = TypeManager.IsDelegateType (param_type);
3991 if (a.ArgType == Argument.AType.AddressOf) {
3992 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
3993 ArrayList args = new ArrayList();
3995 string param_name = pd.ParameterDesc(i).Replace('+', '.');
3996 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
3998 New temp_new = new New ((Expression)pname, args, Location.Null);
3999 Expression del_temp = temp_new.DoResolve(ec);
4001 if (del_temp == null)
4002 return ConversionType.None;
4004 a = new Argument (del_temp, Argument.AType.Expression);
4005 if (!a.Resolve(ec, Location.Null))
4006 return ConversionType.None;
4010 if (a.ArgType == Argument.AType.AddressOf)
4011 return ConversionType.None;
4014 if (a.ArgType != Argument.AType.NoArg && (mod & Parameter.Modifier.REF) != 0) {
4015 a = new Argument (a.Expr, Argument.AType.Ref);
4016 if (!a.Resolve(ec,Location.Null))
4017 return ConversionType.None;
4020 ConversionType match = ConversionType.None;
4021 if (i == array_param_index)
4022 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
4023 if (match == ConversionType.None && array_param_index >= 0 && i >= array_param_index) {
4025 param_type = param_type.GetElementType ();
4027 if (match == ConversionType.None)
4028 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
4029 if (match == ConversionType.None)
4030 return ConversionType.None;
4032 if (match == ConversionType.Narrowing) {
4034 if (a.Expr.Type == TypeManager.object_type)
4035 objectArgsPresent = true;
4037 objectArgsPresent = false;
4040 } else if (result == ConversionType.None)
4045 if (num_narr_conv > 0) // There were narrowing conversions other than those for object arguments
4046 objectArgsPresent = false;
4051 internal static ArrayList ReorderArguments (MethodBase mb,
4052 ArrayList Arguments,
4053 CaseInsensitiveHashtable namedArgs,
4057 ArrayList orderedArgs = new ArrayList ();
4058 ParameterData pd = GetParameterData (mb);
4060 for (int index = 0; index < pd.Count; index ++) {
4061 string paramName = pd.ParameterName (index);
4062 if (namedArgs.Contains (paramName)) {
4063 if ((pd.ParameterModifier (index) & Parameter.Modifier.PARAMS) == Parameter.Modifier.PARAMS) {
4065 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Named argument cannot match a ParamArray parameter";
4068 int argIndex = (int) namedArgs [paramName];
4069 orderedArgs.Add (Arguments [argIndex]);
4071 Parameter.Modifier p_mod = pd.ParameterModifier (index) & Parameter.Modifier.OPTIONAL;
4072 if (p_mod == Parameter.Modifier.OPTIONAL)
4073 orderedArgs.Add (new Argument (pd.ParameterName (index), new EmptyExpression (), Argument.AType.NoArg));
4076 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Argument not specified for parameter '" + paramName + "'";
4081 if (Arguments.Count > orderedArgs.Count) {
4082 for (int argIndex = 0; argIndex < Arguments.Count; argIndex ++) {
4083 string argName = ((Argument) Arguments [argIndex]).ParamName;
4085 for (int paramIndex = 0; paramIndex < pd.Count; paramIndex ++) {
4086 string paramName = pd.ParameterName (paramIndex);
4087 if (String.Compare (argName, paramName, true) == 0) {
4094 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': '" + argName + "' is not a parameter";
4104 static bool compare_name_filter (MemberInfo m, object filterCriteria)
4106 return (m.Name == ((string) filterCriteria));
4110 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4111 ref ArrayList Arguments, Location loc)
4113 bool isLateBindingRequired;
4114 return OverloadResolve (ec, me, ref Arguments, loc, out isLateBindingRequired);
4117 // We need an overload for OverloadResolve because Invocation.DoResolve
4118 // must pass Arguments by reference, since a later call to IsApplicable
4119 // can change the argument list if optional parameters are defined
4120 // in the method declaration
4121 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4122 ArrayList Arguments, Location loc)
4124 ArrayList a = Arguments;
4125 return OverloadResolve (ec, me, ref a, loc);
4129 static string ToString(MethodBase mbase)
4134 if (mbase is MethodBuilder)
4136 MethodBuilder mb = (MethodBuilder) mbase;
4137 String res = mb.ReturnType + " (";
4138 ParameterInfo [] parms = mb.GetParameters();
4139 for (int i = 0; i < parms.Length; i++) {
4142 res += parms[i].ParameterType;
4148 return mbase.ToString();
4153 /// Find the Applicable Function Members (7.4.2.1)
4155 /// me: Method Group expression with the members to select.
4156 /// it might contain constructors or methods (or anything
4157 /// that maps to a method).
4159 /// Arguments: ArrayList containing resolved Argument objects.
4161 /// loc: The location if we want an error to be reported, or a Null
4162 /// location for "probing" purposes.
4164 /// isLateBindingRequired : Flag to indicate that this method call is
4165 /// is a candidate for late binding. Set to true if
4166 /// there is atleast one object argument and we get
4167 /// * Two or more candidates that require widening conv
4168 /// * Two or more candidates require narrowing conversions
4169 /// (for object arguments **only**)
4170 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4171 /// that is the best match of me on Arguments.
4174 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4175 ref ArrayList Arguments, Location loc,
4176 out bool isLateBindingRequired)
4178 MethodBase method = null;
4180 ArrayList candidates = new ArrayList ();
4181 ArrayList lateBindingCandidates = new ArrayList ();
4182 Hashtable expanded_candidates = new Hashtable();
4183 int narrow_count = 0;
4184 bool narrowing_candidate = false;
4186 isLateBindingRequired = false;
4187 CaseInsensitiveHashtable namedArgs = new CaseInsensitiveHashtable ();
4189 if (Arguments == null)
4192 argument_count = Arguments.Count;
4194 if (!CheckNamedArguments (Arguments, loc))
4197 if (!GetNamedArgPos (Arguments, ref namedArgs, loc))
4200 ArrayList newarglist = Arguments;
4201 foreach (MethodBase candidate in me.Methods){
4202 bool candidate_expanded, object_args_present;
4203 newarglist = Arguments;
4204 if (argument_count > 0 && namedArgs.Count != 0) {
4205 newarglist = ReorderArguments (candidate, Arguments, namedArgs, ref errorMsg, loc);
4206 if (newarglist == null)
4210 ConversionType m = IsApplicable (ec, newarglist, candidate, out candidate_expanded, out object_args_present);
4211 if (candidate_expanded)
4212 expanded_candidates [candidate] = candidate;
4213 if (m == ConversionType.None)
4215 else if (m == ConversionType.Narrowing) {
4216 if (object_args_present) // if the narrowing conversion was due
4217 // to the argument being an object
4218 lateBindingCandidates.Add (candidate);
4219 if (method == null) {
4221 narrowing_candidate = true;
4224 } else if (m == ConversionType.Widening) {
4225 if (method == null || narrowing_candidate) {
4227 narrowing_candidate = false;
4229 Applicability res = BetterFunction (ec, Arguments, candidate, method, true, loc);
4230 if (res == Applicability.Same)
4231 continue; // should check it overrides?
4232 if (res == Applicability.Better)
4235 candidates.Add (candidate);
4239 if (candidates.Count == 0) {
4240 if (lateBindingCandidates.Count > 1) {
4241 isLateBindingRequired = true;
4245 if (narrow_count > 1) {
4246 if (lateBindingCandidates.Count == 1)
4247 method = (MethodBase) lateBindingCandidates [0];
4250 } else if (narrow_count == 1)
4252 } else if (candidates.Count == 1) {
4253 method = (MethodBase)candidates [0];
4258 if (method == null) {
4260 // Okay so we have failed to find anything so we
4261 // return by providing info about the closest match
4263 for (int i = 0; i < me.Methods.Length; ++i) {
4265 MethodBase c = (MethodBase) me.Methods [i];
4266 ParameterData pd = GetParameterData (c);
4268 if (pd.Count != argument_count)
4272 if (narrow_count != 0) {
4273 if (IsApplicable (ec, Arguments, c, out dummy) == ConversionType.None)
4275 Report.Error (1502, loc,
4276 "Overloaded match for method '" +
4277 FullMethodDesc (c) +
4278 "' requires narrowing conversionss");
4281 VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4289 // Now check that there are no ambiguities i.e the selected method
4290 // should be better than all the others
4293 if (candidates != null) {
4294 foreach (MethodBase candidate in candidates){
4295 if (candidate == method)
4299 if (BetterFunction (ec, Arguments, candidate, method,
4300 false, loc) == Applicability.Better) {
4303 "Ambiguous call of '" + me.Name + "' when selecting function due to implicit casts");
4310 // And now check if the arguments are all compatible, perform conversions
4311 // if necessary etc. and return if everything is all right
4316 bool chose_params_expanded = expanded_candidates.Contains (method);
4318 newarglist = Arguments;
4319 if (argument_count > 0 && namedArgs.Count != 0) {
4321 newarglist = ReorderArguments (method, Arguments, namedArgs, ref err, loc);
4322 if (newarglist == null)
4325 Arguments = ConstructArgumentList(ec, newarglist, namedArgs, method);
4326 if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4327 chose_params_expanded, null, loc))
4335 internal static bool CheckNamedArguments (ArrayList Arguments, Location loc)
4337 if (Arguments == null || Arguments.Count == 0)
4340 bool namedArgFound = false;
4341 for (int index = 0; index < Arguments.Count; index ++) {
4342 Argument a = (Argument) Arguments [index];
4343 if (a.ParamName == null || a.ParamName == "") {
4344 if (namedArgFound) {
4345 Report.Error (30241, loc,
4346 "Named argument expected");
4350 namedArgFound = true;
4356 internal static bool GetNamedArgPos (ArrayList Arguments, ref CaseInsensitiveHashtable namedArgs, Location loc)
4359 if (Arguments == null || Arguments.Count == 0)
4361 for (int index = 0; index < Arguments.Count; index ++) {
4362 Argument a = (Argument) Arguments [index];
4363 if (a.ParamName == null || a.ParamName == "")
4364 // none of the args are named
4366 if (namedArgs.Contains (a.ParamName)) {
4367 Report.Error (30274, loc, "Parameter '" + a.ParamName +"'already has a matching argument");
4370 namedArgs.Add (a.ParamName, index);
4375 public static ArrayList ConstructArgumentList (EmitContext ec, ArrayList Arguments, CaseInsensitiveHashtable namedArgs, MethodBase method)
4377 ArrayList newarglist = new ArrayList();
4378 int arg_count = Arguments == null ? 0 : Arguments.Count;
4380 ParameterData pd = GetParameterData (method);
4381 bool argNamesGiven = (namedArgs.Count > 0);
4382 for (int i = 0; i < arg_count; i++) {
4383 Argument a = (Argument) Arguments [i];
4384 Type param_type = pd.ParameterType (i);
4386 bool IsDelegate = TypeManager.IsDelegateType (param_type);
4387 if (a.ArgType == Argument.AType.NoArg) {
4388 Expression pdvalue = pd.DefaultValue (i);
4389 pdvalue.Resolve (ec);
4390 if (pdvalue != NullLiteral.Null)
4391 pdvalue = ConvertImplicit (ec, pdvalue, param_type, Location.Null);;
4393 a = new Argument (pd.ParameterName (i), pdvalue, Argument.AType.Expression);
4395 a = new Argument (pdvalue, Argument.AType.Expression);
4396 a.Resolve (ec, Location.Null);
4400 if (a.ArgType == Argument.AType.AddressOf) {
4401 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
4402 ArrayList args = new ArrayList();
4404 string param_name = pd.ParameterDesc(i).Replace('+', '.');
4405 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
4407 New temp_new = new New ((Expression)pname, args, Location.Null);
4408 Expression del_temp = temp_new.DoResolve(ec);
4409 a = new Argument (del_temp, Argument.AType.Expression);
4410 a.Resolve(ec, Location.Null);
4413 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0) {
4414 a.ArgType = Argument.AType.Ref;
4415 a.Resolve(ec, Location.Null);
4421 if (HasArrayParameter (pd) && arg_count == pd.Count - 1)
4424 for (int i = arg_count; i < pd.Count; i++) {
4425 Type param_type = pd.ParameterType (i);
4426 Expression e = pd.DefaultValue (i);
4428 if (e != NullLiteral.Null)
4429 e = ConvertImplicit (ec, e, param_type, Location.Null);
4432 a = new Argument (e, Argument.AType.Expression);
4434 a = new Argument (pd.ParameterName (i), e, Argument.AType.Expression);
4435 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0)
4436 a.ArgType = Argument.AType.Ref;
4437 a.Resolve (ec, Location.Null);
4444 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4447 bool chose_params_expanded,
4451 return (VerifyArgumentsCompat (ec, Arguments, argument_count,
4452 method, chose_params_expanded, delegate_type, loc, null));
4455 public static bool VerifyArgumentsCompat (EmitContext ec,
4456 ArrayList Arguments,
4459 bool chose_params_expanded,
4462 string InvokingProperty)
4464 ParameterData pd = GetParameterData (method);
4465 int pd_count = pd.Count;
4467 for (int j = 0; j < argument_count; j++) {
4468 Argument a = (Argument) Arguments [j];
4469 Expression a_expr = a.Expr;
4470 Type parameter_type = pd.ParameterType(j);
4472 if (parameter_type == null)
4474 Error_WrongNumArguments(loc, (InvokingProperty == null)?((delegate_type == null)?FullMethodDesc (method):delegate_type.ToString ()):InvokingProperty, argument_count);
4477 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
4478 chose_params_expanded)
4479 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
4480 // By pass conversion for foll. case and handle it in EmitArguments()
4482 if (a.ArgType != Argument.AType.Ref && a.Type != parameter_type){
4485 conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
4488 if (!Location.IsNull (loc)) {
4489 if (delegate_type == null)
4490 if (InvokingProperty == null)
4491 Report.Error (1502, loc,
4492 "The best overloaded match for method '" +
4493 FullMethodDesc (method) +
4494 "' has some invalid arguments");
4496 Report.Error (1502, loc,
4499 "' has some invalid arguments");
4501 Report.Error (1594, loc,
4502 "Delegate '" + delegate_type.ToString () +
4503 "' has some invalid arguments.");
4504 Report.Error (1503, loc,
4505 "Argument " + (j+1) +
4506 ": Cannot convert from '" + Argument.FullDesc (a)
4507 + "' to '" + pd.ParameterDesc (j) + "'");
4514 // Update the argument with the implicit conversion
4520 Parameter.Modifier a_mod = a.GetParameterModifier () &
4521 ~(Parameter.Modifier.REF);
4522 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4523 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
4525 if (a_mod != p_mod &&
4526 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4527 if (!Location.IsNull (loc)) {
4528 Report.Error (1502, loc,
4529 "The best overloaded match for method '" + FullMethodDesc (method)+
4530 "' has some invalid arguments");
4531 Report.Error (1503, loc,
4532 "Argument " + (j+1) +
4533 ": Cannot convert from '" + Argument.FullDesc (a)
4534 + "' to '" + pd.ParameterDesc (j) + "'");
4544 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4546 this.is_left_hand = true;
4547 Expression expr_to_return = DoResolve (ec);
4548 if (expr_to_return is PropertyGroupExpr) {
4549 PropertyGroupExpr pe = expr_to_return as PropertyGroupExpr;
4550 pe = (PropertyGroupExpr) pe.ResolveLValue (ec, right_side);
4553 if (pe.IndexerAccessRequired) {
4554 if (pe.Type.IsArray) {
4555 // If we are here, expr must be an ArrayAccess
4556 ArrayList idxs = new ArrayList();
4557 foreach (Argument a in Arguments)
4561 ElementAccess ea = new ElementAccess (expr_to_return, idxs, expr.Location);
4562 ArrayAccess aa = new ArrayAccess (ea, expr_to_return.Location);
4563 expr_to_return = aa.DoResolve(ec);
4564 expr_to_return.eclass = ExprClass.Variable;
4567 // check whether this is a indexer
4569 ArrayList idxs = new ArrayList();
4570 foreach (Argument a in Arguments) {
4573 ElementAccess ea = new ElementAccess (expr_to_return, idxs, expr.Location);
4574 IndexerAccess ia = new IndexerAccess (ea, expr_to_return.Location);
4576 expr_to_return = ia.DoResolveLValue (ec, right_side);
4578 expr_to_return = ia.DoResolve(ec);
4580 return expr_to_return;
4584 if (expr_to_return is IndexerAccess && is_left_hand) {
4585 IndexerAccess ia = expr_to_return as IndexerAccess;
4586 expr_to_return = ia.DoResolveLValue (ec, right_side);
4589 return expr_to_return;
4592 public override Expression DoResolve (EmitContext ec)
4594 if (method != null) // already resolved
4597 // First, resolve the expression that is used to
4598 // trigger the invocation
4600 Expression expr_to_return = null;
4601 Expression temp = null;
4603 if (expr is BaseAccess)
4607 if ((ec.ReturnType != null) && (expr.ToString() == ec.BlockName)) {
4608 ec.InvokingOwnOverload = true;
4609 flags = ResolveFlags.MethodGroup;
4610 temp = expr.Resolve (ec, flags);
4611 ec.InvokingOwnOverload = false;
4615 ec.InvokingOwnOverload = false;
4616 flags = ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup;
4617 temp = expr.Resolve (ec, flags);
4624 if (expr is MemberAccess) {
4625 MemberAccess m = expr as MemberAccess;
4626 if (m.Expr.Type == TypeManager.object_type) {
4627 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4628 loc, expr, Arguments,
4629 is_retval_required, is_left_hand);
4630 if (!etmp.ResolveArguments (ec))
4632 etmp.GenerateLateBindingStatements();
4633 this.is_latebinding = true;
4634 return etmp.Resolve (ec);
4642 if (expr is Invocation) {
4643 // FIXME Calls which return an Array are not resolved (here or in the grammar)
4644 expr = expr.Resolve(ec);
4647 if (!(expr is MethodGroupExpr || expr is PropertyGroupExpr))
4649 Type expr_type = expr.Type;
4651 if (expr_type != null)
4653 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4655 return (new DelegateInvocation (
4656 this.expr, Arguments, loc)).Resolve (ec);
4661 // Next, evaluate all the expressions in the argument list
4663 if (Arguments != null)
4665 foreach (Argument a in Arguments)
4667 if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
4668 Report.Error (999, "This item cannot have empty arguments");
4670 if (!a.Resolve (ec, loc))
4675 if (expr is MethodGroupExpr)
4677 MethodGroupExpr mg = (MethodGroupExpr) expr;
4678 bool isLateBindingRequired = false;
4679 method = OverloadResolve (ec, mg, ref Arguments, loc, out isLateBindingRequired);
4682 if (isLateBindingRequired) {
4683 Expression type_expr = new TypeOf (Parser.DecomposeQI (mg.DeclaringType.Name, loc), loc);
4684 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4685 loc, null, mg.Name, type_expr,
4686 Arguments, is_retval_required, is_left_hand);
4687 if (! etmp.ResolveArguments (ec))
4689 etmp.GenerateLateBindingStatements ();
4690 return etmp.Resolve (ec);
4693 "Could not find any applicable function to invoke for this argument list" + errorMsg);
4697 if ((method as MethodInfo) != null)
4699 MethodInfo mi = method as MethodInfo;
4700 type = TypeManager.TypeToCoreType (mi.ReturnType);
4701 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4702 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4705 if ((method as ConstructorInfo) != null)
4707 ConstructorInfo ci = method as ConstructorInfo;
4708 type = TypeManager.void_type;
4709 if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4710 SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);
4721 eclass = ExprClass.Value;
4722 expr_to_return = this;
4723 return expr_to_return;
4726 if (expr is PropertyGroupExpr)
4728 PropertyGroupExpr pe = ((PropertyGroupExpr) expr);
4729 if (pe.Arguments != null)
4730 goto skip_already_resolved_property;
4731 if (Arguments != null)
4732 pe.Arguments = (ArrayList) Arguments.Clone ();
4735 string name = pe.Name;
4736 pe = (PropertyGroupExpr) pe.Resolve (ec);
4738 Error (30057, "Property '" + name + "' cannot be invoked with given arguments");
4742 if (!pe.IndexerAccessRequired)
4747 skip_already_resolved_property:
4748 if (expr.Type.IsArray) {
4749 // If we are here, expr must be an ArrayAccess
4750 ArrayList idxs = new ArrayList();
4751 foreach (Argument a in Arguments)
4755 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4756 ArrayAccess aa = new ArrayAccess (ea, expr.Location);
4757 expr_to_return = aa.DoResolve(ec);
4758 expr_to_return.eclass = ExprClass.Variable;
4761 // check whether this is a indexer
4763 ArrayList idxs = new ArrayList();
4764 foreach (Argument a in Arguments) {
4767 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4768 IndexerAccess ia = new IndexerAccess (ea, expr.Location);
4770 expr_to_return = ia.DoResolve(ec);
4772 expr_to_return = ia.DoResolve(ec);
4774 // Since all the above are failed we need to do
4777 if (expr_to_return == null) {
4779 // We can't resolve now, but we
4780 // have to try to access the array with a call
4781 // to LateIndexGet/Set in the runtime
4782 if (! is_left_hand) {
4783 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4786 if (!etmp.ResolveArguments (ec))
4788 etmp.GenerateLateBindingStatements();
4789 return etmp.Resolve (ec);
4795 return expr_to_return;
4798 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4800 Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
4801 arg_count + "' arguments");
4805 // Emits the list of arguments as an array
4807 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4809 ILGenerator ig = ec.ig;
4810 int count = arguments.Count - idx;
4811 Argument a = (Argument) arguments [idx];
4812 Type t = a.Expr.Type;
4813 string array_type = t.FullName + "[]";
4816 array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4817 IntConstant.EmitInt (ig, count);
4818 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4819 ig.Emit (OpCodes.Stloc, array);
4821 int top = arguments.Count;
4822 for (int j = idx; j < top; j++){
4823 a = (Argument) arguments [j];
4825 ig.Emit (OpCodes.Ldloc, array);
4826 IntConstant.EmitInt (ig, j - idx);
4829 ArrayAccess.EmitStoreOpcode (ig, t);
4831 ig.Emit (OpCodes.Ldloc, array);
4835 /// Emits a list of resolved Arguments that are in the arguments
4838 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4840 ParameterData pd = GetParameterData (mb);
4842 // If we are calling a params method with no arguments, special case it
4844 if (arguments == null){
4846 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4847 ILGenerator ig = ec.ig;
4849 IntConstant.EmitInt (ig, 0);
4850 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4855 int top = arguments.Count;
4857 for (int i = 0; i < top; i++){
4858 Argument a = (Argument) arguments [i];
4859 Type parameter_type = pd.ParameterType(i);
4860 Type argtype = a.Type;
4861 Type arg_expr_type = a.Expr.Type;
4863 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4865 // Special case if we are passing the same data as the
4866 // params argument, do not put it in an array.
4868 if (pd.ParameterType (i) == a.Type)
4871 EmitParams (ec, i, arguments);
4874 if ((a.ArgType == Argument.AType.Ref ) &&
4875 (parameter_type != arg_expr_type ||
4876 ! (a.Expr is IMemoryLocation))) {
4878 LocalTemporary localtmp = new LocalTemporary (ec, parameter_type );
4880 if((arg_expr_type != parameter_type) && (a.ArgType == Argument.AType.Ref)) {
4881 Expression e = ConvertImplicit (ec, a.Expr, parameter_type, Location.Null);
4882 is_byref_conversion = true;
4889 if (tempvars == null)
4890 tempvars = new ArrayList ();
4891 if (a.Expr is IMemoryLocation && is_byref_conversion ) {
4894 argtype = argtype.GetElementType();
4895 conv = ConvertImplicit (ec, localtmp, argtype, Location.Null);
4896 tempvars.Add (new Assign (a.Expr, conv, Location.Null));
4898 } else if (a.Expr is PropertyGroupExpr) {
4899 // FIXME: We shouldnt be doing Resolve from inside 'Emit'.
4900 // Have to find a way to push this up to 'Resolve'
4903 argtype = argtype.GetElementType();
4904 conv = ConvertImplicit (ec, localtmp, argtype, Location.Null);
4905 Assign assgn = new Assign (a.Expr, conv, Location.Null);
4906 Expression e = assgn.Resolve (ec);
4909 localtmp.Store (ec);
4910 a = new Argument (localtmp, a.ArgType);
4917 if (pd.Count > top &&
4918 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4919 ILGenerator ig = ec.ig;
4921 IntConstant.EmitInt (ig, 0);
4922 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4927 /// is_base tells whether we want to force the use of the 'call'
4928 /// opcode instead of using callvirt. Call is required to call
4929 /// a specific method, while callvirt will always use the most
4930 /// recent method in the vtable.
4932 /// is_static tells whether this is an invocation on a static method
4934 /// instance_expr is an expression that represents the instance
4935 /// it must be non-null if is_static is false.
4937 /// method is the method to invoke.
4939 /// Arguments is the list of arguments to pass to the method or constructor.
4941 public static void EmitCall (EmitContext ec, bool is_base,
4942 bool is_static, Expression instance_expr,
4943 MethodBase method, ArrayList Arguments, Location loc)
4945 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
4948 public static void EmitCall (EmitContext ec, bool is_base,
4949 bool is_static, Expression instance_expr,
4950 MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)
4952 ILGenerator ig = ec.ig;
4953 bool struct_call = false;
4954 bool is_myclass = false;
4956 if (instance_expr is This && ((This) instance_expr).AccessType == This.TypeOfAccess.MyClass)
4959 Type decl_type = method.DeclaringType;
4961 if (!RootContext.StdLib)
4963 // Replace any calls to the system's System.Array type with calls to
4964 // the newly created one.
4965 if (method == TypeManager.system_int_array_get_length)
4966 method = TypeManager.int_array_get_length;
4967 else if (method == TypeManager.system_int_array_get_rank)
4968 method = TypeManager.int_array_get_rank;
4969 else if (method == TypeManager.system_object_array_clone)
4970 method = TypeManager.object_array_clone;
4971 else if (method == TypeManager.system_int_array_get_length_int)
4972 method = TypeManager.int_array_get_length_int;
4973 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4974 method = TypeManager.int_array_get_lower_bound_int;
4975 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4976 method = TypeManager.int_array_get_upper_bound_int;
4977 else if (method == TypeManager.system_void_array_copyto_array_int)
4978 method = TypeManager.void_array_copyto_array_int;
4982 // This checks the 'ConditionalAttribute' on the method, and the
4983 // ObsoleteAttribute
4985 TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4986 if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4988 if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4993 if (decl_type.IsValueType)
4996 // If this is ourselves, push "this"
4998 if (instance_expr == null)
5000 ig.Emit (OpCodes.Ldarg_0);
5005 // Push the instance expression
5007 if (instance_expr.Type.IsValueType)
5010 // Special case: calls to a function declared in a
5011 // reference-type with a value-type argument need
5012 // to have their value boxed.
5015 if (decl_type.IsValueType)
5018 // If the expression implements IMemoryLocation, then
5019 // we can optimize and use AddressOf on the
5022 // If not we have to use some temporary storage for
5024 if (instance_expr is IMemoryLocation)
5026 ((IMemoryLocation)instance_expr).
5027 AddressOf (ec, AddressOp.LoadStore);
5031 Type t = instance_expr.Type;
5033 instance_expr.Emit (ec);
5034 LocalBuilder temp = ig.DeclareLocal (t);
5035 ig.Emit (OpCodes.Stloc, temp);
5036 ig.Emit (OpCodes.Ldloca, temp);
5041 instance_expr.Emit (ec);
5042 ig.Emit (OpCodes.Box, instance_expr.Type);
5046 instance_expr.Emit (ec);
5050 if (prop_args != null && prop_args.Count > 0)
5052 if (Arguments == null)
5053 Arguments = new ArrayList();
5055 for (int i = prop_args.Count-1; i >=0 ; i--)
5057 Arguments.Insert (0,prop_args[i]);
5062 EmitArguments (ec, method, Arguments);
5064 if (is_static || struct_call || is_base || is_myclass)
5066 if (method is MethodInfo)
5068 ig.Emit (OpCodes.Call, (MethodInfo) method);
5071 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5075 if (method is MethodInfo)
5076 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
5078 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
5083 static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
5085 int top = prop_args.Count;
5087 for (int i = 0; i < top; i++)
5089 Argument a = (Argument) prop_args [i];
5095 public override void Emit (EmitContext ec)
5097 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5100 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5103 public override void EmitStatement (EmitContext ec)
5108 // Pop the return value if there is one
5110 if (method is MethodInfo){
5111 Type ret = ((MethodInfo)method).ReturnType;
5112 if ((TypeManager.TypeToCoreType (ret) != TypeManager.void_type) && !this.is_latebinding) {
5113 ec.ig.Emit (OpCodes.Pop);
5115 if (tempvars != null) {
5116 foreach (Expression s in tempvars) {
5117 if (s is ExpressionStatement)
5118 ((ExpressionStatement) s).EmitStatement (ec);
5131 // This class is used to "disable" the code generation for the
5132 // temporary variable when initializing value types.
5134 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5135 public void AddressOf (EmitContext ec, AddressOp Mode)
5142 /// Implements the new expression
5144 public class New : ExpressionStatement {
5145 public readonly ArrayList Arguments;
5146 public readonly Expression RequestedType;
5148 MethodBase method = null;
5151 // If set, the new expression is for a value_target, and
5152 // we will not leave anything on the stack.
5154 Expression value_target;
5155 bool value_target_set = false;
5156 public bool isDelegate = false;
5158 public New (Expression requested_type, ArrayList arguments, Location l)
5160 RequestedType = requested_type;
5161 Arguments = arguments;
5165 public Expression ValueTypeVariable {
5167 return value_target;
5171 value_target = value;
5172 value_target_set = true;
5177 // This function is used to disable the following code sequence for
5178 // value type initialization:
5180 // AddressOf (temporary)
5184 // Instead the provide will have provided us with the address on the
5185 // stack to store the results.
5187 static Expression MyEmptyExpression;
5189 public void DisableTemporaryValueType ()
5191 if (MyEmptyExpression == null)
5192 MyEmptyExpression = new EmptyAddressOf ();
5195 // To enable this, look into:
5196 // test-34 and test-89 and self bootstrapping.
5198 // For instance, we can avoid a copy by using 'newobj'
5199 // instead of Call + Push-temp on value types.
5200 // value_target = MyEmptyExpression;
5203 public override Expression DoResolve (EmitContext ec)
5205 if (this.isDelegate) {
5206 // if its a delegate resolve the type of RequestedType first
5207 Expression dtype = RequestedType.Resolve(ec);
5208 string ts = (dtype.Type.ToString()).Replace ('+','.');
5209 dtype = Mono.MonoBASIC.Parser.DecomposeQI (ts, Location.Null);
5211 type = ec.DeclSpace.ResolveType (dtype, false, loc);
5214 type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5219 bool IsDelegate = TypeManager.IsDelegateType (type);
5222 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5224 if (type.IsInterface || type.IsAbstract){
5226 30376, "It is not possible to create instances of Interfaces " +
5227 "or classes marked as MustInherit");
5231 bool is_struct = false;
5232 is_struct = type.IsValueType;
5233 eclass = ExprClass.Value;
5236 // SRE returns a match for .ctor () on structs (the object constructor),
5237 // so we have to manually ignore it.
5239 if (is_struct && Arguments == null)
5243 ml = MemberLookupFinal (ec, type, ".ctor",
5244 MemberTypes.Constructor,
5245 AllBindingFlags | BindingFlags.Public, loc);
5250 if (! (ml is MethodGroupExpr)){
5252 ml.Error118 ("method group");
5258 if (Arguments != null){
5259 foreach (Argument a in Arguments){
5260 if (!a.Resolve (ec, loc))
5265 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
5270 if (method == null) {
5271 if (!is_struct || Arguments.Count > 0) {
5273 "New invocation: Can not find a constructor for " +
5274 "this argument list");
5282 // This DoEmit can be invoked in two contexts:
5283 // * As a mechanism that will leave a value on the stack (new object)
5284 // * As one that wont (init struct)
5286 // You can control whether a value is required on the stack by passing
5287 // need_value_on_stack. The code *might* leave a value on the stack
5288 // so it must be popped manually
5290 // If we are dealing with a ValueType, we have a few
5291 // situations to deal with:
5293 // * The target is a ValueType, and we have been provided
5294 // the instance (this is easy, we are being assigned).
5296 // * The target of New is being passed as an argument,
5297 // to a boxing operation or a function that takes a
5300 // In this case, we need to create a temporary variable
5301 // that is the argument of New.
5303 // Returns whether a value is left on the stack
5305 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5307 bool is_value_type = type.IsValueType;
5308 ILGenerator ig = ec.ig;
5313 // Allow DoEmit() to be called multiple times.
5314 // We need to create a new LocalTemporary each time since
5315 // you can't share LocalBuilders among ILGeneators.
5316 if (!value_target_set)
5317 value_target = new LocalTemporary (ec, type);
5319 ml = (IMemoryLocation) value_target;
5320 ml.AddressOf (ec, AddressOp.Store);
5324 Invocation.EmitArguments (ec, method, Arguments);
5328 ig.Emit (OpCodes.Initobj, type);
5330 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5331 if (need_value_on_stack){
5332 value_target.Emit (ec);
5337 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5342 public override void Emit (EmitContext ec)
5347 public override void EmitStatement (EmitContext ec)
5349 if (DoEmit (ec, false))
5350 ec.ig.Emit (OpCodes.Pop);
5355 /// 14.5.10.2: Represents an array creation expression.
5359 /// There are two possible scenarios here: one is an array creation
5360 /// expression that specifies the dimensions and optionally the
5361 /// initialization data and the other which does not need dimensions
5362 /// specified but where initialization data is mandatory.
5364 public class ArrayCreation : ExpressionStatement {
5365 Expression requested_base_type;
5366 ArrayList initializers;
5369 // The list of Argument types.
5370 // This is used to construct the 'newarray' or constructor signature
5372 ArrayList arguments;
5375 // Method used to create the array object.
5377 MethodBase new_method = null;
5379 Type array_element_type;
5380 Type underlying_type;
5381 bool is_one_dimensional = false;
5382 bool is_builtin_type = false;
5383 bool expect_initializers = false;
5384 int num_arguments = 0;
5388 ArrayList array_data;
5393 // The number of array initializers that we can handle
5394 // via the InitializeArray method - through EmitStaticInitializers
5396 int num_automatic_initializers;
5398 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5400 this.requested_base_type = requested_base_type;
5401 this.initializers = initializers;
5405 arguments = new ArrayList ();
5407 foreach (Expression e in exprs) {
5408 arguments.Add (new Argument (e, Argument.AType.Expression));
5413 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5415 this.requested_base_type = requested_base_type;
5416 this.initializers = initializers;
5420 //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
5422 //string tmp = rank.Substring (rank.LastIndexOf ("["));
5424 //dimensions = tmp.Length - 1;
5425 expect_initializers = true;
5428 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5430 StringBuilder sb = new StringBuilder (rank);
5433 for (int i = 1; i < idx_count; i++)
5438 return new ComposedCast (base_type, sb.ToString (), loc);
5441 void Error_IncorrectArrayInitializer ()
5443 Error (30567, "Incorrectly structured array initializer");
5446 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5448 if (specified_dims) {
5449 Argument a = (Argument) arguments [idx];
5451 if (!a.Resolve (ec, loc))
5454 if (!(a.Expr is Constant)) {
5455 Error (150, "A constant value is expected");
5459 int value = (int) ((Constant) a.Expr).GetValue ();
5461 if (value != probe.Count) {
5462 Error_IncorrectArrayInitializer ();
5466 bounds [idx] = value;
5469 int child_bounds = -1;
5470 foreach (object o in probe) {
5471 if (o is ArrayList) {
5472 int current_bounds = ((ArrayList) o).Count;
5474 if (child_bounds == -1)
5475 child_bounds = current_bounds;
5477 else if (child_bounds != current_bounds){
5478 Error_IncorrectArrayInitializer ();
5481 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5485 if (child_bounds != -1){
5486 Error_IncorrectArrayInitializer ();
5490 Expression tmp = (Expression) o;
5491 tmp = tmp.Resolve (ec);
5495 // Console.WriteLine ("I got: " + tmp);
5496 // Handle initialization from vars, fields etc.
5498 Expression conv = ConvertImplicitRequired (
5499 ec, tmp, underlying_type, loc);
5504 if (conv is StringConstant)
5505 array_data.Add (conv);
5506 else if (conv is Constant) {
5507 array_data.Add (conv);
5508 num_automatic_initializers++;
5510 array_data.Add (conv);
5517 public void UpdateIndices (EmitContext ec)
5520 for (ArrayList probe = initializers; probe != null;) {
5521 if (probe.Count > 0 && probe [0] is ArrayList) {
5522 Expression e = new IntConstant (probe.Count);
5523 arguments.Add (new Argument (e, Argument.AType.Expression));
5525 bounds [i++] = probe.Count;
5527 probe = (ArrayList) probe [0];
5530 Expression e = new IntConstant (probe.Count);
5531 arguments.Add (new Argument (e, Argument.AType.Expression));
5533 bounds [i++] = probe.Count;
5540 public bool ValidateInitializers (EmitContext ec, Type array_type)
5542 if (initializers == null) {
5543 if (expect_initializers)
5549 if (underlying_type == null)
5553 // We use this to store all the date values in the order in which we
5554 // will need to store them in the byte blob later
5556 array_data = new ArrayList ();
5557 bounds = new Hashtable ();
5561 if (arguments != null) {
5562 ret = CheckIndices (ec, initializers, 0, true);
5565 arguments = new ArrayList ();
5567 ret = CheckIndices (ec, initializers, 0, false);
5574 if (arguments.Count != dimensions) {
5575 Error_IncorrectArrayInitializer ();
5584 void Error_NegativeArrayIndex ()
5586 Error (284, "Can not create array with a negative size");
5590 // Converts 'source' to an int, uint, long or ulong.
5592 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5596 bool old_checked = ec.CheckState;
5597 ec.CheckState = true;
5599 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
5600 if (target == null){
5601 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
5602 if (target == null){
5603 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
5604 if (target == null){
5605 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
5607 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
5611 ec.CheckState = old_checked;
5614 // Only positive constants are allowed at compile time
5616 if (target is Constant){
5617 if (target is IntConstant){
5618 if (((IntConstant) target).Value < 0){
5619 Error_NegativeArrayIndex ();
5624 if (target is LongConstant){
5625 if (((LongConstant) target).Value < 0){
5626 Error_NegativeArrayIndex ();
5638 // Creates the type of the array
5640 bool LookupType (EmitContext ec)
5642 StringBuilder array_qualifier = new StringBuilder (rank);
5645 // 'In the first form allocates an array instace of the type that results
5646 // from deleting each of the individual expression from the expression list'
5648 if (num_arguments > 0) {
5649 array_qualifier.Append ("[");
5650 for (int i = num_arguments-1; i > 0; i--)
5651 array_qualifier.Append (",");
5652 array_qualifier.Append ("]");
5658 Expression array_type_expr;
5659 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5660 type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5665 underlying_type = type;
5666 if (underlying_type.IsArray)
5667 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
5668 dimensions = type.GetArrayRank ();
5673 public override Expression DoResolve (EmitContext ec)
5677 if (!LookupType (ec))
5681 // First step is to validate the initializers and fill
5682 // in any missing bits
5684 if (!ValidateInitializers (ec, type))
5687 if (arguments == null)
5690 arg_count = arguments.Count;
5691 foreach (Argument a in arguments){
5692 if (!a.Resolve (ec, loc))
5695 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5696 if (real_arg == null)
5703 array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
5705 if (arg_count == 1) {
5706 is_one_dimensional = true;
5707 eclass = ExprClass.Value;
5711 is_builtin_type = TypeManager.IsBuiltinType (type);
5713 if (is_builtin_type) {
5716 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5717 AllBindingFlags, loc);
5719 if (!(ml is MethodGroupExpr)) {
5720 ml.Error118 ("method group");
5725 Error (-6, "New invocation: Can not find a constructor for " +
5726 "this argument list");
5730 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5732 if (new_method == null) {
5733 Error (-6, "New invocation: Can not find a constructor for " +
5734 "this argument list");
5738 eclass = ExprClass.Value;
5741 ModuleBuilder mb = CodeGen.ModuleBuilder;
5742 ArrayList args = new ArrayList ();
5744 if (arguments != null) {
5745 for (int i = 0; i < arg_count; i++)
5746 args.Add (TypeManager.int32_type);
5749 Type [] arg_types = null;
5752 arg_types = new Type [args.Count];
5754 args.CopyTo (arg_types, 0);
5756 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5759 if (new_method == null) {
5760 Error (-6, "New invocation: Can not find a constructor for " +
5761 "this argument list");
5765 eclass = ExprClass.Value;
5770 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5775 int count = array_data.Count;
5777 if (underlying_type.IsEnum)
5778 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5780 factor = GetTypeSize (underlying_type);
5782 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5784 data = new byte [(count * factor + 4) & ~3];
5787 for (int i = 0; i < count; ++i) {
5788 object v = array_data [i];
5790 if (v is EnumConstant)
5791 v = ((EnumConstant) v).Child;
5793 if (v is Constant && !(v is StringConstant))
5794 v = ((Constant) v).GetValue ();
5800 if (underlying_type == TypeManager.int64_type){
5801 if (!(v is Expression)){
5802 long val = (long) v;
5804 for (int j = 0; j < factor; ++j) {
5805 data [idx + j] = (byte) (val & 0xFF);
5809 } else if (underlying_type == TypeManager.uint64_type){
5810 if (!(v is Expression)){
5811 ulong val = (ulong) v;
5813 for (int j = 0; j < factor; ++j) {
5814 data [idx + j] = (byte) (val & 0xFF);
5818 } else if (underlying_type == TypeManager.float_type) {
5819 if (!(v is Expression)){
5820 element = BitConverter.GetBytes ((float) v);
5822 for (int j = 0; j < factor; ++j)
5823 data [idx + j] = element [j];
5825 } else if (underlying_type == TypeManager.double_type) {
5826 if (!(v is Expression)){
5827 element = BitConverter.GetBytes ((double) v);
5829 for (int j = 0; j < factor; ++j)
5830 data [idx + j] = element [j];
5832 } else if (underlying_type == TypeManager.char_type){
5833 if (!(v is Expression)){
5834 int val = (int) ((char) v);
5836 data [idx] = (byte) (val & 0xff);
5837 data [idx+1] = (byte) (val >> 8);
5839 } else if (underlying_type == TypeManager.short_type){
5840 if (!(v is Expression)){
5841 int val = (int) ((short) v);
5843 data [idx] = (byte) (val & 0xff);
5844 data [idx+1] = (byte) (val >> 8);
5846 } else if (underlying_type == TypeManager.ushort_type){
5847 if (!(v is Expression)){
5848 int val = (int) ((ushort) v);
5850 data [idx] = (byte) (val & 0xff);
5851 data [idx+1] = (byte) (val >> 8);
5853 } else if (underlying_type == TypeManager.int32_type) {
5854 if (!(v is Expression)){
5857 data [idx] = (byte) (val & 0xff);
5858 data [idx+1] = (byte) ((val >> 8) & 0xff);
5859 data [idx+2] = (byte) ((val >> 16) & 0xff);
5860 data [idx+3] = (byte) (val >> 24);
5862 } else if (underlying_type == TypeManager.uint32_type) {
5863 if (!(v is Expression)){
5864 uint val = (uint) v;
5866 data [idx] = (byte) (val & 0xff);
5867 data [idx+1] = (byte) ((val >> 8) & 0xff);
5868 data [idx+2] = (byte) ((val >> 16) & 0xff);
5869 data [idx+3] = (byte) (val >> 24);
5871 } else if (underlying_type == TypeManager.sbyte_type) {
5872 if (!(v is Expression)){
5873 sbyte val = (sbyte) v;
5874 data [idx] = (byte) val;
5876 } else if (underlying_type == TypeManager.byte_type) {
5877 if (!(v is Expression)){
5878 byte val = (byte) v;
5879 data [idx] = (byte) val;
5881 } else if (underlying_type == TypeManager.bool_type) {
5882 if (!(v is Expression)){
5883 bool val = (bool) v;
5884 data [idx] = (byte) (val ? 1 : 0);
5886 } else if (underlying_type == TypeManager.decimal_type){
5887 if (!(v is Expression)){
5888 int [] bits = Decimal.GetBits ((decimal) v);
5891 for (int j = 0; j < 4; j++){
5892 data [p++] = (byte) (bits [j] & 0xff);
5893 data [p++] = (byte) ((bits [j] >> 8) & 0xff);
5894 data [p++] = (byte) ((bits [j] >> 16) & 0xff);
5895 data [p++] = (byte) (bits [j] >> 24);
5899 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5908 // Emits the initializers for the array
5910 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5913 // First, the static data
5916 ILGenerator ig = ec.ig;
5918 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5920 fb = RootContext.MakeStaticData (data);
5923 ig.Emit (OpCodes.Dup);
5924 ig.Emit (OpCodes.Ldtoken, fb);
5925 ig.Emit (OpCodes.Call,
5926 TypeManager.void_initializearray_array_fieldhandle);
5930 // Emits pieces of the array that can not be computed at compile
5931 // time (variables and string locations).
5933 // This always expect the top value on the stack to be the array
5935 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5937 ILGenerator ig = ec.ig;
5938 int dims = bounds.Count;
5939 int [] current_pos = new int [dims];
5940 int top = array_data.Count;
5941 LocalBuilder temp = ig.DeclareLocal (type);
5943 ig.Emit (OpCodes.Stloc, temp);
5945 MethodInfo set = null;
5949 ModuleBuilder mb = null;
5950 mb = CodeGen.ModuleBuilder;
5951 args = new Type [dims + 1];
5954 for (j = 0; j < dims; j++)
5955 args [j] = TypeManager.int32_type;
5957 args [j] = array_element_type;
5959 set = mb.GetArrayMethod (
5961 CallingConventions.HasThis | CallingConventions.Standard,
5962 TypeManager.void_type, args);
5965 for (int i = 0; i < top; i++){
5967 Expression e = null;
5969 if (array_data [i] is Expression)
5970 e = (Expression) array_data [i];
5974 // Basically we do this for string literals and
5975 // other non-literal expressions
5977 if (e is StringConstant || !(e is Constant) ||
5978 num_automatic_initializers <= 2) {
5979 Type etype = e.Type;
5981 ig.Emit (OpCodes.Ldloc, temp);
5983 for (int idx = 0; idx < dims; idx++)
5984 IntConstant.EmitInt (ig, current_pos [idx]);
5987 // If we are dealing with a struct, get the
5988 // address of it, so we can store it.
5991 etype.IsSubclassOf (TypeManager.value_type) &&
5992 (!TypeManager.IsBuiltinType (etype) ||
5993 etype == TypeManager.decimal_type)) {
5998 // Let new know that we are providing
5999 // the address where to store the results
6001 n.DisableTemporaryValueType ();
6004 ig.Emit (OpCodes.Ldelema, etype);
6010 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
6012 ig.Emit (OpCodes.Call, set);
6019 for (int j = dims - 1; j >= 0; j--){
6021 if (current_pos [j] < (int) bounds [j])
6023 current_pos [j] = 0;
6028 ig.Emit (OpCodes.Ldloc, temp);
6031 void EmitArrayArguments (EmitContext ec)
6033 ILGenerator ig = ec.ig;
6035 foreach (Argument a in arguments) {
6036 Type atype = a.Type;
6039 if (atype == TypeManager.uint64_type)
6040 ig.Emit (OpCodes.Conv_Ovf_U4);
6041 else if (atype == TypeManager.int64_type)
6042 ig.Emit (OpCodes.Conv_Ovf_I4);
6046 void DoEmit (EmitContext ec, bool is_statement)
6048 ILGenerator ig = ec.ig;
6050 EmitArrayArguments (ec);
6051 if (is_one_dimensional)
6052 ig.Emit (OpCodes.Newarr, array_element_type);
6054 if (is_builtin_type)
6055 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6057 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6060 if (initializers != null){
6062 // FIXME: Set this variable correctly.
6064 bool dynamic_initializers = true;
6066 if (underlying_type != TypeManager.string_type &&
6067 underlying_type != TypeManager.object_type) {
6068 if (num_automatic_initializers > 2)
6069 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
6072 if (dynamic_initializers)
6073 EmitDynamicInitializers (ec, !is_statement);
6077 public override void Emit (EmitContext ec)
6082 public override void EmitStatement (EmitContext ec)
6090 /// Represents the 'this' construct
6092 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6094 public enum TypeOfAccess : byte {
6100 TypeOfAccess access_type;
6102 public This (TypeOfAccess access_type, Block block, Location loc)
6106 this.access_type = access_type;
6109 public This (Block block, Location loc)
6113 this.access_type = TypeOfAccess.Me;
6116 public This (Location loc)
6119 this.access_type = TypeOfAccess.Me;
6122 public TypeOfAccess AccessType {
6123 get { return access_type; }
6126 public bool IsAssigned (EmitContext ec, Location loc)
6131 return vi.IsAssigned (ec, loc);
6134 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
6139 return vi.IsFieldAssigned (ec, field_name, loc);
6142 public void SetAssigned (EmitContext ec)
6145 vi.SetAssigned (ec);
6148 public void SetFieldAssigned (EmitContext ec, string field_name)
6151 vi.SetFieldAssigned (ec, field_name);
6154 public override Expression DoResolve (EmitContext ec)
6156 eclass = ExprClass.Variable;
6157 type = ec.ContainerType;
6160 Error (26, "Keyword this not valid in static code");
6165 vi = block.ThisVariable;
6170 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6174 VariableInfo vi = ec.CurrentBlock.ThisVariable;
6176 vi.SetAssigned (ec);
6178 if (ec.TypeContainer is Class){
6179 Error (1604, "Cannot assign to 'this'");
6186 public override void Emit (EmitContext ec)
6188 ILGenerator ig = ec.ig;
6190 ig.Emit (OpCodes.Ldarg_0);
6191 if (ec.TypeContainer is Struct)
6192 ig.Emit (OpCodes.Ldobj, type);
6195 public void EmitAssign (EmitContext ec, Expression source)
6197 ILGenerator ig = ec.ig;
6199 if (ec.TypeContainer is Struct){
6200 ig.Emit (OpCodes.Ldarg_0);
6202 ig.Emit (OpCodes.Stobj, type);
6205 ig.Emit (OpCodes.Starg, 0);
6209 public void AddressOf (EmitContext ec, AddressOp mode)
6211 ec.ig.Emit (OpCodes.Ldarg_0);
6214 // FIGURE OUT WHY LDARG_S does not work
6216 // consider: struct X { int val; int P { set { val = value; }}}
6218 // Yes, this looks very bad. Look at 'NOTAS' for
6220 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6225 /// Implements the typeof operator
6227 public class TypeOf : Expression {
6228 public readonly Expression QueriedType;
6231 public TypeOf (Expression queried_type, Location l)
6233 QueriedType = queried_type;
6237 public override Expression DoResolve (EmitContext ec)
6239 typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6241 if (typearg == null)
6244 type = TypeManager.type_type;
6245 eclass = ExprClass.Type;
6249 public override void Emit (EmitContext ec)
6251 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6252 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6255 public Type TypeArg {
6256 get { return typearg; }
6261 /// Implements the sizeof expression
6263 public class SizeOf : Expression {
6264 public readonly Expression QueriedType;
6267 public SizeOf (Expression queried_type, Location l)
6269 this.QueriedType = queried_type;
6273 public override Expression DoResolve (EmitContext ec)
6276 Error (233, "Sizeof may only be used in an unsafe context " +
6277 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6281 type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6282 if (type_queried == null)
6285 if (!TypeManager.IsUnmanagedType (type_queried)){
6286 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.MonoBASIC_Name (type_queried) + ")");
6290 type = TypeManager.int32_type;
6291 eclass = ExprClass.Value;
6295 public override void Emit (EmitContext ec)
6297 int size = GetTypeSize (type_queried);
6300 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6302 IntConstant.EmitInt (ec.ig, size);
6307 /// Implements the member access expression
6309 public class MemberAccess : Expression, ITypeExpression {
6310 public readonly string Identifier;
6312 Expression member_lookup;
6313 bool is_invocation = false;
6315 bool is_addressof = false;
6317 public MemberAccess (Expression expr, string id, Location l)
6324 public MemberAccess (Expression expr, string id, Location l, bool isInvocation)
6329 is_invocation = isInvocation;
6332 public bool IsInvocation {
6334 return is_invocation;
6337 is_invocation = value;
6341 public bool IsAddressOf {
6343 is_addressof = value;
6347 public bool IsLeftHand {
6349 return is_left_hand;
6352 is_left_hand = value;
6356 public Expression Expr {
6362 static void error176 (Location loc, string name)
6364 Report.Error (176, loc, "Static member '" +
6365 name + "' cannot be accessed " +
6366 "with an instance reference, qualify with a " +
6367 "type name instead");
6370 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6372 if (left_original == null)
6375 if (!(left_original is SimpleName))
6378 SimpleName sn = (SimpleName) left_original;
6380 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6387 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6388 Expression left, Location loc,
6389 Expression left_original)
6391 bool left_is_type, left_is_explicit;
6394 // If 'left' is null, then we're called from SimpleNameResolve and this is
6395 // a member in the currently defining class.
6397 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6398 left_is_explicit = false;
6400 // Implicitly default to 'this' unless we're static.
6401 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6404 left_is_type = left is TypeExpr;
6405 left_is_explicit = true;
6408 if (member_lookup is FieldExpr){
6409 FieldExpr fe = (FieldExpr) member_lookup;
6410 FieldInfo fi = fe.FieldInfo;
6411 Type decl_type = fi.DeclaringType;
6413 if (fi is FieldBuilder) {
6414 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6417 if (!c.LookupConstantValue (out o, ec))
6420 object real_value = ((Constant) c.Expr).GetValue ();
6421 Expression exp = Constantify (real_value, fi.FieldType);
6427 // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
6429 if (fi.IsInitOnly && !(fi is FieldBuilder) && fi.FieldType == TypeManager.decimal_type) {
6430 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
6431 if (attrs.Length == 1)
6432 return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
6438 Type t = fi.FieldType;
6442 if (fi is FieldBuilder)
6443 o = TypeManager.GetValue ((FieldBuilder) fi);
6445 o = fi.GetValue (fi);
6447 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6448 if (left_is_explicit && !left_is_type &&
6449 !IdenticalNameAndTypeName (ec, left_original, loc)) {
6450 error176 (loc, fe.FieldInfo.Name);
6454 Expression enum_member = MemberLookup (
6455 ec, decl_type, "value__", MemberTypes.Field,
6456 AllBindingFlags, loc);
6458 Enum en = TypeManager.LookupEnum (decl_type);
6462 c = Constantify (o, en.UnderlyingType);
6464 c = Constantify (o, enum_member.Type);
6466 return new EnumConstant (c, decl_type);
6469 Expression exp = Constantify (o, t);
6471 if (left_is_explicit && !left_is_type) {
6472 error176 (loc, fe.FieldInfo.Name);
6479 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6486 if (member_lookup is IMemberExpr) {
6487 IMemberExpr me = (IMemberExpr) member_lookup;
6490 if (me is PropertyGroupExpr) {
6491 PropertyGroupExpr mg = me as PropertyGroupExpr;
6492 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6493 mg.IsExplicitImpl = left_is_explicit;
6496 if (IdenticalNameAndTypeName (ec, left_original, loc))
6497 return member_lookup;
6499 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6503 MethodGroupExpr mg = me as MethodGroupExpr;
6504 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6505 mg.IsExplicitImpl = left_is_explicit;
6508 if (IdenticalNameAndTypeName (ec, left_original, loc))
6509 return member_lookup;
6511 // SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6517 if (!me.IsInstance){
6518 if (IdenticalNameAndTypeName (ec, left_original, loc))
6519 return member_lookup;
6521 /*if (left_is_explicit) {
6522 error176 (loc, me.Name);
6528 // Since we can not check for instance objects in SimpleName,
6529 // becaue of the rule that allows types and variables to share
6530 // the name (as long as they can be de-ambiguated later, see
6531 // IdenticalNameAndTypeName), we have to check whether left
6532 // is an instance variable in a static context
6534 // However, if the left-hand value is explicitly given, then
6535 // it is already our instance expression, so we aren't in
6539 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6540 IMemberExpr mexp = (IMemberExpr) left;
6542 if (!mexp.IsStatic){
6543 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6548 me.InstanceExpression = left;
6551 return member_lookup;
6554 if (member_lookup is TypeExpr){
6555 member_lookup.Resolve (ec, ResolveFlags.Type);
6556 return member_lookup;
6559 Console.WriteLine ("Left is: " + left);
6560 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6561 Environment.Exit (0);
6565 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6568 throw new Exception ();
6570 // Resolve the expression with flow analysis turned off, we'll do the definite
6571 // assignment checks later. This is because we don't know yet what the expression
6572 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6573 // definite assignment check on the actual field and not on the whole struct.
6576 Expression original = expr;
6577 expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6582 if (expr is SimpleName){
6583 SimpleName child_expr = (SimpleName) expr;
6585 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
6586 ((SimpleName) new_expr).IsInvocation = is_invocation;
6588 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6589 return new_expr.Resolve (ec, flags);
6591 return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup | ResolveFlags.VariableOrValue);
6594 int errors = Report.Errors;
6596 Type expr_type = expr.Type;
6598 if (expr is TypeExpr){
6599 //FIXME: add access level check
6600 //if (!ec.DeclSpace.CheckAccessLevel (expr_type)) {
6601 // Error (30390, "'" + TypeManager.MonoBASIC_Name (expr_type) + "' " +
6602 // "is inaccessible because of its protection level");
6606 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6607 Enum en = TypeManager.LookupEnum (expr_type);
6610 object value = en.LookupEnumValue (Identifier);
6613 Constant c = Constantify (value, en.UnderlyingType);
6614 return new EnumConstant (c, expr_type);
6616 Report.Error (30456, loc,
6617 Identifier + " is not found in member list of enum " + en.Name);
6623 if (expr_type.IsPointer){
6624 Error (30311, "The '.' operator can not be applied to pointer operands (" +
6625 TypeManager.MonoBASIC_Name (expr_type) + ")");
6629 member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
6630 if (member_lookup == null)
6632 // Error has already been reported.
6633 if (errors < Report.Errors)
6637 // Try looking the member up from the same type, if we find
6638 // it, we know that the error was due to limited visibility
6640 object lookup = TypeManager.MemberLookup (
6641 expr_type, expr_type, AllMemberTypes, AllBindingFlags |
6642 BindingFlags.NonPublic, Identifier);
6644 if (lookup == null) {
6645 if (expr_type != TypeManager.object_type)
6646 Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
6647 // If this came as a part of Invocation,
6648 // Since argumets are not known, return null,
6649 // let Invocation's Resolve take care
6653 else if (! is_left_hand) {
6654 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
6656 true, is_left_hand);
6657 etmp.GenerateLateBindingStatements();
6658 return etmp.Resolve (ec);
6661 // if the expression is a left hand side of an assignment,
6662 // return null, as we dont know the RHS
6663 // Let assign take care of Late Binding
6668 if ((expr_type != ec.ContainerType) &&
6669 ec.ContainerType.IsSubclassOf (expr_type))
6672 // Although a derived class can access protected members of
6673 // its base class it cannot do so through an instance of the
6674 // base class (CS1540). If the expr_type is a parent of the
6675 // ec.ContainerType and the lookup succeeds with the latter one,
6676 // then we are in this situation.
6678 lookup = TypeManager.MemberLookup(
6679 ec.ContainerType, ec.ContainerType, AllMemberTypes,
6680 AllBindingFlags, Identifier);
6683 Error (1540, "Cannot access protected member '" +
6684 expr_type + "." + Identifier + "' " +
6685 "via a qualifier of type '" + TypeManager.MonoBASIC_Name (expr_type) + "'; the " +
6686 "qualifier must be of type '" + TypeManager.MonoBASIC_Name (ec.ContainerType) + "' " +
6687 "(or derived from it)");
6689 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6690 "is inaccessible because of its protection level");
6692 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6693 "is inaccessible because of its protection level");
6698 if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))) {
6699 Enum en = TypeManager.LookupEnum (expr_type);
6702 object value = en.LookupEnumValue (Identifier);
6703 expr_type = TypeManager.int32_type;
6704 if (value != null) {
6705 Constant c = Constantify (value, en.UnderlyingType);
6706 return new EnumConstant (c, en.UnderlyingType);
6708 Report.Error (30456, loc,
6709 Identifier + " is not found in member list of enum " + en.Name);
6714 if (member_lookup is TypeExpr){
6715 member_lookup.Resolve (ec, ResolveFlags.Type);
6717 return member_lookup;
6718 } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6721 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6722 if (member_lookup == null)
6725 if ((member_lookup is MethodGroupExpr) && ! is_invocation && !is_addressof) {
6726 Expression inv = new Invocation (this, new ArrayList (), loc);
6727 return inv.Resolve (ec);
6730 if (member_lookup is PropertyGroupExpr && is_invocation) // As we dont know the arguments yet
6731 return member_lookup;
6733 // The following DoResolve/DoResolveLValue will do the definite assignment
6735 if (right_side != null)
6736 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6738 member_lookup = member_lookup.DoResolve (ec);
6741 return member_lookup;
6744 public override Expression DoResolve (EmitContext ec)
6746 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6747 ResolveFlags.SimpleName | ResolveFlags.Type);
6750 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6752 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6753 ResolveFlags.SimpleName | ResolveFlags.Type);
6756 public Expression DoResolveType (EmitContext ec)
6758 return DoResolve (ec, null, ResolveFlags.Type);
6761 public override void Emit (EmitContext ec)
6763 throw new Exception ("Should not happen");
6766 public override string ToString ()
6768 return expr + "." + Identifier;
6775 /// Implements checked expressions
6777 public class CheckedExpr : Expression {
6779 public Expression Expr;
6781 public CheckedExpr (Expression e, Location l)
6787 public override Expression DoResolve (EmitContext ec)
6789 bool last_const_check = ec.ConstantCheckState;
6791 ec.ConstantCheckState = true;
6792 Expr = Expr.Resolve (ec);
6793 ec.ConstantCheckState = last_const_check;
6798 if (Expr is Constant)
6801 eclass = Expr.eclass;
6806 public override void Emit (EmitContext ec)
6808 bool last_check = ec.CheckState;
6809 bool last_const_check = ec.ConstantCheckState;
6811 ec.CheckState = true;
6812 ec.ConstantCheckState = true;
6814 ec.CheckState = last_check;
6815 ec.ConstantCheckState = last_const_check;
6821 /// Implements the unchecked expression
6823 public class UnCheckedExpr : Expression {
6825 public Expression Expr;
6827 public UnCheckedExpr (Expression e, Location l)
6833 public override Expression DoResolve (EmitContext ec)
6835 bool last_const_check = ec.ConstantCheckState;
6837 ec.ConstantCheckState = false;
6838 Expr = Expr.Resolve (ec);
6839 ec.ConstantCheckState = last_const_check;
6844 if (Expr is Constant)
6847 eclass = Expr.eclass;
6852 public override void Emit (EmitContext ec)
6854 bool last_check = ec.CheckState;
6855 bool last_const_check = ec.ConstantCheckState;
6857 ec.CheckState = false;
6858 ec.ConstantCheckState = false;
6860 ec.CheckState = last_check;
6861 ec.ConstantCheckState = last_const_check;
6867 /// An Element Access expression.
6869 /// During semantic analysis these are transformed into
6870 /// IndexerAccess or ArrayAccess
6872 public class ElementAccess : Expression {
6873 public ArrayList Arguments;
6874 public Expression Expr;
6876 public ElementAccess (Expression e, ArrayList e_list, Location l)
6885 Arguments = new ArrayList ();
6886 foreach (Expression tmp in e_list)
6887 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6891 bool CommonResolve (EmitContext ec)
6893 Expr = Expr.Resolve (ec);
6898 if (Arguments == null)
6901 foreach (Argument a in Arguments){
6902 if (!a.Resolve (ec, loc))
6909 Expression MakePointerAccess ()
6913 if (t == TypeManager.void_ptr_type){
6916 "The array index operation is not valid for void pointers");
6919 if (Arguments.Count != 1){
6922 "A pointer must be indexed by a single value");
6925 Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
6927 return new Indirection (p, loc);
6930 public override Expression DoResolve (EmitContext ec)
6932 if (!CommonResolve (ec))
6936 // We perform some simple tests, and then to "split" the emit and store
6937 // code we create an instance of a different class, and return that.
6939 // I am experimenting with this pattern.
6944 return (new ArrayAccess (this, loc)).Resolve (ec);
6945 else if (t.IsPointer)
6946 return MakePointerAccess ();
6948 return (new IndexerAccess (this, loc)).Resolve (ec);
6951 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6953 if (!CommonResolve (ec))
6958 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
6959 else if (t.IsPointer)
6960 return MakePointerAccess ();
6962 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
6965 public override void Emit (EmitContext ec)
6967 throw new Exception ("Should never be reached");
6972 /// Implements array access
6974 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
6976 // Points to our "data" repository
6980 LocalTemporary [] cached_locations;
6982 public ArrayAccess (ElementAccess ea_data, Location l)
6985 eclass = ExprClass.Variable;
6989 public override Expression DoResolve (EmitContext ec)
6991 //ExprClass eclass = ea.Expr.eclass;
6994 // As long as the type is valid
6995 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
6996 eclass == ExprClass.Value)) {
6997 ea.Expr.Error118 ("variable or value");
7002 Type t = ea.Expr.Type;
7004 if (t == typeof (System.Object))
7006 // We can't resolve now, but we
7007 // have to try to access the array with a call
7008 // to LateIndexGet in the runtime
7010 Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
7011 Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
7012 ArrayList adims = new ArrayList();
7014 ArrayList ainit = new ArrayList();
7015 foreach (Argument a in ea.Arguments)
7016 ainit.Add ((Expression) a.Expr);
7018 adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));
7020 Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
7022 ArrayList args = new ArrayList();
7023 args.Add (new Argument(ea.Expr, Argument.AType.Expression));
7024 args.Add (new Argument(oace, Argument.AType.Expression));
7025 args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
7027 Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
7028 lig_call = lig_call.Resolve(ec);
7032 if (t.GetArrayRank () != ea.Arguments.Count){
7034 "Incorrect number of indexes for array " +
7035 " expected: " + t.GetArrayRank () + " got: " +
7036 ea.Arguments.Count);
7039 type = TypeManager.TypeToCoreType (t.GetElementType ());
7040 if (type.IsPointer && !ec.InUnsafe){
7041 UnsafeError (ea.Location);
7045 foreach (Argument a in ea.Arguments){
7046 Type argtype = a.Type;
7048 if (argtype == TypeManager.int32_type ||
7049 argtype == TypeManager.uint32_type ||
7050 argtype == TypeManager.int64_type ||
7051 argtype == TypeManager.uint64_type)
7055 // Mhm. This is strage, because the Argument.Type is not the same as
7056 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7058 // Wonder if I will run into trouble for this.
7060 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7065 eclass = ExprClass.Variable;
7071 /// Emits the right opcode to load an object of Type 't'
7072 /// from an array of T
7074 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7076 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7077 ig.Emit (OpCodes.Ldelem_U1);
7078 else if (type == TypeManager.sbyte_type)
7079 ig.Emit (OpCodes.Ldelem_I1);
7080 else if (type == TypeManager.short_type)
7081 ig.Emit (OpCodes.Ldelem_I2);
7082 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7083 ig.Emit (OpCodes.Ldelem_U2);
7084 else if (type == TypeManager.int32_type)
7085 ig.Emit (OpCodes.Ldelem_I4);
7086 else if (type == TypeManager.uint32_type)
7087 ig.Emit (OpCodes.Ldelem_U4);
7088 else if (type == TypeManager.uint64_type)
7089 ig.Emit (OpCodes.Ldelem_I8);
7090 else if (type == TypeManager.int64_type)
7091 ig.Emit (OpCodes.Ldelem_I8);
7092 else if (type == TypeManager.float_type)
7093 ig.Emit (OpCodes.Ldelem_R4);
7094 else if (type == TypeManager.double_type)
7095 ig.Emit (OpCodes.Ldelem_R8);
7096 else if (type == TypeManager.intptr_type)
7097 ig.Emit (OpCodes.Ldelem_I);
7098 else if (type.IsValueType){
7099 ig.Emit (OpCodes.Ldelema, type);
7100 ig.Emit (OpCodes.Ldobj, type);
7102 ig.Emit (OpCodes.Ldelem_Ref);
7106 /// Emits the right opcode to store an object of Type 't'
7107 /// from an array of T.
7109 static public void EmitStoreOpcode (ILGenerator ig, Type t)
7111 t = TypeManager.TypeToCoreType (t);
7112 if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
7113 t = TypeManager.EnumToUnderlying (t);
7114 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7115 t == TypeManager.bool_type)
7116 ig.Emit (OpCodes.Stelem_I1);
7117 else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
7118 ig.Emit (OpCodes.Stelem_I2);
7119 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7120 ig.Emit (OpCodes.Stelem_I4);
7121 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7122 ig.Emit (OpCodes.Stelem_I8);
7123 else if (t == TypeManager.float_type)
7124 ig.Emit (OpCodes.Stelem_R4);
7125 else if (t == TypeManager.double_type)
7126 ig.Emit (OpCodes.Stelem_R8);
7127 else if (t == TypeManager.intptr_type)
7128 ig.Emit (OpCodes.Stelem_I);
7129 else if (t.IsValueType){
7130 ig.Emit (OpCodes.Stobj, t);
7132 ig.Emit (OpCodes.Stelem_Ref);
7135 MethodInfo FetchGetMethod ()
7137 ModuleBuilder mb = CodeGen.ModuleBuilder;
7138 int arg_count = ea.Arguments.Count;
7139 Type [] args = new Type [arg_count];
7142 for (int i = 0; i < arg_count; i++){
7143 //args [i++] = a.Type;
7144 args [i] = TypeManager.int32_type;
7147 get = mb.GetArrayMethod (
7148 ea.Expr.Type, "Get",
7149 CallingConventions.HasThis |
7150 CallingConventions.Standard,
7156 MethodInfo FetchAddressMethod ()
7158 ModuleBuilder mb = CodeGen.ModuleBuilder;
7159 int arg_count = ea.Arguments.Count;
7160 Type [] args = new Type [arg_count];
7162 string ptr_type_name;
7165 ptr_type_name = type.FullName + "&";
7166 ret_type = Type.GetType (ptr_type_name);
7169 // It is a type defined by the source code we are compiling
7171 if (ret_type == null){
7172 ret_type = mb.GetType (ptr_type_name);
7175 for (int i = 0; i < arg_count; i++){
7176 //args [i++] = a.Type;
7177 args [i] = TypeManager.int32_type;
7180 address = mb.GetArrayMethod (
7181 ea.Expr.Type, "Address",
7182 CallingConventions.HasThis |
7183 CallingConventions.Standard,
7190 // Load the array arguments into the stack.
7192 // If we have been requested to cache the values (cached_locations array
7193 // initialized), then load the arguments the first time and store them
7194 // in locals. otherwise load from local variables.
7196 void LoadArrayAndArguments (EmitContext ec)
7198 ILGenerator ig = ec.ig;
7200 if (cached_locations == null){
7202 foreach (Argument a in ea.Arguments){
7203 Type argtype = a.Expr.Type;
7207 if (argtype == TypeManager.int64_type)
7208 ig.Emit (OpCodes.Conv_Ovf_I);
7209 else if (argtype == TypeManager.uint64_type)
7210 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7215 if (cached_locations [0] == null){
7216 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
7218 ig.Emit (OpCodes.Dup);
7219 cached_locations [0].Store (ec);
7223 foreach (Argument a in ea.Arguments){
7224 Type argtype = a.Expr.Type;
7226 cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
7228 if (argtype == TypeManager.int64_type)
7229 ig.Emit (OpCodes.Conv_Ovf_I);
7230 else if (argtype == TypeManager.uint64_type)
7231 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7233 ig.Emit (OpCodes.Dup);
7234 cached_locations [j].Store (ec);
7240 foreach (LocalTemporary lt in cached_locations)
7244 public new void CacheTemporaries (EmitContext ec)
7246 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
7249 public override void Emit (EmitContext ec)
7251 int rank = ea.Expr.Type.GetArrayRank ();
7252 ILGenerator ig = ec.ig;
7254 LoadArrayAndArguments (ec);
7257 EmitLoadOpcode (ig, type);
7261 method = FetchGetMethod ();
7262 ig.Emit (OpCodes.Call, method);
7266 public void EmitAssign (EmitContext ec, Expression source)
7268 int rank = ea.Expr.Type.GetArrayRank ();
7269 ILGenerator ig = ec.ig;
7270 Type t = source.Type;
7272 LoadArrayAndArguments (ec);
7275 // The stobj opcode used by value types will need
7276 // an address on the stack, not really an array/array
7280 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
7281 (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
7282 ig.Emit (OpCodes.Ldelema, t);
7288 EmitStoreOpcode (ig, t);
7290 ModuleBuilder mb = CodeGen.ModuleBuilder;
7291 int arg_count = ea.Arguments.Count;
7292 Type [] args = new Type [arg_count + 1];
7295 for (int i = 0; i < arg_count; i++){
7296 //args [i++] = a.Type;
7297 args [i] = TypeManager.int32_type;
7300 args [arg_count] = type;
7302 set = mb.GetArrayMethod (
7303 ea.Expr.Type, "Set",
7304 CallingConventions.HasThis |
7305 CallingConventions.Standard,
7306 TypeManager.void_type, args);
7308 ig.Emit (OpCodes.Call, set);
7312 public void AddressOf (EmitContext ec, AddressOp mode)
7314 int rank = ea.Expr.Type.GetArrayRank ();
7315 ILGenerator ig = ec.ig;
7317 LoadArrayAndArguments (ec);
7320 ig.Emit (OpCodes.Ldelema, type);
7322 MethodInfo address = FetchAddressMethod ();
7323 ig.Emit (OpCodes.Call, address);
7330 public ArrayList getters, setters;
7331 static Hashtable map;
7335 map = new Hashtable ();
7338 Indexers (MemberInfo [] mi)
7340 foreach (PropertyInfo property in mi){
7341 MethodInfo get, set;
7343 get = property.GetGetMethod (true);
7345 if (getters == null)
7346 getters = new ArrayList ();
7351 set = property.GetSetMethod (true);
7353 if (setters == null)
7354 setters = new ArrayList ();
7360 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7362 Indexers ix = (Indexers) map [lookup_type];
7368 string p_name = TypeManager.IndexerPropertyName (lookup_type, out innerType);
7370 if ( p_name == null )
7373 MemberInfo [] mi = TypeManager.MemberLookup (
7374 caller_type, innerType, MemberTypes.Property,
7375 BindingFlags.Public | BindingFlags.Instance, p_name);
7377 if (mi == null || mi.Length == 0)
7380 ix = new Indexers (mi);
7381 //map [lookup_type] = ix;
7382 map [innerType] = ix;
7387 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
7389 Indexers ix = (Indexers) map [lookup_type];
7394 ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
7398 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7399 if (ifaces != null) {
7400 foreach (Type itype in ifaces) {
7401 ix = GetIndexersForTypeOrInterface (caller_type, itype);
7411 /// Expressions that represent an indexer call.
7413 public class IndexerAccess : Expression, IAssignMethod {
7415 // Points to our "data" repository
7417 MethodInfo get, set;
7419 ArrayList set_arguments;
7420 //bool is_base_indexer;
7422 protected Type indexer_type;
7423 protected Type current_type;
7424 protected Expression instance_expr;
7425 protected ArrayList arguments;
7427 public IndexerAccess (ElementAccess ea, Location loc)
7428 : this (ea.Expr, false, loc)
7430 this.arguments = ea.Arguments;
7433 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7436 this.instance_expr = instance_expr;
7437 //this.is_base_indexer = is_base_indexer;
7438 this.eclass = ExprClass.Value;
7442 public Expression Instance {
7444 return instance_expr;
7448 public ArrayList Arguments {
7454 protected virtual bool CommonResolve (EmitContext ec)
7456 indexer_type = instance_expr.Type;
7457 current_type = ec.ContainerType;
7462 public override Expression DoResolve (EmitContext ec)
7464 if (!CommonResolve (ec))
7468 // Step 1: Query for all 'Item' *properties*. Notice
7469 // that the actual methods are pointed from here.
7471 // This is a group of properties, piles of them.
7473 if (ilist == null) {
7474 ilist = Indexers.GetIndexersForType (
7475 current_type, indexer_type, loc);
7477 if (ilist == null && indexer_type != TypeManager.object_type) {
7478 Report.Error (30367, loc,
7479 "Type '" + TypeManager.MonoBASIC_Name (indexer_type) +
7480 "' does not have any indexers defined");
7482 //Report.Error (21, loc,
7483 // "Type '" + TypeManager.MonoBASIC_Name (indexer_type) +
7484 // "' does not have any indexers defined");
7490 // Step 2: find the proper match
7492 if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
7493 get = (MethodInfo) Invocation.OverloadResolve (
7494 ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
7497 if (instance_expr.Type != TypeManager.object_type)
7498 Error (30524, "indexer can not be used in this context, because " +
7499 "it lacks a 'get' accessor");
7503 type = get.ReturnType;
7504 if (type.IsPointer && !ec.InUnsafe){
7509 eclass = ExprClass.IndexerAccess;
7513 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7515 if (!CommonResolve (ec))
7518 Type right_type = right_side.Type;
7520 if (ilist == null) {
7521 ilist = Indexers.GetIndexersForType (
7522 current_type, indexer_type, loc);
7523 if (ilist == null && indexer_type != TypeManager.object_type) {
7524 Report.Error (21, loc,
7525 "Type '" + TypeManager.MonoBASIC_Name (indexer_type) +
7526 "' does not have any indexers defined");
7531 if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
7532 set_arguments = (ArrayList) arguments.Clone ();
7533 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7535 set = (MethodInfo) Invocation.OverloadResolve (
7536 ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
7540 Error (30526, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
7541 "] lacks a 'set' accessor");
7545 type = TypeManager.void_type;
7546 eclass = ExprClass.IndexerAccess;
7550 public override void Emit (EmitContext ec)
7552 Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
7556 // source is ignored, because we already have a copy of it from the
7557 // LValue resolution and we have already constructed a pre-cached
7558 // version of the arguments (ea.set_arguments);
7560 public void EmitAssign (EmitContext ec, Expression source)
7562 Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
7567 /// The base operator for method names
7569 public class BaseAccess : Expression {
7570 public string member;
7572 public BaseAccess (string member, Location l)
7574 this.member = member;
7578 public override Expression DoResolve (EmitContext ec)
7580 Expression member_lookup;
7581 Type current_type = ec.ContainerType;
7582 Type base_type = current_type.BaseType;
7586 Error (1511, "Keyword MyBase is not allowed in static method");
7590 if (member == "New")
7593 member_lookup = MemberLookup (ec, current_type, base_type, member,
7594 AllMemberTypes, AllBindingFlags, loc);
7596 if (member_lookup == null) {
7598 TypeManager.MonoBASIC_Name (base_type) + " does not " +
7599 "contain a definition for '" + member + "'");
7606 left = new TypeExpr (base_type, loc);
7610 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7612 if (e is PropertyExpr) {
7613 PropertyExpr pe = (PropertyExpr) e;
7621 public override void Emit (EmitContext ec)
7623 throw new Exception ("Should never be called");
7628 /// The base indexer operator
7630 public class BaseIndexerAccess : IndexerAccess {
7631 public BaseIndexerAccess (ArrayList args, Location loc)
7632 : base (null, true, loc)
7634 arguments = new ArrayList ();
7635 foreach (Expression tmp in args)
7636 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7639 protected override bool CommonResolve (EmitContext ec)
7641 instance_expr = ec.This;
7643 current_type = ec.ContainerType.BaseType;
7644 indexer_type = current_type;
7646 foreach (Argument a in arguments){
7647 if (!a.Resolve (ec, loc))
7656 /// This class exists solely to pass the Type around and to be a dummy
7657 /// that can be passed to the conversion functions (this is used by
7658 /// foreach implementation to typecast the object return value from
7659 /// get_Current into the proper type. All code has been generated and
7660 /// we only care about the side effect conversions to be performed
7662 /// This is also now used as a placeholder where a no-action expression
7663 /// is needed (the 'New' class).
7665 public class EmptyExpression : Expression {
7666 public EmptyExpression ()
7668 type = TypeManager.object_type;
7669 eclass = ExprClass.Value;
7670 loc = Location.Null;
7673 public EmptyExpression (Type t)
7676 eclass = ExprClass.Value;
7677 loc = Location.Null;
7680 public override Expression DoResolve (EmitContext ec)
7685 public override void Emit (EmitContext ec)
7687 // nothing, as we only exist to not do anything.
7691 // This is just because we might want to reuse this bad boy
7692 // instead of creating gazillions of EmptyExpressions.
7693 // (CanConvertImplicit uses it)
7695 public void SetType (Type t)
7701 public class UserCast : Expression {
7705 public UserCast (MethodInfo method, Expression source, Location l)
7707 this.method = method;
7708 this.source = source;
7709 type = method.ReturnType;
7710 eclass = ExprClass.Value;
7714 public override Expression DoResolve (EmitContext ec)
7717 // We are born fully resolved
7722 public override void Emit (EmitContext ec)
7724 ILGenerator ig = ec.ig;
7728 if (method is MethodInfo)
7729 ig.Emit (OpCodes.Call, (MethodInfo) method);
7731 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7737 // This class is used to "construct" the type during a typecast
7738 // operation. Since the Type.GetType class in .NET can parse
7739 // the type specification, we just use this to construct the type
7740 // one bit at a time.
7742 public class ComposedCast : Expression, ITypeExpression {
7746 public ComposedCast (Expression left, string dim, Location l)
7753 public Expression DoResolveType (EmitContext ec)
7755 Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7760 // ltype.Fullname is already fully qualified, so we can skip
7761 // a lot of probes, and go directly to TypeManager.LookupType
7763 string cname = ltype.FullName + dim;
7764 type = TypeManager.LookupTypeDirect (cname);
7767 // For arrays of enumerations we are having a problem
7768 // with the direct lookup. Need to investigate.
7770 // For now, fall back to the full lookup in that case.
7772 type = RootContext.LookupType (
7773 ec.DeclSpace, cname, false, loc);
7779 if (!ec.ResolvingTypeTree){
7781 // If the above flag is set, this is being invoked from the ResolveType function.
7782 // Upper layers take care of the type validity in this context.
7784 if (!ec.InUnsafe && type.IsPointer){
7790 eclass = ExprClass.Type;
7794 public override Expression DoResolve (EmitContext ec)
7796 return DoResolveType (ec);
7799 public override void Emit (EmitContext ec)
7801 throw new Exception ("This should never be called");
7804 public override string ToString ()
7811 // This class is used to represent the address of an array, used
7812 // only by the Fixed statement, this is like the C "&a [0]" construct.
7814 public class ArrayPtr : Expression {
7817 public ArrayPtr (Expression array, Location l)
7819 Type array_type = array.Type.GetElementType ();
7823 string array_ptr_type_name = array_type.FullName + "*";
7825 type = Type.GetType (array_ptr_type_name);
7827 ModuleBuilder mb = CodeGen.ModuleBuilder;
7829 type = mb.GetType (array_ptr_type_name);
7832 eclass = ExprClass.Value;
7836 public override void Emit (EmitContext ec)
7838 ILGenerator ig = ec.ig;
7841 IntLiteral.EmitInt (ig, 0);
7842 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
7845 public override Expression DoResolve (EmitContext ec)
7848 // We are born fully resolved
7855 // Used by the fixed statement
7857 public class StringPtr : Expression {
7860 public StringPtr (LocalBuilder b, Location l)
7863 eclass = ExprClass.Value;
7864 type = TypeManager.char_ptr_type;
7868 public override Expression DoResolve (EmitContext ec)
7870 // This should never be invoked, we are born in fully
7871 // initialized state.
7876 public override void Emit (EmitContext ec)
7878 ILGenerator ig = ec.ig;
7880 ig.Emit (OpCodes.Ldloc, b);
7881 ig.Emit (OpCodes.Conv_I);
7882 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
7883 ig.Emit (OpCodes.Add);
7888 // Implements the 'stackalloc' keyword
7890 public class StackAlloc : Expression {
7895 public StackAlloc (Expression type, Expression count, Location l)
7902 public override Expression DoResolve (EmitContext ec)
7904 count = count.Resolve (ec);
7908 if (count.Type != TypeManager.int32_type){
7909 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
7914 if (ec.InCatch || ec.InFinally){
7916 "stackalloc can not be used in a catch or finally block");
7920 otype = ec.DeclSpace.ResolveType (t, false, loc);
7925 if (!TypeManager.VerifyUnManaged (otype, loc))
7928 string ptr_name = otype.FullName + "*";
7929 type = Type.GetType (ptr_name);
7931 ModuleBuilder mb = CodeGen.ModuleBuilder;
7933 type = mb.GetType (ptr_name);
7935 eclass = ExprClass.Value;
7940 public override void Emit (EmitContext ec)
7942 int size = GetTypeSize (otype);
7943 ILGenerator ig = ec.ig;
7946 ig.Emit (OpCodes.Sizeof, otype);
7948 IntConstant.EmitInt (ig, size);
7950 ig.Emit (OpCodes.Mul);
7951 ig.Emit (OpCodes.Localloc);
7954 public class Preserve : ExpressionStatement {
7955 ArrayList args = null;
7956 MethodInfo mi = null;
7957 Expression target = null;
7958 ExpressionStatement source = null;
7961 public Preserve (Expression RedimTarget, ExpressionStatement acExpr, Location l)
7963 Type type = typeof(Microsoft.VisualBasic.CompilerServices.Utils);
7964 mi = type.GetMethod("CopyArray");
7966 target = RedimTarget;
7969 eclass = ExprClass.Value;
7973 public override Expression DoResolve (EmitContext ec)
7976 // We are born fully resolved
7978 type = mi.ReturnType;
7980 source.Resolve (ec);
7985 public override void Emit (EmitContext ec)
7987 args = new ArrayList (2);
7989 args.Add (new Argument (target, Argument.AType.Expression));
7990 args.Add (new Argument (source, Argument.AType.Expression));
7992 Invocation.EmitArguments (ec, mi, args);
7994 ec.ig.Emit (OpCodes.Call, mi);
7998 public override void EmitStatement (EmitContext ec)