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
19 using System.Collections;
20 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 (int error, string s)
77 Report.Error (error, s);
80 static protected void Error (int error, Location loc, string s)
82 Report.Error (error, loc, s);
86 // Utility wrapper routine for Warning, just to beautify the code
88 static protected void Warning (int warning, string s)
90 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 be reported (using Report)
111 // and a null value should be returned.
113 // There are two side effects expected from calling
114 // Resolve(): the the field variable "eclass" should
115 // be set to any value of the enumeration
116 // `ExprClass' and the type variable should be set
117 // to a valid type (this is the type of the
121 public abstract Expression DoResolve (EmitContext ec);
125 // Currently Resolve wraps DoResolve to perform sanity
126 // checking and assertion checking on what we expect from Resolve
129 public Expression Resolve (EmitContext ec)
131 Expression e = DoResolve (ec);
137 if (e.ExprClass == ExprClass.Invalid)
138 throw new Exception ("Expression " + e +
139 " ExprClass is Invalid after resolve");
141 if (e.ExprClass != ExprClass.MethodGroup)
143 throw new Exception ("Expression " + e +
144 " did not set its type after Resolve");
151 // Emits the code for the expression
156 // The Emit method is invoked to generate the code
157 // for the expression.
160 public abstract void Emit (EmitContext ec);
163 // Protected constructor. Only derivate types should
164 // be able to be created
167 protected Expression ()
169 eclass = ExprClass.Invalid;
174 // Returns a literalized version of a literal FieldInfo
176 static Expression Literalize (FieldInfo fi)
178 Type t = fi.FieldType;
179 object v = fi.GetValue (fi);
181 if (t == TypeManager.int32_type)
182 return new IntLiteral ((int) v);
183 else if (t == TypeManager.uint32_type)
184 return new UIntLiteral ((uint) v);
185 else if (t == TypeManager.int64_type)
186 return new LongLiteral ((long) v);
187 else if (t == TypeManager.uint64_type)
188 return new ULongLiteral ((ulong) v);
189 else if (t == TypeManager.float_type)
190 return new FloatLiteral ((float) v);
191 else if (t == TypeManager.double_type)
192 return new DoubleLiteral ((double) v);
193 else if (t == TypeManager.string_type)
194 return new StringLiteral ((string) v);
195 else if (t == TypeManager.short_type)
196 return new IntLiteral ((int) ((short)v));
197 else if (t == TypeManager.ushort_type)
198 return new IntLiteral ((int) ((ushort)v));
199 else if (t == TypeManager.sbyte_type)
200 return new IntLiteral ((int) ((sbyte)v));
201 else if (t == TypeManager.byte_type)
202 return new IntLiteral ((int) ((byte)v));
203 else if (t == TypeManager.char_type)
204 return new IntLiteral ((int) ((char)v));
206 throw new Exception ("Unknown type for literal (" + v.GetType () +
207 "), details: " + fi);
211 // Returns a fully formed expression after a MemberLookup
213 static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi)
215 if (mi is EventInfo){
216 return new EventExpr ((EventInfo) mi);
217 } else if (mi is FieldInfo){
218 FieldInfo fi = (FieldInfo) mi;
221 Expression e = Literalize (fi);
226 return new FieldExpr (fi);
227 } else if (mi is PropertyInfo){
228 return new PropertyExpr ((PropertyInfo) mi);
229 } else if (mi is Type)
230 return new TypeExpr ((Type) mi);
236 // FIXME: Probably implement a cache for (t,name,current_access_set)?
238 // FIXME: We need to cope with access permissions here, or this wont
241 // This code could use some optimizations, but we need to do some
242 // measurements. For example, we could use a delegate to `flag' when
243 // something can not any longer be a method-group (because it is something
247 // If the return value is an Array, then it is an array of
250 // If the return value is an MemberInfo, it is anything, but a Method
254 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
255 // the arguments here and have MemberLookup return only the methods that
256 // match the argument count/type, unlike we are doing now (we delay this
259 // This is so we can catch correctly attempts to invoke instance methods
260 // from a static body (scan for error 120 in ResolveSimpleName).
262 public static Expression MemberLookup (EmitContext ec, Type t, string name,
263 bool same_type, MemberTypes mt, BindingFlags bf)
266 bf |= BindingFlags.NonPublic;
268 MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers (
269 t, mt, bf, Type.FilterName, name);
274 // FIXME : How does this wierd case arise ?
278 if (mi.Length == 1 && !(mi [0] is MethodBase))
279 return Expression.ExprClassFromMemberInfo (ec, mi [0]);
281 for (int i = 0; i < mi.Length; i++)
282 if (!(mi [i] is MethodBase)){
283 Error (-5, "Do not know how to reproduce this case: " +
284 "Methods and non-Method with the same name, " +
285 "report this please");
287 for (i = 0; i < mi.Length; i++){
288 Type tt = mi [i].GetType ();
290 Console.WriteLine (i + ": " + mi [i]);
291 while (tt != TypeManager.object_type){
292 Console.WriteLine (tt);
298 return new MethodGroupExpr (mi);
301 public const MemberTypes AllMemberTypes =
302 MemberTypes.Constructor |
306 MemberTypes.NestedType |
307 MemberTypes.Property;
309 public const BindingFlags AllBindingsFlags =
310 BindingFlags.Public |
311 BindingFlags.Static |
312 BindingFlags.Instance;
314 public static Expression MemberLookup (EmitContext ec, Type t, string name,
317 return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags);
321 // I am in general unhappy with this implementation.
323 // I need to revise this.
326 // static public Expression ResolveMemberAccess (EmitContext ec, string name)
328 // Expression left_e = null;
329 // int dot_pos = name.LastIndexOf (".");
330 // string left = name.Substring (0, dot_pos);
331 // string right = name.Substring (dot_pos + 1);
334 // if ((t = ec.TypeContainer.LookupType (left, false)) != null){
337 // left_e = new TypeExpr (t);
338 // e = new MemberAccess (left_e, right);
339 // return e.Resolve (ec);
342 // // FIXME: IMplement:
345 // // T.P Static property access (P) on Type T.
346 // // e.P instance property access on instance e for P.
351 // if (left_e == null){
352 // Error (246, "Can not find type or namespace `"+left+"'");
356 // switch (left_e.ExprClass){
357 // case ExprClass.Type:
358 // return MemberLookup (ec,
359 // left_e.Type, right,
360 // left_e.Type == ec.TypeContainer.TypeBuilder);
362 // case ExprClass.Namespace:
363 // case ExprClass.PropertyAccess:
364 // case ExprClass.IndexerAccess:
365 // case ExprClass.Variable:
366 // case ExprClass.Value:
367 // case ExprClass.Nothing:
368 // case ExprClass.EventAccess:
369 // case ExprClass.MethodGroup:
370 // case ExprClass.Invalid:
371 // throw new Exception ("Should have got the " + left_e.ExprClass +
372 // " handled before");
378 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
380 Type expr_type = expr.Type;
382 if (target_type == TypeManager.object_type) {
383 if (expr_type.IsClass)
384 return new EmptyCast (expr, target_type);
385 if (expr_type.IsValueType)
386 return new BoxedCast (expr);
387 } else if (expr_type.IsSubclassOf (target_type)) {
388 return new EmptyCast (expr, target_type);
390 // from any class-type S to any interface-type T.
391 if (expr_type.IsClass && target_type.IsInterface) {
392 Type [] interfaces = expr_type.FindInterfaces (Module.FilterTypeName,
393 target_type.FullName);
394 if (interfaces != null)
395 return new EmptyCast (expr, target_type);
398 // from any interface type S to interface-type T.
399 // FIXME : Is it right to use IsAssignableFrom ?
400 if (expr_type.IsInterface && target_type.IsInterface)
401 if (target_type.IsAssignableFrom (expr_type))
402 return new EmptyCast (expr, target_type);
405 // from an array-type S to an array-type of type T
406 if (expr_type.IsArray && target_type.IsArray) {
408 Console.WriteLine ("{0} -> {1}", expr_type, target_type);
409 throw new Exception ("Implement array conversion");
413 // from an array-type to System.Array
414 if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type))
415 return new EmptyCast (expr, target_type);
417 // from any delegate type to System.Delegate
418 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
419 target_type == TypeManager.delegate_type)
420 if (target_type.IsAssignableFrom (expr_type))
421 return new EmptyCast (expr, target_type);
423 // from any array-type or delegate type into System.ICloneable.
424 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
425 if (target_type == TypeManager.icloneable_type)
426 throw new Exception ("Implement conversion to System.ICloneable");
428 // from the null type to any reference-type.
429 if (expr is NullLiteral)
430 return new EmptyCast (expr, target_type);
440 // Handles expressions like this: decimal d; d = 1;
441 // and changes them into: decimal d; d = new System.Decimal (1);
443 static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target)
445 ArrayList args = new ArrayList ();
447 args.Add (new Argument (expr, Argument.AType.Expression));
449 Expression ne = new New (target.FullName, args,
452 return ne.Resolve (ec);
456 // Implicit Numeric Conversions.
458 // expr is the expression to convert, returns a new expression of type
459 // target_type or null if an implicit conversion is not possible.
462 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
463 Type target_type, Location loc)
465 Type expr_type = expr.Type;
468 // Attempt to do the implicit constant expression conversions
470 if (expr is IntLiteral){
473 e = TryImplicitIntConversion (target_type, (IntLiteral) expr);
476 } else if (expr is LongLiteral){
478 // Try the implicit constant expression conversion
479 // from long to ulong, instead of a nice routine,
482 if (((LongLiteral) expr).Value > 0)
483 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
486 if (expr_type == TypeManager.sbyte_type){
488 // From sbyte to short, int, long, float, double.
490 if (target_type == TypeManager.int32_type)
491 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
492 if (target_type == TypeManager.int64_type)
493 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
494 if (target_type == TypeManager.double_type)
495 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
496 if (target_type == TypeManager.float_type)
497 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
498 if (target_type == TypeManager.short_type)
499 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
500 if (target_type == TypeManager.decimal_type)
501 return InternalTypeConstructor (ec, expr, target_type);
502 } else if (expr_type == TypeManager.byte_type){
504 // From byte to short, ushort, int, uint, long, ulong, float, double
506 if ((target_type == TypeManager.short_type) ||
507 (target_type == TypeManager.ushort_type) ||
508 (target_type == TypeManager.int32_type) ||
509 (target_type == TypeManager.uint32_type))
510 return new EmptyCast (expr, target_type);
512 if (target_type == TypeManager.uint64_type)
513 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
514 if (target_type == TypeManager.int64_type)
515 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
517 if (target_type == TypeManager.float_type)
518 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
519 if (target_type == TypeManager.double_type)
520 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
521 if (target_type == TypeManager.decimal_type)
522 return InternalTypeConstructor (ec, expr, target_type);
523 } else if (expr_type == TypeManager.short_type){
525 // From short to int, long, float, double
527 if (target_type == TypeManager.int32_type)
528 return new EmptyCast (expr, target_type);
529 if (target_type == TypeManager.int64_type)
530 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
531 if (target_type == TypeManager.double_type)
532 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
533 if (target_type == TypeManager.float_type)
534 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
535 if (target_type == TypeManager.decimal_type)
536 return InternalTypeConstructor (ec, expr, target_type);
537 } else if (expr_type == TypeManager.ushort_type){
539 // From ushort to int, uint, long, ulong, float, double
541 if (target_type == TypeManager.uint32_type)
542 return new EmptyCast (expr, target_type);
544 if (target_type == TypeManager.uint64_type)
545 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
546 if (target_type == TypeManager.int32_type)
547 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
548 if (target_type == TypeManager.int64_type)
549 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
550 if (target_type == TypeManager.double_type)
551 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
552 if (target_type == TypeManager.float_type)
553 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
554 if (target_type == TypeManager.decimal_type)
555 return InternalTypeConstructor (ec, expr, target_type);
556 } else if (expr_type == TypeManager.int32_type){
558 // From int to long, float, double
560 if (target_type == TypeManager.int64_type)
561 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
562 if (target_type == TypeManager.double_type)
563 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
564 if (target_type == TypeManager.float_type)
565 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
566 if (target_type == TypeManager.decimal_type)
567 return InternalTypeConstructor (ec, expr, target_type);
568 } else if (expr_type == TypeManager.uint32_type){
570 // From uint to long, ulong, float, double
572 if (target_type == TypeManager.int64_type)
573 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
574 if (target_type == TypeManager.uint64_type)
575 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
576 if (target_type == TypeManager.double_type)
577 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
579 if (target_type == TypeManager.float_type)
580 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
582 if (target_type == TypeManager.decimal_type)
583 return InternalTypeConstructor (ec, expr, target_type);
584 } else if ((expr_type == TypeManager.uint64_type) ||
585 (expr_type == TypeManager.int64_type)){
587 // From long/ulong to float, double
589 if (target_type == TypeManager.double_type)
590 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
592 if (target_type == TypeManager.float_type)
593 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
595 if (target_type == TypeManager.decimal_type)
596 return InternalTypeConstructor (ec, expr, target_type);
597 } else if (expr_type == TypeManager.char_type){
599 // From char to ushort, int, uint, long, ulong, float, double
601 if ((target_type == TypeManager.ushort_type) ||
602 (target_type == TypeManager.int32_type) ||
603 (target_type == TypeManager.uint32_type))
604 return new EmptyCast (expr, target_type);
605 if (target_type == TypeManager.uint64_type)
606 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
607 if (target_type == TypeManager.int64_type)
608 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
609 if (target_type == TypeManager.float_type)
610 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
611 if (target_type == TypeManager.double_type)
612 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
613 if (target_type == TypeManager.decimal_type)
614 return InternalTypeConstructor (ec, expr, target_type);
615 } else if (expr_type == TypeManager.float_type){
619 if (target_type == TypeManager.double_type)
620 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
627 // Determines if a standard implicit conversion exists from
628 // expr_type to target_type
630 public static bool StandardConversionExists (Type expr_type, Type target_type)
632 if (expr_type == target_type)
635 // First numeric conversions
637 if (expr_type == TypeManager.sbyte_type){
639 // From sbyte to short, int, long, float, double.
641 if ((target_type == TypeManager.int32_type) ||
642 (target_type == TypeManager.int64_type) ||
643 (target_type == TypeManager.double_type) ||
644 (target_type == TypeManager.float_type) ||
645 (target_type == TypeManager.short_type) ||
646 (target_type == TypeManager.decimal_type))
649 } else if (expr_type == TypeManager.byte_type){
651 // From byte to short, ushort, int, uint, long, ulong, float, double
653 if ((target_type == TypeManager.short_type) ||
654 (target_type == TypeManager.ushort_type) ||
655 (target_type == TypeManager.int32_type) ||
656 (target_type == TypeManager.uint32_type) ||
657 (target_type == TypeManager.uint64_type) ||
658 (target_type == TypeManager.int64_type) ||
659 (target_type == TypeManager.float_type) ||
660 (target_type == TypeManager.double_type) ||
661 (target_type == TypeManager.decimal_type))
664 } else if (expr_type == TypeManager.short_type){
666 // From short to int, long, float, double
668 if ((target_type == TypeManager.int32_type) ||
669 (target_type == TypeManager.int64_type) ||
670 (target_type == TypeManager.double_type) ||
671 (target_type == TypeManager.float_type) ||
672 (target_type == TypeManager.decimal_type))
675 } else if (expr_type == TypeManager.ushort_type){
677 // From ushort to int, uint, long, ulong, float, double
679 if ((target_type == TypeManager.uint32_type) ||
680 (target_type == TypeManager.uint64_type) ||
681 (target_type == TypeManager.int32_type) ||
682 (target_type == TypeManager.int64_type) ||
683 (target_type == TypeManager.double_type) ||
684 (target_type == TypeManager.float_type) ||
685 (target_type == TypeManager.decimal_type))
688 } else if (expr_type == TypeManager.int32_type){
690 // From int to long, float, double
692 if ((target_type == TypeManager.int64_type) ||
693 (target_type == TypeManager.double_type) ||
694 (target_type == TypeManager.float_type) ||
695 (target_type == TypeManager.decimal_type))
698 } else if (expr_type == TypeManager.uint32_type){
700 // From uint to long, ulong, float, double
702 if ((target_type == TypeManager.int64_type) ||
703 (target_type == TypeManager.uint64_type) ||
704 (target_type == TypeManager.double_type) ||
705 (target_type == TypeManager.float_type) ||
706 (target_type == TypeManager.decimal_type))
709 } else if ((expr_type == TypeManager.uint64_type) ||
710 (expr_type == TypeManager.int64_type)) {
712 // From long/ulong to float, double
714 if ((target_type == TypeManager.double_type) ||
715 (target_type == TypeManager.float_type) ||
716 (target_type == TypeManager.decimal_type))
719 } else if (expr_type == TypeManager.char_type){
721 // From char to ushort, int, uint, long, ulong, float, double
723 if ((target_type == TypeManager.ushort_type) ||
724 (target_type == TypeManager.int32_type) ||
725 (target_type == TypeManager.uint32_type) ||
726 (target_type == TypeManager.uint64_type) ||
727 (target_type == TypeManager.int64_type) ||
728 (target_type == TypeManager.float_type) ||
729 (target_type == TypeManager.double_type) ||
730 (target_type == TypeManager.decimal_type))
733 } else if (expr_type == TypeManager.float_type){
737 if (target_type == TypeManager.double_type)
741 // Next reference conversions
743 if (target_type == TypeManager.object_type) {
744 if ((expr_type.IsClass) ||
745 (expr_type.IsValueType))
748 } else if (expr_type.IsSubclassOf (target_type)) {
752 // from any class-type S to any interface-type T.
753 if (expr_type.IsClass && target_type.IsInterface)
756 // from any interface type S to interface-type T.
757 // FIXME : Is it right to use IsAssignableFrom ?
758 if (expr_type.IsInterface && target_type.IsInterface)
759 if (target_type.IsAssignableFrom (expr_type))
762 // from an array-type S to an array-type of type T
763 if (expr_type.IsArray && target_type.IsArray)
766 // from an array-type to System.Array
767 if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type))
770 // from any delegate type to System.Delegate
771 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
772 target_type == TypeManager.delegate_type)
773 if (target_type.IsAssignableFrom (expr_type))
776 // from any array-type or delegate type into System.ICloneable.
777 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
778 if (target_type == TypeManager.icloneable_type)
781 // from the null type to any reference-type.
782 // FIXME : How do we do this ?
790 // Finds "most encompassed type" according to the spec (13.4.2)
791 // amongst the methods in the MethodGroupExpr which convert from a
792 // type encompassing source_type
794 static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type)
798 for (int i = me.Methods.Length; i > 0; ) {
801 MethodBase mb = me.Methods [i];
802 ParameterData pd = Invocation.GetParameterData (mb);
803 Type param_type = pd.ParameterType (0);
805 if (StandardConversionExists (source_type, param_type)) {
809 if (StandardConversionExists (param_type, best))
818 // Finds "most encompassing type" according to the spec (13.4.2)
819 // amongst the methods in the MethodGroupExpr which convert to a
820 // type encompassed by target_type
822 static Type FindMostEncompassingType (MethodGroupExpr me, Type target)
826 for (int i = me.Methods.Length; i > 0; ) {
829 MethodInfo mi = (MethodInfo) me.Methods [i];
830 Type ret_type = mi.ReturnType;
832 if (StandardConversionExists (ret_type, target)) {
836 if (!StandardConversionExists (ret_type, best))
848 // User-defined Implicit conversions
850 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
851 Type target, Location loc)
853 return UserDefinedConversion (ec, source, target, loc, false);
857 // User-defined Explicit conversions
859 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
860 Type target, Location loc)
862 return UserDefinedConversion (ec, source, target, loc, true);
866 // User-defined conversions
868 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
869 Type target, Location loc,
870 bool look_for_explicit)
872 Expression mg1 = null, mg2 = null, mg3 = null, mg4 = null;
873 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
875 MethodBase method = null;
876 Type source_type = source.Type;
880 // If we have a boolean type, we need to check for the True operator
882 // FIXME : How does the False operator come into the picture ?
883 // FIXME : This doesn't look complete and very correct !
884 if (target == TypeManager.bool_type)
887 op_name = "op_Implicit";
889 mg1 = MemberLookup (ec, source_type, op_name, false);
891 if (source_type.BaseType != null)
892 mg2 = MemberLookup (ec, source_type.BaseType, op_name, false);
894 mg3 = MemberLookup (ec, target, op_name, false);
896 if (target.BaseType != null)
897 mg4 = MemberLookup (ec, target.BaseType, op_name, false);
899 MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2);
900 MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4);
902 MethodGroupExpr union3 = Invocation.MakeUnionSet (union1, union2);
904 MethodGroupExpr union4 = null;
906 if (look_for_explicit) {
908 op_name = "op_Explicit";
910 mg5 = MemberLookup (ec, source_type, op_name, false);
912 if (source_type.BaseType != null)
913 mg6 = MemberLookup (ec, source_type.BaseType, op_name, false);
915 mg7 = MemberLookup (ec, target, op_name, false);
917 if (target.BaseType != null)
918 mg8 = MemberLookup (ec, target.BaseType, op_name, false);
920 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6);
921 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8);
923 union4 = Invocation.MakeUnionSet (union5, union6);
926 MethodGroupExpr union = Invocation.MakeUnionSet (union3, union4);
930 Type most_specific_source, most_specific_target;
932 most_specific_source = FindMostEncompassedType (union, source_type);
933 if (most_specific_source == null)
936 most_specific_target = FindMostEncompassingType (union, target);
937 if (most_specific_target == null)
942 for (int i = union.Methods.Length; i > 0;) {
945 MethodBase mb = union.Methods [i];
946 ParameterData pd = Invocation.GetParameterData (mb);
947 MethodInfo mi = (MethodInfo) union.Methods [i];
949 if (pd.ParameterType (0) == most_specific_source &&
950 mi.ReturnType == most_specific_target) {
956 if (method == null || count > 1) {
957 Report.Error (-11, loc, "Ambiguous user defined conversion");
962 // This will do the conversion to the best match that we
963 // found. Now we need to perform an implict standard conversion
964 // if the best match was not the type that we were requested
967 if (look_for_explicit)
968 source=ConvertExplicit (ec, source, most_specific_source, loc);
970 source = ConvertImplicitStandard (ec, source,
971 most_specific_source, loc);
976 e = new UserCast ((MethodInfo) method, source);
978 if (e.Type != target){
979 if (!look_for_explicit)
980 e = ConvertImplicitStandard (ec, e, target, loc);
982 e = ConvertExplicitStandard (ec, e, target, loc);
993 // Converts implicitly the resolved expression `expr' into the
994 // `target_type'. It returns a new expression that can be used
995 // in a context that expects a `target_type'.
997 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
998 Type target_type, Location loc)
1000 Type expr_type = expr.Type;
1003 if (expr_type == target_type)
1006 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1010 e = ImplicitReferenceConversion (expr, target_type);
1014 e = ImplicitUserConversion (ec, expr, target_type, loc);
1018 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1019 IntLiteral i = (IntLiteral) expr;
1022 return new EmptyCast (expr, target_type);
1030 // Attempts to apply the `Standard Implicit
1031 // Conversion' rules to the expression `expr' into
1032 // the `target_type'. It returns a new expression
1033 // that can be used in a context that expects a
1036 // This is different from `ConvertImplicit' in that the
1037 // user defined implicit conversions are excluded.
1039 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
1040 Type target_type, Location loc)
1042 Type expr_type = expr.Type;
1045 if (expr_type == target_type)
1048 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1052 e = ImplicitReferenceConversion (expr, target_type);
1056 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1057 IntLiteral i = (IntLiteral) expr;
1060 return new EmptyCast (expr, target_type);
1065 // Attemps to perform an implict constant conversion of the IntLiteral
1066 // into a different data type using casts (See Implicit Constant
1067 // Expression Conversions)
1069 static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il)
1071 int value = il.Value;
1073 if (target_type == TypeManager.sbyte_type){
1074 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1076 } else if (target_type == TypeManager.byte_type){
1077 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1079 } else if (target_type == TypeManager.short_type){
1080 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1082 } else if (target_type == TypeManager.ushort_type){
1083 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1085 } else if (target_type == TypeManager.uint32_type){
1087 // we can optimize this case: a positive int32
1088 // always fits on a uint32
1092 } else if (target_type == TypeManager.uint64_type){
1094 // we can optimize this case: a positive int32
1095 // always fits on a uint64. But we need an opcode
1099 return new OpcodeCast (il, target_type, OpCodes.Conv_I8);
1106 // Attemptes to implicityly convert `target' into `type', using
1107 // ConvertImplicit. If there is no implicit conversion, then
1108 // an error is signaled
1110 static public Expression ConvertImplicitRequired (EmitContext ec, Expression target,
1111 Type type, Location loc)
1115 e = ConvertImplicit (ec, target, type, loc);
1119 string msg = "Can not convert implicitly from `"+
1120 TypeManager.CSharpName (target.Type) + "' to `" +
1121 TypeManager.CSharpName (type) + "'";
1123 Error (29, loc, msg);
1129 // Performs the explicit numeric conversions
1131 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr,
1134 Type expr_type = expr.Type;
1136 if (expr_type == TypeManager.sbyte_type){
1138 // From sbyte to byte, ushort, uint, ulong, char
1140 if (target_type == TypeManager.byte_type)
1141 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1142 if (target_type == TypeManager.ushort_type)
1143 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1144 if (target_type == TypeManager.uint32_type)
1145 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1146 if (target_type == TypeManager.uint64_type)
1147 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1148 if (target_type == TypeManager.char_type)
1149 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1150 } else if (expr_type == TypeManager.byte_type){
1152 // From byte to sbyte and char
1154 if (target_type == TypeManager.sbyte_type)
1155 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1156 if (target_type == TypeManager.char_type)
1157 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1158 } else if (expr_type == TypeManager.short_type){
1160 // From short to sbyte, byte, ushort, uint, ulong, char
1162 if (target_type == TypeManager.sbyte_type)
1163 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1164 if (target_type == TypeManager.byte_type)
1165 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1166 if (target_type == TypeManager.ushort_type)
1167 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1168 if (target_type == TypeManager.uint32_type)
1169 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1170 if (target_type == TypeManager.uint64_type)
1171 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1172 if (target_type == TypeManager.char_type)
1173 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1174 } else if (expr_type == TypeManager.ushort_type){
1176 // From ushort to sbyte, byte, short, char
1178 if (target_type == TypeManager.sbyte_type)
1179 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1180 if (target_type == TypeManager.byte_type)
1181 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1182 if (target_type == TypeManager.short_type)
1183 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1184 if (target_type == TypeManager.char_type)
1185 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1186 } else if (expr_type == TypeManager.int32_type){
1188 // From int to sbyte, byte, short, ushort, uint, ulong, char
1190 if (target_type == TypeManager.sbyte_type)
1191 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1192 if (target_type == TypeManager.byte_type)
1193 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1194 if (target_type == TypeManager.short_type)
1195 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1196 if (target_type == TypeManager.ushort_type)
1197 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1198 if (target_type == TypeManager.uint32_type)
1199 return new EmptyCast (expr, target_type);
1200 if (target_type == TypeManager.uint64_type)
1201 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1202 if (target_type == TypeManager.char_type)
1203 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1204 } else if (expr_type == TypeManager.uint32_type){
1206 // From uint to sbyte, byte, short, ushort, int, char
1208 if (target_type == TypeManager.sbyte_type)
1209 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1210 if (target_type == TypeManager.byte_type)
1211 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1212 if (target_type == TypeManager.short_type)
1213 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1214 if (target_type == TypeManager.ushort_type)
1215 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1216 if (target_type == TypeManager.int32_type)
1217 return new EmptyCast (expr, target_type);
1218 if (target_type == TypeManager.char_type)
1219 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1220 } else if (expr_type == TypeManager.int64_type){
1222 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1224 if (target_type == TypeManager.sbyte_type)
1225 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1226 if (target_type == TypeManager.byte_type)
1227 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1228 if (target_type == TypeManager.short_type)
1229 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1230 if (target_type == TypeManager.ushort_type)
1231 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1232 if (target_type == TypeManager.int32_type)
1233 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1234 if (target_type == TypeManager.uint32_type)
1235 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1236 if (target_type == TypeManager.uint64_type)
1237 return new EmptyCast (expr, target_type);
1238 if (target_type == TypeManager.char_type)
1239 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1240 } else if (expr_type == TypeManager.uint64_type){
1242 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1244 if (target_type == TypeManager.sbyte_type)
1245 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1246 if (target_type == TypeManager.byte_type)
1247 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1248 if (target_type == TypeManager.short_type)
1249 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1250 if (target_type == TypeManager.ushort_type)
1251 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1252 if (target_type == TypeManager.int32_type)
1253 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1254 if (target_type == TypeManager.uint32_type)
1255 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1256 if (target_type == TypeManager.int64_type)
1257 return new EmptyCast (expr, target_type);
1258 if (target_type == TypeManager.char_type)
1259 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1260 } else if (expr_type == TypeManager.char_type){
1262 // From char to sbyte, byte, short
1264 if (target_type == TypeManager.sbyte_type)
1265 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1266 if (target_type == TypeManager.byte_type)
1267 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1268 if (target_type == TypeManager.short_type)
1269 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1270 } else if (expr_type == TypeManager.float_type){
1272 // From float to sbyte, byte, short,
1273 // ushort, int, uint, long, ulong, char
1276 if (target_type == TypeManager.sbyte_type)
1277 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1278 if (target_type == TypeManager.byte_type)
1279 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1280 if (target_type == TypeManager.short_type)
1281 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1282 if (target_type == TypeManager.ushort_type)
1283 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1284 if (target_type == TypeManager.int32_type)
1285 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1286 if (target_type == TypeManager.uint32_type)
1287 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1288 if (target_type == TypeManager.int64_type)
1289 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1290 if (target_type == TypeManager.uint64_type)
1291 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1292 if (target_type == TypeManager.char_type)
1293 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1294 if (target_type == TypeManager.decimal_type)
1295 return InternalTypeConstructor (ec, expr, target_type);
1296 } else if (expr_type == TypeManager.double_type){
1298 // From double to byte, byte, short,
1299 // ushort, int, uint, long, ulong,
1300 // char, float or decimal
1302 if (target_type == TypeManager.sbyte_type)
1303 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1304 if (target_type == TypeManager.byte_type)
1305 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1306 if (target_type == TypeManager.short_type)
1307 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1308 if (target_type == TypeManager.ushort_type)
1309 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1310 if (target_type == TypeManager.int32_type)
1311 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1312 if (target_type == TypeManager.uint32_type)
1313 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1314 if (target_type == TypeManager.int64_type)
1315 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1316 if (target_type == TypeManager.uint64_type)
1317 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1318 if (target_type == TypeManager.char_type)
1319 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1320 if (target_type == TypeManager.float_type)
1321 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
1322 if (target_type == TypeManager.decimal_type)
1323 return InternalTypeConstructor (ec, expr, target_type);
1326 // decimal is taken care of by the op_Explicit methods.
1332 // Implements Explicit Reference conversions
1334 static Expression ConvertReferenceExplicit (Expression expr, Type target_type)
1336 Type expr_type = expr.Type;
1337 bool target_is_value_type = target_type.IsValueType;
1340 // From object to any reference type
1342 if (expr_type == TypeManager.object_type && !target_is_value_type)
1343 return new ClassCast (expr, target_type);
1349 // Performs an explicit conversion of the expression `expr' whose
1350 // type is expr.Type to `target_type'.
1352 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
1353 Type target_type, Location loc)
1355 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
1360 ne = ConvertNumericExplicit (ec, expr, target_type);
1364 ne = ConvertReferenceExplicit (expr, target_type);
1368 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1372 Report.Error (30, loc, "Cannot convert type '" + TypeManager.CSharpName (expr.Type) + "' to '"
1373 + TypeManager.CSharpName (target_type) + "'");
1378 // Same as ConverExplicit, only it doesn't include user defined conversions
1380 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
1381 Type target_type, Location l)
1383 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
1388 ne = ConvertNumericExplicit (ec, expr, target_type);
1392 ne = ConvertReferenceExplicit (expr, target_type);
1396 Report.Error (30, l, "Cannot convert type '" +
1397 TypeManager.CSharpName (expr.Type) + "' to '" +
1398 TypeManager.CSharpName (target_type) + "'");
1402 static string ExprClassName (ExprClass c)
1405 case ExprClass.Invalid:
1407 case ExprClass.Value:
1409 case ExprClass.Variable:
1411 case ExprClass.Namespace:
1413 case ExprClass.Type:
1415 case ExprClass.MethodGroup:
1416 return "method group";
1417 case ExprClass.PropertyAccess:
1418 return "property access";
1419 case ExprClass.EventAccess:
1420 return "event access";
1421 case ExprClass.IndexerAccess:
1422 return "indexer access";
1423 case ExprClass.Nothing:
1426 throw new Exception ("Should not happen");
1430 // Reports that we were expecting `expr' to be of class `expected'
1432 protected void report118 (Location loc, Expression expr, string expected)
1434 string kind = "Unknown";
1437 kind = ExprClassName (expr.ExprClass);
1439 Error (118, loc, "Expression denotes a '" + kind +
1440 "' where an " + expected + " was expected");
1445 // This is just a base class for expressions that can
1446 // appear on statements (invocations, object creation,
1447 // assignments, post/pre increment and decrement). The idea
1448 // being that they would support an extra Emition interface that
1449 // does not leave a result on the stack.
1452 public abstract class ExpressionStatement : Expression {
1455 // Requests the expression to be emitted in a `statement'
1456 // context. This means that no new value is left on the
1457 // stack after invoking this method (constrasted with
1458 // Emit that will always leave a value on the stack).
1460 public abstract void EmitStatement (EmitContext ec);
1464 // This kind of cast is used to encapsulate the child
1465 // whose type is child.Type into an expression that is
1466 // reported to return "return_type". This is used to encapsulate
1467 // expressions which have compatible types, but need to be dealt
1468 // at higher levels with.
1470 // For example, a "byte" expression could be encapsulated in one
1471 // of these as an "unsigned int". The type for the expression
1472 // would be "unsigned int".
1476 public class EmptyCast : Expression {
1477 protected Expression child;
1479 public EmptyCast (Expression child, Type return_type)
1481 ExprClass = child.ExprClass;
1486 public override Expression DoResolve (EmitContext ec)
1488 // This should never be invoked, we are born in fully
1489 // initialized state.
1494 public override void Emit (EmitContext ec)
1501 // This kind of cast is used to encapsulate Value Types in objects.
1503 // The effect of it is to box the value type emitted by the previous
1506 public class BoxedCast : EmptyCast {
1508 public BoxedCast (Expression expr)
1509 : base (expr, TypeManager.object_type)
1513 public override Expression DoResolve (EmitContext ec)
1515 // This should never be invoked, we are born in fully
1516 // initialized state.
1521 public override void Emit (EmitContext ec)
1524 ec.ig.Emit (OpCodes.Box, child.Type);
1529 // This kind of cast is used to encapsulate a child expression
1530 // that can be trivially converted to a target type using one or
1531 // two opcodes. The opcodes are passed as arguments.
1533 public class OpcodeCast : EmptyCast {
1537 public OpcodeCast (Expression child, Type return_type, OpCode op)
1538 : base (child, return_type)
1542 second_valid = false;
1545 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1546 : base (child, return_type)
1551 second_valid = true;
1554 public override Expression DoResolve (EmitContext ec)
1556 // This should never be invoked, we are born in fully
1557 // initialized state.
1562 public override void Emit (EmitContext ec)
1574 // This kind of cast is used to encapsulate a child and cast it
1575 // to the class requested
1577 public class ClassCast : EmptyCast {
1578 public ClassCast (Expression child, Type return_type)
1579 : base (child, return_type)
1584 public override Expression DoResolve (EmitContext ec)
1586 // This should never be invoked, we are born in fully
1587 // initialized state.
1592 public override void Emit (EmitContext ec)
1596 ec.ig.Emit (OpCodes.Castclass, type);
1602 // Unary expressions.
1606 // Unary implements unary expressions. It derives from
1607 // ExpressionStatement becuase the pre/post increment/decrement
1608 // operators can be used in a statement context.
1610 public class Unary : ExpressionStatement {
1611 public enum Operator {
1612 Addition, Subtraction, Negate, BitComplement,
1613 Indirection, AddressOf, PreIncrement,
1614 PreDecrement, PostIncrement, PostDecrement
1619 ArrayList Arguments;
1623 public Unary (Operator op, Expression expr, Location loc)
1630 public Expression Expr {
1640 public Operator Oper {
1651 // Returns a stringified representation of the Operator
1656 case Operator.Addition:
1658 case Operator.Subtraction:
1660 case Operator.Negate:
1662 case Operator.BitComplement:
1664 case Operator.AddressOf:
1666 case Operator.Indirection:
1668 case Operator.PreIncrement : case Operator.PostIncrement :
1670 case Operator.PreDecrement : case Operator.PostDecrement :
1674 return oper.ToString ();
1677 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1679 if (expr.Type == target_type)
1682 return ConvertImplicit (ec, expr, target_type, new Location (-1));
1685 void error23 (Type t)
1688 23, loc, "Operator " + OperName () +
1689 " cannot be applied to operand of type `" +
1690 TypeManager.CSharpName (t) + "'");
1694 // Returns whether an object of type `t' can be incremented
1695 // or decremented with add/sub (ie, basically whether we can
1696 // use pre-post incr-decr operations on it, but it is not a
1697 // System.Decimal, which we test elsewhere)
1699 static bool IsIncrementableNumber (Type t)
1701 return (t == TypeManager.sbyte_type) ||
1702 (t == TypeManager.byte_type) ||
1703 (t == TypeManager.short_type) ||
1704 (t == TypeManager.ushort_type) ||
1705 (t == TypeManager.int32_type) ||
1706 (t == TypeManager.uint32_type) ||
1707 (t == TypeManager.int64_type) ||
1708 (t == TypeManager.uint64_type) ||
1709 (t == TypeManager.char_type) ||
1710 (t.IsSubclassOf (TypeManager.enum_type)) ||
1711 (t == TypeManager.float_type) ||
1712 (t == TypeManager.double_type);
1715 Expression ResolveOperator (EmitContext ec)
1717 Type expr_type = expr.Type;
1720 // Step 1: Perform Operator Overload location
1725 if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
1726 op_name = "op_Increment";
1727 else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
1728 op_name = "op_Decrement";
1730 op_name = "op_" + oper;
1732 mg = MemberLookup (ec, expr_type, op_name, false);
1734 if (mg == null && expr_type.BaseType != null)
1735 mg = MemberLookup (ec, expr_type.BaseType, op_name, false);
1738 Arguments = new ArrayList ();
1739 Arguments.Add (new Argument (expr, Argument.AType.Expression));
1741 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg,
1743 if (method != null) {
1744 MethodInfo mi = (MethodInfo) method;
1745 type = mi.ReturnType;
1748 error23 (expr_type);
1755 // Step 2: Default operations on CLI native types.
1758 // Only perform numeric promotions on:
1761 if (expr_type == null)
1764 if (oper == Operator.Negate){
1765 if (expr_type != TypeManager.bool_type) {
1766 error23 (expr.Type);
1770 type = TypeManager.bool_type;
1774 if (oper == Operator.BitComplement) {
1775 if (!((expr_type == TypeManager.int32_type) ||
1776 (expr_type == TypeManager.uint32_type) ||
1777 (expr_type == TypeManager.int64_type) ||
1778 (expr_type == TypeManager.uint64_type) ||
1779 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
1780 error23 (expr.Type);
1787 if (oper == Operator.Addition) {
1789 // A plus in front of something is just a no-op, so return the child.
1795 // Deals with -literals
1796 // int operator- (int x)
1797 // long operator- (long x)
1798 // float operator- (float f)
1799 // double operator- (double d)
1800 // decimal operator- (decimal d)
1802 if (oper == Operator.Subtraction){
1804 // Fold a "- Constant" into a negative constant
1807 Expression e = null;
1810 // Is this a constant?
1812 if (expr is IntLiteral)
1813 e = new IntLiteral (-((IntLiteral) expr).Value);
1814 else if (expr is LongLiteral)
1815 e = new LongLiteral (-((LongLiteral) expr).Value);
1816 else if (expr is FloatLiteral)
1817 e = new FloatLiteral (-((FloatLiteral) expr).Value);
1818 else if (expr is DoubleLiteral)
1819 e = new DoubleLiteral (-((DoubleLiteral) expr).Value);
1820 else if (expr is DecimalLiteral)
1821 e = new DecimalLiteral (-((DecimalLiteral) expr).Value);
1829 // Not a constant we can optimize, perform numeric
1830 // promotions to int, long, double.
1833 // The following is inneficient, because we call
1834 // ConvertImplicit too many times.
1836 // It is also not clear if we should convert to Float
1837 // or Double initially.
1839 Location loc = new Location (-1);
1841 if (expr_type == TypeManager.uint32_type){
1843 // FIXME: handle exception to this rule that
1844 // permits the int value -2147483648 (-2^31) to
1845 // bt written as a decimal interger literal
1847 type = TypeManager.int64_type;
1848 expr = ConvertImplicit (ec, expr, type, loc);
1852 if (expr_type == TypeManager.uint64_type){
1854 // FIXME: Handle exception of `long value'
1855 // -92233720368547758087 (-2^63) to be written as
1856 // decimal integer literal.
1858 error23 (expr_type);
1862 e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc);
1869 e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc);
1876 e = ConvertImplicit (ec, expr, TypeManager.double_type, loc);
1883 error23 (expr_type);
1888 // The operand of the prefix/postfix increment decrement operators
1889 // should be an expression that is classified as a variable,
1890 // a property access or an indexer access
1892 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
1893 oper == Operator.PostDecrement || oper == Operator.PostIncrement){
1894 if (expr.ExprClass == ExprClass.Variable){
1895 if (IsIncrementableNumber (expr_type) ||
1896 expr_type == TypeManager.decimal_type){
1900 } else if (expr.ExprClass == ExprClass.IndexerAccess){
1902 // FIXME: Verify that we have both get and set methods
1904 throw new Exception ("Implement me");
1905 } else if (expr.ExprClass == ExprClass.PropertyAccess){
1907 // FIXME: Verify that we have both get and set methods
1909 throw new Exception ("Implement me");
1911 report118 (loc, expr, "variable, indexer or property access");
1915 if (oper == Operator.AddressOf){
1916 if (expr.ExprClass != ExprClass.Variable){
1917 Error (211, "Cannot take the address of non-variables");
1920 type = Type.GetType (expr.Type.ToString () + "*");
1923 Error (187, "No such operator '" + OperName () + "' defined for type '" +
1924 TypeManager.CSharpName (expr_type) + "'");
1929 public override Expression DoResolve (EmitContext ec)
1931 expr = expr.Resolve (ec);
1936 eclass = ExprClass.Value;
1937 return ResolveOperator (ec);
1940 public override void Emit (EmitContext ec)
1942 ILGenerator ig = ec.ig;
1943 Type expr_type = expr.Type;
1945 if (method != null) {
1947 // Note that operators are static anyway
1949 if (Arguments != null)
1950 Invocation.EmitArguments (ec, method, Arguments);
1953 // Post increment/decrement operations need a copy at this
1956 if (oper == Operator.PostDecrement || oper == Operator.PostIncrement)
1957 ig.Emit (OpCodes.Dup);
1960 ig.Emit (OpCodes.Call, (MethodInfo) method);
1963 // Pre Increment and Decrement operators
1965 if (oper == Operator.PreIncrement || oper == Operator.PreDecrement){
1966 ig.Emit (OpCodes.Dup);
1970 // Increment and Decrement should store the result
1972 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
1973 oper == Operator.PostDecrement || oper == Operator.PostIncrement){
1974 ((LValue) expr).Store (ec);
1980 case Operator.Addition:
1981 throw new Exception ("This should be caught by Resolve");
1983 case Operator.Subtraction:
1985 ig.Emit (OpCodes.Neg);
1988 case Operator.Negate:
1990 ig.Emit (OpCodes.Ldc_I4_0);
1991 ig.Emit (OpCodes.Ceq);
1994 case Operator.BitComplement:
1996 ig.Emit (OpCodes.Not);
1999 case Operator.AddressOf:
2000 ((LValue)expr).AddressOf (ec);
2003 case Operator.Indirection:
2004 throw new Exception ("Not implemented yet");
2006 case Operator.PreIncrement:
2007 case Operator.PreDecrement:
2008 if (expr.ExprClass == ExprClass.Variable){
2010 // Resolve already verified that it is an "incrementable"
2013 ig.Emit (OpCodes.Ldc_I4_1);
2015 if (oper == Operator.PreDecrement)
2016 ig.Emit (OpCodes.Sub);
2018 ig.Emit (OpCodes.Add);
2019 ig.Emit (OpCodes.Dup);
2020 ((LValue) expr).Store (ec);
2022 throw new Exception ("Handle Indexers and Properties here");
2026 case Operator.PostIncrement:
2027 case Operator.PostDecrement:
2028 if (expr.ExprClass == ExprClass.Variable){
2030 // Resolve already verified that it is an "incrementable"
2033 ig.Emit (OpCodes.Dup);
2034 ig.Emit (OpCodes.Ldc_I4_1);
2036 if (oper == Operator.PostDecrement)
2037 ig.Emit (OpCodes.Sub);
2039 ig.Emit (OpCodes.Add);
2040 ((LValue) expr).Store (ec);
2042 throw new Exception ("Handle Indexers and Properties here");
2047 throw new Exception ("This should not happen: Operator = "
2048 + oper.ToString ());
2053 public override void EmitStatement (EmitContext ec)
2056 // FIXME: we should rewrite this code to generate
2057 // better code for ++ and -- as we know we wont need
2058 // the values on the stack
2061 ec.ig.Emit (OpCodes.Pop);
2065 public class Probe : Expression {
2066 public readonly string ProbeType;
2067 public readonly Operator Oper;
2071 public enum Operator {
2075 public Probe (Operator oper, Expression expr, string probe_type)
2078 ProbeType = probe_type;
2082 public Expression Expr {
2088 public override Expression DoResolve (EmitContext ec)
2090 probe_type = ec.TypeContainer.LookupType (ProbeType, false);
2092 if (probe_type == null)
2095 expr = expr.Resolve (ec);
2097 type = TypeManager.bool_type;
2098 eclass = ExprClass.Value;
2103 public override void Emit (EmitContext ec)
2105 ILGenerator ig = ec.ig;
2109 if (Oper == Operator.Is){
2110 ig.Emit (OpCodes.Isinst, probe_type);
2111 ig.Emit (OpCodes.Ldnull);
2112 ig.Emit (OpCodes.Cgt_Un);
2114 ig.Emit (OpCodes.Isinst, probe_type);
2120 // This represents a typecast in the source language.
2122 // FIXME: Cast expressions have an unusual set of parsing
2123 // rules, we need to figure those out.
2125 public class Cast : Expression {
2130 public Cast (string cast_type, Expression expr, Location loc)
2132 this.target_type = cast_type;
2137 public string TargetType {
2143 public Expression Expr {
2152 public override Expression DoResolve (EmitContext ec)
2154 expr = expr.Resolve (ec);
2158 type = ec.TypeContainer.LookupType (target_type, false);
2159 eclass = ExprClass.Value;
2164 expr = ConvertExplicit (ec, expr, type, loc);
2169 public override void Emit (EmitContext ec)
2172 // This one will never happen
2174 throw new Exception ("Should not happen");
2178 public class Binary : Expression {
2179 public enum Operator {
2180 Multiply, Division, Modulus,
2181 Addition, Subtraction,
2182 LeftShift, RightShift,
2183 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
2184 Equality, Inequality,
2193 Expression left, right;
2195 ArrayList Arguments;
2199 public Binary (Operator oper, Expression left, Expression right, Location loc)
2207 public Operator Oper {
2216 public Expression Left {
2225 public Expression Right {
2236 // Returns a stringified representation of the Operator
2241 case Operator.Multiply:
2243 case Operator.Division:
2245 case Operator.Modulus:
2247 case Operator.Addition:
2249 case Operator.Subtraction:
2251 case Operator.LeftShift:
2253 case Operator.RightShift:
2255 case Operator.LessThan:
2257 case Operator.GreaterThan:
2259 case Operator.LessThanOrEqual:
2261 case Operator.GreaterThanOrEqual:
2263 case Operator.Equality:
2265 case Operator.Inequality:
2267 case Operator.BitwiseAnd:
2269 case Operator.BitwiseOr:
2271 case Operator.ExclusiveOr:
2273 case Operator.LogicalOr:
2275 case Operator.LogicalAnd:
2279 return oper.ToString ();
2282 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
2284 if (expr.Type == target_type)
2287 return ConvertImplicit (ec, expr, target_type, new Location (-1));
2291 // Note that handling the case l == Decimal || r == Decimal
2292 // is taken care of by the Step 1 Operator Overload resolution.
2294 void DoNumericPromotions (EmitContext ec, Type l, Type r)
2296 if (l == TypeManager.double_type || r == TypeManager.double_type){
2298 // If either operand is of type double, the other operand is
2299 // conveted to type double.
2301 if (r != TypeManager.double_type)
2302 right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
2303 if (l != TypeManager.double_type)
2304 left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
2306 type = TypeManager.double_type;
2307 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
2309 // if either operand is of type float, th eother operand is
2310 // converd to type float.
2312 if (r != TypeManager.double_type)
2313 right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
2314 if (l != TypeManager.double_type)
2315 left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
2316 type = TypeManager.float_type;
2317 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
2321 // If either operand is of type ulong, the other operand is
2322 // converted to type ulong. or an error ocurrs if the other
2323 // operand is of type sbyte, short, int or long
2326 if (l == TypeManager.uint64_type){
2327 if (r != TypeManager.uint64_type && right is IntLiteral){
2328 e = TryImplicitIntConversion (l, (IntLiteral) right);
2334 if (left is IntLiteral){
2335 e = TryImplicitIntConversion (r, (IntLiteral) left);
2342 if ((other == TypeManager.sbyte_type) ||
2343 (other == TypeManager.short_type) ||
2344 (other == TypeManager.int32_type) ||
2345 (other == TypeManager.int64_type)){
2346 string oper = OperName ();
2348 Error (34, loc, "Operator `" + OperName ()
2349 + "' is ambiguous on operands of type `"
2350 + TypeManager.CSharpName (l) + "' "
2351 + "and `" + TypeManager.CSharpName (r)
2354 type = TypeManager.uint64_type;
2355 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
2357 // If either operand is of type long, the other operand is converted
2360 if (l != TypeManager.int64_type)
2361 left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
2362 if (r != TypeManager.int64_type)
2363 right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
2365 type = TypeManager.int64_type;
2366 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
2368 // If either operand is of type uint, and the other
2369 // operand is of type sbyte, short or int, othe operands are
2370 // converted to type long.
2374 if (l == TypeManager.uint32_type)
2376 else if (r == TypeManager.uint32_type)
2379 if ((other == TypeManager.sbyte_type) ||
2380 (other == TypeManager.short_type) ||
2381 (other == TypeManager.int32_type)){
2382 left = ForceConversion (ec, left, TypeManager.int64_type);
2383 right = ForceConversion (ec, right, TypeManager.int64_type);
2384 type = TypeManager.int64_type;
2387 // if either operand is of type uint, the other
2388 // operand is converd to type uint
2390 left = ForceConversion (ec, left, TypeManager.uint32_type);
2391 right = ForceConversion (ec, right, TypeManager.uint32_type);
2392 type = TypeManager.uint32_type;
2394 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2395 if (l != TypeManager.decimal_type)
2396 left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
2397 if (r != TypeManager.decimal_type)
2398 right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
2400 type = TypeManager.decimal_type;
2402 Expression l_tmp, r_tmp;
2404 l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
2405 if (l_tmp == null) {
2411 r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
2412 if (r_tmp == null) {
2418 type = TypeManager.int32_type;
2425 "Operator " + OperName () + " cannot be applied to operands of type `" +
2426 TypeManager.CSharpName (left.Type) + "' and `" +
2427 TypeManager.CSharpName (right.Type) + "'");
2431 Expression CheckShiftArguments (EmitContext ec)
2435 Type r = right.Type;
2437 e = ForceConversion (ec, right, TypeManager.int32_type);
2444 if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
2445 ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
2446 ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
2447 ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
2457 Expression ResolveOperator (EmitContext ec)
2460 Type r = right.Type;
2463 // Step 1: Perform Operator Overload location
2465 Expression left_expr, right_expr;
2467 string op = "op_" + oper;
2469 left_expr = MemberLookup (ec, l, op, false);
2470 if (left_expr == null && l.BaseType != null)
2471 left_expr = MemberLookup (ec, l.BaseType, op, false);
2473 right_expr = MemberLookup (ec, r, op, false);
2474 if (right_expr == null && r.BaseType != null)
2475 right_expr = MemberLookup (ec, r.BaseType, op, false);
2477 MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
2479 if (union != null) {
2480 Arguments = new ArrayList ();
2481 Arguments.Add (new Argument (left, Argument.AType.Expression));
2482 Arguments.Add (new Argument (right, Argument.AType.Expression));
2484 method = Invocation.OverloadResolve (ec, union, Arguments, loc);
2485 if (method != null) {
2486 MethodInfo mi = (MethodInfo) method;
2487 type = mi.ReturnType;
2496 // Step 2: Default operations on CLI native types.
2499 // Only perform numeric promotions on:
2500 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2502 if (oper == Operator.Addition){
2504 // If any of the arguments is a string, cast to string
2506 if (l == TypeManager.string_type){
2507 if (r == TypeManager.string_type){
2509 method = TypeManager.string_concat_string_string;
2512 method = TypeManager.string_concat_object_object;
2513 right = ConvertImplicit (ec, right,
2514 TypeManager.object_type, loc);
2516 type = TypeManager.string_type;
2518 Arguments = new ArrayList ();
2519 Arguments.Add (new Argument (left, Argument.AType.Expression));
2520 Arguments.Add (new Argument (right, Argument.AType.Expression));
2524 } else if (r == TypeManager.string_type){
2526 method = TypeManager.string_concat_object_object;
2527 Arguments = new ArrayList ();
2528 Arguments.Add (new Argument (left, Argument.AType.Expression));
2529 Arguments.Add (new Argument (right, Argument.AType.Expression));
2531 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2532 type = TypeManager.string_type;
2538 // FIXME: is Delegate operator + (D x, D y) handled?
2542 if (oper == Operator.LeftShift || oper == Operator.RightShift)
2543 return CheckShiftArguments (ec);
2545 if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2546 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
2549 type = TypeManager.bool_type;
2554 // We are dealing with numbers
2557 DoNumericPromotions (ec, l, r);
2559 if (left == null || right == null)
2563 if (oper == Operator.BitwiseAnd ||
2564 oper == Operator.BitwiseOr ||
2565 oper == Operator.ExclusiveOr){
2566 if (!((l == TypeManager.int32_type) ||
2567 (l == TypeManager.uint32_type) ||
2568 (l == TypeManager.int64_type) ||
2569 (l == TypeManager.uint64_type))){
2576 if (oper == Operator.Equality ||
2577 oper == Operator.Inequality ||
2578 oper == Operator.LessThanOrEqual ||
2579 oper == Operator.LessThan ||
2580 oper == Operator.GreaterThanOrEqual ||
2581 oper == Operator.GreaterThan){
2582 type = TypeManager.bool_type;
2588 public override Expression DoResolve (EmitContext ec)
2590 left = left.Resolve (ec);
2591 right = right.Resolve (ec);
2593 if (left == null || right == null)
2596 if (left.Type == null)
2597 throw new Exception (
2598 "Resolve returned non null, but did not set the type! (" +
2600 if (right.Type == null)
2601 throw new Exception (
2602 "Resolve returned non null, but did not set the type! (" +
2605 eclass = ExprClass.Value;
2607 return ResolveOperator (ec);
2610 public bool IsBranchable ()
2612 if (oper == Operator.Equality ||
2613 oper == Operator.Inequality ||
2614 oper == Operator.LessThan ||
2615 oper == Operator.GreaterThan ||
2616 oper == Operator.LessThanOrEqual ||
2617 oper == Operator.GreaterThanOrEqual){
2624 // This entry point is used by routines that might want
2625 // to emit a brfalse/brtrue after an expression, and instead
2626 // they could use a more compact notation.
2628 // Typically the code would generate l.emit/r.emit, followed
2629 // by the comparission and then a brtrue/brfalse. The comparissions
2630 // are sometimes inneficient (there are not as complete as the branches
2631 // look for the hacks in Emit using double ceqs).
2633 // So for those cases we provide EmitBranchable that can emit the
2634 // branch with the test
2636 public void EmitBranchable (EmitContext ec, int target)
2639 bool close_target = false;
2645 case Operator.Equality:
2647 opcode = OpCodes.Beq_S;
2649 opcode = OpCodes.Beq;
2652 case Operator.Inequality:
2654 opcode = OpCodes.Bne_Un_S;
2656 opcode = OpCodes.Bne_Un;
2659 case Operator.LessThan:
2661 opcode = OpCodes.Blt_S;
2663 opcode = OpCodes.Blt;
2666 case Operator.GreaterThan:
2668 opcode = OpCodes.Bgt_S;
2670 opcode = OpCodes.Bgt;
2673 case Operator.LessThanOrEqual:
2675 opcode = OpCodes.Ble_S;
2677 opcode = OpCodes.Ble;
2680 case Operator.GreaterThanOrEqual:
2682 opcode = OpCodes.Bge_S;
2684 opcode = OpCodes.Ble;
2688 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
2689 + oper.ToString ());
2692 ec.ig.Emit (opcode, target);
2695 public override void Emit (EmitContext ec)
2697 ILGenerator ig = ec.ig;
2699 Type r = right.Type;
2702 if (method != null) {
2704 // Note that operators are static anyway
2706 if (Arguments != null)
2707 Invocation.EmitArguments (ec, method, Arguments);
2709 if (method is MethodInfo)
2710 ig.Emit (OpCodes.Call, (MethodInfo) method);
2712 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2721 case Operator.Multiply:
2723 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2724 opcode = OpCodes.Mul_Ovf;
2725 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2726 opcode = OpCodes.Mul_Ovf_Un;
2728 opcode = OpCodes.Mul;
2730 opcode = OpCodes.Mul;
2734 case Operator.Division:
2735 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2736 opcode = OpCodes.Div_Un;
2738 opcode = OpCodes.Div;
2741 case Operator.Modulus:
2742 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2743 opcode = OpCodes.Rem_Un;
2745 opcode = OpCodes.Rem;
2748 case Operator.Addition:
2750 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2751 opcode = OpCodes.Add_Ovf;
2752 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2753 opcode = OpCodes.Add_Ovf_Un;
2755 opcode = OpCodes.Mul;
2757 opcode = OpCodes.Add;
2760 case Operator.Subtraction:
2762 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2763 opcode = OpCodes.Sub_Ovf;
2764 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2765 opcode = OpCodes.Sub_Ovf_Un;
2767 opcode = OpCodes.Sub;
2769 opcode = OpCodes.Sub;
2772 case Operator.RightShift:
2773 opcode = OpCodes.Shr;
2776 case Operator.LeftShift:
2777 opcode = OpCodes.Shl;
2780 case Operator.Equality:
2781 opcode = OpCodes.Ceq;
2784 case Operator.Inequality:
2785 ec.ig.Emit (OpCodes.Ceq);
2786 ec.ig.Emit (OpCodes.Ldc_I4_0);
2788 opcode = OpCodes.Ceq;
2791 case Operator.LessThan:
2792 opcode = OpCodes.Clt;
2795 case Operator.GreaterThan:
2796 opcode = OpCodes.Cgt;
2799 case Operator.LessThanOrEqual:
2800 ec.ig.Emit (OpCodes.Cgt);
2801 ec.ig.Emit (OpCodes.Ldc_I4_0);
2803 opcode = OpCodes.Ceq;
2806 case Operator.GreaterThanOrEqual:
2807 ec.ig.Emit (OpCodes.Clt);
2808 ec.ig.Emit (OpCodes.Ldc_I4_1);
2810 opcode = OpCodes.Sub;
2813 case Operator.LogicalOr:
2814 case Operator.BitwiseOr:
2815 opcode = OpCodes.Or;
2818 case Operator.LogicalAnd:
2819 case Operator.BitwiseAnd:
2820 opcode = OpCodes.And;
2823 case Operator.ExclusiveOr:
2824 opcode = OpCodes.Xor;
2828 throw new Exception ("This should not happen: Operator = "
2829 + oper.ToString ());
2836 public class Conditional : Expression {
2837 Expression expr, trueExpr, falseExpr;
2840 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
2843 this.trueExpr = trueExpr;
2844 this.falseExpr = falseExpr;
2848 public Expression Expr {
2854 public Expression TrueExpr {
2860 public Expression FalseExpr {
2866 public override Expression DoResolve (EmitContext ec)
2868 expr = expr.Resolve (ec);
2870 if (expr.Type != TypeManager.bool_type)
2871 expr = Expression.ConvertImplicitRequired (
2872 ec, expr, TypeManager.bool_type, loc);
2874 trueExpr = trueExpr.Resolve (ec);
2875 falseExpr = falseExpr.Resolve (ec);
2877 if (expr == null || trueExpr == null || falseExpr == null)
2880 if (trueExpr.Type == falseExpr.Type)
2881 type = trueExpr.Type;
2886 // First, if an implicit conversion exists from trueExpr
2887 // to falseExpr, then the result type is of type falseExpr.Type
2889 conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc);
2891 type = falseExpr.Type;
2893 } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){
2894 type = trueExpr.Type;
2897 Error (173, loc, "The type of the conditional expression can " +
2898 "not be computed because there is no implicit conversion" +
2899 " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
2900 " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
2905 eclass = ExprClass.Value;
2909 public override void Emit (EmitContext ec)
2911 ILGenerator ig = ec.ig;
2912 Label false_target = ig.DefineLabel ();
2913 Label end_target = ig.DefineLabel ();
2916 ig.Emit (OpCodes.Brfalse, false_target);
2918 ig.Emit (OpCodes.Br, end_target);
2919 ig.MarkLabel (false_target);
2920 falseExpr.Emit (ec);
2921 ig.MarkLabel (end_target);
2926 // SimpleName expressions are initially formed of a single
2927 // word and it only happens at the beginning of the expression.
2929 // The expression will try to be bound to a Field, a Method
2930 // group or a Property. If those fail we pass the name to our
2931 // caller and the SimpleName is compounded to perform a type
2932 // lookup. The idea behind this process is that we want to avoid
2933 // creating a namespace map from the assemblies, as that requires
2934 // the GetExportedTypes function to be called and a hashtable to
2935 // be constructed which reduces startup time. If later we find
2936 // that this is slower, we should create a `NamespaceExpr' expression
2937 // that fully participates in the resolution process.
2939 // For example `System.Console.WriteLine' is decomposed into
2940 // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
2942 // The first SimpleName wont produce a match on its own, so it will
2944 // MemberAccess (SimpleName ("System.Console"), "WriteLine").
2946 // System.Console will produce a TypeExpr match.
2948 // The downside of this is that we might be hitting `LookupType' too many
2949 // times with this scheme.
2951 public class SimpleName : Expression {
2952 public readonly string Name;
2953 public readonly Location Location;
2955 public SimpleName (string name, Location l)
2961 public static void Error120 (string name)
2965 "An object reference is required " +
2966 "for the non-static field `"+name+"'");
2970 // Checks whether we are trying to access an instance
2971 // property, method or field from a static body.
2973 Expression MemberStaticCheck (Expression e)
2975 if (e is FieldExpr){
2976 FieldInfo fi = ((FieldExpr) e).FieldInfo;
2982 } else if (e is MethodGroupExpr){
2983 MethodGroupExpr mg = (MethodGroupExpr) e;
2985 if (!mg.RemoveInstanceMethods ()){
2986 Error120 (mg.Methods [0].Name);
2990 } else if (e is PropertyExpr){
2991 if (!((PropertyExpr) e).IsStatic){
3001 // 7.5.2: Simple Names.
3003 // Local Variables and Parameters are handled at
3004 // parse time, so they never occur as SimpleNames.
3006 public override Expression DoResolve (EmitContext ec)
3011 // Stage 1: Performed by the parser (binding to local or parameters).
3015 // Stage 2: Lookup members
3017 e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true);
3020 // Stage 3: Lookup symbol in the various namespaces.
3024 if ((t = ec.TypeContainer.LookupType (Name, true)) != null)
3025 return new TypeExpr (t);
3028 // Stage 3 part b: Lookup up if we are an alias to a type
3031 // Since we are cheating: we only do the Alias lookup for
3032 // namespaces if the name does not include any dots in it
3035 // IMPLEMENT ME. Read mcs/mcs/TODO for ideas, or rewrite
3036 // using NamespaceExprs (dunno how that fixes the alias
3037 // per-file though).
3039 // No match, maybe our parent can compose us
3040 // into something meaningful.
3045 // Step 2, continues here.
3049 if (e is FieldExpr){
3050 FieldExpr fe = (FieldExpr) e;
3052 if (!fe.FieldInfo.IsStatic)
3053 fe.InstanceExpression = new This ();
3057 return MemberStaticCheck (e);
3062 public override void Emit (EmitContext ec)
3065 // If this is ever reached, then we failed to
3066 // find the name as a namespace
3069 Error (103, Location, "The name `" + Name +
3070 "' does not exist in the class `" +
3071 ec.TypeContainer.Name + "'");
3076 // A simple interface that should be implemeneted by LValues
3078 public interface LValue {
3081 // The Store method should store the contents of the top
3082 // of the stack into the storage that is implemented by
3083 // the particular implementation of LValue
3085 void Store (EmitContext ec);
3088 // The AddressOf method should generate code that loads
3089 // the address of the LValue and leaves it on the stack
3091 void AddressOf (EmitContext ec);
3094 public class LocalVariableReference : Expression, LValue {
3095 public readonly string Name;
3096 public readonly Block Block;
3098 public LocalVariableReference (Block block, string name)
3102 eclass = ExprClass.Variable;
3105 public VariableInfo VariableInfo {
3107 return Block.GetVariableInfo (Name);
3111 public override Expression DoResolve (EmitContext ec)
3113 VariableInfo vi = Block.GetVariableInfo (Name);
3115 type = vi.VariableType;
3119 public override void Emit (EmitContext ec)
3121 VariableInfo vi = VariableInfo;
3122 ILGenerator ig = ec.ig;
3129 ig.Emit (OpCodes.Ldloc_0);
3133 ig.Emit (OpCodes.Ldloc_1);
3137 ig.Emit (OpCodes.Ldloc_2);
3141 ig.Emit (OpCodes.Ldloc_3);
3146 ig.Emit (OpCodes.Ldloc_S, (byte) idx);
3148 ig.Emit (OpCodes.Ldloc, idx);
3153 public static void Store (ILGenerator ig, int idx)
3157 ig.Emit (OpCodes.Stloc_0);
3161 ig.Emit (OpCodes.Stloc_1);
3165 ig.Emit (OpCodes.Stloc_2);
3169 ig.Emit (OpCodes.Stloc_3);
3174 ig.Emit (OpCodes.Stloc_S, (byte) idx);
3176 ig.Emit (OpCodes.Stloc, idx);
3181 public void Store (EmitContext ec)
3183 ILGenerator ig = ec.ig;
3184 VariableInfo vi = VariableInfo;
3188 // Funny seems the above generates optimal code for us, but
3189 // seems to take too long to generate what we need.
3190 // ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3195 public void AddressOf (EmitContext ec)
3197 VariableInfo vi = VariableInfo;
3204 ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx);
3206 ec.ig.Emit (OpCodes.Ldloca, idx);
3210 public class ParameterReference : Expression, LValue {
3211 public readonly Parameters Pars;
3212 public readonly String Name;
3213 public readonly int Idx;
3216 public ParameterReference (Parameters pars, int idx, string name)
3221 eclass = ExprClass.Variable;
3224 public override Expression DoResolve (EmitContext ec)
3226 Type [] types = Pars.GetParameterInfo (ec.TypeContainer);
3237 public override void Emit (EmitContext ec)
3240 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3242 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3245 public void Store (EmitContext ec)
3248 ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3250 ec.ig.Emit (OpCodes.Starg, arg_idx);
3254 public void AddressOf (EmitContext ec)
3257 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3259 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3264 // Used for arguments to New(), Invocation()
3266 public class Argument {
3273 public readonly AType Type;
3274 public Expression expr;
3276 public Argument (Expression expr, AType type)
3282 public Expression Expr {
3292 public bool Resolve (EmitContext ec)
3294 expr = expr.Resolve (ec);
3296 return expr != null;
3299 public void Emit (EmitContext ec)
3306 // Invocation of methods or delegates.
3308 public class Invocation : ExpressionStatement {
3309 public readonly ArrayList Arguments;
3310 public readonly Location Location;
3313 MethodBase method = null;
3315 static Hashtable method_parameter_cache;
3317 static Invocation ()
3319 method_parameter_cache = new Hashtable ();
3323 // arguments is an ArrayList, but we do not want to typecast,
3324 // as it might be null.
3326 // FIXME: only allow expr to be a method invocation or a
3327 // delegate invocation (7.5.5)
3329 public Invocation (Expression expr, ArrayList arguments, Location l)
3332 Arguments = arguments;
3336 public Expression Expr {
3343 // Returns the Parameters (a ParameterData interface) for the
3346 public static ParameterData GetParameterData (MethodBase mb)
3348 object pd = method_parameter_cache [mb];
3351 return (ParameterData) pd;
3353 if (mb is MethodBuilder || mb is ConstructorBuilder){
3354 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
3356 InternalParameters ip = mc.ParameterInfo;
3357 method_parameter_cache [mb] = ip;
3359 return (ParameterData) ip;
3361 ParameterInfo [] pi = mb.GetParameters ();
3362 ReflectionParameters rp = new ReflectionParameters (pi);
3363 method_parameter_cache [mb] = rp;
3365 return (ParameterData) rp;
3370 // Tells whether a user defined conversion from Type `from' to
3371 // Type `to' exists.
3373 // FIXME: we could implement a cache here.
3375 static bool ConversionExists (EmitContext ec, Type from, Type to)
3377 // Locate user-defined implicit operators
3381 mg = MemberLookup (ec, to, "op_Implicit", false);
3384 MethodGroupExpr me = (MethodGroupExpr) mg;
3386 for (int i = me.Methods.Length; i > 0;) {
3388 MethodBase mb = me.Methods [i];
3389 ParameterData pd = GetParameterData (mb);
3391 if (from == pd.ParameterType (0))
3396 mg = MemberLookup (ec, from, "op_Implicit", false);
3399 MethodGroupExpr me = (MethodGroupExpr) mg;
3401 for (int i = me.Methods.Length; i > 0;) {
3403 MethodBase mb = me.Methods [i];
3404 MethodInfo mi = (MethodInfo) mb;
3406 if (mi.ReturnType == to)
3415 // Determines "better conversion" as specified in 7.4.2.3
3416 // Returns : 1 if a->p is better
3417 // 0 if a->q or neither is better
3419 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, bool use_standard)
3422 Type argument_type = a.Expr.Type;
3423 Expression argument_expr = a.Expr;
3425 if (argument_type == null)
3426 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3431 if (argument_type == p)
3434 if (argument_type == q)
3438 // Now probe whether an implicit constant expression conversion
3441 // An implicit constant expression conversion permits the following
3444 // * A constant-expression of type `int' can be converted to type
3445 // sbyte, byute, short, ushort, uint, ulong provided the value of
3446 // of the expression is withing the range of the destination type.
3448 // * A constant-expression of type long can be converted to type
3449 // ulong, provided the value of the constant expression is not negative
3451 // FIXME: Note that this assumes that constant folding has
3452 // taken place. We dont do constant folding yet.
3455 if (argument_expr is IntLiteral){
3456 IntLiteral ei = (IntLiteral) argument_expr;
3457 int value = ei.Value;
3459 if (p == TypeManager.sbyte_type){
3460 if (value >= SByte.MinValue && value <= SByte.MaxValue)
3462 } else if (p == TypeManager.byte_type){
3463 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3465 } else if (p == TypeManager.short_type){
3466 if (value >= Int16.MinValue && value <= Int16.MaxValue)
3468 } else if (p == TypeManager.ushort_type){
3469 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3471 } else if (p == TypeManager.uint32_type){
3473 // we can optimize this case: a positive int32
3474 // always fits on a uint32
3478 } else if (p == TypeManager.uint64_type){
3480 // we can optimize this case: a positive int32
3481 // always fits on a uint64
3486 } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
3487 LongLiteral ll = (LongLiteral) argument_expr;
3489 if (p == TypeManager.uint64_type){
3500 tmp = ConvertImplicitStandard (ec, argument_expr, p, Location.Null);
3502 tmp = ConvertImplicit (ec, argument_expr, p, Location.Null);
3511 if (ConversionExists (ec, p, q) == true &&
3512 ConversionExists (ec, q, p) == false)
3515 if (p == TypeManager.sbyte_type)
3516 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3517 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3520 if (p == TypeManager.short_type)
3521 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3522 q == TypeManager.uint64_type)
3525 if (p == TypeManager.int32_type)
3526 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3529 if (p == TypeManager.int64_type)
3530 if (q == TypeManager.uint64_type)
3537 // Determines "Better function" and returns an integer indicating :
3538 // 0 if candidate ain't better
3539 // 1 if candidate is better than the current best match
3541 static int BetterFunction (EmitContext ec, ArrayList args,
3542 MethodBase candidate, MethodBase best,
3545 ParameterData candidate_pd = GetParameterData (candidate);
3546 ParameterData best_pd;
3552 argument_count = args.Count;
3554 if (candidate_pd.Count == 0 && argument_count == 0)
3558 if (candidate_pd.Count == argument_count) {
3560 for (int j = argument_count; j > 0;) {
3563 Argument a = (Argument) args [j];
3565 x = BetterConversion (
3566 ec, a, candidate_pd.ParameterType (j), null,
3582 best_pd = GetParameterData (best);
3584 if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
3585 int rating1 = 0, rating2 = 0;
3587 for (int j = argument_count; j > 0;) {
3591 Argument a = (Argument) args [j];
3593 x = BetterConversion (ec, a, candidate_pd.ParameterType (j),
3594 best_pd.ParameterType (j), use_standard);
3595 y = BetterConversion (ec, a, best_pd.ParameterType (j),
3596 candidate_pd.ParameterType (j), use_standard);
3602 if (rating1 > rating2)
3611 public static string FullMethodDesc (MethodBase mb)
3613 StringBuilder sb = new StringBuilder (mb.Name);
3614 ParameterData pd = GetParameterData (mb);
3617 for (int i = pd.Count; i > 0;) {
3619 sb.Append (TypeManager.CSharpName (pd.ParameterType (i)));
3625 return sb.ToString ();
3628 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
3630 MemberInfo [] miset;
3631 MethodGroupExpr union;
3633 if (mg1 != null && mg2 != null) {
3635 MethodGroupExpr left_set = null, right_set = null;
3636 int length1 = 0, length2 = 0;
3638 left_set = (MethodGroupExpr) mg1;
3639 length1 = left_set.Methods.Length;
3641 right_set = (MethodGroupExpr) mg2;
3642 length2 = right_set.Methods.Length;
3644 ArrayList common = new ArrayList ();
3646 for (int i = 0; i < left_set.Methods.Length; i++) {
3647 for (int j = 0; j < right_set.Methods.Length; j++) {
3648 if (left_set.Methods [i] == right_set.Methods [j])
3649 common.Add (left_set.Methods [i]);
3653 miset = new MemberInfo [length1 + length2 - common.Count];
3655 left_set.Methods.CopyTo (miset, 0);
3659 for (int j = 0; j < right_set.Methods.Length; j++)
3660 if (!common.Contains (right_set.Methods [j]))
3661 miset [length1 + k++] = right_set.Methods [j];
3663 union = new MethodGroupExpr (miset);
3667 } else if (mg1 == null && mg2 != null) {
3669 MethodGroupExpr me = (MethodGroupExpr) mg2;
3671 miset = new MemberInfo [me.Methods.Length];
3672 me.Methods.CopyTo (miset, 0);
3674 union = new MethodGroupExpr (miset);
3678 } else if (mg2 == null && mg1 != null) {
3680 MethodGroupExpr me = (MethodGroupExpr) mg1;
3682 miset = new MemberInfo [me.Methods.Length];
3683 me.Methods.CopyTo (miset, 0);
3685 union = new MethodGroupExpr (miset);
3694 // Find the Applicable Function Members (7.4.2.1)
3696 // me: Method Group expression with the members to select.
3697 // it might contain constructors or methods (or anything
3698 // that maps to a method).
3700 // Arguments: ArrayList containing resolved Argument objects.
3702 // loc: The location if we want an error to be reported, or a Null
3703 // location for "probing" purposes.
3705 // inside_user_defined: controls whether OverloadResolve should use the
3706 // ConvertImplicit or ConvertImplicitStandard during overload resolution.
3708 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3709 // that is the best match of me on Arguments.
3712 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3713 ArrayList Arguments, Location loc,
3716 ArrayList afm = new ArrayList ();
3717 int best_match_idx = -1;
3718 MethodBase method = null;
3721 for (int i = me.Methods.Length; i > 0; ){
3723 MethodBase candidate = me.Methods [i];
3726 x = BetterFunction (ec, Arguments, candidate, method, use_standard);
3732 method = me.Methods [best_match_idx];
3736 if (Arguments == null)
3739 argument_count = Arguments.Count;
3743 // Now we see if we can at least find a method with the same number of arguments
3744 // and then try doing implicit conversion on the arguments
3745 if (best_match_idx == -1) {
3747 for (int i = me.Methods.Length; i > 0;) {
3749 MethodBase mb = me.Methods [i];
3750 pd = GetParameterData (mb);
3752 if (pd.Count == argument_count) {
3754 method = me.Methods [best_match_idx];
3765 // And now convert implicitly, each argument to the required type
3767 pd = GetParameterData (method);
3769 for (int j = argument_count; j > 0;) {
3771 Argument a = (Argument) Arguments [j];
3772 Expression a_expr = a.Expr;
3773 Type parameter_type = pd.ParameterType (j);
3775 if (a_expr.Type != parameter_type){
3779 conv = ConvertImplicitStandard (ec, a_expr, parameter_type,
3782 conv = ConvertImplicit (ec, a_expr, parameter_type,
3786 if (!Location.IsNull (loc)) {
3788 "The best overloaded match for method '" + FullMethodDesc (method) +
3789 "' has some invalid arguments");
3791 "Argument " + (j+1) +
3792 ": Cannot convert from '" + TypeManager.CSharpName (a_expr.Type)
3793 + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'");
3798 // Update the argument with the implicit conversion
3808 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3809 ArrayList Arguments, Location loc)
3811 return OverloadResolve (ec, me, Arguments, loc, false);
3814 public override Expression DoResolve (EmitContext ec)
3817 // First, resolve the expression that is used to
3818 // trigger the invocation
3820 this.expr = expr.Resolve (ec);
3821 if (this.expr == null)
3824 if (!(this.expr is MethodGroupExpr)){
3825 report118 (Location, this.expr, "method group");
3830 // Next, evaluate all the expressions in the argument list
3832 if (Arguments != null){
3833 for (int i = Arguments.Count; i > 0;){
3835 Argument a = (Argument) Arguments [i];
3837 if (!a.Resolve (ec))
3842 method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments,
3845 if (method == null){
3846 Error (-6, Location,
3847 "Could not find any applicable function for this argument list");
3851 if (method is MethodInfo)
3852 type = ((MethodInfo)method).ReturnType;
3854 eclass = ExprClass.Value;
3858 public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments)
3862 if (Arguments != null)
3863 top = Arguments.Count;
3867 for (int i = 0; i < top; i++){
3868 Argument a = (Argument) Arguments [i];
3874 public override void Emit (EmitContext ec)
3876 bool is_static = method.IsStatic;
3877 ILGenerator ig = ec.ig;
3878 bool struct_call = false;
3881 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
3884 // If this is ourselves, push "this"
3886 if (mg.InstanceExpression == null){
3887 ig.Emit (OpCodes.Ldarg_0);
3889 Expression ie = mg.InstanceExpression;
3892 // Push the instance expression
3894 if (ie.Type.IsSubclassOf (TypeManager.value_type)){
3899 // If the expression is an LValue, then
3900 // we can optimize and use AddressOf on the
3903 // If not we have to use some temporary storage for
3906 ((LValue) ie).AddressOf (ec);
3909 LocalBuilder temp = ec.GetTemporaryStorage (ie.Type);
3910 ig.Emit (OpCodes.Stloc, temp);
3911 ig.Emit (OpCodes.Ldloca, temp);
3918 if (Arguments != null)
3919 EmitArguments (ec, method, Arguments);
3921 if (is_static || struct_call){
3922 if (method is MethodInfo)
3923 ig.Emit (OpCodes.Call, (MethodInfo) method);
3925 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3927 if (method is MethodInfo)
3928 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
3930 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
3934 public override void EmitStatement (EmitContext ec)
3939 // Pop the return value if there is one
3941 if (method is MethodInfo){
3942 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
3943 ec.ig.Emit (OpCodes.Pop);
3948 public class New : ExpressionStatement {
3955 public readonly NType NewType;
3956 public readonly ArrayList Arguments;
3957 public readonly string RequestedType;
3959 // These are for the case when we have an array
3960 public readonly string Rank;
3961 public readonly ArrayList Initializers;
3964 MethodBase method = null;
3966 public New (string requested_type, ArrayList arguments, Location loc)
3968 RequestedType = requested_type;
3969 Arguments = arguments;
3970 NewType = NType.Object;
3974 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location loc)
3976 RequestedType = requested_type;
3978 Initializers = initializers;
3979 NewType = NType.Array;
3982 Arguments = new ArrayList ();
3984 foreach (Expression e in exprs)
3985 Arguments.Add (new Argument (e, Argument.AType.Expression));
3989 public static string FormLookupType (string base_type, int idx_count, string rank)
3991 StringBuilder sb = new StringBuilder (base_type);
3996 for (int i = 1; i < idx_count; i++)
4000 return sb.ToString ();
4004 public override Expression DoResolve (EmitContext ec)
4006 if (NewType == NType.Object) {
4008 type = ec.TypeContainer.LookupType (RequestedType, false);
4015 ml = MemberLookup (ec, type, ".ctor", false,
4016 MemberTypes.Constructor, AllBindingsFlags);
4018 if (! (ml is MethodGroupExpr)){
4020 // FIXME: Find proper error
4022 report118 (Location, ml, "method group");
4026 if (Arguments != null){
4027 for (int i = Arguments.Count; i > 0;){
4029 Argument a = (Argument) Arguments [i];
4031 if (!a.Resolve (ec))
4036 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments,
4039 if (method == null) {
4040 Error (-6, Location,
4041 "New invocation: Can not find a constructor for this argument list");
4045 eclass = ExprClass.Value;
4049 if (NewType == NType.Array) {
4050 throw new Exception ("Finish array creation");
4056 public override void Emit (EmitContext ec)
4058 Invocation.EmitArguments (ec, method, Arguments);
4059 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4062 public override void EmitStatement (EmitContext ec)
4065 ec.ig.Emit (OpCodes.Pop);
4070 // Represents the `this' construct
4072 public class This : Expression, LValue {
4073 public override Expression DoResolve (EmitContext ec)
4075 eclass = ExprClass.Variable;
4076 type = ec.TypeContainer.TypeBuilder;
4079 // FIXME: Verify that this is only used in instance contexts.
4084 public override void Emit (EmitContext ec)
4086 ec.ig.Emit (OpCodes.Ldarg_0);
4089 public void Store (EmitContext ec)
4092 // Assignment to the "this" variable.
4094 // FIXME: Apparently this is a bug that we
4095 // must catch as `this' seems to be readonly ;-)
4097 ec.ig.Emit (OpCodes.Starg, 0);
4100 public void AddressOf (EmitContext ec)
4102 ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4107 // Implements the typeof operator
4109 public class TypeOf : Expression {
4110 public readonly string QueriedType;
4113 public TypeOf (string queried_type)
4115 QueriedType = queried_type;
4118 public override Expression DoResolve (EmitContext ec)
4120 typearg = ec.TypeContainer.LookupType (QueriedType, false);
4122 if (typearg == null)
4125 type = TypeManager.type_type;
4126 eclass = ExprClass.Type;
4130 public override void Emit (EmitContext ec)
4132 ec.ig.Emit (OpCodes.Ldtoken, typearg);
4133 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4137 public class SizeOf : Expression {
4138 public readonly string QueriedType;
4140 public SizeOf (string queried_type)
4142 this.QueriedType = queried_type;
4145 public override Expression DoResolve (EmitContext ec)
4147 // FIXME: Implement;
4148 throw new Exception ("Unimplemented");
4152 public override void Emit (EmitContext ec)
4154 throw new Exception ("Implement me");
4158 public class MemberAccess : Expression {
4159 public readonly string Identifier;
4161 Expression member_lookup;
4164 public MemberAccess (Expression expr, string id, Location l)
4171 public Expression Expr {
4177 void error176 (Location loc, string name)
4179 Report.Error (176, loc, "Static member `" +
4180 name + "' cannot be accessed " +
4181 "with an instance reference, qualify with a " +
4182 "type name instead");
4185 public override Expression DoResolve (EmitContext ec)
4187 expr = expr.Resolve (ec);
4192 if (expr is SimpleName){
4193 SimpleName child_expr = (SimpleName) expr;
4195 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
4197 return expr.Resolve (ec);
4200 member_lookup = MemberLookup (ec, expr.Type, Identifier, false);
4205 if (member_lookup is MethodGroupExpr){
4206 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
4211 if (expr is TypeExpr){
4212 if (!mg.RemoveInstanceMethods ()){
4213 error176 (loc, mg.Methods [0].Name);
4217 return member_lookup;
4221 // Instance.MethodGroup
4223 if (!mg.RemoveStaticMethods ()){
4224 SimpleName.Error120 (mg.Methods [0].Name);
4228 mg.InstanceExpression = expr;
4230 return member_lookup;
4233 if (member_lookup is FieldExpr){
4234 FieldExpr fe = (FieldExpr) member_lookup;
4236 if (expr is TypeExpr){
4237 if (!fe.FieldInfo.IsStatic){
4238 error176 (loc, fe.FieldInfo.Name);
4241 return member_lookup;
4243 if (fe.FieldInfo.IsStatic){
4244 error176 (loc, fe.FieldInfo.Name);
4247 fe.InstanceExpression = expr;
4253 Console.WriteLine ("Support for " + member_lookup + " is not present yet");
4254 Environment.Exit (0);
4258 public override void Emit (EmitContext ec)
4260 throw new Exception ("Should not happen I think");
4266 // Fully resolved expression that evaluates to a type
4268 public class TypeExpr : Expression {
4269 public TypeExpr (Type t)
4272 eclass = ExprClass.Type;
4275 override public Expression DoResolve (EmitContext ec)
4280 override public void Emit (EmitContext ec)
4282 throw new Exception ("Implement me");
4287 // MethodGroup Expression.
4289 // This is a fully resolved expression that evaluates to a type
4291 public class MethodGroupExpr : Expression {
4292 public MethodBase [] Methods;
4293 Expression instance_expression = null;
4295 public MethodGroupExpr (MemberInfo [] mi)
4297 Methods = new MethodBase [mi.Length];
4298 mi.CopyTo (Methods, 0);
4299 eclass = ExprClass.MethodGroup;
4303 // `A method group may have associated an instance expression'
4305 public Expression InstanceExpression {
4307 return instance_expression;
4311 instance_expression = value;
4315 override public Expression DoResolve (EmitContext ec)
4320 override public void Emit (EmitContext ec)
4322 throw new Exception ("This should never be reached");
4325 bool RemoveMethods (bool keep_static)
4327 ArrayList smethods = new ArrayList ();
4328 int top = Methods.Length;
4331 for (i = 0; i < top; i++){
4332 MethodBase mb = Methods [i];
4334 if (mb.IsStatic == keep_static)
4338 if (smethods.Count == 0)
4341 Methods = new MethodBase [smethods.Count];
4342 smethods.CopyTo (Methods, 0);
4348 // Removes any instance methods from the MethodGroup, returns
4349 // false if the resulting set is empty.
4351 public bool RemoveInstanceMethods ()
4353 return RemoveMethods (true);
4357 // Removes any static methods from the MethodGroup, returns
4358 // false if the resulting set is empty.
4360 public bool RemoveStaticMethods ()
4362 return RemoveMethods (false);
4367 // Fully resolved expression that evaluates to a Field
4369 public class FieldExpr : Expression, LValue {
4370 public readonly FieldInfo FieldInfo;
4371 public Expression InstanceExpression;
4373 public FieldExpr (FieldInfo fi)
4376 eclass = ExprClass.Variable;
4377 type = fi.FieldType;
4380 override public Expression DoResolve (EmitContext ec)
4382 if (!FieldInfo.IsStatic){
4383 if (InstanceExpression == null){
4384 throw new Exception ("non-static FieldExpr without instance var\n" +
4385 "You have to assign the Instance variable\n" +
4386 "Of the FieldExpr to set this\n");
4389 InstanceExpression = InstanceExpression.Resolve (ec);
4390 if (InstanceExpression == null)
4397 override public void Emit (EmitContext ec)
4399 ILGenerator ig = ec.ig;
4401 if (FieldInfo.IsStatic)
4402 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4404 InstanceExpression.Emit (ec);
4406 ig.Emit (OpCodes.Ldfld, FieldInfo);
4410 public void Store (EmitContext ec)
4412 if (FieldInfo.IsStatic)
4413 ec.ig.Emit (OpCodes.Stsfld, FieldInfo);
4415 ec.ig.Emit (OpCodes.Stfld, FieldInfo);
4418 public void AddressOf (EmitContext ec)
4420 if (FieldInfo.IsStatic)
4421 ec.ig.Emit (OpCodes.Ldsflda, FieldInfo);
4423 InstanceExpression.Emit (ec);
4424 ec.ig.Emit (OpCodes.Ldflda, FieldInfo);
4430 // Fully resolved expression that evaluates to a Property
4432 public class PropertyExpr : Expression {
4433 public readonly PropertyInfo PropertyInfo;
4434 public readonly bool IsStatic;
4436 public PropertyExpr (PropertyInfo pi)
4439 eclass = ExprClass.PropertyAccess;
4442 MethodBase [] acc = pi.GetAccessors ();
4444 for (int i = 0; i < acc.Length; i++)
4445 if (acc [i].IsStatic)
4448 type = pi.PropertyType;
4451 override public Expression DoResolve (EmitContext ec)
4453 // We are born in resolved state.
4457 override public void Emit (EmitContext ec)
4459 // FIXME: Implement;
4460 throw new Exception ("Unimplemented");
4465 // Fully resolved expression that evaluates to a Expression
4467 public class EventExpr : Expression {
4468 public readonly EventInfo EventInfo;
4470 public EventExpr (EventInfo ei)
4473 eclass = ExprClass.EventAccess;
4476 override public Expression DoResolve (EmitContext ec)
4478 // We are born in resolved state.
4482 override public void Emit (EmitContext ec)
4484 throw new Exception ("Implement me");
4485 // FIXME: Implement.
4489 public class CheckedExpr : Expression {
4491 public Expression Expr;
4493 public CheckedExpr (Expression e)
4498 public override Expression DoResolve (EmitContext ec)
4500 Expr = Expr.Resolve (ec);
4505 eclass = Expr.ExprClass;
4510 public override void Emit (EmitContext ec)
4512 bool last_check = ec.CheckState;
4514 ec.CheckState = true;
4516 ec.CheckState = last_check;
4521 public class UnCheckedExpr : Expression {
4523 public Expression Expr;
4525 public UnCheckedExpr (Expression e)
4530 public override Expression DoResolve (EmitContext ec)
4532 Expr = Expr.Resolve (ec);
4537 eclass = Expr.ExprClass;
4542 public override void Emit (EmitContext ec)
4544 bool last_check = ec.CheckState;
4546 ec.CheckState = false;
4548 ec.CheckState = last_check;
4553 public class ElementAccess : Expression, LValue {
4555 public ArrayList Arguments;
4556 public Expression Expr;
4560 public ElementAccess (Expression e, ArrayList e_list, Location loc)
4564 Arguments = new ArrayList ();
4565 foreach (Expression tmp in e_list)
4566 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
4571 public override Expression DoResolve (EmitContext ec)
4573 Expr = Expr.Resolve (ec);
4575 //Console.WriteLine (Expr.ToString ());
4580 if (Arguments == null)
4583 if (Expr.ExprClass != ExprClass.Variable) {
4584 report118 (location, Expr, "variable");
4588 if (Arguments != null){
4589 for (int i = Arguments.Count; i > 0;){
4591 Argument a = (Argument) Arguments [i];
4593 if (!a.Resolve (ec))
4596 Type a_type = a.expr.Type;
4597 if (!(StandardConversionExists (a_type, TypeManager.int32_type) ||
4598 StandardConversionExists (a_type, TypeManager.uint32_type) ||
4599 StandardConversionExists (a_type, TypeManager.int64_type) ||
4600 StandardConversionExists (a_type, TypeManager.uint64_type)))
4606 // FIXME : Implement the actual storage here.
4608 throw new Exception ("Finish element access");
4612 public void Store (EmitContext ec)
4614 throw new Exception ("Implement me !");
4617 public void AddressOf (EmitContext ec)
4619 throw new Exception ("Implement me !");
4622 public override void Emit (EmitContext ec)
4624 throw new Exception ("Implement me !");
4629 public class BaseAccess : Expression {
4631 public enum BaseAccessType {
4636 public readonly BaseAccessType BAType;
4637 public readonly string Member;
4638 public readonly ArrayList Arguments;
4640 public BaseAccess (BaseAccessType t, string member, ArrayList args)
4648 public override Expression DoResolve (EmitContext ec)
4650 // FIXME: Implement;
4651 throw new Exception ("Unimplemented");
4655 public override void Emit (EmitContext ec)
4657 throw new Exception ("Unimplemented");
4662 // This class exists solely to pass the Type around and to be a dummy
4663 // that can be passed to the conversion functions (this is used by
4664 // foreach implementation to typecast the object return value from
4665 // get_Current into the proper type. All code has been generated and
4666 // we only care about the side effect conversions to be performed
4669 public class EmptyExpression : Expression {
4670 public EmptyExpression ()
4672 type = TypeManager.object_type;
4673 eclass = ExprClass.Value;
4676 public override Expression DoResolve (EmitContext ec)
4681 public override void Emit (EmitContext ec)
4683 // nothing, as we only exist to not do anything.
4687 public class UserCast : Expression {
4691 public UserCast (MethodInfo method, Expression source)
4693 this.method = method;
4694 this.source = source;
4695 type = method.ReturnType;
4696 eclass = ExprClass.Value;
4699 public override Expression DoResolve (EmitContext ec)
4702 // We are born fully resolved
4707 public override void Emit (EmitContext ec)
4709 ILGenerator ig = ec.ig;
4713 if (method is MethodInfo)
4714 ig.Emit (OpCodes.Call, (MethodInfo) method);
4716 ig.Emit (OpCodes.Call, (ConstructorInfo) method);