2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
11 // Maybe we should make Resolve be an instance method that just calls
12 // the virtual DoResolve function and checks conditions like the eclass
13 // and type being set if a non-null value is returned. For robustness
18 using System.Collections;
19 using System.Diagnostics;
21 using System.Reflection;
22 using System.Reflection.Emit;
26 // The ExprClass class contains the is used to pass the
27 // classification of an expression (value, variable, namespace,
28 // type, method group, property access, event access, indexer access,
31 public enum ExprClass {
35 Variable, // Every Variable should implement LValue
46 // Base class for expressions
48 public abstract class Expression {
49 protected ExprClass eclass;
62 public ExprClass ExprClass {
73 // Utility wrapper routine for Error, just to beautify the code
75 static protected void Error (TypeContainer tc, int error, string s)
77 tc.RootContext.Report.Error (error, s);
80 static protected void Error (TypeContainer tc, int error, Location l, string s)
82 tc.RootContext.Report.Error (error, l, s);
86 // Utility wrapper routine for Warning, just to beautify the code
88 static protected void Warning (TypeContainer tc, int warning, string s)
90 tc.RootContext.Report.Warning (warning, s);
94 // Performs semantic analysis on the Expression
98 // The Resolve method is invoked to perform the semantic analysis
101 // The return value is an expression (it can be the
102 // same expression in some cases) or a new
103 // expression that better represents this node.
105 // For example, optimizations of Unary (LiteralInt)
106 // would return a new LiteralInt with a negated
109 // If there is an error during semantic analysis,
110 // then an error should
111 // be reported (using TypeContainer.RootContext.Report) and a null
112 // value should be returned.
114 // There are two side effects expected from calling
115 // Resolve(): the the field variable "eclass" should
116 // be set to any value of the enumeration
117 // `ExprClass' and the type variable should be set
118 // to a valid type (this is the type of the
122 public abstract Expression DoResolve (TypeContainer tc);
126 // Currently Resolve wraps DoResolve to perform sanity
127 // checking and assertion checking on what we expect from Resolve
130 public Expression Resolve (TypeContainer tc)
132 Expression e = DoResolve (tc);
135 if (e.ExprClass == ExprClass.Invalid)
136 throw new Exception ("Expression " + e +
137 " ExprClass is Invalid after resolve");
139 if (e.ExprClass != ExprClass.MethodGroup)
141 throw new Exception ("Expression " + e +
142 " did not set its type after Resolve");
149 // Emits the code for the expression
154 // The Emit method is invoked to generate the code
155 // for the expression.
158 public abstract void Emit (EmitContext ec);
161 // Protected constructor. Only derivate types should
162 // be able to be created
165 protected Expression ()
167 eclass = ExprClass.Invalid;
172 // Returns a fully formed expression after a MemberLookup
174 static Expression ExprClassFromMemberInfo (MemberInfo mi)
176 if (mi is EventInfo){
177 return new EventExpr ((EventInfo) mi);
178 } else if (mi is FieldInfo){
179 return new FieldExpr ((FieldInfo) mi);
180 } else if (mi is PropertyInfo){
181 return new PropertyExpr ((PropertyInfo) mi);
182 } else if (mi is Type)
183 return new TypeExpr ((Type) mi);
189 // FIXME: Probably implement a cache for (t,name,current_access_set)?
191 // FIXME: We need to cope with access permissions here, or this wont
194 // This code could use some optimizations, but we need to do some
195 // measurements. For example, we could use a delegate to `flag' when
196 // something can not any longer be a method-group (because it is something
200 // If the return value is an Array, then it is an array of
203 // If the return value is an MemberInfo, it is anything, but a Method
207 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
208 // the arguments here and have MemberLookup return only the methods that
209 // match the argument count/type, unlike we are doing now (we delay this
212 // This is so we can catch correctly attempts to invoke instance methods
213 // from a static body (scan for error 120 in ResolveSimpleName).
215 public static Expression MemberLookup (TypeContainer tc, Type t, string name,
216 bool same_type, MemberTypes mt, BindingFlags bf)
219 bf |= BindingFlags.NonPublic;
221 MemberInfo [] mi = tc.RootContext.TypeManager.FindMembers (
222 t, mt, bf, Type.FilterName, name);
227 if (mi.Length == 1 && !(mi [0] is MethodBase))
228 return Expression.ExprClassFromMemberInfo (mi [0]);
230 for (int i = 0; i < mi.Length; i++)
231 if (!(mi [i] is MethodBase)){
233 -5, "Do not know how to reproduce this case: " +
234 "Methods and non-Method with the same name, " +
235 "report this please");
237 for (i = 0; i < mi.Length; i++){
238 Type tt = mi [i].GetType ();
240 Console.WriteLine (i + ": " + mi [i]);
241 while (tt != TypeManager.object_type){
242 Console.WriteLine (tt);
248 return new MethodGroupExpr (mi);
251 public const MemberTypes AllMemberTypes =
252 MemberTypes.Constructor |
256 MemberTypes.NestedType |
257 MemberTypes.Property;
259 public const BindingFlags AllBindingsFlags =
260 BindingFlags.Public |
261 BindingFlags.Static |
262 BindingFlags.Instance;
264 public static Expression MemberLookup (TypeContainer tc, Type t, string name,
267 return MemberLookup (tc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
271 // I am in general unhappy with this implementation.
273 // I need to revise this.
275 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
277 Expression left_e = null;
278 int dot_pos = name.LastIndexOf (".");
279 string left = name.Substring (0, dot_pos);
280 string right = name.Substring (dot_pos + 1);
283 if ((t = tc.LookupType (left, false)) != null)
284 left_e = new TypeExpr (t);
290 // T.P Static property access (P) on Type T.
291 // e.P instance property access on instance e for P.
297 Error (tc, 246, "Can not find type or namespace `"+left+"'");
301 switch (left_e.ExprClass){
303 return MemberLookup (tc,
305 left_e.Type == tc.TypeBuilder);
307 case ExprClass.Namespace:
308 case ExprClass.PropertyAccess:
309 case ExprClass.IndexerAccess:
310 case ExprClass.Variable:
311 case ExprClass.Value:
312 case ExprClass.Nothing:
313 case ExprClass.EventAccess:
314 case ExprClass.MethodGroup:
315 case ExprClass.Invalid:
316 throw new Exception ("Should have got the " + left_e.ExprClass +
323 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
325 Type expr_type = expr.Type;
327 if (target_type == TypeManager.object_type) {
328 if (expr_type.IsClass)
329 return new EmptyCast (expr, target_type);
330 if (expr_type.IsValueType)
331 return new BoxedCast (expr);
332 } else if (expr_type.IsSubclassOf (target_type))
333 return new EmptyCast (expr, target_type);
335 // FIXME: missing implicit reference conversions:
337 // from any class-type S to any interface-type T.
338 // from any interface type S to interface-type T.
339 // from an array-type S to an array-type of type T
340 // from an array-type to System.Array
341 // from any delegate type to System.Delegate
342 // from any array-type or delegate type into System.ICloneable.
343 // from the null type to any reference-type.
351 // Handles expressions like this: decimal d; d = 1;
352 // and changes them into: decimal d; d = new System.Decimal (1);
354 static Expression InternalTypeConstructor (TypeContainer tc, Expression expr, Type target)
356 ArrayList args = new ArrayList ();
358 args.Add (new Argument (expr, Argument.AType.Expression));
360 Console.WriteLine ("The InternalTypeConstructor is: " + expr);
361 Expression ne = new New (target.FullName, args,
362 new Location ("FIXME", 1, 1));
364 return ne.Resolve (tc);
368 // Implicit Numeric Conversions.
370 // expr is the expression to convert, returns a new expression of type
371 // target_type or null if an implicit conversion is not possible.
374 static public Expression ImplicitNumericConversion (TypeContainer tc, Expression expr,
375 Type target_type, Location l)
377 Type expr_type = expr.Type;
380 // Attempt to do the implicit constant expression conversions
382 if (expr is IntLiteral){
385 e = TryImplicitIntConversion (target_type, (IntLiteral) expr);
388 } else if (expr is LongLiteral){
390 // Try the implicit constant expression conversion
391 // from long to ulong, instead of a nice routine,
394 if (((LongLiteral) expr).Value > 0)
398 if (expr_type == TypeManager.sbyte_type){
400 // From sbyte to short, int, long, float, double.
402 if (target_type == TypeManager.int32_type)
403 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
404 if (target_type == TypeManager.int64_type)
405 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
406 if (target_type == TypeManager.double_type)
407 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
408 if (target_type == TypeManager.float_type)
409 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
410 if (target_type == TypeManager.short_type)
411 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
412 if (target_type == TypeManager.decimal_type)
413 return InternalTypeConstructor (tc, expr, target_type);
414 } else if (expr_type == TypeManager.byte_type){
416 // From byte to short, ushort, int, uint, long, ulong, float, double
418 if ((target_type == TypeManager.short_type) ||
419 (target_type == TypeManager.ushort_type) ||
420 (target_type == TypeManager.int32_type) ||
421 (target_type == TypeManager.uint32_type))
422 return new EmptyCast (expr, target_type);
424 if (target_type == TypeManager.uint64_type)
425 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
426 if (target_type == TypeManager.int64_type)
427 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
429 if (target_type == TypeManager.float_type)
430 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
431 if (target_type == TypeManager.double_type)
432 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
433 if (target_type == TypeManager.decimal_type)
434 return InternalTypeConstructor (tc, expr, target_type);
435 } else if (expr_type == TypeManager.short_type){
437 // From short to int, long, float, double
439 if (target_type == TypeManager.int32_type)
440 return new EmptyCast (expr, target_type);
441 if (target_type == TypeManager.int64_type)
442 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
443 if (target_type == TypeManager.double_type)
444 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
445 if (target_type == TypeManager.float_type)
446 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
447 if (target_type == TypeManager.decimal_type)
448 return InternalTypeConstructor (tc, expr, target_type);
449 } else if (expr_type == TypeManager.ushort_type){
451 // From ushort to int, uint, long, ulong, float, double
453 if ((target_type == TypeManager.uint32_type) ||
454 (target_type == TypeManager.uint64_type))
455 return new EmptyCast (expr, target_type);
457 if (target_type == TypeManager.int32_type)
458 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
459 if (target_type == TypeManager.int64_type)
460 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
461 if (target_type == TypeManager.double_type)
462 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
463 if (target_type == TypeManager.float_type)
464 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
465 if (target_type == TypeManager.decimal_type)
466 return InternalTypeConstructor (tc, expr, target_type);
467 } else if (expr_type == TypeManager.int32_type){
469 // From int to long, float, double
471 if (target_type == TypeManager.int64_type)
472 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
473 if (target_type == TypeManager.double_type)
474 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
475 if (target_type == TypeManager.float_type)
476 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
477 if (target_type == TypeManager.decimal_type)
478 return InternalTypeConstructor (tc, expr, target_type);
479 } else if (expr_type == TypeManager.uint32_type){
481 // From uint to long, ulong, float, double
483 if (target_type == TypeManager.int64_type)
484 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
485 if (target_type == TypeManager.uint64_type)
486 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
487 if (target_type == TypeManager.double_type)
488 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
490 if (target_type == TypeManager.float_type)
491 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
493 if (target_type == TypeManager.decimal_type)
494 return InternalTypeConstructor (tc, expr, target_type);
495 } else if ((expr_type == TypeManager.uint64_type) ||
496 (expr_type == TypeManager.int64_type)){
498 // From long/ulong to float, double
500 if (target_type == TypeManager.double_type)
501 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
503 if (target_type == TypeManager.float_type)
504 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
506 if (target_type == TypeManager.decimal_type)
507 return InternalTypeConstructor (tc, expr, target_type);
508 } else if (expr_type == TypeManager.char_type){
510 // From char to ushort, int, uint, long, ulong, float, double
512 if ((target_type == TypeManager.ushort_type) ||
513 (target_type == TypeManager.int32_type) ||
514 (target_type == TypeManager.uint32_type))
515 return new EmptyCast (expr, target_type);
516 if (target_type == TypeManager.uint64_type)
517 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
518 if (target_type == TypeManager.int64_type)
519 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
520 if (target_type == TypeManager.float_type)
521 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
522 if (target_type == TypeManager.double_type)
523 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
524 if (target_type == TypeManager.decimal_type)
525 return InternalTypeConstructor (tc, expr, target_type);
526 } else if (expr_type == TypeManager.float_type){
530 if (target_type == TypeManager.double_type)
531 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
538 // User-defined implicit conversions
540 static public Expression ImplicitUserConversion (TypeContainer tc, Expression source,
541 Type target, Location l)
547 mg1 = MemberLookup (tc, source.Type, "op_Implicit", false);
548 mg2 = MemberLookup (tc, target, "op_Implicit", false);
550 MethodGroupExpr union = Invocation.MakeUnionSet (mg1, mg2);
553 arguments = new ArrayList ();
554 arguments.Add (new Argument (source, Argument.AType.Expression));
556 method = Invocation.OverloadResolve (tc, union, arguments, l, true);
558 if (method != null) {
559 MethodInfo mi = (MethodInfo) method;
561 if (mi.ReturnType == target)
562 return new UserImplicitCast (mi, arguments);
566 // If we have a boolean type, we need to check for the True
567 // and False operators too.
569 if (target == TypeManager.bool_type) {
571 mg1 = MemberLookup (tc, source.Type, "op_True", false);
572 mg2 = MemberLookup (tc, target, "op_True", false);
574 union = Invocation.MakeUnionSet (mg1, mg2);
579 arguments = new ArrayList ();
580 arguments.Add (new Argument (source, Argument.AType.Expression));
582 method = Invocation.OverloadResolve (tc, union, arguments,
583 new Location ("FIXME", 1, 1), true);
584 if (method != null) {
585 MethodInfo mi = (MethodInfo) method;
587 if (mi.ReturnType == target)
588 return new UserImplicitCast (mi, arguments);
596 // Converts implicitly the resolved expression `expr' into the
597 // `target_type'. It returns a new expression that can be used
598 // in a context that expects a `target_type'.
600 static public Expression ConvertImplicit (TypeContainer tc, Expression expr,
601 Type target_type, Location l)
603 Type expr_type = expr.Type;
606 if (expr_type == target_type)
609 e = ImplicitNumericConversion (tc, expr, target_type, l);
613 e = ImplicitReferenceConversion (expr, target_type);
617 e = ImplicitUserConversion (tc, expr, target_type, l);
621 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
622 IntLiteral i = (IntLiteral) expr;
625 return new EmptyCast (expr, target_type);
632 // Attempts to apply the `Standard Implicit
633 // Conversion' rules to the expression `expr' into
634 // the `target_type'. It returns a new expression
635 // that can be used in a context that expects a
638 // This is different from `ConvertImplicit' in that the
639 // user defined implicit conversions are excluded.
641 static public Expression ConvertImplicitStandard (TypeContainer tc, Expression expr,
642 Type target_type, Location l)
644 Type expr_type = expr.Type;
647 if (expr_type == target_type)
650 e = ImplicitNumericConversion (tc, expr, target_type, l);
654 e = ImplicitReferenceConversion (expr, target_type);
658 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
659 IntLiteral i = (IntLiteral) expr;
662 return new EmptyCast (expr, target_type);
667 // Attemps to perform an implict constant conversion of the IntLiteral
668 // into a different data type using casts (See Implicit Constant
669 // Expression Conversions)
671 static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il)
673 int value = il.Value;
675 if (target_type == TypeManager.sbyte_type){
676 if (value >= SByte.MinValue && value <= SByte.MaxValue)
678 } else if (target_type == TypeManager.byte_type){
679 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
681 } else if (target_type == TypeManager.short_type){
682 if (value >= Int16.MinValue && value <= Int16.MaxValue)
684 } else if (target_type == TypeManager.ushort_type){
685 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
687 } else if (target_type == TypeManager.uint32_type){
689 // we can optimize this case: a positive int32
690 // always fits on a uint32
694 } else if (target_type == TypeManager.uint64_type){
696 // we can optimize this case: a positive int32
697 // always fits on a uint64. But we need an opcode
701 return new OpcodeCast (il, target_type, OpCodes.Conv_I8);
708 // Attemptes to implicityly convert `target' into `type', using
709 // ConvertImplicit. If there is no implicit conversion, then
710 // an error is signaled
712 static public Expression ConvertImplicitRequired (TypeContainer tc, Expression target,
713 Type type, Location l)
717 e = ConvertImplicit (tc, target, type, l);
721 string msg = "Can not convert implicitly from `"+
722 TypeManager.CSharpName (target.Type) + "' to `" +
723 TypeManager.CSharpName (type) + "'";
725 Error (tc, 29, l, msg);
731 // Performs the explicit numeric conversions
733 static Expression ConvertNumericExplicit (TypeContainer tc, Expression expr,
736 Type expr_type = expr.Type;
738 if (expr_type == TypeManager.sbyte_type){
740 // From sbyte to byte, ushort, uint, ulong, char
742 if (target_type == TypeManager.byte_type)
743 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
744 if (target_type == TypeManager.ushort_type)
745 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
746 if (target_type == TypeManager.uint32_type)
747 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
748 if (target_type == TypeManager.uint64_type)
749 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
750 if (target_type == TypeManager.char_type)
751 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
752 } else if (expr_type == TypeManager.byte_type){
754 // From byte to sbyte and char
756 if (target_type == TypeManager.sbyte_type)
757 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
758 if (target_type == TypeManager.char_type)
759 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
760 } else if (expr_type == TypeManager.short_type){
762 // From short to sbyte, byte, ushort, uint, ulong, char
764 if (target_type == TypeManager.sbyte_type)
765 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
766 if (target_type == TypeManager.byte_type)
767 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
768 if (target_type == TypeManager.ushort_type)
769 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
770 if (target_type == TypeManager.uint32_type)
771 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
772 if (target_type == TypeManager.uint64_type)
773 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
774 if (target_type == TypeManager.char_type)
775 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
776 } else if (expr_type == TypeManager.ushort_type){
778 // From ushort to sbyte, byte, short, char
780 if (target_type == TypeManager.sbyte_type)
781 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
782 if (target_type == TypeManager.byte_type)
783 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
784 if (target_type == TypeManager.short_type)
785 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
786 if (target_type == TypeManager.char_type)
787 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
788 } else if (expr_type == TypeManager.int32_type){
790 // From int to sbyte, byte, short, ushort, uint, ulong, char
792 if (target_type == TypeManager.sbyte_type)
793 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
794 if (target_type == TypeManager.byte_type)
795 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
796 if (target_type == TypeManager.short_type)
797 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
798 if (target_type == TypeManager.ushort_type)
799 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
800 if (target_type == TypeManager.uint32_type)
801 return new EmptyCast (expr, target_type);
802 if (target_type == TypeManager.uint64_type)
803 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
804 if (target_type == TypeManager.char_type)
805 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
806 } else if (expr_type == TypeManager.uint32_type){
808 // From uint to sbyte, byte, short, ushort, int, char
810 if (target_type == TypeManager.sbyte_type)
811 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
812 if (target_type == TypeManager.byte_type)
813 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
814 if (target_type == TypeManager.short_type)
815 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
816 if (target_type == TypeManager.ushort_type)
817 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
818 if (target_type == TypeManager.int32_type)
819 return new EmptyCast (expr, target_type);
820 if (target_type == TypeManager.char_type)
821 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
822 } else if (expr_type == TypeManager.int64_type){
824 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
826 if (target_type == TypeManager.sbyte_type)
827 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
828 if (target_type == TypeManager.byte_type)
829 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
830 if (target_type == TypeManager.short_type)
831 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
832 if (target_type == TypeManager.ushort_type)
833 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
834 if (target_type == TypeManager.int32_type)
835 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
836 if (target_type == TypeManager.uint32_type)
837 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
838 if (target_type == TypeManager.uint64_type)
839 return new EmptyCast (expr, target_type);
840 if (target_type == TypeManager.char_type)
841 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
842 } else if (expr_type == TypeManager.uint64_type){
844 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
846 if (target_type == TypeManager.sbyte_type)
847 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
848 if (target_type == TypeManager.byte_type)
849 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
850 if (target_type == TypeManager.short_type)
851 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
852 if (target_type == TypeManager.ushort_type)
853 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
854 if (target_type == TypeManager.int32_type)
855 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
856 if (target_type == TypeManager.uint32_type)
857 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
858 if (target_type == TypeManager.int64_type)
859 return new EmptyCast (expr, target_type);
860 if (target_type == TypeManager.char_type)
861 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
862 } else if (expr_type == TypeManager.char_type){
864 // From char to sbyte, byte, short
866 if (target_type == TypeManager.sbyte_type)
867 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
868 if (target_type == TypeManager.byte_type)
869 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
870 if (target_type == TypeManager.short_type)
871 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
872 } else if (expr_type == TypeManager.float_type){
874 // From float to sbyte, byte, short,
875 // ushort, int, uint, long, ulong, char
878 if (target_type == TypeManager.sbyte_type)
879 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
880 if (target_type == TypeManager.byte_type)
881 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
882 if (target_type == TypeManager.short_type)
883 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
884 if (target_type == TypeManager.ushort_type)
885 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
886 if (target_type == TypeManager.int32_type)
887 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
888 if (target_type == TypeManager.uint32_type)
889 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
890 if (target_type == TypeManager.int64_type)
891 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
892 if (target_type == TypeManager.uint64_type)
893 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
894 if (target_type == TypeManager.char_type)
895 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
896 if (target_type == TypeManager.decimal_type)
897 return InternalTypeConstructor (tc, expr, target_type);
898 } else if (expr_type == TypeManager.double_type){
900 // From double to byte, byte, short,
901 // ushort, int, uint, long, ulong,
902 // char, float or decimal
904 Console.WriteLine ("Ok, I am a double " + target_type);
905 if (target_type == TypeManager.sbyte_type)
906 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
907 if (target_type == TypeManager.byte_type)
908 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
909 if (target_type == TypeManager.short_type)
910 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
911 if (target_type == TypeManager.ushort_type)
912 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
913 if (target_type == TypeManager.int32_type)
914 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
915 if (target_type == TypeManager.uint32_type)
916 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
917 if (target_type == TypeManager.int64_type)
918 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
919 if (target_type == TypeManager.uint64_type)
920 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
921 if (target_type == TypeManager.char_type)
922 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
923 if (target_type == TypeManager.float_type)
924 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
925 if (target_type == TypeManager.decimal_type)
926 return InternalTypeConstructor (tc, expr, target_type);
929 // decimal is taken care of by the op_Explicit methods.
935 // Implements Explicit Reference conversions
937 static Expression ConvertReferenceExplicit (TypeContainer tc, Expression expr,
940 Type expr_type = expr.Type;
941 bool target_is_value_type = target_type.IsValueType;
944 // From object to any reference type
946 if (expr_type == TypeManager.object_type && !target_is_value_type)
947 return new ClassCast (expr, expr_type);
953 // Performs an explicit conversion of the expression `expr' whose
954 // type is expr.Type to `target_type'.
956 static public Expression ConvertExplicit (TypeContainer tc, Expression expr,
959 Expression ne = ConvertImplicit (tc, expr, target_type, Location.Null);
964 ne = ConvertNumericExplicit (tc, expr, target_type);
968 ne = ConvertReferenceExplicit (tc, expr, target_type);
975 static string ExprClassName (ExprClass c)
978 case ExprClass.Invalid:
980 case ExprClass.Value:
982 case ExprClass.Variable:
984 case ExprClass.Namespace:
988 case ExprClass.MethodGroup:
989 return "method group";
990 case ExprClass.PropertyAccess:
991 return "property access";
992 case ExprClass.EventAccess:
993 return "event access";
994 case ExprClass.IndexerAccess:
995 return "indexer access";
996 case ExprClass.Nothing:
999 throw new Exception ("Should not happen");
1003 // Reports that we were expecting `expr' to be of class `expected'
1005 protected void report118 (TypeContainer tc, Location l, Expression expr, string expected)
1007 string kind = "Unknown";
1010 kind = ExprClassName (expr.ExprClass);
1012 Error (tc, 118, l, "Expression denotes a '" + kind +
1013 "' where an " + expected + " was expected");
1018 // This is just a base class for expressions that can
1019 // appear on statements (invocations, object creation,
1020 // assignments, post/pre increment and decrement). The idea
1021 // being that they would support an extra Emition interface that
1022 // does not leave a result on the stack.
1025 public abstract class ExpressionStatement : Expression {
1028 // Requests the expression to be emitted in a `statement'
1029 // context. This means that no new value is left on the
1030 // stack after invoking this method (constrasted with
1031 // Emit that will always leave a value on the stack).
1033 public abstract void EmitStatement (EmitContext ec);
1037 // This kind of cast is used to encapsulate the child
1038 // whose type is child.Type into an expression that is
1039 // reported to return "return_type". This is used to encapsulate
1040 // expressions which have compatible types, but need to be dealt
1041 // at higher levels with.
1043 // For example, a "byte" expression could be encapsulated in one
1044 // of these as an "unsigned int". The type for the expression
1045 // would be "unsigned int".
1049 public class EmptyCast : Expression {
1050 protected Expression child;
1052 public EmptyCast (Expression child, Type return_type)
1054 ExprClass = child.ExprClass;
1059 public override Expression DoResolve (TypeContainer tc)
1061 // This should never be invoked, we are born in fully
1062 // initialized state.
1067 public override void Emit (EmitContext ec)
1074 // This kind of cast is used to encapsulate Value Types in objects.
1076 // The effect of it is to box the value type emitted by the previous
1079 public class BoxedCast : EmptyCast {
1081 public BoxedCast (Expression expr)
1082 : base (expr, TypeManager.object_type)
1086 public override Expression DoResolve (TypeContainer tc)
1088 // This should never be invoked, we are born in fully
1089 // initialized state.
1094 public override void Emit (EmitContext ec)
1097 ec.ig.Emit (OpCodes.Box, child.Type);
1102 // This kind of cast is used to encapsulate a child expression
1103 // that can be trivially converted to a target type using one or
1104 // two opcodes. The opcodes are passed as arguments.
1106 public class OpcodeCast : EmptyCast {
1110 public OpcodeCast (Expression child, Type return_type, OpCode op)
1111 : base (child, return_type)
1115 second_valid = false;
1118 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1119 : base (child, return_type)
1124 second_valid = true;
1127 public override Expression DoResolve (TypeContainer tc)
1129 // This should never be invoked, we are born in fully
1130 // initialized state.
1135 public override void Emit (EmitContext ec)
1147 // This kind of cast is used to encapsulate a child and cast it
1148 // to the class requested
1150 public class ClassCast : EmptyCast {
1151 public ClassCast (Expression child, Type return_type)
1152 : base (child, return_type)
1157 public override Expression DoResolve (TypeContainer tc)
1159 // This should never be invoked, we are born in fully
1160 // initialized state.
1165 public override void Emit (EmitContext ec)
1169 ec.ig.Emit (OpCodes.Castclass, type);
1175 // Unary expressions.
1179 // Unary implements unary expressions. It derives from
1180 // ExpressionStatement becuase the pre/post increment/decrement
1181 // operators can be used in a statement context.
1183 public class Unary : ExpressionStatement {
1184 public enum Operator {
1185 Addition, Subtraction, Negate, BitComplement,
1186 Indirection, AddressOf, PreIncrement,
1187 PreDecrement, PostIncrement, PostDecrement
1192 ArrayList Arguments;
1196 public Unary (Operator op, Expression expr, Location loc)
1200 this.location = loc;
1203 public Expression Expr {
1213 public Operator Oper {
1224 // Returns a stringified representation of the Operator
1229 case Operator.Addition:
1231 case Operator.Subtraction:
1233 case Operator.Negate:
1235 case Operator.BitComplement:
1237 case Operator.AddressOf:
1239 case Operator.Indirection:
1241 case Operator.PreIncrement : case Operator.PostIncrement :
1243 case Operator.PreDecrement : case Operator.PostDecrement :
1247 return oper.ToString ();
1250 Expression ForceConversion (TypeContainer tc, Expression expr, Type target_type)
1252 if (expr.Type == target_type)
1255 return ConvertImplicit (tc, expr, target_type, new Location ("FIXME", 1, 1));
1258 void report23 (Report r, Type t)
1260 r.Error (23, "Operator " + OperName () + " cannot be applied to operand of type `" +
1261 TypeManager.CSharpName (t) + "'");
1265 // Returns whether an object of type `t' can be incremented
1266 // or decremented with add/sub (ie, basically whether we can
1267 // use pre-post incr-decr operations on it, but it is not a
1268 // System.Decimal, which we test elsewhere)
1270 static bool IsIncrementableNumber (Type t)
1272 return (t == TypeManager.sbyte_type) ||
1273 (t == TypeManager.byte_type) ||
1274 (t == TypeManager.short_type) ||
1275 (t == TypeManager.ushort_type) ||
1276 (t == TypeManager.int32_type) ||
1277 (t == TypeManager.uint32_type) ||
1278 (t == TypeManager.int64_type) ||
1279 (t == TypeManager.uint64_type) ||
1280 (t == TypeManager.char_type) ||
1281 (t.IsSubclassOf (TypeManager.enum_type)) ||
1282 (t == TypeManager.float_type) ||
1283 (t == TypeManager.double_type);
1286 Expression ResolveOperator (TypeContainer tc)
1288 Type expr_type = expr.Type;
1291 // Step 1: Perform Operator Overload location
1296 if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
1297 op_name = "op_Increment";
1298 else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
1299 op_name = "op_Decrement";
1301 op_name = "op_" + oper;
1303 mg = MemberLookup (tc, expr_type, op_name, false);
1306 Arguments = new ArrayList ();
1307 Arguments.Add (new Argument (expr, Argument.AType.Expression));
1309 method = Invocation.OverloadResolve (tc, (MethodGroupExpr) mg,
1310 Arguments, location);
1311 if (method != null) {
1312 MethodInfo mi = (MethodInfo) method;
1314 type = mi.ReturnType;
1320 // Step 2: Default operations on CLI native types.
1323 // Only perform numeric promotions on:
1326 if (expr_type == null)
1329 if (oper == Operator.Negate){
1330 if (expr_type != TypeManager.bool_type) {
1331 report23 (tc.RootContext.Report, expr.Type);
1335 type = TypeManager.bool_type;
1339 if (oper == Operator.BitComplement) {
1340 if (!((expr_type == TypeManager.int32_type) ||
1341 (expr_type == TypeManager.uint32_type) ||
1342 (expr_type == TypeManager.int64_type) ||
1343 (expr_type == TypeManager.uint64_type) ||
1344 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
1345 report23 (tc.RootContext.Report, expr.Type);
1352 if (oper == Operator.Addition) {
1354 // A plus in front of something is just a no-op, so return the child.
1360 // Deals with -literals
1361 // int operator- (int x)
1362 // long operator- (long x)
1363 // float operator- (float f)
1364 // double operator- (double d)
1365 // decimal operator- (decimal d)
1367 if (oper == Operator.Subtraction){
1369 // Fold a "- Constant" into a negative constant
1372 Expression e = null;
1375 // Is this a constant?
1377 if (expr is IntLiteral)
1378 e = new IntLiteral (-((IntLiteral) expr).Value);
1379 else if (expr is LongLiteral)
1380 e = new LongLiteral (-((LongLiteral) expr).Value);
1381 else if (expr is FloatLiteral)
1382 e = new FloatLiteral (-((FloatLiteral) expr).Value);
1383 else if (expr is DoubleLiteral)
1384 e = new DoubleLiteral (-((DoubleLiteral) expr).Value);
1385 else if (expr is DecimalLiteral)
1386 e = new DecimalLiteral (-((DecimalLiteral) expr).Value);
1394 // Not a constant we can optimize, perform numeric
1395 // promotions to int, long, double.
1398 // The following is inneficient, because we call
1399 // ConvertImplicit too many times.
1401 // It is also not clear if we should convert to Float
1402 // or Double initially.
1404 Location l = new Location ("FIXME", 1, 1);
1406 if (expr_type == TypeManager.uint32_type){
1408 // FIXME: handle exception to this rule that
1409 // permits the int value -2147483648 (-2^31) to
1410 // bt written as a decimal interger literal
1412 type = TypeManager.int64_type;
1413 expr = ConvertImplicit (tc, expr, type, l);
1417 if (expr_type == TypeManager.uint64_type){
1419 // FIXME: Handle exception of `long value'
1420 // -92233720368547758087 (-2^63) to be written as
1421 // decimal integer literal.
1423 report23 (tc.RootContext.Report, expr_type);
1427 e = ConvertImplicit (tc, expr, TypeManager.int32_type, l);
1434 e = ConvertImplicit (tc, expr, TypeManager.int64_type, l);
1441 e = ConvertImplicit (tc, expr, TypeManager.double_type, l);
1448 report23 (tc.RootContext.Report, expr_type);
1453 // The operand of the prefix/postfix increment decrement operators
1454 // should be an expression that is classified as a variable,
1455 // a property access or an indexer access
1457 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
1458 oper == Operator.PostDecrement || oper == Operator.PostIncrement){
1459 if (expr.ExprClass == ExprClass.Variable){
1460 if (IsIncrementableNumber (expr_type) ||
1461 expr_type == TypeManager.decimal_type){
1465 } else if (expr.ExprClass == ExprClass.IndexerAccess){
1467 // FIXME: Verify that we have both get and set methods
1469 throw new Exception ("Implement me");
1470 } else if (expr.ExprClass == ExprClass.PropertyAccess){
1472 // FIXME: Verify that we have both get and set methods
1474 throw new Exception ("Implement me");
1476 report118 (tc, location, expr,
1477 "variable, indexer or property access");
1481 if (oper == Operator.AddressOf){
1482 if (expr.ExprClass != ExprClass.Variable){
1483 Error (tc, 211, "Cannot take the address of non-variables");
1486 type = Type.GetType (expr.Type.ToString () + "*");
1489 Error (tc, 187, "No such operator '" + OperName () + "' defined for type '" +
1490 TypeManager.CSharpName (expr_type) + "'");
1495 public override Expression DoResolve (TypeContainer tc)
1497 expr = expr.Resolve (tc);
1502 eclass = ExprClass.Value;
1503 return ResolveOperator (tc);
1506 public override void Emit (EmitContext ec)
1508 ILGenerator ig = ec.ig;
1509 Type expr_type = expr.Type;
1511 if (method != null) {
1513 // Note that operators are static anyway
1515 if (Arguments != null)
1516 Invocation.EmitArguments (ec, method, Arguments);
1519 // Post increment/decrement operations need a copy at this
1522 if (oper == Operator.PostDecrement || oper == Operator.PostIncrement)
1523 ig.Emit (OpCodes.Dup);
1526 ig.Emit (OpCodes.Call, (MethodInfo) method);
1529 // Pre Increment and Decrement operators
1531 if (oper == Operator.PreIncrement || oper == Operator.PreDecrement){
1532 ig.Emit (OpCodes.Dup);
1536 // Increment and Decrement should store the result
1538 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
1539 oper == Operator.PostDecrement || oper == Operator.PostIncrement){
1540 ((LValue) expr).Store (ec);
1546 case Operator.Addition:
1547 throw new Exception ("This should be caught by Resolve");
1549 case Operator.Subtraction:
1551 ig.Emit (OpCodes.Neg);
1554 case Operator.Negate:
1556 ig.Emit (OpCodes.Ldc_I4_0);
1557 ig.Emit (OpCodes.Ceq);
1560 case Operator.BitComplement:
1562 ig.Emit (OpCodes.Not);
1565 case Operator.AddressOf:
1566 ((LValue)expr).AddressOf (ec);
1569 case Operator.Indirection:
1570 throw new Exception ("Not implemented yet");
1572 case Operator.PreIncrement:
1573 case Operator.PreDecrement:
1574 if (expr.ExprClass == ExprClass.Variable){
1576 // Resolve already verified that it is an "incrementable"
1579 ig.Emit (OpCodes.Ldc_I4_1);
1581 if (oper == Operator.PreDecrement)
1582 ig.Emit (OpCodes.Sub);
1584 ig.Emit (OpCodes.Add);
1585 ig.Emit (OpCodes.Dup);
1586 ((LValue) expr).Store (ec);
1588 throw new Exception ("Handle Indexers and Properties here");
1592 case Operator.PostIncrement:
1593 case Operator.PostDecrement:
1594 if (expr.ExprClass == ExprClass.Variable){
1596 // Resolve already verified that it is an "incrementable"
1599 ig.Emit (OpCodes.Dup);
1600 ig.Emit (OpCodes.Ldc_I4_1);
1602 if (oper == Operator.PostDecrement)
1603 ig.Emit (OpCodes.Sub);
1605 ig.Emit (OpCodes.Add);
1606 ((LValue) expr).Store (ec);
1608 throw new Exception ("Handle Indexers and Properties here");
1613 throw new Exception ("This should not happen: Operator = "
1614 + oper.ToString ());
1619 public override void EmitStatement (EmitContext ec)
1622 // FIXME: we should rewrite this code to generate
1623 // better code for ++ and -- as we know we wont need
1624 // the values on the stack
1627 ec.ig.Emit (OpCodes.Pop);
1631 public class Probe : Expression {
1632 public readonly string ProbeType;
1633 public readonly Operator Oper;
1637 public enum Operator {
1641 public Probe (Operator oper, Expression expr, string probe_type)
1644 ProbeType = probe_type;
1648 public Expression Expr {
1654 public override Expression DoResolve (TypeContainer tc)
1656 probe_type = tc.LookupType (ProbeType, false);
1658 if (probe_type == null)
1661 expr = expr.Resolve (tc);
1663 type = TypeManager.bool_type;
1664 eclass = ExprClass.Value;
1669 public override void Emit (EmitContext ec)
1671 ILGenerator ig = ec.ig;
1675 if (Oper == Operator.Is){
1676 ig.Emit (OpCodes.Isinst, probe_type);
1677 ig.Emit (OpCodes.Ldnull);
1678 ig.Emit (OpCodes.Cgt_Un);
1680 ig.Emit (OpCodes.Isinst, probe_type);
1686 // This represents a typecast in the source language.
1688 // FIXME: Cast expressions have an unusual set of parsing
1689 // rules, we need to figure those out.
1691 public class Cast : Expression {
1695 public Cast (string cast_type, Expression expr)
1697 this.target_type = cast_type;
1701 public string TargetType {
1707 public Expression Expr {
1716 public override Expression DoResolve (TypeContainer tc)
1718 expr = expr.Resolve (tc);
1722 type = tc.LookupType (target_type, false);
1723 eclass = ExprClass.Value;
1728 expr = ConvertExplicit (tc, expr, type);
1733 public override void Emit (EmitContext ec)
1736 // This one will never happen
1738 throw new Exception ("Should not happen");
1742 public class Binary : Expression {
1743 public enum Operator {
1744 Multiply, Division, Modulus,
1745 Addition, Subtraction,
1746 LeftShift, RightShift,
1747 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1748 Equality, Inequality,
1757 Expression left, right;
1759 ArrayList Arguments;
1763 public Binary (Operator oper, Expression left, Expression right, Location loc)
1768 this.location = loc;
1771 public Operator Oper {
1780 public Expression Left {
1789 public Expression Right {
1800 // Returns a stringified representation of the Operator
1805 case Operator.Multiply:
1807 case Operator.Division:
1809 case Operator.Modulus:
1811 case Operator.Addition:
1813 case Operator.Subtraction:
1815 case Operator.LeftShift:
1817 case Operator.RightShift:
1819 case Operator.LessThan:
1821 case Operator.GreaterThan:
1823 case Operator.LessThanOrEqual:
1825 case Operator.GreaterThanOrEqual:
1827 case Operator.Equality:
1829 case Operator.Inequality:
1831 case Operator.BitwiseAnd:
1833 case Operator.BitwiseOr:
1835 case Operator.ExclusiveOr:
1837 case Operator.LogicalOr:
1839 case Operator.LogicalAnd:
1843 return oper.ToString ();
1846 Expression ForceConversion (TypeContainer tc, Expression expr, Type target_type)
1848 if (expr.Type == target_type)
1851 return ConvertImplicit (tc, expr, target_type, new Location ("FIXME", 1, 1));
1855 // Note that handling the case l == Decimal || r == Decimal
1856 // is taken care of by the Step 1 Operator Overload resolution.
1858 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
1860 if (l == TypeManager.double_type || r == TypeManager.double_type){
1862 // If either operand is of type double, the other operand is
1863 // conveted to type double.
1865 if (r != TypeManager.double_type)
1866 right = ConvertImplicit (tc, right, TypeManager.double_type, location);
1867 if (l != TypeManager.double_type)
1868 left = ConvertImplicit (tc, left, TypeManager.double_type, location);
1870 type = TypeManager.double_type;
1871 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1873 // if either operand is of type float, th eother operand is
1874 // converd to type float.
1876 if (r != TypeManager.double_type)
1877 right = ConvertImplicit (tc, right, TypeManager.float_type, location);
1878 if (l != TypeManager.double_type)
1879 left = ConvertImplicit (tc, left, TypeManager.float_type, location);
1880 type = TypeManager.float_type;
1881 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
1885 // If either operand is of type ulong, the other operand is
1886 // converted to type ulong. or an error ocurrs if the other
1887 // operand is of type sbyte, short, int or long
1890 if (l == TypeManager.uint64_type){
1891 if (r != TypeManager.uint64_type && right is IntLiteral){
1892 e = TryImplicitIntConversion (l, (IntLiteral) right);
1898 if (left is IntLiteral){
1899 e = TryImplicitIntConversion (r, (IntLiteral) left);
1906 if ((other == TypeManager.sbyte_type) ||
1907 (other == TypeManager.short_type) ||
1908 (other == TypeManager.int32_type) ||
1909 (other == TypeManager.int64_type)){
1910 string oper = OperName ();
1912 Error (tc, 34, location, "Operator `" + OperName ()
1913 + "' is ambiguous on operands of type `"
1914 + TypeManager.CSharpName (l) + "' "
1915 + "and `" + TypeManager.CSharpName (r)
1918 type = TypeManager.uint64_type;
1919 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1921 // If either operand is of type long, the other operand is converted
1924 if (l != TypeManager.int64_type)
1925 left = ConvertImplicit (tc, left, TypeManager.int64_type, location);
1926 if (r != TypeManager.int64_type)
1927 right = ConvertImplicit (tc, right, TypeManager.int64_type, location);
1929 type = TypeManager.int64_type;
1930 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1932 // If either operand is of type uint, and the other
1933 // operand is of type sbyte, short or int, othe operands are
1934 // converted to type long.
1938 if (l == TypeManager.uint32_type)
1940 else if (r == TypeManager.uint32_type)
1943 if ((other == TypeManager.sbyte_type) ||
1944 (other == TypeManager.short_type) ||
1945 (other == TypeManager.int32_type)){
1946 left = ForceConversion (tc, left, TypeManager.int64_type);
1947 right = ForceConversion (tc, right, TypeManager.int64_type);
1948 type = TypeManager.int64_type;
1951 // if either operand is of type uint, the other
1952 // operand is converd to type uint
1954 left = ForceConversion (tc, left, TypeManager.uint32_type);
1955 right = ForceConversion (tc, right, TypeManager.uint32_type);
1956 type = TypeManager.uint32_type;
1958 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1959 if (l != TypeManager.decimal_type)
1960 left = ConvertImplicit (tc, left, TypeManager.decimal_type, location);
1961 if (r != TypeManager.decimal_type)
1962 right = ConvertImplicit (tc, right, TypeManager.decimal_type, location);
1964 type = TypeManager.decimal_type;
1966 left = ForceConversion (tc, left, TypeManager.int32_type);
1967 right = ForceConversion (tc, right, TypeManager.int32_type);
1968 type = TypeManager.int32_type;
1972 void error19 (TypeContainer tc)
1975 "Operator " + OperName () + " cannot be applied to operands of type `" +
1976 TypeManager.CSharpName (left.Type) + "' and `" +
1977 TypeManager.CSharpName (right.Type) + "'");
1981 Expression CheckShiftArguments (TypeContainer tc)
1985 Type r = right.Type;
1987 e = ForceConversion (tc, right, TypeManager.int32_type);
1994 Location loc = location;
1996 if (((e = ConvertImplicit (tc, left, TypeManager.int32_type, loc)) != null) ||
1997 ((e = ConvertImplicit (tc, left, TypeManager.uint32_type, loc)) != null) ||
1998 ((e = ConvertImplicit (tc, left, TypeManager.int64_type, loc)) != null) ||
1999 ((e = ConvertImplicit (tc, left, TypeManager.uint64_type, loc)) != null)){
2009 Expression ResolveOperator (TypeContainer tc)
2012 Type r = right.Type;
2015 // Step 1: Perform Operator Overload location
2017 Expression left_expr, right_expr;
2019 string op = "op_" + oper;
2021 left_expr = MemberLookup (tc, l, op, false);
2023 right_expr = MemberLookup (tc, r, op, false);
2025 MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
2027 if (union != null) {
2028 Arguments = new ArrayList ();
2029 Arguments.Add (new Argument (left, Argument.AType.Expression));
2030 Arguments.Add (new Argument (right, Argument.AType.Expression));
2032 method = Invocation.OverloadResolve (tc, union, Arguments, location);
2033 if (method != null) {
2034 MethodInfo mi = (MethodInfo) method;
2036 type = mi.ReturnType;
2042 // Step 2: Default operations on CLI native types.
2045 // Only perform numeric promotions on:
2046 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2048 if (oper == Operator.Addition){
2050 // If any of the arguments is a string, cast to string
2052 if (l == TypeManager.string_type){
2053 if (r == TypeManager.string_type){
2055 method = TypeManager.string_concat_string_string;
2058 method = TypeManager.string_concat_object_object;
2059 right = ConvertImplicit (tc, right,
2060 TypeManager.object_type, location);
2062 type = TypeManager.string_type;
2064 Arguments = new ArrayList ();
2065 Arguments.Add (new Argument (left, Argument.AType.Expression));
2066 Arguments.Add (new Argument (right, Argument.AType.Expression));
2070 } else if (r == TypeManager.string_type){
2072 method = TypeManager.string_concat_object_object;
2073 Arguments = new ArrayList ();
2074 Arguments.Add (new Argument (left, Argument.AType.Expression));
2075 Arguments.Add (new Argument (right, Argument.AType.Expression));
2077 left = ConvertImplicit (tc, left, TypeManager.object_type, location);
2078 type = TypeManager.string_type;
2084 // FIXME: is Delegate operator + (D x, D y) handled?
2088 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2089 return CheckShiftArguments (tc);
2091 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2092 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
2095 type = TypeManager.bool_type;
2100 // We are dealing with numbers
2103 DoNumericPromotions (tc, l, r);
2105 if (left == null || right == null)
2108 if (oper == Operator.BitwiseAnd ||
2109 oper == Operator.BitwiseOr ||
2110 oper == Operator.ExclusiveOr){
2111 if (!((l == TypeManager.int32_type) ||
2112 (l == TypeManager.uint32_type) ||
2113 (l == TypeManager.int64_type) ||
2114 (l == TypeManager.uint64_type))){
2121 if (oper == Operator.Equality ||
2122 oper == Operator.Inequality ||
2123 oper == Operator.LessThanOrEqual ||
2124 oper == Operator.LessThan ||
2125 oper == Operator.GreaterThanOrEqual ||
2126 oper == Operator.GreaterThan){
2127 type = TypeManager.bool_type;
2133 public override Expression DoResolve (TypeContainer tc)
2135 left = left.Resolve (tc);
2136 right = right.Resolve (tc);
2138 if (left == null || right == null)
2141 if (left.Type == null)
2142 throw new Exception (
2143 "Resolve returned non null, but did not set the type! (" +
2145 if (right.Type == null)
2146 throw new Exception (
2147 "Resolve returned non null, but did not set the type! (" +
2150 eclass = ExprClass.Value;
2152 return ResolveOperator (tc);
2155 public bool IsBranchable ()
2157 if (oper == Operator.Equality ||
2158 oper == Operator.Inequality ||
2159 oper == Operator.LessThan ||
2160 oper == Operator.GreaterThan ||
2161 oper == Operator.LessThanOrEqual ||
2162 oper == Operator.GreaterThanOrEqual){
2169 // This entry point is used by routines that might want
2170 // to emit a brfalse/brtrue after an expression, and instead
2171 // they could use a more compact notation.
2173 // Typically the code would generate l.emit/r.emit, followed
2174 // by the comparission and then a brtrue/brfalse. The comparissions
2175 // are sometimes inneficient (there are not as complete as the branches
2176 // look for the hacks in Emit using double ceqs).
2178 // So for those cases we provide EmitBranchable that can emit the
2179 // branch with the test
2181 public void EmitBranchable (EmitContext ec, int target)
2184 bool close_target = false;
2190 case Operator.Equality:
2192 opcode = OpCodes.Beq_S;
2194 opcode = OpCodes.Beq;
2197 case Operator.Inequality:
2199 opcode = OpCodes.Bne_Un_S;
2201 opcode = OpCodes.Bne_Un;
2204 case Operator.LessThan:
2206 opcode = OpCodes.Blt_S;
2208 opcode = OpCodes.Blt;
2211 case Operator.GreaterThan:
2213 opcode = OpCodes.Bgt_S;
2215 opcode = OpCodes.Bgt;
2218 case Operator.LessThanOrEqual:
2220 opcode = OpCodes.Ble_S;
2222 opcode = OpCodes.Ble;
2225 case Operator.GreaterThanOrEqual:
2227 opcode = OpCodes.Bge_S;
2229 opcode = OpCodes.Ble;
2233 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
2234 + oper.ToString ());
2237 ec.ig.Emit (opcode, target);
2240 public override void Emit (EmitContext ec)
2242 ILGenerator ig = ec.ig;
2244 Type r = right.Type;
2247 if (method != null) {
2249 // Note that operators are static anyway
2251 if (Arguments != null)
2252 Invocation.EmitArguments (ec, method, Arguments);
2254 if (method is MethodInfo)
2255 ig.Emit (OpCodes.Call, (MethodInfo) method);
2257 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2266 case Operator.Multiply:
2268 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2269 opcode = OpCodes.Mul_Ovf;
2270 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2271 opcode = OpCodes.Mul_Ovf_Un;
2273 opcode = OpCodes.Mul;
2275 opcode = OpCodes.Mul;
2279 case Operator.Division:
2280 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2281 opcode = OpCodes.Div_Un;
2283 opcode = OpCodes.Div;
2286 case Operator.Modulus:
2287 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2288 opcode = OpCodes.Rem_Un;
2290 opcode = OpCodes.Rem;
2293 case Operator.Addition:
2295 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2296 opcode = OpCodes.Add_Ovf;
2297 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2298 opcode = OpCodes.Add_Ovf_Un;
2300 opcode = OpCodes.Mul;
2302 opcode = OpCodes.Add;
2305 case Operator.Subtraction:
2307 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2308 opcode = OpCodes.Sub_Ovf;
2309 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2310 opcode = OpCodes.Sub_Ovf_Un;
2312 opcode = OpCodes.Sub;
2314 opcode = OpCodes.Sub;
2317 case Operator.RightShift:
2318 opcode = OpCodes.Shr;
2321 case Operator.LeftShift:
2322 opcode = OpCodes.Shl;
2325 case Operator.Equality:
2326 opcode = OpCodes.Ceq;
2329 case Operator.Inequality:
2330 ec.ig.Emit (OpCodes.Ceq);
2331 ec.ig.Emit (OpCodes.Ldc_I4_0);
2333 opcode = OpCodes.Ceq;
2336 case Operator.LessThan:
2337 opcode = OpCodes.Clt;
2340 case Operator.GreaterThan:
2341 opcode = OpCodes.Cgt;
2344 case Operator.LessThanOrEqual:
2345 ec.ig.Emit (OpCodes.Cgt);
2346 ec.ig.Emit (OpCodes.Ldc_I4_0);
2348 opcode = OpCodes.Ceq;
2351 case Operator.GreaterThanOrEqual:
2352 ec.ig.Emit (OpCodes.Clt);
2353 ec.ig.Emit (OpCodes.Ldc_I4_1);
2355 opcode = OpCodes.Sub;
2358 case Operator.LogicalOr:
2359 case Operator.BitwiseOr:
2360 opcode = OpCodes.Or;
2363 case Operator.LogicalAnd:
2364 case Operator.BitwiseAnd:
2365 opcode = OpCodes.And;
2368 case Operator.ExclusiveOr:
2369 opcode = OpCodes.Xor;
2373 throw new Exception ("This should not happen: Operator = "
2374 + oper.ToString ());
2381 public class Conditional : Expression {
2382 Expression expr, trueExpr, falseExpr;
2385 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2388 this.trueExpr = trueExpr;
2389 this.falseExpr = falseExpr;
2393 public Expression Expr {
2399 public Expression TrueExpr {
2405 public Expression FalseExpr {
2411 public override Expression DoResolve (TypeContainer tc)
2413 expr = expr.Resolve (tc);
2415 if (expr.Type != TypeManager.bool_type)
2416 expr = Expression.ConvertImplicitRequired (
2417 tc, expr, TypeManager.bool_type, l);
2419 trueExpr = trueExpr.Resolve (tc);
2420 falseExpr = falseExpr.Resolve (tc);
2422 if (expr == null || trueExpr == null || falseExpr == null)
2425 if (trueExpr.Type == falseExpr.Type)
2426 type = trueExpr.Type;
2431 // First, if an implicit conversion exists from trueExpr
2432 // to falseExpr, then the result type is of type falseExpr.Type
2434 conv = ConvertImplicit (tc, trueExpr, falseExpr.Type, l);
2436 type = falseExpr.Type;
2438 } else if ((conv = ConvertImplicit (tc,falseExpr,trueExpr.Type,l)) != null){
2439 type = trueExpr.Type;
2442 Error (tc, 173, l, "The type of the conditional expression can " +
2443 "not be computed because there is no implicit conversion" +
2444 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2445 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2450 eclass = ExprClass.Value;
2454 public override void Emit (EmitContext ec)
2456 ILGenerator ig = ec.ig;
2457 Label false_target = ig.DefineLabel ();
2458 Label end_target = ig.DefineLabel ();
2461 ig.Emit (OpCodes.Brfalse, false_target);
2463 ig.Emit (OpCodes.Br, end_target);
2464 ig.MarkLabel (false_target);
2465 falseExpr.Emit (ec);
2466 ig.MarkLabel (end_target);
2470 public class SimpleName : Expression {
2471 public readonly string Name;
2472 public readonly Location Location;
2474 public SimpleName (string name, Location l)
2481 // Checks whether we are trying to access an instance
2482 // property, method or field from a static body.
2484 Expression MemberStaticCheck (Report r, Expression e)
2486 if (e is FieldExpr){
2487 FieldInfo fi = ((FieldExpr) e).FieldInfo;
2491 "An object reference is required " +
2492 "for the non-static field `"+Name+"'");
2495 } else if (e is MethodGroupExpr){
2496 // FIXME: Pending reorganization of MemberLookup
2497 // Basically at this point we should have the
2498 // best match already selected for us, and
2499 // we should only have to check a *single*
2500 // Method for its static on/off bit.
2502 } else if (e is PropertyExpr){
2503 if (!((PropertyExpr) e).IsStatic){
2505 "An object reference is required " +
2506 "for the non-static property access `"+
2516 // 7.5.2: Simple Names.
2518 // Local Variables and Parameters are handled at
2519 // parse time, so they never occur as SimpleNames.
2521 Expression ResolveSimpleName (TypeContainer tc)
2524 Report r = tc.RootContext.Report;
2526 e = MemberLookup (tc, tc.TypeBuilder, Name, true);
2530 else if (e is FieldExpr){
2531 FieldExpr fe = (FieldExpr) e;
2533 if (!fe.FieldInfo.IsStatic)
2534 fe.Instance = new This ();
2537 if ((tc.ModFlags & Modifiers.STATIC) != 0)
2538 return MemberStaticCheck (r, e);
2544 // Do step 3 of the Simple Name resolution.
2546 // FIXME: implement me.
2548 Error (tc, 103, Location, "The name `" + Name + "' does not exist in the class `" +
2555 // SimpleName needs to handle a multitude of cases:
2557 // simple_names and qualified_identifiers are placed on
2558 // the tree equally.
2560 public override Expression DoResolve (TypeContainer tc)
2562 if (Name.IndexOf (".") != -1)
2563 return ResolveMemberAccess (tc, Name);
2565 return ResolveSimpleName (tc);
2568 public override void Emit (EmitContext ec)
2570 throw new Exception ("SimpleNames should be gone from the tree");
2575 // A simple interface that should be implemeneted by LValues
2577 public interface LValue {
2580 // The Store method should store the contents of the top
2581 // of the stack into the storage that is implemented by
2582 // the particular implementation of LValue
2584 void Store (EmitContext ec);
2587 // The AddressOf method should generate code that loads
2588 // the address of the LValue and leaves it on the stack
2590 void AddressOf (EmitContext ec);
2593 public class LocalVariableReference : Expression, LValue {
2594 public readonly string Name;
2595 public readonly Block Block;
2597 public LocalVariableReference (Block block, string name)
2601 eclass = ExprClass.Variable;
2604 public VariableInfo VariableInfo {
2606 return Block.GetVariableInfo (Name);
2610 public override Expression DoResolve (TypeContainer tc)
2612 VariableInfo vi = Block.GetVariableInfo (Name);
2614 type = vi.VariableType;
2618 public override void Emit (EmitContext ec)
2620 VariableInfo vi = VariableInfo;
2621 ILGenerator ig = ec.ig;
2628 ig.Emit (OpCodes.Ldloc_0);
2632 ig.Emit (OpCodes.Ldloc_1);
2636 ig.Emit (OpCodes.Ldloc_2);
2640 ig.Emit (OpCodes.Ldloc_3);
2645 ig.Emit (OpCodes.Ldloc_S, (byte) idx);
2647 ig.Emit (OpCodes.Ldloc, idx);
2652 public void Store (EmitContext ec)
2654 ILGenerator ig = ec.ig;
2655 VariableInfo vi = VariableInfo;
2661 ig.Emit (OpCodes.Stloc_0);
2665 ig.Emit (OpCodes.Stloc_1);
2669 ig.Emit (OpCodes.Stloc_2);
2673 ig.Emit (OpCodes.Stloc_3);
2678 ig.Emit (OpCodes.Stloc_S, (byte) idx);
2680 ig.Emit (OpCodes.Stloc, idx);
2685 public void AddressOf (EmitContext ec)
2687 VariableInfo vi = VariableInfo;
2694 ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx);
2696 ec.ig.Emit (OpCodes.Ldloca, idx);
2700 public class ParameterReference : Expression, LValue {
2701 public readonly Parameters Pars;
2702 public readonly String Name;
2703 public readonly int Idx;
2705 public ParameterReference (Parameters pars, int idx, string name)
2710 eclass = ExprClass.Variable;
2713 public override Expression DoResolve (TypeContainer tc)
2715 Type [] types = Pars.GetParameterInfo (tc);
2722 public override void Emit (EmitContext ec)
2725 ec.ig.Emit (OpCodes.Ldarg_S, (byte) Idx);
2727 ec.ig.Emit (OpCodes.Ldarg, Idx);
2730 public void Store (EmitContext ec)
2733 ec.ig.Emit (OpCodes.Starg_S, (byte) Idx);
2735 ec.ig.Emit (OpCodes.Starg, Idx);
2739 public void AddressOf (EmitContext ec)
2742 ec.ig.Emit (OpCodes.Ldarga_S, (byte) Idx);
2744 ec.ig.Emit (OpCodes.Ldarga, Idx);
2749 // Used for arguments to New(), Invocation()
2751 public class Argument {
2758 public readonly AType Type;
2761 public Argument (Expression expr, AType type)
2767 public Expression Expr {
2777 public bool Resolve (TypeContainer tc)
2779 expr = expr.Resolve (tc);
2781 return expr != null;
2784 public void Emit (EmitContext ec)
2791 // Invocation of methods or delegates.
2793 public class Invocation : ExpressionStatement {
2794 public readonly ArrayList Arguments;
2795 public readonly Location Location;
2798 MethodBase method = null;
2800 static Hashtable method_parameter_cache;
2802 static Invocation ()
2804 method_parameter_cache = new Hashtable ();
2808 // arguments is an ArrayList, but we do not want to typecast,
2809 // as it might be null.
2811 // FIXME: only allow expr to be a method invocation or a
2812 // delegate invocation (7.5.5)
2814 public Invocation (Expression expr, ArrayList arguments, Location l)
2817 Arguments = arguments;
2821 public Expression Expr {
2828 // Returns the Parameters (a ParameterData interface) for the
2831 static ParameterData GetParameterData (MethodBase mb)
2833 object pd = method_parameter_cache [mb];
2836 return (ParameterData) pd;
2838 if (mb is MethodBuilder || mb is ConstructorBuilder){
2839 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
2841 InternalParameters ip = mc.ParameterInfo;
2842 method_parameter_cache [mb] = ip;
2844 return (ParameterData) ip;
2846 ParameterInfo [] pi = mb.GetParameters ();
2847 ReflectionParameters rp = new ReflectionParameters (pi);
2848 method_parameter_cache [mb] = rp;
2850 return (ParameterData) rp;
2855 // Tells whether a user defined conversion from Type `from' to
2856 // Type `to' exists.
2858 // FIXME: we could implement a cache here.
2860 static bool ConversionExists (TypeContainer tc, Type from, Type to)
2862 // Locate user-defined implicit operators
2866 mg = MemberLookup (tc, to, "op_Implicit", false);
2869 MethodGroupExpr me = (MethodGroupExpr) mg;
2871 for (int i = me.Methods.Length; i > 0;) {
2873 MethodBase mb = me.Methods [i];
2874 ParameterData pd = GetParameterData (mb);
2876 if (from == pd.ParameterType (0))
2881 mg = MemberLookup (tc, from, "op_Implicit", false);
2884 MethodGroupExpr me = (MethodGroupExpr) mg;
2886 for (int i = me.Methods.Length; i > 0;) {
2888 MethodBase mb = me.Methods [i];
2889 MethodInfo mi = (MethodInfo) mb;
2891 if (mi.ReturnType == to)
2900 // Determines "better conversion" as specified in 7.4.2.3
2901 // Returns : 1 if a->p is better
2902 // 0 if a->q or neither is better
2904 static int BetterConversion (TypeContainer tc, Argument a, Type p, Type q, bool use_standard)
2907 Type argument_type = a.Expr.Type;
2908 Expression argument_expr = a.Expr;
2910 if (argument_type == null)
2911 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
2916 if (argument_type == p)
2919 if (argument_type == q)
2923 // Now probe whether an implicit constant expression conversion
2926 // An implicit constant expression conversion permits the following
2929 // * A constant-expression of type `int' can be converted to type
2930 // sbyte, byute, short, ushort, uint, ulong provided the value of
2931 // of the expression is withing the range of the destination type.
2933 // * A constant-expression of type long can be converted to type
2934 // ulong, provided the value of the constant expression is not negative
2936 // FIXME: Note that this assumes that constant folding has
2937 // taken place. We dont do constant folding yet.
2940 if (argument_expr is IntLiteral){
2941 IntLiteral ei = (IntLiteral) argument_expr;
2942 int value = ei.Value;
2944 if (p == TypeManager.sbyte_type){
2945 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2947 } else if (p == TypeManager.byte_type){
2948 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
2950 } else if (p == TypeManager.short_type){
2951 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2953 } else if (p == TypeManager.ushort_type){
2954 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2956 } else if (p == TypeManager.uint32_type){
2958 // we can optimize this case: a positive int32
2959 // always fits on a uint32
2963 } else if (p == TypeManager.uint64_type){
2965 // we can optimize this case: a positive int32
2966 // always fits on a uint64
2971 } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
2972 LongLiteral ll = (LongLiteral) argument_expr;
2974 if (p == TypeManager.uint64_type){
2985 tmp = ConvertImplicitStandard (tc, argument_expr, p, Location.Null);
2987 tmp = ConvertImplicit (tc, argument_expr, p, Location.Null);
2996 if (ConversionExists (tc, p, q) == true &&
2997 ConversionExists (tc, q, p) == false)
3000 if (p == TypeManager.sbyte_type)
3001 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3002 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3005 if (p == TypeManager.short_type)
3006 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3007 q == TypeManager.uint64_type)
3010 if (p == TypeManager.int32_type)
3011 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3014 if (p == TypeManager.int64_type)
3015 if (q == TypeManager.uint64_type)
3022 // Determines "Better function" and returns an integer indicating :
3023 // 0 if candidate ain't better
3024 // 1 if candidate is better than the current best match
3026 static int BetterFunction (TypeContainer tc, ArrayList args,
3027 MethodBase candidate, MethodBase best,
3030 ParameterData candidate_pd = GetParameterData (candidate);
3031 ParameterData best_pd;
3037 argument_count = args.Count;
3039 if (candidate_pd.Count == 0 && argument_count == 0)
3043 if (candidate_pd.Count == argument_count) {
3045 for (int j = argument_count; j > 0;) {
3048 Argument a = (Argument) args [j];
3050 x = BetterConversion (
3051 tc, a, candidate_pd.ParameterType (j), null,
3067 best_pd = GetParameterData (best);
3069 if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
3070 int rating1 = 0, rating2 = 0;
3072 for (int j = argument_count; j > 0;) {
3076 Argument a = (Argument) args [j];
3078 x = BetterConversion (tc, a, candidate_pd.ParameterType (j),
3079 best_pd.ParameterType (j), use_standard);
3080 y = BetterConversion (tc, a, best_pd.ParameterType (j),
3081 candidate_pd.ParameterType (j), use_standard);
3087 if (rating1 > rating2)
3096 public static string FullMethodDesc (MethodBase mb)
3098 StringBuilder sb = new StringBuilder (mb.Name);
3099 ParameterData pd = GetParameterData (mb);
3102 for (int i = pd.Count; i > 0;) {
3104 sb.Append (TypeManager.CSharpName (pd.ParameterType (i)));
3110 return sb.ToString ();
3113 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
3116 if (mg1 != null || mg2 != null) {
3118 MethodGroupExpr left_set = null, right_set = null;
3119 int length1 = 0, length2 = 0;
3122 left_set = (MethodGroupExpr) mg1;
3123 length1 = left_set.Methods.Length;
3127 right_set = (MethodGroupExpr) mg2;
3128 length2 = right_set.Methods.Length;
3131 MemberInfo [] miset = new MemberInfo [length1 + length2];
3132 if (left_set != null)
3133 left_set.Methods.CopyTo (miset, 0);
3134 if (right_set != null)
3135 right_set.Methods.CopyTo (miset, length1);
3137 MethodGroupExpr union = new MethodGroupExpr (miset);
3148 // Find the Applicable Function Members (7.4.2.1)
3150 // me: Method Group expression with the members to select.
3151 // it might contain constructors or methods (or anything
3152 // that maps to a method).
3154 // Arguments: ArrayList containing resolved Argument objects.
3156 // loc: The location if we want an error to be reported, or a Null
3157 // location for "probing" purposes.
3159 // inside_user_defined: controls whether OverloadResolve should use the
3160 // ConvertImplicit or ConvertImplicitStandard during overload resolution.
3162 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3163 // that is the best match of me on Arguments.
3166 public static MethodBase OverloadResolve (TypeContainer tc, MethodGroupExpr me,
3167 ArrayList Arguments, Location loc,
3170 ArrayList afm = new ArrayList ();
3171 int best_match_idx = -1;
3172 MethodBase method = null;
3175 for (int i = me.Methods.Length; i > 0; ){
3177 MethodBase candidate = me.Methods [i];
3180 x = BetterFunction (tc, Arguments, candidate, method, use_standard);
3186 method = me.Methods [best_match_idx];
3190 if (Arguments == null)
3193 argument_count = Arguments.Count;
3197 // Now we see if we can at least find a method with the same number of arguments
3198 // and then try doing implicit conversion on the arguments
3199 if (best_match_idx == -1) {
3201 for (int i = me.Methods.Length; i > 0;) {
3203 MethodBase mb = me.Methods [i];
3204 pd = GetParameterData (mb);
3206 if (pd.Count == argument_count) {
3208 method = me.Methods [best_match_idx];
3219 // And now convert implicitly, each argument to the required type
3221 pd = GetParameterData (method);
3223 for (int j = argument_count; j > 0;) {
3225 Argument a = (Argument) Arguments [j];
3226 Expression a_expr = a.Expr;
3227 Type parameter_type = pd.ParameterType (j);
3229 if (a_expr.Type != parameter_type){
3233 conv = ConvertImplicitStandard (tc, a_expr, parameter_type,
3236 conv = ConvertImplicit (tc, a_expr, parameter_type,
3240 if (!Location.IsNull (loc)) {
3241 Error (tc, 1502, loc,
3242 "The best overloaded match for method '" + FullMethodDesc (method) +
3243 "' has some invalid arguments");
3244 Error (tc, 1503, loc,
3245 "Argument " + (j+1) +
3246 ": Cannot convert from '" + TypeManager.CSharpName (a_expr.Type)
3247 + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'");
3252 // Update the argument with the implicit conversion
3262 public static MethodBase OverloadResolve (TypeContainer tc, MethodGroupExpr me,
3263 ArrayList Arguments, Location loc)
3265 return OverloadResolve (tc, me, Arguments, loc, false);
3268 public override Expression DoResolve (TypeContainer tc)
3271 // First, resolve the expression that is used to
3272 // trigger the invocation
3274 this.expr = expr.Resolve (tc);
3275 if (this.expr == null)
3278 if (!(this.expr is MethodGroupExpr)){
3279 report118 (tc, Location, this.expr, "method group");
3284 // Next, evaluate all the expressions in the argument list
3286 if (Arguments != null){
3287 for (int i = Arguments.Count; i > 0;){
3289 Argument a = (Argument) Arguments [i];
3291 if (!a.Resolve (tc))
3296 method = OverloadResolve (tc, (MethodGroupExpr) this.expr, Arguments,
3299 if (method == null){
3300 Error (tc, -6, Location,
3301 "Could not find any applicable function for this argument list");
3305 if (method is MethodInfo)
3306 type = ((MethodInfo)method).ReturnType;
3308 eclass = ExprClass.Value;
3312 public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments)
3316 if (Arguments != null)
3317 top = Arguments.Count;
3321 for (int i = 0; i < top; i++){
3322 Argument a = (Argument) Arguments [i];
3328 public override void Emit (EmitContext ec)
3330 bool is_static = method.IsStatic;
3333 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3336 // If this is ourselves, push "this"
3338 if (mg.InstanceExpression == null){
3339 ec.ig.Emit (OpCodes.Ldarg_0);
3342 // Push the instance expression
3344 mg.InstanceExpression.Emit (ec);
3348 if (Arguments != null)
3349 EmitArguments (ec, method, Arguments);
3352 if (method is MethodInfo)
3353 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
3355 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3357 if (method is MethodInfo)
3358 ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3360 ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3364 public override void EmitStatement (EmitContext ec)
3369 // Pop the return value if there is one
3371 if (method is MethodInfo){
3372 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3373 ec.ig.Emit (OpCodes.Pop);
3378 public class New : ExpressionStatement {
3385 public readonly NType NewType;
3386 public readonly ArrayList Arguments;
3387 public readonly string RequestedType;
3388 // These are for the case when we have an array
3389 public readonly string Rank;
3390 public readonly ArrayList Indices;
3391 public readonly ArrayList Initializers;
3394 MethodBase method = null;
3396 public New (string requested_type, ArrayList arguments, Location loc)
3398 RequestedType = requested_type;
3399 Arguments = arguments;
3400 NewType = NType.Object;
3404 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location loc)
3406 RequestedType = requested_type;
3409 Initializers = initializers;
3410 NewType = NType.Array;
3414 public override Expression DoResolve (TypeContainer tc)
3416 type = tc.LookupType (RequestedType, false);
3423 ml = MemberLookup (tc, type, ".ctor", false,
3424 MemberTypes.Constructor, AllBindingsFlags);
3426 if (! (ml is MethodGroupExpr)){
3428 // FIXME: Find proper error
3430 report118 (tc, Location, ml, "method group");
3434 if (Arguments != null){
3435 for (int i = Arguments.Count; i > 0;){
3437 Argument a = (Argument) Arguments [i];
3439 if (!a.Resolve (tc))
3444 method = Invocation.OverloadResolve (tc, (MethodGroupExpr) ml, Arguments,
3447 if (method == null) {
3448 Error (tc, -6, Location,
3449 "New invocation: Can not find a constructor for this argument list");
3453 eclass = ExprClass.Value;
3457 public override void Emit (EmitContext ec)
3459 Invocation.EmitArguments (ec, method, Arguments);
3460 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
3463 public override void EmitStatement (EmitContext ec)
3466 ec.ig.Emit (OpCodes.Pop);
3471 // Represents the `this' construct
3473 public class This : Expression, LValue {
3474 public override Expression DoResolve (TypeContainer tc)
3476 eclass = ExprClass.Variable;
3477 type = tc.TypeBuilder;
3480 // FIXME: Verify that this is only used in instance contexts.
3485 public override void Emit (EmitContext ec)
3487 ec.ig.Emit (OpCodes.Ldarg_0);
3490 public void Store (EmitContext ec)
3493 // Assignment to the "this" variable.
3495 // FIXME: Apparently this is a bug that we
3496 // must catch as `this' seems to be readonly ;-)
3498 ec.ig.Emit (OpCodes.Starg, 0);
3501 public void AddressOf (EmitContext ec)
3503 ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
3507 public class TypeOf : Expression {
3508 public readonly string QueriedType;
3510 public TypeOf (string queried_type)
3512 QueriedType = queried_type;
3515 public override Expression DoResolve (TypeContainer tc)
3517 type = tc.LookupType (QueriedType, false);
3522 eclass = ExprClass.Type;
3526 public override void Emit (EmitContext ec)
3528 throw new Exception ("Implement me");
3529 // FIXME: Implement.
3533 public class SizeOf : Expression {
3534 public readonly string QueriedType;
3536 public SizeOf (string queried_type)
3538 this.QueriedType = queried_type;
3541 public override Expression DoResolve (TypeContainer tc)
3543 // FIXME: Implement;
3544 throw new Exception ("Unimplemented");
3548 public override void Emit (EmitContext ec)
3550 throw new Exception ("Implement me");
3554 public class MemberAccess : Expression {
3555 public readonly string Identifier;
3557 Expression member_lookup;
3559 public MemberAccess (Expression expr, string id)
3565 public Expression Expr {
3571 public override Expression DoResolve (TypeContainer tc)
3573 Expression new_expression = expr.Resolve (tc);
3575 if (new_expression == null)
3578 member_lookup = MemberLookup (tc, expr.Type, Identifier, false);
3580 if (member_lookup is MethodGroupExpr){
3581 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
3584 // Bind the instance expression to it
3586 // FIXME: This is a horrible way of detecting if it is
3587 // an instance expression. Figure out how to fix this.
3590 if (expr is LocalVariableReference ||
3591 expr is ParameterReference ||
3593 mg.InstanceExpression = expr;
3595 return member_lookup;
3596 } else if (member_lookup is FieldExpr){
3597 FieldExpr fe = (FieldExpr) member_lookup;
3601 return member_lookup;
3604 // FIXME: This should generate the proper node
3605 // ie, for a Property Access, it should like call it
3608 return member_lookup;
3611 public override void Emit (EmitContext ec)
3613 throw new Exception ("Should not happen I think");
3619 // Nodes of type Namespace are created during the semantic
3620 // analysis to resolve member_access/qualified_identifier/simple_name
3623 // They are born `resolved'.
3625 public class NamespaceExpr : Expression {
3626 public readonly string Name;
3628 public NamespaceExpr (string name)
3631 eclass = ExprClass.Namespace;
3634 public override Expression DoResolve (TypeContainer tc)
3639 public override void Emit (EmitContext ec)
3641 throw new Exception ("Namespace expressions should never be emitted");
3646 // Fully resolved expression that evaluates to a type
3648 public class TypeExpr : Expression {
3649 public TypeExpr (Type t)
3652 eclass = ExprClass.Type;
3655 override public Expression DoResolve (TypeContainer tc)
3660 override public void Emit (EmitContext ec)
3662 throw new Exception ("Implement me");
3667 // MethodGroup Expression.
3669 // This is a fully resolved expression that evaluates to a type
3671 public class MethodGroupExpr : Expression {
3672 public readonly MethodBase [] Methods;
3673 Expression instance_expression = null;
3675 public MethodGroupExpr (MemberInfo [] mi)
3677 Methods = new MethodBase [mi.Length];
3678 mi.CopyTo (Methods, 0);
3679 eclass = ExprClass.MethodGroup;
3683 // `A method group may have associated an instance expression'
3685 public Expression InstanceExpression {
3687 return instance_expression;
3691 instance_expression = value;
3695 override public Expression DoResolve (TypeContainer tc)
3700 override public void Emit (EmitContext ec)
3702 throw new Exception ("This should never be reached");
3706 // Fully resolved expression that evaluates to a Field
3708 public class FieldExpr : Expression, LValue {
3709 public readonly FieldInfo FieldInfo;
3710 public Expression Instance;
3712 public FieldExpr (FieldInfo fi)
3715 eclass = ExprClass.Variable;
3716 type = fi.FieldType;
3719 override public Expression DoResolve (TypeContainer tc)
3721 if (!FieldInfo.IsStatic){
3722 if (Instance == null){
3723 throw new Exception ("non-static FieldExpr without instance var\n" +
3724 "You have to assign the Instance variable\n" +
3725 "Of the FieldExpr to set this\n");
3728 Instance = Instance.Resolve (tc);
3729 if (Instance == null)
3736 override public void Emit (EmitContext ec)
3738 ILGenerator ig = ec.ig;
3740 if (FieldInfo.IsStatic)
3741 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3745 ig.Emit (OpCodes.Ldfld, FieldInfo);
3749 public void Store (EmitContext ec)
3751 if (FieldInfo.IsStatic)
3752 ec.ig.Emit (OpCodes.Stsfld, FieldInfo);
3754 ec.ig.Emit (OpCodes.Stfld, FieldInfo);
3757 public void AddressOf (EmitContext ec)
3759 if (FieldInfo.IsStatic)
3760 ec.ig.Emit (OpCodes.Ldsflda, FieldInfo);
3763 ec.ig.Emit (OpCodes.Ldflda, FieldInfo);
3769 // Fully resolved expression that evaluates to a Property
3771 public class PropertyExpr : Expression {
3772 public readonly PropertyInfo PropertyInfo;
3773 public readonly bool IsStatic;
3775 public PropertyExpr (PropertyInfo pi)
3778 eclass = ExprClass.PropertyAccess;
3781 MethodBase [] acc = pi.GetAccessors ();
3783 for (int i = 0; i < acc.Length; i++)
3784 if (acc [i].IsStatic)
3787 type = pi.PropertyType;
3790 override public Expression DoResolve (TypeContainer tc)
3792 // We are born in resolved state.
3796 override public void Emit (EmitContext ec)
3798 // FIXME: Implement;
3799 throw new Exception ("Unimplemented");
3804 // Fully resolved expression that evaluates to a Expression
3806 public class EventExpr : Expression {
3807 public readonly EventInfo EventInfo;
3809 public EventExpr (EventInfo ei)
3812 eclass = ExprClass.EventAccess;
3815 override public Expression DoResolve (TypeContainer tc)
3817 // We are born in resolved state.
3821 override public void Emit (EmitContext ec)
3823 throw new Exception ("Implement me");
3824 // FIXME: Implement.
3828 public class CheckedExpr : Expression {
3830 public Expression Expr;
3832 public CheckedExpr (Expression e)
3837 public override Expression DoResolve (TypeContainer tc)
3839 Expr = Expr.Resolve (tc);
3844 eclass = Expr.ExprClass;
3849 public override void Emit (EmitContext ec)
3851 bool last_check = ec.CheckState;
3853 ec.CheckState = true;
3855 ec.CheckState = last_check;
3860 public class UnCheckedExpr : Expression {
3862 public Expression Expr;
3864 public UnCheckedExpr (Expression e)
3869 public override Expression DoResolve (TypeContainer tc)
3871 Expr = Expr.Resolve (tc);
3876 eclass = Expr.ExprClass;
3881 public override void Emit (EmitContext ec)
3883 bool last_check = ec.CheckState;
3885 ec.CheckState = false;
3887 ec.CheckState = last_check;
3892 public class ElementAccess : Expression {
3894 public readonly ArrayList Arguments;
3895 public readonly Expression Expr;
3897 public ElementAccess (Expression e, ArrayList e_list)
3903 public override Expression DoResolve (TypeContainer tc)
3905 // FIXME: Implement;
3906 throw new Exception ("Unimplemented");
3910 public override void Emit (EmitContext ec)
3912 // FIXME : Implement !
3913 throw new Exception ("Unimplemented");
3918 public class BaseAccess : Expression {
3920 public enum BaseAccessType {
3925 public readonly BaseAccessType BAType;
3926 public readonly string Member;
3927 public readonly ArrayList Arguments;
3929 public BaseAccess (BaseAccessType t, string member, ArrayList args)
3937 public override Expression DoResolve (TypeContainer tc)
3939 // FIXME: Implement;
3940 throw new Exception ("Unimplemented");
3944 public override void Emit (EmitContext ec)
3946 throw new Exception ("Unimplemented");
3950 public class UserImplicitCast : Expression {
3952 ArrayList arguments;
3954 public UserImplicitCast (MethodInfo method, ArrayList arguments)
3956 this.method = method;
3957 this.arguments = arguments;
3958 type = method.ReturnType;
3959 eclass = ExprClass.Value;
3962 public override Expression DoResolve (TypeContainer tc)
3965 // We are born in a fully resolved state
3970 public override void Emit (EmitContext ec)
3972 ILGenerator ig = ec.ig;
3974 // Note that operators are static anyway
3976 if (arguments != null)
3977 Invocation.EmitArguments (ec, method, arguments);
3979 if (method is MethodInfo)
3980 ig.Emit (OpCodes.Call, (MethodInfo) method);
3982 ig.Emit (OpCodes.Call, (ConstructorInfo) method);