2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Manjula GHM (mmanjula@novell.com)
8 // (C) 2001 Ximian, Inc.
12 namespace Mono.MonoBASIC {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Allows SimpleNames to be returned.
56 // This is used by MemberAccess to construct long names that can not be
57 // partially resolved (namespace-qualified names for example).
60 // Mask of all the expression class flags.
63 // Disable control flow analysis while resolving the expression.
64 // This is used when resolving the instance expression of a field expression.
65 DisableFlowAnalysis = 16
69 // This is just as a hint to AddressOf of what will be done with the
72 public enum AddressOp {
79 /// This interface is implemented by variables
81 public interface IMemoryLocation {
83 /// The AddressOf method should generate code that loads
84 /// the address of the object and leaves it on the stack.
86 /// The 'mode' argument is used to notify the expression
87 /// of whether this will be used to read from the address or
88 /// write to the address.
90 /// This is just a hint that can be used to provide good error
91 /// reporting, and should have no other side effects.
93 void AddressOf (EmitContext ec, AddressOp mode);
97 /// This interface is implemented by variables
99 public interface IVariable {
101 /// Checks whether the variable has already been assigned at
102 /// the current position of the method's control flow and
103 /// reports an appropriate error message if not.
105 /// If the variable is a struct, then this call checks whether
106 /// all of its fields (including all private ones) have been
109 bool IsAssigned (EmitContext ec, Location loc);
112 /// Checks whether field 'name' in this struct has been assigned.
114 bool IsFieldAssigned (EmitContext ec, string name, Location loc);
117 /// Tells the flow analysis code that the variable has already
118 /// been assigned at the current code position.
120 /// If the variable is a struct, this call marks all its fields
121 /// (including private fields) as being assigned.
123 void SetAssigned (EmitContext ec);
126 /// Tells the flow analysis code that field 'name' in this struct
127 /// has already been assigned atthe current code position.
129 void SetFieldAssigned (EmitContext ec, string name);
133 /// This interface denotes an expression which evaluates to a member
134 /// of a struct or a class.
136 public interface IMemberExpr
139 /// The name of this member.
146 /// Whether this is an instance member.
153 /// Whether this is a static member.
160 /// The type which declares this member.
167 /// The instance expression associated with this member, if it's a
168 /// non-static member.
170 Expression InstanceExpression {
176 /// Expression which resolves to a type.
178 public interface ITypeExpression
181 /// Resolve the expression, but only lookup types.
183 Expression DoResolveType (EmitContext ec);
187 /// Base class for expressions
189 public abstract class Expression {
190 public ExprClass eclass;
192 protected Location loc;
204 public Location Location {
211 /// Utility wrapper routine for Error, just to beautify the code
213 public void Error (int error, string s)
215 if (!Location.IsNull (loc))
216 Report.Error (error, loc, s);
218 Report.Error (error, s);
222 /// Utility wrapper routine for Warning, just to beautify the code
224 public void Warning (int warning, string s)
226 if (!Location.IsNull (loc))
227 Report.Warning (warning, loc, s);
229 Report.Warning (warning, s);
233 /// Utility wrapper routine for Warning, only prints the warning if
234 /// warnings of level 'level' are enabled.
236 public void Warning (int warning, int level, string s)
238 if (level <= RootContext.WarningLevel)
239 Warning (warning, s);
242 static public void Error_CannotConvertType (Location loc, Type source, Type target)
244 Report.Error (30, loc, "Cannot convert type '" +
245 TypeManager.MonoBASIC_Name (source) + "' to '" +
246 TypeManager.MonoBASIC_Name (target) + "'");
250 /// Performs semantic analysis on the Expression
254 /// The Resolve method is invoked to perform the semantic analysis
257 /// The return value is an expression (it can be the
258 /// same expression in some cases) or a new
259 /// expression that better represents this node.
261 /// For example, optimizations of Unary (LiteralInt)
262 /// would return a new LiteralInt with a negated
265 /// If there is an error during semantic analysis,
266 /// then an error should be reported (using Report)
267 /// and a null value should be returned.
269 /// There are two side effects expected from calling
270 /// Resolve(): the the field variable "eclass" should
271 /// be set to any value of the enumeration
272 /// 'ExprClass' and the type variable should be set
273 /// to a valid type (this is the type of the
276 public abstract Expression DoResolve (EmitContext ec);
278 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
280 return DoResolve (ec);
284 /// Resolves an expression and performs semantic analysis on it.
288 /// Currently Resolve wraps DoResolve to perform sanity
289 /// checking and assertion checking on what we expect from Resolve.
291 public Expression Resolve (EmitContext ec, ResolveFlags flags)
293 // Are we doing a types-only search ?
294 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type) {
295 ITypeExpression type_expr = this as ITypeExpression;
297 if (type_expr == null)
300 return type_expr.DoResolveType (ec);
303 bool old_do_flow_analysis = ec.DoFlowAnalysis;
304 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
305 ec.DoFlowAnalysis = false;
309 if (this is SimpleName)
310 e = ((SimpleName) this).DoResolveAllowStatic (ec);
314 ec.DoFlowAnalysis = old_do_flow_analysis;
320 if (e is SimpleName){
321 SimpleName s = (SimpleName) e;
323 if ((flags & ResolveFlags.SimpleName) == 0) {
325 object lookup = TypeManager.MemberLookup (
326 ec.ContainerType, ec.ContainerType, AllMemberTypes,
327 AllBindingFlags | BindingFlags.NonPublic, s.Name);
329 Error (30390, "'" + s.Name + "' " +
330 "is inaccessible because of its protection level");
332 Error (30451, "The name '" + s.Name + "' could not be " +
333 "found in '" + ec.DeclSpace.Name + "'");
340 if ((e is TypeExpr) || (e is ComposedCast)) {
341 if ((flags & ResolveFlags.Type) == 0) {
351 if ((flags & ResolveFlags.VariableOrValue) == 0) {
357 case ExprClass.MethodGroup:
358 if ((flags & ResolveFlags.MethodGroup) == 0) {
359 MethodGroupExpr mg = (MethodGroupExpr) e;
360 Invocation i = new Invocation (mg, new ArrayList(), Location.Null);
361 Expression te = i.Resolve(ec);
362 //((MethodGroupExpr) e).ReportUsageError ();
368 case ExprClass.Value:
369 case ExprClass.Variable:
370 case ExprClass.PropertyAccess:
371 case ExprClass.EventAccess:
372 case ExprClass.IndexerAccess:
373 if ((flags & ResolveFlags.VariableOrValue) == 0) {
380 throw new Exception ("Expression " + e.GetType () +
381 " ExprClass is Invalid after resolve");
385 throw new Exception (
386 "Expression " + e.GetType () +
387 " did not set its type after Resolve\n" +
388 "called from: " + this.GetType ());
394 /// Resolves an expression and performs semantic analysis on it.
396 public Expression Resolve (EmitContext ec)
398 return Resolve (ec, ResolveFlags.VariableOrValue);
402 /// Resolves an expression for LValue assignment
406 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
407 /// checking and assertion checking on what we expect from Resolve
409 public Expression ResolveLValue (EmitContext ec, Expression right_side)
411 Expression e = DoResolveLValue (ec, right_side);
414 if (e is SimpleName){
415 SimpleName s = (SimpleName) e;
419 "The name '" + s.Name + "' could not be found in '" +
420 ec.DeclSpace.Name + "'");
424 if (e.eclass == ExprClass.Invalid)
425 throw new Exception ("Expression " + e +
426 " ExprClass is Invalid after resolve");
428 if (e.eclass == ExprClass.MethodGroup) {
429 MethodGroupExpr mg = (MethodGroupExpr) e;
430 Invocation i = new Invocation (mg, new ArrayList(), Location.Null);
431 Expression te = i.Resolve(ec);
433 //((MethodGroupExpr) e).ReportUsageError ();
438 throw new Exception ("Expression " + e +
439 " did not set its type after Resolve");
446 /// Emits the code for the expression
450 /// The Emit method is invoked to generate the code
451 /// for the expression.
453 public abstract void Emit (EmitContext ec);
456 /// Protected constructor. Only derivate types should
457 /// be able to be created
460 protected Expression ()
462 eclass = ExprClass.Invalid;
467 /// Returns a literalized version of a literal FieldInfo
471 /// The possible return values are:
472 /// IntConstant, UIntConstant
473 /// LongLiteral, ULongConstant
474 /// FloatConstant, DoubleConstant
477 /// The value returned is already resolved.
479 public static Constant Constantify (object v, Type t)
481 if (t == TypeManager.int32_type)
482 return new IntConstant ((int) v);
483 else if (t == TypeManager.uint32_type)
484 return new UIntConstant ((uint) v);
485 else if (t == TypeManager.int64_type)
486 return new LongConstant ((long) v);
487 else if (t == TypeManager.uint64_type)
488 return new ULongConstant ((ulong) v);
489 else if (t == TypeManager.float_type)
490 return new FloatConstant ((float) v);
491 else if (t == TypeManager.double_type)
492 return new DoubleConstant ((double) v);
493 else if (t == TypeManager.string_type)
494 return new StringConstant ((string) v);
495 else if (t == TypeManager.short_type)
496 return new ShortConstant ((short)v);
497 else if (t == TypeManager.ushort_type)
498 return new UShortConstant ((ushort)v);
499 else if (t == TypeManager.sbyte_type)
500 return new SByteConstant (((sbyte)v));
501 else if (t == TypeManager.byte_type)
502 return new ByteConstant ((byte)v);
503 else if (t == TypeManager.char_type)
504 return new CharConstant ((char)v);
505 else if (t == TypeManager.bool_type)
506 return new BoolConstant ((bool) v);
507 else if (t == TypeManager.decimal_type)
508 return new DecimalConstant ((decimal)v);
509 else if (TypeManager.IsEnumType (t)){
510 Constant e = Constantify (v, TypeManager.EnumToUnderlying (v.GetType ()));
512 return new EnumConstant (e, t);
514 throw new Exception ("Unknown type for constant (" + t +
519 /// Returns a fully formed expression after a MemberLookup
521 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
524 return new EventExpr ((EventInfo) mi, loc);
525 else if (mi is FieldInfo)
526 return new FieldExpr ((FieldInfo) mi, loc);
527 else if (mi is PropertyInfo)
528 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
529 else if (mi is Type){
530 return new TypeExpr ((System.Type) mi, loc);
537 // FIXME: Probably implement a cache for (t,name,current_access_set)?
539 // This code could use some optimizations, but we need to do some
540 // measurements. For example, we could use a delegate to 'flag' when
541 // something can not any longer be a method-group (because it is something
545 // If the return value is an Array, then it is an array of
548 // If the return value is an MemberInfo, it is anything, but a Method
552 // FIXME: When calling MemberLookup inside an 'Invocation', we should pass
553 // the arguments here and have MemberLookup return only the methods that
554 // match the argument count/type, unlike we are doing now (we delay this
557 // This is so we can catch correctly attempts to invoke instance methods
558 // from a static body (scan for error 120 in ResolveSimpleName).
561 // FIXME: Potential optimization, have a static ArrayList
564 public static Expression MemberLookup (EmitContext ec, Type t, string name,
565 MemberTypes mt, BindingFlags bf, Location loc)
567 return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
571 // Lookup type 't' for code in class 'invocation_type'. Note that it's important
572 // to set 'invocation_type' correctly since this method also checks whether the
573 // invoking class is allowed to access the member in class 't'. When you want to
574 // explicitly do a lookup in the base class, you must set both 't' and 'invocation_type'
575 // to the base class (although a derived class can access protected members of its base
576 // class it cannot do so through an instance of the base class (error CS1540)).
579 public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
580 string name, MemberTypes mt, BindingFlags bf,
583 MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
588 int count = mi.Length;
590 if (mi [0] is MethodBase)
591 return new MethodGroupExpr (mi, loc);
593 if (mi [0] is PropertyInfo)
594 return new PropertyGroupExpr (mi, loc);
599 return ExprClassFromMemberInfo (ec, mi [0], loc);
602 public const MemberTypes AllMemberTypes =
603 MemberTypes.Constructor |
607 MemberTypes.NestedType |
608 MemberTypes.Property;
610 public const BindingFlags AllBindingFlags =
611 BindingFlags.Public |
612 BindingFlags.Static |
613 BindingFlags.Instance |
614 BindingFlags.IgnoreCase;
616 public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc)
618 return MemberLookup (ec, ec.ContainerType, t, name, AllMemberTypes, AllBindingFlags, loc);
621 public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
623 return MemberLookup (ec, ec.ContainerType, t, name,
624 MemberTypes.Method, AllBindingFlags, loc);
628 /// This is a wrapper for MemberLookup that is not used to "probe", but
629 /// to find a final definition. If the final definition is not found, we
630 /// look for private members and display a useful debugging message if we
633 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
636 return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
639 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
640 MemberTypes mt, BindingFlags bf, Location loc)
644 int errors = Report.Errors;
646 e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
651 // Error has already been reported.
652 if (errors < Report.Errors)
655 e = MemberLookup (ec, t, name, AllMemberTypes,
656 AllBindingFlags | BindingFlags.NonPublic, loc);
659 30456, loc, "'" + t + "' does not contain a definition " +
660 "for '" + name + "'");
663 30390, loc, "'" + t + "." + name +
664 "' is inaccessible due to its protection level");
670 static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
672 EventInfo ei = event_expr.EventInfo;
674 return TypeManager.GetPrivateFieldOfEvent (ei);
677 static EmptyExpression MyEmptyExpr;
678 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
680 Type expr_type = expr.Type;
682 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
683 // if we are a method group, emit a warning
689 // notice that it is possible to write "ValueType v = 1", the ValueType here
690 // is an abstract class, and not really a value type, so we apply the same rules.
692 if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) {
694 // A pointer type cannot be converted to object
696 if (expr_type.IsPointer)
699 if (expr_type.IsValueType)
700 return new BoxedCast (expr);
701 if (expr_type.IsClass || expr_type.IsInterface)
702 return new EmptyCast (expr, target_type);
703 } else if (expr_type.IsSubclassOf (target_type)) {
705 // Special case: enumeration to System.Enum.
706 // System.Enum is not a value type, it is a class, so we need
707 // a boxing conversion
709 if (expr_type.IsEnum)
710 return new BoxedCast (expr);
712 return new EmptyCast (expr, target_type);
715 // This code is kind of mirrored inside StandardConversionExists
716 // with the small distinction that we only probe there
718 // Always ensure that the code here and there is in sync
720 // from the null type to any reference-type.
721 if (expr is NullLiteral && !target_type.IsValueType)
722 return new EmptyCast (expr, target_type);
724 // from any class-type S to any interface-type T.
725 if (target_type.IsInterface) {
726 if (TypeManager.ImplementsInterface (expr_type, target_type)){
727 if (expr_type.IsClass)
728 return new EmptyCast (expr, target_type);
729 else if (expr_type.IsValueType)
730 return new BoxedCast (expr);
734 // from any interface type S to interface-type T.
735 if (expr_type.IsInterface && target_type.IsInterface) {
736 if (TypeManager.ImplementsInterface (expr_type, target_type))
737 return new EmptyCast (expr, target_type);
742 // from an array-type S to an array-type of type T
743 if (expr_type.IsArray && target_type.IsArray) {
744 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
746 Type expr_element_type = expr_type.GetElementType ();
748 if (MyEmptyExpr == null)
749 MyEmptyExpr = new EmptyExpression ();
751 MyEmptyExpr.SetType (expr_element_type);
752 Type target_element_type = target_type.GetElementType ();
754 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
755 if (StandardConversionExists (MyEmptyExpr,
756 target_element_type))
757 return new EmptyCast (expr, target_type);
762 // from an array-type to System.Array
763 if (expr_type.IsArray && target_type == TypeManager.array_type)
764 return new EmptyCast (expr, target_type);
766 // from any delegate type to System.Delegate
767 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
768 target_type == TypeManager.delegate_type)
769 return new EmptyCast (expr, target_type);
771 // from any array-type or delegate type into System.ICloneable.
772 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
773 if (target_type == TypeManager.icloneable_type)
774 return new EmptyCast (expr, target_type);
784 /// Implicit Numeric Conversions.
786 /// expr is the expression to convert, returns a new expression of type
787 /// target_type or null if an implicit conversion is not possible.
789 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
790 Type target_type, Location loc)
792 Type expr_type = expr.Type;
795 // Attempt to do the implicit constant expression conversions
797 if (expr is BoolConstant || expr is IntConstant || expr is LongConstant || expr is DoubleConstant || expr is FloatConstant){
800 e = TryImplicitNumericConversion (target_type, (Constant) expr);
804 if (target_type == TypeManager.byte_type ||
805 target_type == TypeManager.short_type ||
806 target_type == TypeManager.int32_type ||
807 target_type == TypeManager.int64_type ||
808 target_type == TypeManager.float_type) {
811 if (expr is IntConstant)
812 val = ((IntConstant) expr).Value.ToString();
813 if (expr is LongConstant)
814 val = ((LongConstant) expr).Value.ToString();
815 if (expr is FloatConstant)
816 val = ((FloatConstant) expr).Value.ToString();
817 if (expr is DoubleConstant)
818 val = ((DoubleConstant) expr).Value.ToString();
819 Error_ConstantValueCannotBeConverted(loc, val, target_type);
822 } else if (expr is LongConstant && target_type == TypeManager.uint64_type) {
824 // Try the implicit constant expression conversion
825 // from long to ulong, instead of a nice routine,
828 long v = ((LongConstant) expr).Value;
830 return new ULongConstant ((ulong) v);
833 Type real_target_type = target_type;
835 if (target_type == TypeManager.bool_type) {
837 if (expr_type == TypeManager.decimal_type) {
838 return RTConversionExpression (ec, "System.Convert",".ToBoolean" , expr, loc);
841 if ((expr_type != TypeManager.char_type) &&
842 (expr_type != TypeManager.string_type) &&
843 (expr_type != TypeManager.object_type))
844 return new NumericToBoolCast (expr, expr.Type);
847 if (expr_type == TypeManager.bool_type){
849 if (real_target_type == TypeManager.sbyte_type)
850 return new BoolToNumericCast (expr, target_type);
851 if (real_target_type == TypeManager.byte_type)
852 return new BoolToNumericCast (expr, target_type);
853 if (real_target_type == TypeManager.int32_type)
854 return new BoolToNumericCast (expr, target_type);
855 if (real_target_type == TypeManager.int64_type)
856 return new BoolToNumericCast (expr, target_type);
857 if (real_target_type == TypeManager.double_type)
858 return new BoolToNumericCast (expr, target_type);
859 if (real_target_type == TypeManager.float_type)
860 return new BoolToNumericCast (expr, target_type);
861 if (real_target_type == TypeManager.short_type)
862 return new BoolToNumericCast (expr, target_type);
863 if (real_target_type == TypeManager.decimal_type)
864 return RTConversionExpression(ec, "DecimalType.FromBoolean", expr, loc);
865 } else if (expr_type == TypeManager.sbyte_type){
867 // From sbyte to short, int, long, float, double.
869 if (real_target_type == TypeManager.int32_type)
870 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
871 if (real_target_type == TypeManager.int64_type)
872 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
873 if (real_target_type == TypeManager.double_type)
874 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
875 if (real_target_type == TypeManager.float_type)
876 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
877 if (real_target_type == TypeManager.short_type)
878 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
879 } else if (expr_type == TypeManager.byte_type){
881 // From byte to short, ushort, int, uint, long, ulong, float, double
883 if ((real_target_type == TypeManager.short_type) ||
884 (real_target_type == TypeManager.ushort_type) ||
885 (real_target_type == TypeManager.int32_type) ||
886 (real_target_type == TypeManager.uint32_type))
887 return new EmptyCast (expr, target_type);
889 if (real_target_type == TypeManager.uint64_type)
890 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
891 if (real_target_type == TypeManager.int64_type)
892 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
893 if (real_target_type == TypeManager.float_type)
894 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
895 if (real_target_type == TypeManager.double_type)
896 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
897 } else if (expr_type == TypeManager.short_type){
899 // From short to int, long, float, double
901 if (real_target_type == TypeManager.int32_type)
902 return new EmptyCast (expr, target_type);
903 if (real_target_type == TypeManager.int64_type)
904 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
905 if (real_target_type == TypeManager.double_type)
906 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
907 if (real_target_type == TypeManager.float_type)
908 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
909 } else if (expr_type == TypeManager.ushort_type){
911 // From ushort to int, uint, long, ulong, float, double
913 if (real_target_type == TypeManager.uint32_type)
914 return new EmptyCast (expr, target_type);
916 if (real_target_type == TypeManager.uint64_type)
917 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
918 if (real_target_type == TypeManager.int32_type)
919 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
920 if (real_target_type == TypeManager.int64_type)
921 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
922 if (real_target_type == TypeManager.double_type)
923 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
924 if (real_target_type == TypeManager.float_type)
925 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
926 } else if (expr_type == TypeManager.int32_type){
928 // From int to long, float, double
930 if (real_target_type == TypeManager.int64_type)
931 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
932 if (real_target_type == TypeManager.double_type)
933 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
934 if (real_target_type == TypeManager.float_type)
935 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
936 } else if (expr_type == TypeManager.uint32_type){
938 // From uint to long, ulong, float, double
940 if (real_target_type == TypeManager.int64_type)
941 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
942 if (real_target_type == TypeManager.uint64_type)
943 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
944 if (real_target_type == TypeManager.double_type)
945 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
947 if (real_target_type == TypeManager.float_type)
948 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
950 } else if (expr_type == TypeManager.int64_type){
952 // From long/ulong to float, double
954 if (real_target_type == TypeManager.double_type)
955 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
956 if (real_target_type == TypeManager.float_type)
957 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
958 } else if (expr_type == TypeManager.uint64_type){
960 // From ulong to float, double
962 if (real_target_type == TypeManager.double_type)
963 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
965 if (real_target_type == TypeManager.float_type)
966 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
968 } else if (expr_type == TypeManager.string_type){
970 if (real_target_type == TypeManager.bool_type)
971 return RTConversionExpression (ec, "BooleanType.FromString" , expr, loc);
972 if (real_target_type == TypeManager.decimal_type)
973 return RTConversionExpression (ec, "DecimalType.FromString" , expr, loc);
974 if (real_target_type == TypeManager.float_type)
975 return RTConversionExpression (ec, "SingleType.FromString" , expr, loc);
976 if (real_target_type == TypeManager.short_type)
977 return RTConversionExpression (ec, "ShortType.FromString" , expr, loc);
978 if (real_target_type == TypeManager.int64_type)
979 return RTConversionExpression (ec, "LongType.FromString" , expr, loc);
980 if (real_target_type == TypeManager.int32_type)
981 return RTConversionExpression (ec, "IntegerType.FromString" , expr, loc);
982 if (real_target_type == TypeManager.double_type)
983 return RTConversionExpression (ec, "DoubleType.FromString" , expr, loc);
984 if (real_target_type == TypeManager.byte_type)
985 return RTConversionExpression (ec, "ByteType.FromString" , expr, loc);
986 } else if (expr_type == TypeManager.float_type){
990 if (real_target_type == TypeManager.decimal_type)
991 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
992 if (real_target_type == TypeManager.double_type)
993 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
995 } else if (expr_type == TypeManager.double_type){
997 if (real_target_type == TypeManager.decimal_type)
998 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
999 } else if (expr_type == TypeManager.decimal_type){
1001 if (real_target_type == TypeManager.bool_type)
1002 return RTConversionExpression (ec, "BooleanType.FromDecimal" , expr, loc);
1003 if (real_target_type == TypeManager.short_type)
1004 return RTConversionExpression(ec, "System.Convert", ".ToInt16", expr, loc);
1005 if (real_target_type == TypeManager.byte_type)
1006 return RTConversionExpression(ec, "System.Convert", ".ToByte", expr, loc);
1007 if (real_target_type == TypeManager.int32_type)
1008 return RTConversionExpression(ec, "System.Convert", ".ToInt32", expr, loc);
1009 if (real_target_type == TypeManager.int64_type)
1010 return RTConversionExpression(ec, "System.Convert", ".ToInt64", expr, loc);
1011 if (real_target_type == TypeManager.float_type)
1012 return RTConversionExpression(ec, "System.Convert", ".ToSingle", expr, loc);
1013 if (real_target_type == TypeManager.double_type)
1014 return RTConversionExpression(ec, "System.Convert", ".ToDouble", expr, loc);
1021 // Tests whether an implicit reference conversion exists between expr_type
1024 public static bool ImplicitReferenceConversionExists (Expression expr, Type expr_type, Type target_type)
1027 // This is the boxed case.
1029 if (target_type == TypeManager.object_type) {
1030 if ((expr_type.IsClass) ||
1031 (expr_type.IsValueType) ||
1032 (expr_type.IsInterface))
1035 } else if (expr_type.IsSubclassOf (target_type)) {
1038 // Please remember that all code below actually comes
1039 // from ImplicitReferenceConversion so make sure code remains in sync
1041 // from any class-type S to any interface-type T.
1042 if (target_type.IsInterface) {
1043 if (TypeManager.ImplementsInterface (expr_type, target_type))
1047 // from any interface type S to interface-type T.
1048 if (expr_type.IsInterface && target_type.IsInterface)
1049 if (TypeManager.ImplementsInterface (expr_type, target_type))
1052 // from an array-type S to an array-type of type T
1053 if (expr_type.IsArray && target_type.IsArray) {
1054 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
1056 Type expr_element_type = expr_type.GetElementType ();
1058 if (MyEmptyExpr == null)
1059 MyEmptyExpr = new EmptyExpression ();
1061 MyEmptyExpr.SetType (expr_element_type);
1062 Type target_element_type = target_type.GetElementType ();
1064 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
1065 if (StandardConversionExists (MyEmptyExpr,
1066 target_element_type))
1071 // from an array-type to System.Array
1072 if (expr_type.IsArray && (target_type == TypeManager.array_type))
1075 // from any delegate type to System.Delegate
1076 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
1077 target_type == TypeManager.delegate_type)
1078 if (target_type.IsAssignableFrom (expr_type))
1081 // from any array-type or delegate type into System.ICloneable.
1082 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
1083 if (target_type == TypeManager.icloneable_type)
1086 // from the null type to any reference-type.
1087 if (expr is NullLiteral && !target_type.IsValueType &&
1088 !TypeManager.IsEnumType (target_type))
1097 /// Same as StandardConversionExists except that it also looks at
1098 /// implicit user defined conversions - needed for overload resolution
1100 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
1102 if (StandardConversionExists (expr, target_type) == true)
1106 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
1116 /// Determines if a standard implicit conversion exists from
1117 /// expr_type to target_type
1119 public static bool StandardConversionExists (Expression expr, Type target_type)
1121 return WideningConversionExists (expr, expr.type, target_type);
1124 public static bool WideningConversionExists (Type expr_type, Type target_type)
1126 return WideningConversionExists (null, expr_type, target_type);
1129 public static bool WideningConversionExists (Expression expr, Type target_type)
1131 return WideningConversionExists (expr, expr.Type, target_type);
1134 public static bool WideningConversionExists (Expression expr, Type expr_type, Type target_type)
1137 if (expr_type == null || expr_type == TypeManager.void_type)
1140 if (expr_type == target_type)
1143 // Conversions from enum to underlying type are widening.
1144 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1145 expr_type = TypeManager.EnumToUnderlying (expr_type);
1147 if (expr_type == target_type)
1150 // First numeric conversions
1152 if (expr_type == TypeManager.sbyte_type){
1154 // From sbyte to short, int, long, float, double.
1156 if ((target_type == TypeManager.int32_type) ||
1157 (target_type == TypeManager.int64_type) ||
1158 (target_type == TypeManager.double_type) ||
1159 (target_type == TypeManager.float_type) ||
1160 (target_type == TypeManager.short_type) ||
1161 (target_type == TypeManager.decimal_type))
1164 } else if (expr_type == TypeManager.byte_type){
1166 // From byte to short, ushort, int, uint, long, ulong, float, double
1168 if ((target_type == TypeManager.short_type) ||
1169 (target_type == TypeManager.bool_type) ||
1170 (target_type == TypeManager.ushort_type) ||
1171 (target_type == TypeManager.int32_type) ||
1172 (target_type == TypeManager.uint32_type) ||
1173 (target_type == TypeManager.uint64_type) ||
1174 (target_type == TypeManager.int64_type) ||
1175 (target_type == TypeManager.float_type) ||
1176 (target_type == TypeManager.double_type) ||
1177 (target_type == TypeManager.decimal_type))
1180 } else if (expr_type == TypeManager.short_type){
1182 // From short to int, long, float, double
1184 if ((target_type == TypeManager.int32_type) ||
1185 (target_type == TypeManager.bool_type) ||
1186 (target_type == TypeManager.int64_type) ||
1187 (target_type == TypeManager.double_type) ||
1188 (target_type == TypeManager.float_type) ||
1189 (target_type == TypeManager.decimal_type))
1192 } else if (expr_type == TypeManager.ushort_type){
1194 // From ushort to int, uint, long, ulong, float, double
1196 if ((target_type == TypeManager.uint32_type) ||
1197 (target_type == TypeManager.uint64_type) ||
1198 (target_type == TypeManager.int32_type) ||
1199 (target_type == TypeManager.int64_type) ||
1200 (target_type == TypeManager.double_type) ||
1201 (target_type == TypeManager.float_type) ||
1202 (target_type == TypeManager.decimal_type))
1205 } else if (expr_type == TypeManager.int32_type){
1207 // From int to long, float, double
1209 if ((target_type == TypeManager.int64_type) ||
1210 (target_type == TypeManager.bool_type) ||
1211 (target_type == TypeManager.double_type) ||
1212 (target_type == TypeManager.float_type) ||
1213 (target_type == TypeManager.decimal_type))
1216 } else if (expr_type == TypeManager.uint32_type){
1218 // From uint to long, ulong, float, double
1220 if ((target_type == TypeManager.int64_type) ||
1221 (target_type == TypeManager.bool_type) ||
1222 (target_type == TypeManager.uint64_type) ||
1223 (target_type == TypeManager.double_type) ||
1224 (target_type == TypeManager.float_type) ||
1225 (target_type == TypeManager.decimal_type))
1228 } else if ((expr_type == TypeManager.uint64_type) ||
1229 (expr_type == TypeManager.int64_type)) {
1231 // From long/ulong to float, double
1233 if ((target_type == TypeManager.double_type) ||
1234 (target_type == TypeManager.bool_type) ||
1235 (target_type == TypeManager.float_type) ||
1236 (target_type == TypeManager.decimal_type))
1239 } else if (expr_type == TypeManager.decimal_type) {
1240 if (target_type == TypeManager.float_type ||
1241 target_type == TypeManager.double_type)
1243 } else if (expr_type == TypeManager.float_type){
1245 // float to double, decimal
1247 if (target_type == TypeManager.double_type)
1249 } else if (expr_type == TypeManager.double_type){
1251 if ((target_type == TypeManager.bool_type))
1255 if (ImplicitReferenceConversionExists (expr, expr_type, target_type))
1259 if (expr is IntConstant){
1260 int value = ((IntConstant) expr).Value;
1262 if (target_type == TypeManager.sbyte_type){
1263 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1265 } else if (target_type == TypeManager.byte_type){
1266 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1268 } else if (target_type == TypeManager.short_type){
1269 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1271 } else if (target_type == TypeManager.ushort_type){
1272 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1274 } else if (target_type == TypeManager.uint32_type){
1277 } else if (target_type == TypeManager.uint64_type){
1279 // we can optimize this case: a positive int32
1280 // always fits on a uint64. But we need an opcode
1287 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
1291 if (expr is LongConstant && target_type == TypeManager.uint64_type){
1293 // Try the implicit constant expression conversion
1294 // from long to ulong, instead of a nice routine,
1295 // we just inline it
1297 long v = ((LongConstant) expr).Value;
1303 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1304 IntLiteral i = (IntLiteral) expr;
1310 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
1317 // Used internally by FindMostEncompassedType, this is used
1318 // to avoid creating lots of objects in the tight loop inside
1319 // FindMostEncompassedType
1321 static EmptyExpression priv_fmet_param;
1324 /// Finds "most encompassed type" according to the spec (13.4.2)
1325 /// amongst the methods in the MethodGroupExpr
1327 static Type FindMostEncompassedType (ArrayList types)
1331 if (priv_fmet_param == null)
1332 priv_fmet_param = new EmptyExpression ();
1334 foreach (Type t in types){
1335 priv_fmet_param.SetType (t);
1342 if (StandardConversionExists (priv_fmet_param, best))
1350 // Used internally by FindMostEncompassingType, this is used
1351 // to avoid creating lots of objects in the tight loop inside
1352 // FindMostEncompassingType
1354 static EmptyExpression priv_fmee_ret;
1357 /// Finds "most encompassing type" according to the spec (13.4.2)
1358 /// amongst the types in the given set
1360 static Type FindMostEncompassingType (ArrayList types)
1364 if (priv_fmee_ret == null)
1365 priv_fmee_ret = new EmptyExpression ();
1367 foreach (Type t in types){
1368 priv_fmee_ret.SetType (best);
1375 if (StandardConversionExists (priv_fmee_ret, t))
1383 // Used to avoid creating too many objects
1385 static EmptyExpression priv_fms_expr;
1388 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
1389 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
1390 /// for explicit and implicit conversion operators.
1392 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
1393 bool apply_explicit_conv_rules,
1396 ArrayList src_types_set = new ArrayList ();
1398 if (priv_fms_expr == null)
1399 priv_fms_expr = new EmptyExpression ();
1402 // If any operator converts from S then Sx = S
1404 Type source_type= source.Type;
1405 foreach (MethodBase mb in me.Methods){
1406 ParameterData pd = Invocation.GetParameterData (mb);
1407 Type param_type = pd.ParameterType (0);
1409 if (param_type == source_type)
1412 if (apply_explicit_conv_rules) {
1415 // Find the set of applicable user-defined conversion operators, U. This set
1417 // user-defined implicit or explicit conversion operators declared by
1418 // the classes or structs in D that convert from a type encompassing
1419 // or encompassed by S to a type encompassing or encompassed by T
1421 priv_fms_expr.SetType (param_type);
1422 if (StandardConversionExists (priv_fms_expr, source_type))
1423 src_types_set.Add (param_type);
1425 if (StandardConversionExists (source, param_type))
1426 src_types_set.Add (param_type);
1430 // Only if S is encompassed by param_type
1432 if (StandardConversionExists (source, param_type))
1433 src_types_set.Add (param_type);
1438 // Explicit Conv rules
1440 if (apply_explicit_conv_rules) {
1441 ArrayList candidate_set = new ArrayList ();
1443 foreach (Type param_type in src_types_set){
1444 if (StandardConversionExists (source, param_type))
1445 candidate_set.Add (param_type);
1448 if (candidate_set.Count != 0)
1449 return FindMostEncompassedType (candidate_set);
1455 if (apply_explicit_conv_rules)
1456 return FindMostEncompassingType (src_types_set);
1458 return FindMostEncompassedType (src_types_set);
1462 // Useful in avoiding proliferation of objects
1464 static EmptyExpression priv_fmt_expr;
1467 /// Finds the most specific target Tx according to section 13.4.4
1469 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
1470 bool apply_explicit_conv_rules,
1473 ArrayList tgt_types_set = new ArrayList ();
1475 if (priv_fmt_expr == null)
1476 priv_fmt_expr = new EmptyExpression ();
1479 // If any operator converts to T then Tx = T
1481 foreach (MethodInfo mi in me.Methods){
1482 Type ret_type = mi.ReturnType;
1484 if (ret_type == target)
1487 if (apply_explicit_conv_rules) {
1490 // Find the set of applicable user-defined conversion operators, U.
1492 // This set consists of the
1493 // user-defined implicit or explicit conversion operators declared by
1494 // the classes or structs in D that convert from a type encompassing
1495 // or encompassed by S to a type encompassing or encompassed by T
1497 priv_fms_expr.SetType (ret_type);
1498 if (StandardConversionExists (priv_fms_expr, target))
1499 tgt_types_set.Add (ret_type);
1501 priv_fms_expr.SetType (target);
1502 if (StandardConversionExists (priv_fms_expr, ret_type))
1503 tgt_types_set.Add (ret_type);
1507 // Only if T is encompassed by param_type
1509 priv_fms_expr.SetType (ret_type);
1510 if (StandardConversionExists (priv_fms_expr, target))
1511 tgt_types_set.Add (ret_type);
1516 // Explicit conv rules
1518 if (apply_explicit_conv_rules) {
1519 ArrayList candidate_set = new ArrayList ();
1521 foreach (Type ret_type in tgt_types_set){
1522 priv_fmt_expr.SetType (ret_type);
1524 if (StandardConversionExists (priv_fmt_expr, target))
1525 candidate_set.Add (ret_type);
1528 if (candidate_set.Count != 0)
1529 return FindMostEncompassingType (candidate_set);
1533 // Okay, final case !
1535 if (apply_explicit_conv_rules)
1536 return FindMostEncompassedType (tgt_types_set);
1538 return FindMostEncompassingType (tgt_types_set);
1542 /// User-defined Implicit conversions
1544 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1545 Type target, Location loc)
1547 return UserDefinedConversion (ec, source, target, loc, false);
1551 /// User-defined Explicit conversions
1553 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1554 Type target, Location loc)
1556 return UserDefinedConversion (ec, source, target, loc, true);
1560 /// Computes the MethodGroup for the user-defined conversion
1561 /// operators from source_type to target_type. 'look_for_explicit'
1562 /// controls whether we should also include the list of explicit
1565 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1566 Type source_type, Type target_type,
1567 Location loc, bool look_for_explicit)
1569 Expression mg1 = null, mg2 = null;
1570 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1574 // FIXME : How does the False operator come into the picture ?
1575 // This doesn't look complete and very correct !
1577 if (target_type == TypeManager.bool_type && !look_for_explicit)
1578 op_name = "op_True";
1580 op_name = "op_Implicit";
1582 MethodGroupExpr union3;
1584 mg1 = MethodLookup (ec, source_type, op_name, loc);
1585 if (source_type.BaseType != null)
1586 mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1589 union3 = (MethodGroupExpr) mg2;
1590 else if (mg2 == null)
1591 union3 = (MethodGroupExpr) mg1;
1593 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1595 mg1 = MethodLookup (ec, target_type, op_name, loc);
1598 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1600 union3 = (MethodGroupExpr) mg1;
1603 if (target_type.BaseType != null)
1604 mg1 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1608 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1610 union3 = (MethodGroupExpr) mg1;
1613 MethodGroupExpr union4 = null;
1615 if (look_for_explicit) {
1616 op_name = "op_Explicit";
1618 mg5 = MemberLookup (ec, source_type, op_name, loc);
1619 if (source_type.BaseType != null)
1620 mg6 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1622 mg7 = MemberLookup (ec, target_type, op_name, loc);
1623 if (target_type.BaseType != null)
1624 mg8 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1626 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1627 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1629 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1632 return Invocation.MakeUnionSet (union3, union4, loc);
1636 /// User-defined conversions
1638 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1639 Type target, Location loc,
1640 bool look_for_explicit)
1642 MethodGroupExpr union;
1643 Type source_type = source.Type;
1644 MethodBase method = null;
1646 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1650 Type most_specific_source, most_specific_target;
1653 foreach (MethodBase m in union.Methods){
1654 Console.WriteLine ("Name: " + m.Name);
1655 Console.WriteLine (" : " + ((MethodInfo)m).ReturnType);
1659 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
1660 if (most_specific_source == null)
1663 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
1664 if (most_specific_target == null)
1669 foreach (MethodBase mb in union.Methods){
1670 ParameterData pd = Invocation.GetParameterData (mb);
1671 MethodInfo mi = (MethodInfo) mb;
1673 if (pd.ParameterType (0) == most_specific_source &&
1674 mi.ReturnType == most_specific_target) {
1680 if (method == null || count > 1)
1685 // This will do the conversion to the best match that we
1686 // found. Now we need to perform an implict standard conversion
1687 // if the best match was not the type that we were requested
1690 if (look_for_explicit)
1691 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1693 source = ConvertImplicitStandard (ec, source, most_specific_source, loc);
1699 e = new UserCast ((MethodInfo) method, source, loc);
1700 if (e.Type != target){
1701 if (!look_for_explicit)
1702 e = ConvertImplicitStandard (ec, e, target, loc);
1704 e = ConvertExplicitStandard (ec, e, target, loc);
1710 /// Converts implicitly the resolved expression 'expr' into the
1711 /// 'target_type'. It returns a new expression that can be used
1712 /// in a context that expects a 'target_type'.
1714 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1715 Type target_type, Location loc)
1717 Type expr_type = expr.Type;
1721 if (expr_type == target_type)
1724 if (target_type == null)
1725 throw new Exception ("Target type is null");
1727 e = ConvertImplicitStandard (ec, expr, target_type, loc);
1731 e = ImplicitUserConversion (ec, expr, target_type, loc);
1736 e = NarrowingConversion (ec, expr, target_type, loc);
1744 /// Converts the resolved expression 'expr' into the
1745 /// 'target_type' using the Microsoft.VisualBasic runtime.
1746 /// It returns a new expression that can be used
1747 /// in a context that expects a 'target_type'.
1749 static private Expression RTConversionExpression (EmitContext ec, string s, Expression expr, Location loc)
1755 etmp = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices." + s, loc);
1756 args = new ArrayList();
1757 arg = new Argument (expr, Argument.AType.Expression);
1759 e = (Expression) new Invocation (etmp, args, loc);
1764 static private Expression RTConversionExpression (EmitContext ec, string ns, string method, Expression expr, Location loc)
1770 etmp = Mono.MonoBASIC.Parser.DecomposeQI(ns+method, loc);
1771 args = new ArrayList();
1772 arg = new Argument (expr, Argument.AType.Expression);
1774 e = (Expression) new Invocation (etmp, args, loc);
1780 static public bool NarrowingConversionExists (EmitContext ec, Expression expr, Type target_type)
1782 Type expr_type = expr.Type;
1783 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1784 expr_type = TypeManager.EnumToUnderlying (expr_type);
1786 if (target_type.IsSubclassOf (TypeManager.enum_type))
1787 target_type = TypeManager.EnumToUnderlying (target_type);
1790 if (expr_type == target_type)
1793 if (target_type == TypeManager.sbyte_type){
1795 // To sbyte from short, int, long, float, double.
1797 if ((expr_type == TypeManager.int32_type) ||
1798 (expr_type == TypeManager.int64_type) ||
1799 (expr_type == TypeManager.double_type) ||
1800 (expr_type == TypeManager.float_type) ||
1801 (expr_type == TypeManager.short_type) ||
1802 (expr_type == TypeManager.decimal_type))
1805 } else if (target_type == TypeManager.byte_type){
1807 // To byte from short, ushort, int, uint, long, ulong, float, double
1809 if ((expr_type == TypeManager.short_type) ||
1810 (expr_type == TypeManager.ushort_type) ||
1811 (expr_type == TypeManager.int32_type) ||
1812 (expr_type == TypeManager.uint32_type) ||
1813 (expr_type == TypeManager.uint64_type) ||
1814 (expr_type == TypeManager.int64_type) ||
1815 (expr_type == TypeManager.float_type) ||
1816 (expr_type == TypeManager.double_type) ||
1817 (expr_type == TypeManager.decimal_type))
1820 } else if (target_type == TypeManager.short_type){
1822 // To short from int, long, float, double
1824 if ((expr_type == TypeManager.int32_type) ||
1825 (expr_type == TypeManager.int64_type) ||
1826 (expr_type == TypeManager.double_type) ||
1827 (expr_type == TypeManager.float_type) ||
1828 (expr_type == TypeManager.decimal_type))
1831 } else if (target_type == TypeManager.ushort_type){
1833 // To ushort from int, uint, long, ulong, float, double
1835 if ((expr_type == TypeManager.uint32_type) ||
1836 (expr_type == TypeManager.uint64_type) ||
1837 (expr_type == TypeManager.int32_type) ||
1838 (expr_type == TypeManager.int64_type) ||
1839 (expr_type == TypeManager.double_type) ||
1840 (expr_type == TypeManager.float_type) ||
1841 (expr_type == TypeManager.decimal_type))
1844 } else if (target_type == TypeManager.int32_type){
1846 // To int from long, float, double
1848 if ((expr_type == TypeManager.int64_type) ||
1849 (expr_type == TypeManager.double_type) ||
1850 (expr_type == TypeManager.float_type) ||
1851 (expr_type == TypeManager.decimal_type))
1854 } else if (target_type == TypeManager.uint32_type){
1856 // To uint from long, ulong, float, double
1858 if ((expr_type == TypeManager.int64_type) ||
1859 (expr_type == TypeManager.uint64_type) ||
1860 (expr_type == TypeManager.double_type) ||
1861 (expr_type == TypeManager.float_type) ||
1862 (expr_type == TypeManager.decimal_type))
1865 } else if ((target_type == TypeManager.uint64_type) ||
1866 (target_type == TypeManager.int64_type)) {
1868 // To long/ulong from float, double
1870 if ((expr_type == TypeManager.double_type) ||
1871 (expr_type == TypeManager.float_type) ||
1872 (expr_type == TypeManager.decimal_type))
1875 } else if (target_type == TypeManager.decimal_type){
1876 if (expr_type == TypeManager.float_type ||
1877 expr_type == TypeManager.double_type)
1879 } else if (target_type == TypeManager.float_type){
1881 // To float from double
1883 if (expr_type == TypeManager.double_type)
1887 return (NarrowingConversion (ec, expr, target_type,Location.Null)) != null;
1890 static public Expression NarrowingConversion (EmitContext ec, Expression expr,
1891 Type target_type, Location loc)
1893 Type expr_type = expr.Type;
1895 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1896 expr_type = TypeManager.EnumToUnderlying (expr_type);
1898 if (target_type.IsSubclassOf (TypeManager.enum_type))
1899 target_type = TypeManager.EnumToUnderlying (target_type);
1901 if (expr_type == target_type)
1904 if (target_type == TypeManager.sbyte_type){
1906 // To sbyte from short, int, long, float, double.
1908 if (expr_type == TypeManager.int32_type)
1909 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1910 if (expr_type == TypeManager.int64_type)
1911 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1912 if (expr_type == TypeManager.short_type)
1913 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1915 if (expr_type == TypeManager.float_type) {
1916 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1917 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
1919 if (expr_type == TypeManager.double_type) {
1920 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1921 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
1924 } else if (target_type == TypeManager.byte_type){
1926 // To byte from short, ushort, int, uint, long, ulong, float, double
1928 if (expr_type == TypeManager.short_type)
1929 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1930 if (expr_type == TypeManager.ushort_type)
1931 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1932 if (expr_type == TypeManager.int32_type)
1933 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1934 if (expr_type == TypeManager.uint32_type)
1935 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1936 if (expr_type == TypeManager.uint64_type)
1937 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1938 if (expr_type == TypeManager.int64_type)
1939 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1941 if (expr_type == TypeManager.float_type) {
1942 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1943 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
1945 if (expr_type == TypeManager.double_type) {
1946 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1947 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
1950 } else if (target_type == TypeManager.short_type) {
1952 // To short from int, long, float, double
1954 if (expr_type == TypeManager.int32_type)
1955 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1956 if (expr_type == TypeManager.int64_type)
1957 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
1959 if (expr_type == TypeManager.float_type) {
1960 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1961 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
1963 if (expr_type == TypeManager.double_type) {
1964 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1965 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
1968 } else if (target_type == TypeManager.ushort_type) {
1970 // To ushort from int, uint, long, ulong, float, double
1972 if (expr_type == TypeManager.uint32_type)
1973 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
1974 if (expr_type == TypeManager.uint64_type)
1975 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
1976 if (expr_type == TypeManager.int32_type)
1977 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
1978 if (expr_type == TypeManager.int64_type)
1979 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
1981 if (expr_type == TypeManager.float_type) {
1982 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1983 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
1986 if (expr_type == TypeManager.double_type) {
1987 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1988 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
1991 } else if (target_type == TypeManager.int32_type){
1993 // To int from long, float, double
1995 if (expr_type == TypeManager.int64_type)
1996 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
1998 if (expr_type == TypeManager.float_type) {
1999 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2000 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2002 if (expr_type == TypeManager.double_type) {
2003 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2004 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2007 } else if (target_type == TypeManager.uint32_type){
2009 // To uint from long, ulong, float, double
2011 if (expr_type == TypeManager.int64_type)
2012 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2013 if (expr_type == TypeManager.uint64_type)
2014 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2015 if (expr_type == TypeManager.float_type) {
2016 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2017 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2019 if (expr_type == TypeManager.double_type) {
2020 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2021 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2024 } else if (target_type == TypeManager.uint64_type) {
2026 // To long/ulong from float, double
2028 if (expr_type == TypeManager.float_type) {
2029 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2030 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2032 if (expr_type == TypeManager.double_type) {
2033 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2034 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2037 } else if (target_type == TypeManager.int64_type) {
2039 // To long/ulong from float, double
2041 if (expr_type == TypeManager.float_type) {
2042 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2043 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2045 if (expr_type == TypeManager.double_type) {
2046 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2047 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2050 } else if (target_type == TypeManager.float_type){
2052 // To float from double
2054 if (expr_type == TypeManager.double_type)
2055 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2058 TypeCode dest_type = Type.GetTypeCode (target_type);
2059 TypeCode src_type = Type.GetTypeCode (expr_type);
2060 Expression e = null;
2062 switch (dest_type) {
2063 case TypeCode.String:
2065 case TypeCode.SByte:
2067 e = RTConversionExpression(ec, "StringType.FromByte", expr, loc);
2069 case TypeCode.UInt16:
2070 case TypeCode.Int16:
2071 e = RTConversionExpression(ec, "StringType.FromShort", expr, loc);
2073 case TypeCode.UInt32:
2074 case TypeCode.Int32:
2075 e = RTConversionExpression(ec, "StringType.FromInteger", expr, loc);
2077 case TypeCode.UInt64:
2078 case TypeCode.Int64:
2079 e = RTConversionExpression(ec, "StringType.FromLong", expr, loc);
2082 e = RTConversionExpression(ec, "StringType.FromChar", expr, loc);
2084 case TypeCode.Single:
2085 e = RTConversionExpression(ec, "StringType.FromSingle", expr, loc);
2087 case TypeCode.Double:
2088 e = RTConversionExpression(ec, "StringType.FromDouble", expr, loc);
2090 case TypeCode.Boolean:
2091 e = RTConversionExpression(ec, "StringType.FromBoolean", expr, loc);
2093 case TypeCode.DateTime:
2094 e = RTConversionExpression(ec, "StringType.FromDate", expr, loc);
2096 case TypeCode.Decimal:
2097 e = RTConversionExpression(ec, "StringType.FromDecimal", expr, loc);
2099 case TypeCode.Object:
2100 e = RTConversionExpression(ec, "StringType.FromObject", expr, loc);
2105 case TypeCode.Double:
2107 case TypeCode.String:
2108 e = RTConversionExpression(ec, "DoubleType.FromString", expr, loc);
2110 case TypeCode.Object:
2111 e = RTConversionExpression(ec, "DoubleType.FromObject", expr, loc);
2116 case TypeCode.Single:
2118 case TypeCode.String:
2119 e = RTConversionExpression(ec, "SingleType.FromString", expr, loc);
2121 case TypeCode.Object:
2122 e = RTConversionExpression(ec, "SingleType.FromObject", expr, loc);
2127 case TypeCode.Decimal:
2129 case TypeCode.String:
2130 e = RTConversionExpression(ec, "DecimalType.FromString", expr, loc);
2132 case TypeCode.Object:
2133 e = RTConversionExpression(ec, "DecimalType.FromObject", expr, loc);
2138 case TypeCode.Int64:
2139 case TypeCode.UInt64:
2141 case TypeCode.String:
2142 e = RTConversionExpression(ec, "LongType.FromString", expr, loc);
2144 case TypeCode.Object:
2145 e = RTConversionExpression(ec, "LongType.FromObject", expr, loc);
2149 case TypeCode.Int32:
2150 case TypeCode.UInt32:
2152 case TypeCode.String:
2153 e = RTConversionExpression(ec, "IntegerType.FromString", expr, loc);
2155 case TypeCode.Object:
2156 e = RTConversionExpression(ec, "IntegerType.FromObject", expr, loc);
2161 case TypeCode.Int16:
2162 case TypeCode.UInt16:
2164 case TypeCode.String:
2165 e = RTConversionExpression(ec, "ShortType.FromString", expr, loc);
2167 case TypeCode.Object:
2168 e = RTConversionExpression(ec, "ShortType.FromObject", expr, loc);
2175 case TypeCode.String:
2176 e = RTConversionExpression(ec, "BooleanType.FromString", expr, loc);
2178 case TypeCode.Object:
2179 e = RTConversionExpression(ec, "ByteType.FromObject", expr, loc);
2183 case TypeCode.Boolean:
2185 case TypeCode.String:
2186 e = RTConversionExpression(ec, "BooleanType.FromString", expr, loc);
2188 case TypeCode.Object:
2189 e = RTConversionExpression(ec, "BooleanType.FromObject", expr, loc);
2193 case TypeCode.DateTime:
2195 case TypeCode.String:
2196 e = RTConversionExpression(ec, "DateType.FromString", expr, loc);
2198 case TypeCode.Object:
2199 e = RTConversionExpression(ec, "DateType.FromObject", expr, loc);
2206 case TypeCode.String:
2207 e = RTConversionExpression(ec, "CharType.FromString", expr, loc);
2214 // We must examine separately some types that
2215 // don't have a TypeCode but are supported
2217 if (expr_type == typeof(System.String) && target_type == typeof (System.Char[])) {
2218 e = RTConversionExpression(ec, "CharArrayType.FromString", expr, loc);
2222 // VB.NET Objects can be converted to anything by default
2223 // unless, that is, an exception at runtime blows it all
2224 if (src_type == TypeCode.Object) {
2225 Expression cast_type = Mono.MonoBASIC.Parser.DecomposeQI(target_type.ToString(), loc);
2226 Cast ce = new Cast (cast_type, expr, loc);
2227 ce.IsRuntimeCast = true;
2228 return ce.Resolve (ec);
2233 static public Expression ConvertNothingToDefaultValues (EmitContext ec, Expression expr,
2234 Type target_type, Location loc)
2236 switch (Type.GetTypeCode (target_type)) {
2237 case TypeCode.Boolean :
2238 return new BoolConstant (false);
2239 case TypeCode.Byte :
2240 return new ByteConstant (0);
2241 case TypeCode.Char :
2242 return new CharConstant ((char)0);
2243 case TypeCode.SByte :
2244 return new SByteConstant (0);
2245 case TypeCode.Int16 :
2246 return new ShortConstant (0);
2247 case TypeCode.Int32 :
2248 return new IntConstant (0);
2249 case TypeCode.Int64 :
2250 return new LongConstant (0);
2251 case TypeCode.Decimal :
2252 return new DecimalConstant (System.Decimal.Zero);
2253 case TypeCode.Single :
2254 return new FloatConstant (0.0F);
2255 case TypeCode.Double :
2256 return new DoubleConstant (0.0);
2263 /// Attempts to apply the 'Standard Implicit
2264 /// Conversion' rules to the expression 'expr' into
2265 /// the 'target_type'. It returns a new expression
2266 /// that can be used in a context that expects a
2269 /// This is different from 'ConvertImplicit' in that the
2270 /// user defined implicit conversions are excluded.
2272 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
2273 Type target_type, Location loc)
2275 Type expr_type = expr.Type;
2277 if (expr_type.IsSubclassOf (TypeManager.enum_type))
2278 expr_type = TypeManager.EnumToUnderlying (expr_type);
2282 if (expr is NullLiteral) {
2283 if (target_type == TypeManager.string_type)
2285 e = ConvertNothingToDefaultValues (ec, expr, target_type, loc);
2290 if (expr_type == target_type)
2293 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2298 if (expr is StringConstant && target_type == TypeManager.char_type)
2299 return new CharConstant (((StringConstant) expr).Value [0]);
2301 if (expr is CharConstant && target_type == TypeManager.string_type)
2302 return new StringConstant (((CharConstant) expr).Value.ToString ());
2304 e = ImplicitReferenceConversion (expr, target_type);
2308 if (expr.Type.IsSubclassOf (TypeManager.enum_type)) {
2309 expr_type = TypeManager.EnumToUnderlying (expr.Type);
2310 expr = new EmptyCast (expr, expr_type);
2311 if (expr_type == target_type)
2313 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2319 if (expr_type.IsPointer){
2320 if (target_type == TypeManager.void_ptr_type)
2321 return new EmptyCast (expr, target_type);
2324 // yep, comparing pointer types cant be done with
2325 // t1 == t2, we have to compare their element types.
2327 if (target_type.IsPointer){
2328 if (target_type.GetElementType()==expr_type.GetElementType())
2333 if (target_type.IsPointer){
2334 if (expr is NullLiteral)
2335 return new EmptyCast (expr, target_type);
2343 /// Attemps to perform an implict constant conversion of the any Numeric Constant
2344 /// into a different data type using casts (See Implicit Constant
2345 /// Expression Conversions)
2347 static protected Expression TryImplicitNumericConversion (Type target_type, Constant ic)
2350 if (ic is BoolConstant) {
2351 bool val = (bool) ((BoolConstant)ic).Value;
2353 if (target_type == TypeManager.byte_type)
2354 value = Byte.MaxValue;
2359 if (ic is IntConstant)
2360 value = (double)((IntConstant)ic).Value;
2362 if (ic is LongConstant)
2363 value = (double) ((LongConstant)ic).Value;
2365 if (ic is FloatConstant) {
2366 value = (double) ((FloatConstant)ic).Value;
2369 if (ic is DoubleConstant) {
2370 value = ((DoubleConstant)ic).Value;
2374 // FIXME: This could return constants instead of EmptyCasts
2376 if (target_type == TypeManager.bool_type){
2378 return new BoolConstant (true);
2379 return new BoolConstant (false);
2380 } else if (target_type == TypeManager.sbyte_type){
2381 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2382 return new SByteConstant ((sbyte) System.Math.Round (value));
2383 } else if (target_type == TypeManager.byte_type){
2384 if (value >= Byte.MinValue && value <= Byte.MaxValue)
2385 return new ByteConstant ((byte) System.Math.Round (value));
2386 } else if (target_type == TypeManager.short_type){
2387 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2388 return new ShortConstant ((short) System.Math.Round (value));
2389 } else if (target_type == TypeManager.ushort_type){
2390 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2391 return new UShortConstant ((ushort) System.Math.Round (value));
2392 } else if (target_type == TypeManager.int32_type){
2393 if (value >= Int32.MinValue && value <= Int32.MaxValue)
2394 return new IntConstant ((int) System.Math.Round (value));
2395 } else if (target_type == TypeManager.uint32_type){
2397 return new UIntConstant ((uint) System.Math.Round (value));
2398 } else if (target_type == TypeManager.int64_type){
2399 return new LongConstant ((long) System.Math.Round (value));
2400 } else if (target_type == TypeManager.uint64_type){
2402 // we can optimize this case: a positive int32
2403 // always fits on a uint64. But we need an opcode
2407 return new ULongConstant ((ulong)System.Math.Round ( value));
2408 } else if (target_type == TypeManager.float_type){
2409 return new FloatConstant ((float) value);
2410 } else if (target_type == TypeManager.double_type){
2411 return new DoubleConstant ((double) value);
2414 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
2415 Type underlying = TypeManager.EnumToUnderlying (target_type);
2416 Constant e = (Constant) ic;
2419 // Possibly, we need to create a different 0 literal before passing
2422 if (underlying == TypeManager.int64_type)
2423 e = new LongLiteral (0);
2424 else if (underlying == TypeManager.uint64_type)
2425 e = new ULongLiteral (0);
2427 return new EnumConstant (e, target_type);
2432 static public void Error_CannotConvertImplicit (Location loc, Type source, Type target)
2434 string msg = "Cannot convert implicitly from '"+
2435 TypeManager.MonoBASIC_Name (source) + "' to '" +
2436 TypeManager.MonoBASIC_Name (target) + "'";
2438 throw new Exception (msg);
2440 // Report.Error (30512, loc, msg);
2443 static public void Error_CannotConvertTypeStrict (Type source, Type target, Location loc)
2446 30512, loc, "Cannot convert implicitly from '" +
2447 TypeManager.MonoBASIC_Name (source) + "' to '" +
2448 TypeManager.MonoBASIC_Name (target) + "' with Option Strict On.");
2452 /// Attemptes to implicityly convert 'target' into 'type', using
2453 /// ConvertImplicit. If there is no implicit conversion, then
2454 /// an error is signaled
2456 static public Expression ConvertImplicitRequired (EmitContext ec, Expression source,
2457 Type target_type, Location loc)
2461 e = ConvertImplicit (ec, source, target_type, loc);
2467 if (source is DoubleLiteral && target_type == TypeManager.float_type){
2468 Report.Error (664, loc,
2469 "Double literal cannot be implicitly converted to " +
2470 "float type, use F suffix to create a float literal");
2473 Error_CannotConvertImplicit (loc, source.Type, target_type);
2479 /// Performs the explicit numeric conversions
2481 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc)
2483 Type expr_type = expr.Type;
2486 // If we have an enumeration, extract the underlying type,
2487 // use this during the comparison, but wrap around the original
2490 Type real_target_type = target_type;
2492 if (TypeManager.IsEnumType (real_target_type))
2493 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
2495 if (StandardConversionExists (expr, real_target_type)){
2496 Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc);
2498 if (real_target_type != target_type)
2499 return new EmptyCast (ce, target_type);
2503 if (expr_type == TypeManager.sbyte_type){
2505 // From sbyte to byte, ushort, uint, ulong, char
2507 if (real_target_type == TypeManager.byte_type)
2508 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
2509 if (real_target_type == TypeManager.ushort_type)
2510 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
2511 if (real_target_type == TypeManager.uint32_type)
2512 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
2513 if (real_target_type == TypeManager.uint64_type)
2514 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
2515 } else if (expr_type == TypeManager.byte_type){
2517 // From byte to sbyte and char
2519 if (real_target_type == TypeManager.sbyte_type)
2520 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
2521 } else if (expr_type == TypeManager.short_type){
2523 // From short to sbyte, byte, ushort, uint, ulong, char
2525 if (real_target_type == TypeManager.sbyte_type)
2526 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
2527 if (real_target_type == TypeManager.byte_type)
2528 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
2529 if (real_target_type == TypeManager.ushort_type)
2530 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
2531 if (real_target_type == TypeManager.uint32_type)
2532 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
2533 if (real_target_type == TypeManager.uint64_type)
2534 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
2535 } else if (expr_type == TypeManager.ushort_type){
2537 // From ushort to sbyte, byte, short, char
2539 if (real_target_type == TypeManager.sbyte_type)
2540 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
2541 if (real_target_type == TypeManager.byte_type)
2542 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
2543 if (real_target_type == TypeManager.short_type)
2544 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
2545 } else if (expr_type == TypeManager.int32_type){
2547 // From int to sbyte, byte, short, ushort, uint, ulong, char
2549 if (real_target_type == TypeManager.sbyte_type)
2550 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
2551 if (real_target_type == TypeManager.byte_type)
2552 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
2553 if (real_target_type == TypeManager.short_type)
2554 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
2555 if (real_target_type == TypeManager.ushort_type)
2556 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
2557 if (real_target_type == TypeManager.uint32_type)
2558 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
2559 if (real_target_type == TypeManager.uint64_type)
2560 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
2561 } else if (expr_type == TypeManager.uint32_type){
2563 // From uint to sbyte, byte, short, ushort, int, char
2565 if (real_target_type == TypeManager.sbyte_type)
2566 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
2567 if (real_target_type == TypeManager.byte_type)
2568 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
2569 if (real_target_type == TypeManager.short_type)
2570 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
2571 if (real_target_type == TypeManager.ushort_type)
2572 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
2573 if (real_target_type == TypeManager.int32_type)
2574 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
2575 } else if (expr_type == TypeManager.int64_type){
2577 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
2579 if (real_target_type == TypeManager.sbyte_type)
2580 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
2581 if (real_target_type == TypeManager.byte_type)
2582 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
2583 if (real_target_type == TypeManager.short_type)
2584 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
2585 if (real_target_type == TypeManager.ushort_type)
2586 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2587 if (real_target_type == TypeManager.int32_type)
2588 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2589 if (real_target_type == TypeManager.uint32_type)
2590 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2591 if (real_target_type == TypeManager.uint64_type)
2592 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
2593 } else if (expr_type == TypeManager.uint64_type){
2595 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
2597 if (real_target_type == TypeManager.sbyte_type)
2598 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
2599 if (real_target_type == TypeManager.byte_type)
2600 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
2601 if (real_target_type == TypeManager.short_type)
2602 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
2603 if (real_target_type == TypeManager.ushort_type)
2604 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
2605 if (real_target_type == TypeManager.int32_type)
2606 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2607 if (real_target_type == TypeManager.uint32_type)
2608 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
2609 if (real_target_type == TypeManager.int64_type)
2610 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
2611 } else if (expr_type == TypeManager.float_type){
2613 // From float to sbyte, byte, short,
2614 // ushort, int, uint, long, ulong, char
2617 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2618 if (real_target_type == TypeManager.sbyte_type)
2619 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
2620 if (real_target_type == TypeManager.byte_type)
2621 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
2622 if (real_target_type == TypeManager.short_type)
2623 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
2624 if (real_target_type == TypeManager.ushort_type)
2625 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2626 if (real_target_type == TypeManager.int32_type)
2627 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2628 if (real_target_type == TypeManager.uint32_type)
2629 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2630 if (real_target_type == TypeManager.int64_type)
2631 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2632 if (real_target_type == TypeManager.uint64_type)
2633 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2634 } else if (expr_type == TypeManager.double_type){
2636 // From double to byte, byte, short,
2637 // ushort, int, uint, long, ulong,
2638 // char, float or decimal
2640 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2641 if (real_target_type == TypeManager.sbyte_type)
2642 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
2643 if (real_target_type == TypeManager.byte_type)
2644 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
2645 if (real_target_type == TypeManager.short_type)
2646 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
2647 if (real_target_type == TypeManager.ushort_type)
2648 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
2649 if (real_target_type == TypeManager.int32_type)
2650 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2651 if (real_target_type == TypeManager.uint32_type)
2652 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2653 if (real_target_type == TypeManager.int64_type)
2654 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2655 if (real_target_type == TypeManager.uint64_type)
2656 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2657 if (real_target_type == TypeManager.float_type)
2658 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2661 // decimal is taken care of by the op_Explicit methods.
2667 /// Returns whether an explicit reference conversion can be performed
2668 /// from source_type to target_type
2670 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
2672 bool target_is_value_type = target_type.IsValueType;
2674 if (source_type == target_type)
2678 // From object to any reference type
2680 if (source_type == TypeManager.object_type && !target_is_value_type)
2684 // From any class S to any class-type T, provided S is a base class of T
2686 if (target_type.IsSubclassOf (source_type))
2690 // From any interface type S to any interface T provided S is not derived from T
2692 if (source_type.IsInterface && target_type.IsInterface){
2693 if (!target_type.IsSubclassOf (source_type))
2698 // From any class type S to any interface T, provided S is not sealed
2699 // and provided S does not implement T.
2701 if (target_type.IsInterface && !source_type.IsSealed &&
2702 !TypeManager.ImplementsInterface (source_type, target_type))
2706 // From any interface-type S to to any class type T, provided T is not
2707 // sealed, or provided T implements S.
2709 if (source_type.IsInterface &&
2710 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
2714 // From an array type S with an element type Se to an array type T with an
2715 // element type Te provided all the following are true:
2716 // * S and T differe only in element type, in other words, S and T
2717 // have the same number of dimensions.
2718 // * Both Se and Te are reference types
2719 // * An explicit referenc conversions exist from Se to Te
2721 if (source_type.IsArray && target_type.IsArray) {
2722 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2724 Type source_element_type = source_type.GetElementType ();
2725 Type target_element_type = target_type.GetElementType ();
2727 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2728 if (ExplicitReferenceConversionExists (source_element_type,
2729 target_element_type))
2735 // From System.Array to any array-type
2736 if (source_type == TypeManager.array_type &&
2737 target_type.IsArray){
2742 // From System delegate to any delegate-type
2744 if (source_type == TypeManager.delegate_type &&
2745 target_type.IsSubclassOf (TypeManager.delegate_type))
2749 // From ICloneable to Array or Delegate types
2751 if (source_type == TypeManager.icloneable_type &&
2752 (target_type == TypeManager.array_type ||
2753 target_type == TypeManager.delegate_type))
2760 /// Implements Explicit Reference conversions
2762 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
2764 Type source_type = source.Type;
2765 bool target_is_value_type = target_type.IsValueType;
2768 // From object to any reference type
2770 if (source_type == TypeManager.object_type && !target_is_value_type)
2771 return new ClassCast (source, target_type);
2775 // From any class S to any class-type T, provided S is a base class of T
2777 if (target_type.IsSubclassOf (source_type))
2778 return new ClassCast (source, target_type);
2781 // From any interface type S to any interface T provided S is not derived from T
2783 if (source_type.IsInterface && target_type.IsInterface){
2784 if (TypeManager.ImplementsInterface (source_type, target_type))
2787 return new ClassCast (source, target_type);
2791 // From any class type S to any interface T, provides S is not sealed
2792 // and provided S does not implement T.
2794 if (target_type.IsInterface && !source_type.IsSealed) {
2795 if (TypeManager.ImplementsInterface (source_type, target_type))
2798 return new ClassCast (source, target_type);
2803 // From any interface-type S to to any class type T, provided T is not
2804 // sealed, or provided T implements S.
2806 if (source_type.IsInterface) {
2807 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type))
2808 return new ClassCast (source, target_type);
2813 // From an array type S with an element type Se to an array type T with an
2814 // element type Te provided all the following are true:
2815 // * S and T differe only in element type, in other words, S and T
2816 // have the same number of dimensions.
2817 // * Both Se and Te are reference types
2818 // * An explicit referenc conversions exist from Se to Te
2820 if (source_type.IsArray && target_type.IsArray) {
2821 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2823 Type source_element_type = source_type.GetElementType ();
2824 Type target_element_type = target_type.GetElementType ();
2826 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2827 if (ExplicitReferenceConversionExists (source_element_type,
2828 target_element_type))
2829 return new ClassCast (source, target_type);
2834 // From System.Array to any array-type
2835 if (source_type == TypeManager.array_type &&
2836 target_type.IsArray) {
2837 return new ClassCast (source, target_type);
2841 // From System delegate to any delegate-type
2843 if (source_type == TypeManager.delegate_type &&
2844 target_type.IsSubclassOf (TypeManager.delegate_type))
2845 return new ClassCast (source, target_type);
2848 // From ICloneable to Array or Delegate types
2850 if (source_type == TypeManager.icloneable_type &&
2851 (target_type == TypeManager.array_type ||
2852 target_type == TypeManager.delegate_type))
2853 return new ClassCast (source, target_type);
2859 /// Performs an explicit conversion of the expression 'expr' whose
2860 /// type is expr.Type to 'target_type'.
2862 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
2863 Type target_type, bool runtimeconv, Location loc)
2865 Type expr_type = expr.Type;
2866 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
2871 ne = ConvertNumericExplicit (ec, expr, target_type, loc);
2876 // Unboxing conversion.
2878 if (expr_type == TypeManager.object_type && target_type.IsValueType)
2879 return new UnboxCast (expr, target_type);
2884 if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
2888 // FIXME: Is there any reason we should have EnumConstant
2889 // dealt with here instead of just using always the
2890 // UnderlyingSystemType to wrap the type?
2892 if (expr is EnumConstant)
2893 e = ((EnumConstant) expr).Child;
2895 e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
2898 Expression t = ConvertImplicit (ec, e, target_type, loc);
2902 t = ConvertNumericExplicit (ec, e, target_type, loc);
2906 t = NarrowingConversion (ec, e, target_type, loc);
2910 Error_CannotConvertType (loc, expr_type, target_type);
2914 ne = ConvertReferenceExplicit (expr, target_type);
2919 if (target_type.IsPointer){
2920 if (expr_type.IsPointer)
2921 return new EmptyCast (expr, target_type);
2923 if (expr_type == TypeManager.sbyte_type ||
2924 expr_type == TypeManager.byte_type ||
2925 expr_type == TypeManager.short_type ||
2926 expr_type == TypeManager.ushort_type ||
2927 expr_type == TypeManager.int32_type ||
2928 expr_type == TypeManager.uint32_type ||
2929 expr_type == TypeManager.uint64_type ||
2930 expr_type == TypeManager.int64_type)
2931 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
2933 if (expr_type.IsPointer){
2934 if (target_type == TypeManager.sbyte_type ||
2935 target_type == TypeManager.byte_type ||
2936 target_type == TypeManager.short_type ||
2937 target_type == TypeManager.ushort_type ||
2938 target_type == TypeManager.int32_type ||
2939 target_type == TypeManager.uint32_type ||
2940 target_type == TypeManager.uint64_type ||
2941 target_type == TypeManager.int64_type){
2942 Expression e = new EmptyCast (expr, TypeManager.uint32_type);
2945 ci = ConvertImplicitStandard (ec, e, target_type, loc);
2950 ce = ConvertNumericExplicit (ec, e, target_type, loc);
2954 // We should always be able to go from an uint32
2955 // implicitly or explicitly to the other integral
2958 throw new Exception ("Internal compiler error");
2963 ne = ExplicitUserConversion (ec, expr, target_type, loc);
2967 if (!(runtimeconv)) {
2968 ne = NarrowingConversion (ec, expr, target_type, loc);
2972 Error_CannotConvertType (loc, expr_type, target_type);
2978 /// Same as ConvertExplicit, only it doesn't include user defined conversions
2980 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
2981 Type target_type, Location l)
2983 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
2988 ne = ConvertNumericExplicit (ec, expr, target_type, l);
2992 ne = ConvertReferenceExplicit (expr, target_type);
2996 ne = NarrowingConversion (ec, expr, target_type, l);
3000 Error_CannotConvertType (l, expr.Type, target_type);
3004 static string ExprClassName (ExprClass c)
3007 case ExprClass.Invalid:
3009 case ExprClass.Value:
3011 case ExprClass.Variable:
3013 case ExprClass.Namespace:
3015 case ExprClass.Type:
3017 case ExprClass.MethodGroup:
3018 return "method group";
3019 case ExprClass.PropertyAccess:
3020 return "property access";
3021 case ExprClass.EventAccess:
3022 return "event access";
3023 case ExprClass.IndexerAccess:
3024 return "indexer access";
3025 case ExprClass.Nothing:
3028 throw new Exception ("Should not happen");
3032 /// Reports that we were expecting 'expr' to be of class 'expected'
3034 public void Error118 (string expected)
3036 string kind = "Unknown";
3038 kind = ExprClassName (eclass);
3040 Error (118, "Expression denotes a '" + kind +
3041 "' where a '" + expected + "' was expected");
3044 public void Error118 (ResolveFlags flags)
3046 ArrayList valid = new ArrayList (10);
3048 if ((flags & ResolveFlags.VariableOrValue) != 0) {
3049 valid.Add ("variable");
3050 valid.Add ("value");
3053 if ((flags & ResolveFlags.Type) != 0)
3056 if ((flags & ResolveFlags.MethodGroup) != 0)
3057 valid.Add ("method group");
3059 if ((flags & ResolveFlags.SimpleName) != 0)
3060 valid.Add ("simple name");
3062 if (valid.Count == 0)
3063 valid.Add ("unknown");
3065 StringBuilder sb = new StringBuilder ();
3066 for (int i = 0; i < valid.Count; i++) {
3069 else if (i == valid.Count)
3071 sb.Append (valid [i]);
3074 string kind = ExprClassName (eclass);
3076 Error (119, "Expression denotes a '" + kind + "' where " +
3077 "a '" + sb.ToString () + "' was expected");
3080 static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t)
3082 Report.Error (30439, l, "Constant value '" + val + "' not representable in type " +
3083 TypeManager.MonoBASIC_Name (t));
3086 public static void UnsafeError (Location loc)
3088 Report.Error (214, loc, "Pointers may only be used in an unsafe context");
3092 /// Converts the IntConstant, UIntConstant, LongConstant or
3093 /// ULongConstant,Double into the integral target_type. Notice
3094 /// that we do not return an 'Expression' we do return
3095 /// a boxed integral type.
3097 /// FIXME: Since I added the new constants, we need to
3098 /// also support conversions from CharConstant, ByteConstant,
3099 /// SByteConstant, UShortConstant, ShortConstant
3101 /// This is used by the switch statement, so the domain
3102 /// of work is restricted to the literals above, and the
3103 /// targets are int32, uint32, char, byte, sbyte, ushort,
3104 /// short, uint64 and int64
3106 public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
3110 if (c.Type == target_type)
3111 return ((Constant) c).GetValue ();
3114 // Make into one of the literals we handle, we dont really care
3115 // about this value as we will just return a few limited types
3117 if (c is EnumConstant)
3118 c = ((EnumConstant)c).WidenToCompilerConstant ();
3120 if (c is IntConstant){
3121 int v = ((IntConstant) c).Value;
3123 if (target_type == TypeManager.uint32_type){
3126 } else if (target_type == TypeManager.byte_type){
3127 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3129 } else if (target_type == TypeManager.sbyte_type){
3130 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3132 } else if (target_type == TypeManager.short_type){
3133 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3135 } else if (target_type == TypeManager.ushort_type){
3136 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3138 } else if (target_type == TypeManager.int64_type)
3140 else if (target_type == TypeManager.uint64_type){
3146 } else if (c is UIntConstant){
3147 uint v = ((UIntConstant) c).Value;
3149 if (target_type == TypeManager.int32_type){
3150 if (v <= Int32.MaxValue)
3152 } else if (target_type == TypeManager.byte_type){
3153 if (v <= Byte.MaxValue)
3155 } else if (target_type == TypeManager.sbyte_type){
3156 if (v <= SByte.MaxValue)
3158 } else if (target_type == TypeManager.short_type){
3159 if (v <= UInt16.MaxValue)
3161 } else if (target_type == TypeManager.ushort_type){
3162 if (v <= UInt16.MaxValue)
3164 } else if (target_type == TypeManager.int64_type)
3166 else if (target_type == TypeManager.uint64_type)
3169 } else if (c is LongConstant){
3170 long v = ((LongConstant) c).Value;
3172 if (target_type == TypeManager.int32_type){
3173 if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
3175 } else if (target_type == TypeManager.uint32_type){
3176 if (v >= 0 && v <= UInt32.MaxValue)
3178 } else if (target_type == TypeManager.byte_type){
3179 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3181 } else if (target_type == TypeManager.sbyte_type){
3182 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3184 } else if (target_type == TypeManager.short_type){
3185 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3187 } else if (target_type == TypeManager.ushort_type){
3188 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3190 } else if (target_type == TypeManager.uint64_type){
3195 } else if (c is ULongConstant){
3196 ulong v = ((ULongConstant) c).Value;
3198 if (target_type == TypeManager.int32_type){
3199 if (v <= Int32.MaxValue)
3201 } else if (target_type == TypeManager.uint32_type){
3202 if (v <= UInt32.MaxValue)
3204 } else if (target_type == TypeManager.byte_type){
3205 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3207 } else if (target_type == TypeManager.sbyte_type){
3208 if (v <= (int) SByte.MaxValue)
3210 } else if (target_type == TypeManager.short_type){
3211 if (v <= UInt16.MaxValue)
3213 } else if (target_type == TypeManager.ushort_type){
3214 if (v <= UInt16.MaxValue)
3216 } else if (target_type == TypeManager.int64_type){
3217 if (v <= Int64.MaxValue)
3221 } else if (c is ByteConstant){
3222 byte v = ((ByteConstant) c).Value;
3224 if (target_type == TypeManager.int32_type)
3226 else if (target_type == TypeManager.uint32_type)
3228 else if (target_type == TypeManager.sbyte_type){
3229 if (v <= SByte.MaxValue)
3231 } else if (target_type == TypeManager.short_type)
3233 else if (target_type == TypeManager.ushort_type)
3235 else if (target_type == TypeManager.int64_type)
3237 else if (target_type == TypeManager.uint64_type)
3240 } else if (c is SByteConstant){
3241 sbyte v = ((SByteConstant) c).Value;
3243 if (target_type == TypeManager.int32_type)
3245 else if (target_type == TypeManager.uint32_type){
3248 } else if (target_type == TypeManager.byte_type){
3251 } else if (target_type == TypeManager.short_type)
3253 else if (target_type == TypeManager.ushort_type){
3256 } else if (target_type == TypeManager.int64_type)
3258 else if (target_type == TypeManager.uint64_type){
3263 } else if (c is ShortConstant){
3264 short v = ((ShortConstant) c).Value;
3266 if (target_type == TypeManager.int32_type){
3268 } else if (target_type == TypeManager.uint32_type){
3271 } else if (target_type == TypeManager.byte_type){
3272 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3274 } else if (target_type == TypeManager.sbyte_type){
3275 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3277 } else if (target_type == TypeManager.ushort_type){
3280 } else if (target_type == TypeManager.int64_type)
3282 else if (target_type == TypeManager.uint64_type)
3286 } else if (c is UShortConstant){
3287 ushort v = ((UShortConstant) c).Value;
3289 if (target_type == TypeManager.int32_type)
3291 else if (target_type == TypeManager.uint32_type)
3293 else if (target_type == TypeManager.byte_type){
3294 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3296 } else if (target_type == TypeManager.sbyte_type){
3297 if (v <= SByte.MaxValue)
3299 } else if (target_type == TypeManager.short_type){
3300 if (v <= Int16.MaxValue)
3302 } else if (target_type == TypeManager.int64_type)
3304 else if (target_type == TypeManager.uint64_type)
3308 } else if (c is CharConstant){
3309 char v = ((CharConstant) c).Value;
3311 if (target_type == TypeManager.int32_type)
3313 else if (target_type == TypeManager.uint32_type)
3315 else if (target_type == TypeManager.byte_type){
3316 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3318 } else if (target_type == TypeManager.sbyte_type){
3319 if (v <= SByte.MaxValue)
3321 } else if (target_type == TypeManager.short_type){
3322 if (v <= Int16.MaxValue)
3324 } else if (target_type == TypeManager.ushort_type)
3326 else if (target_type == TypeManager.int64_type)
3328 else if (target_type == TypeManager.uint64_type)
3333 } else if (c is DoubleConstant){
3334 double v = ((DoubleConstant) c).Value;
3336 if (target_type == TypeManager.sbyte_type){
3337 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3338 return new SByteConstant ((sbyte) System.Math.Round (v));
3339 } else if (target_type == TypeManager.byte_type){
3340 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3341 return new ByteConstant ((byte) System.Math.Round (v));
3342 } else if (target_type == TypeManager.short_type){
3343 if (v >= Int16.MinValue && v <= Int16.MaxValue)
3344 return new ShortConstant ((short) System.Math.Round (v));
3345 } else if (target_type == TypeManager.ushort_type){
3346 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3347 return new UShortConstant ((ushort) System.Math.Round (v));
3348 } else if (target_type == TypeManager.int32_type){
3349 if (v >= Int32.MinValue && v <= Int32.MaxValue)
3350 return new IntConstant ((int) System.Math.Round (v));
3351 } else if (target_type == TypeManager.uint32_type){
3352 if (v >= 0 && v <= UInt32.MaxValue)
3353 return new UIntConstant ((uint) System.Math.Round (v));
3354 } else if (target_type == TypeManager.uint64_type){
3356 return new ULongConstant ((ulong) System.Math.Round (v));
3361 Error_ConstantValueCannotBeConverted (loc, s, target_type);
3366 // Load the object from the pointer.
3368 public static void LoadFromPtr (ILGenerator ig, Type t)
3370 if (t == TypeManager.int32_type)
3371 ig.Emit (OpCodes.Ldind_I4);
3372 else if (t == TypeManager.uint32_type)
3373 ig.Emit (OpCodes.Ldind_U4);
3374 else if (t == TypeManager.short_type)
3375 ig.Emit (OpCodes.Ldind_I2);
3376 else if (t == TypeManager.ushort_type)
3377 ig.Emit (OpCodes.Ldind_U2);
3378 else if (t == TypeManager.char_type)
3379 ig.Emit (OpCodes.Ldind_U2);
3380 else if (t == TypeManager.byte_type)
3381 ig.Emit (OpCodes.Ldind_U1);
3382 else if (t == TypeManager.sbyte_type)
3383 ig.Emit (OpCodes.Ldind_I1);
3384 else if (t == TypeManager.uint64_type)
3385 ig.Emit (OpCodes.Ldind_I8);
3386 else if (t == TypeManager.int64_type)
3387 ig.Emit (OpCodes.Ldind_I8);
3388 else if (t == TypeManager.float_type)
3389 ig.Emit (OpCodes.Ldind_R4);
3390 else if (t == TypeManager.double_type)
3391 ig.Emit (OpCodes.Ldind_R8);
3392 else if (t == TypeManager.bool_type)
3393 ig.Emit (OpCodes.Ldind_I1);
3394 else if (t == TypeManager.intptr_type)
3395 ig.Emit (OpCodes.Ldind_I);
3396 else if (TypeManager.IsEnumType (t)) {
3397 if (t == TypeManager.enum_type)
3398 ig.Emit (OpCodes.Ldind_Ref);
3400 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
3401 } else if (t.IsValueType)
3402 ig.Emit (OpCodes.Ldobj, t);
3404 ig.Emit (OpCodes.Ldind_Ref);
3408 // The stack contains the pointer and the value of type 'type'
3410 public static void StoreFromPtr (ILGenerator ig, Type type)
3412 if (TypeManager.IsEnumType (type))
3413 type = TypeManager.EnumToUnderlying (type);
3414 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
3415 ig.Emit (OpCodes.Stind_I4);
3416 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
3417 ig.Emit (OpCodes.Stind_I8);
3418 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
3419 type == TypeManager.ushort_type)
3420 ig.Emit (OpCodes.Stind_I2);
3421 else if (type == TypeManager.float_type)
3422 ig.Emit (OpCodes.Stind_R4);
3423 else if (type == TypeManager.double_type)
3424 ig.Emit (OpCodes.Stind_R8);
3425 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
3426 type == TypeManager.bool_type)
3427 ig.Emit (OpCodes.Stind_I1);
3428 else if (type == TypeManager.intptr_type)
3429 ig.Emit (OpCodes.Stind_I);
3430 else if (type.IsValueType)
3431 ig.Emit (OpCodes.Stobj, type);
3433 ig.Emit (OpCodes.Stind_Ref);
3437 // Returns the size of type 't' if known, otherwise, 0
3439 public static int GetTypeSize (Type t)
3441 t = TypeManager.TypeToCoreType (t);
3442 if (t == TypeManager.int32_type ||
3443 t == TypeManager.uint32_type ||
3444 t == TypeManager.float_type)
3446 else if (t == TypeManager.int64_type ||
3447 t == TypeManager.uint64_type ||
3448 t == TypeManager.double_type)
3450 else if (t == TypeManager.byte_type ||
3451 t == TypeManager.sbyte_type ||
3452 t == TypeManager.bool_type)
3454 else if (t == TypeManager.short_type ||
3455 t == TypeManager.char_type ||
3456 t == TypeManager.ushort_type)
3458 else if (t == TypeManager.decimal_type)
3465 // Default implementation of IAssignMethod.CacheTemporaries
3467 public void CacheTemporaries (EmitContext ec)
3471 static void Error_NegativeArrayIndex (Location loc)
3473 Report.Error (284, loc, "Can not create array with a negative size");
3477 // Converts 'source' to an int, uint, long or ulong.
3479 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
3483 bool old_checked = ec.CheckState;
3484 ec.CheckState = true;
3486 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
3487 if (target == null){
3488 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
3489 if (target == null){
3490 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
3491 if (target == null){
3492 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
3494 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
3498 ec.CheckState = old_checked;
3501 // Only positive constants are allowed at compile time
3503 if (target is Constant){
3504 if (target is IntConstant){
3505 if (((IntConstant) target).Value < 0){
3506 Error_NegativeArrayIndex (loc);
3511 if (target is LongConstant){
3512 if (((LongConstant) target).Value < 0){
3513 Error_NegativeArrayIndex (loc);
3526 /// This is just a base class for expressions that can
3527 /// appear on statements (invocations, object creation,
3528 /// assignments, post/pre increment and decrement). The idea
3529 /// being that they would support an extra Emition interface that
3530 /// does not leave a result on the stack.
3532 public abstract class ExpressionStatement : Expression {
3535 /// Requests the expression to be emitted in a 'statement'
3536 /// context. This means that no new value is left on the
3537 /// stack after invoking this method (constrasted with
3538 /// Emit that will always leave a value on the stack).
3540 public abstract void EmitStatement (EmitContext ec);
3544 /// This kind of cast is used to encapsulate the child
3545 /// whose type is child.Type into an expression that is
3546 /// reported to return "return_type". This is used to encapsulate
3547 /// expressions which have compatible types, but need to be dealt
3548 /// at higher levels with.
3550 /// For example, a "byte" expression could be encapsulated in one
3551 /// of these as an "unsigned int". The type for the expression
3552 /// would be "unsigned int".
3555 public class EmptyCast : Expression {
3556 protected Expression child;
3558 public EmptyCast (Expression child, Type return_type)
3560 eclass = child.eclass;
3565 public override Expression DoResolve (EmitContext ec)
3567 // This should never be invoked, we are born in fully
3568 // initialized state.
3573 public override void Emit (EmitContext ec)
3580 /// This class is used to wrap literals which belong inside Enums
3582 public class EnumConstant : Constant {
3583 public Constant Child;
3585 public EnumConstant (Constant child, Type enum_type)
3587 eclass = child.eclass;
3592 public override Expression DoResolve (EmitContext ec)
3594 // This should never be invoked, we are born in fully
3595 // initialized state.
3600 public override void Emit (EmitContext ec)
3605 public override object GetValue ()
3607 return Child.GetValue ();
3611 // Converts from one of the valid underlying types for an enumeration
3612 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
3613 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
3615 public Constant WidenToCompilerConstant ()
3617 Type t = TypeManager.EnumToUnderlying (Child.Type);
3618 object v = ((Constant) Child).GetValue ();;
3620 if (t == TypeManager.int32_type)
3621 return new IntConstant ((int) v);
3622 if (t == TypeManager.uint32_type)
3623 return new UIntConstant ((uint) v);
3624 if (t == TypeManager.int64_type)
3625 return new LongConstant ((long) v);
3626 if (t == TypeManager.uint64_type)
3627 return new ULongConstant ((ulong) v);
3628 if (t == TypeManager.short_type)
3629 return new ShortConstant ((short) v);
3630 if (t == TypeManager.ushort_type)
3631 return new UShortConstant ((ushort) v);
3632 if (t == TypeManager.byte_type)
3633 return new ByteConstant ((byte) v);
3634 if (t == TypeManager.sbyte_type)
3635 return new SByteConstant ((sbyte) v);
3637 throw new Exception ("Invalid enumeration underlying type: " + t);
3641 // Extracts the value in the enumeration on its native representation
3643 public object GetPlainValue ()
3645 Type t = TypeManager.EnumToUnderlying (Child.Type);
3646 object v = ((Constant) Child).GetValue ();;
3648 if (t == TypeManager.int32_type)
3650 if (t == TypeManager.uint32_type)
3652 if (t == TypeManager.int64_type)
3654 if (t == TypeManager.uint64_type)
3656 if (t == TypeManager.short_type)
3658 if (t == TypeManager.ushort_type)
3660 if (t == TypeManager.byte_type)
3662 if (t == TypeManager.sbyte_type)
3668 public override string AsString ()
3670 return Child.AsString ();
3673 public override DoubleConstant ConvertToDouble ()
3675 return Child.ConvertToDouble ();
3678 public override FloatConstant ConvertToFloat ()
3680 return Child.ConvertToFloat ();
3683 public override ULongConstant ConvertToULong ()
3685 return Child.ConvertToULong ();
3688 public override LongConstant ConvertToLong ()
3690 return Child.ConvertToLong ();
3693 public override UIntConstant ConvertToUInt ()
3695 return Child.ConvertToUInt ();
3698 public override IntConstant ConvertToInt ()
3700 return Child.ConvertToInt ();
3705 /// This kind of cast is used to encapsulate Value Types in objects.
3707 /// The effect of it is to box the value type emitted by the previous
3710 public class BoxedCast : EmptyCast {
3712 public BoxedCast (Expression expr)
3713 : base (expr, TypeManager.object_type)
3717 public override Expression DoResolve (EmitContext ec)
3719 // This should never be invoked, we are born in fully
3720 // initialized state.
3725 public override void Emit (EmitContext ec)
3729 ec.ig.Emit (OpCodes.Box, child.Type);
3733 public class UnboxCast : EmptyCast {
3734 public UnboxCast (Expression expr, Type return_type)
3735 : base (expr, return_type)
3739 public override Expression DoResolve (EmitContext ec)
3741 // This should never be invoked, we are born in fully
3742 // initialized state.
3747 public override void Emit (EmitContext ec)
3750 ILGenerator ig = ec.ig;
3754 ig.Emit (OpCodes.Dup);
3755 Label unbox = ig.DefineLabel ();
3756 ig.Emit (OpCodes.Brtrue, unbox);
3757 ig.Emit (OpCodes.Pop);
3758 ig.Emit (OpCodes.Ldtoken, t);
3759 ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
3760 MethodInfo createInst = Type.GetType("System.Activator").GetMethod ("CreateInstance", new Type[]{Type.GetType("System.Type")} );
3761 ig.Emit (OpCodes.Call, createInst );
3763 ig.MarkLabel (unbox);
3764 ig.Emit (OpCodes.Unbox, t);
3766 LoadFromPtr (ig, t);
3771 /// This is used to perform explicit numeric conversions.
3773 /// Explicit numeric conversions might trigger exceptions in a checked
3774 /// context, so they should generate the conv.ovf opcodes instead of
3777 public class ConvCast : EmptyCast {
3778 public enum Mode : byte {
3779 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
3781 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
3782 U2_I1, U2_U1, U2_I2, U2_CH,
3783 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
3784 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
3785 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
3786 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
3787 CH_I1, CH_U1, CH_I2,
3788 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
3789 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
3795 public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
3796 : base (child, return_type)
3798 checked_state = ec.CheckState;
3802 public override Expression DoResolve (EmitContext ec)
3804 // This should never be invoked, we are born in fully
3805 // initialized state.
3810 public override void Emit (EmitContext ec)
3812 ILGenerator ig = ec.ig;
3818 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3819 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3820 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3821 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3822 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3824 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3825 case Mode.U1_CH: /* nothing */ break;
3827 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3828 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3829 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3830 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3831 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3832 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3834 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3835 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3836 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3837 case Mode.U2_CH: /* nothing */ break;
3839 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3840 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3841 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3842 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3843 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3844 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3845 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3847 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3848 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3849 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3850 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3851 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3852 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3854 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3855 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3856 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3857 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3858 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3859 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3860 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3861 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3863 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3864 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3865 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3866 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3867 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3868 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
3869 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
3870 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3872 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3873 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3874 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3876 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3877 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3878 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3879 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3880 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3881 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3882 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3883 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3884 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3886 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3887 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3888 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3889 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3890 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3891 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3892 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3893 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3894 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3895 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3899 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
3900 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
3901 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
3902 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
3903 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
3905 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
3906 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
3908 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
3909 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
3910 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
3911 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
3912 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
3913 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
3915 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
3916 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
3917 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
3918 case Mode.U2_CH: /* nothing */ break;
3920 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
3921 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
3922 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
3923 case Mode.I4_U4: /* nothing */ break;
3924 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
3925 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
3926 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
3928 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
3929 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
3930 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
3931 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
3932 case Mode.U4_I4: /* nothing */ break;
3933 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
3935 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
3936 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
3937 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
3938 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
3939 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
3940 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
3941 case Mode.I8_U8: /* nothing */ break;
3942 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
3944 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
3945 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
3946 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
3947 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
3948 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
3949 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
3950 case Mode.U8_I8: /* nothing */ break;
3951 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
3953 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
3954 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
3955 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
3957 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
3958 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
3959 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
3960 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
3961 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
3962 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
3963 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
3964 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
3965 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
3967 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
3968 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
3969 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
3970 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
3971 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
3972 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
3973 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
3974 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
3975 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
3976 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3982 public class OpcodeCast : EmptyCast {
3986 public OpcodeCast (Expression child, Type return_type, OpCode op)
3987 : base (child, return_type)
3991 second_valid = false;
3994 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
3995 : base (child, return_type)
4000 second_valid = true;
4003 public override Expression DoResolve (EmitContext ec)
4005 // This should never be invoked, we are born in fully
4006 // initialized state.
4011 public override void Emit (EmitContext ec)
4022 public class NumericToBoolCast : EmptyCast
4026 public NumericToBoolCast (Expression src, Type src_type)
4027 : base (src, TypeManager.bool_type)
4030 this.src_type = src_type;
4033 public override Expression DoResolve (EmitContext ec)
4038 public override void Emit (EmitContext ec)
4042 if (src_type == TypeManager.byte_type ||
4043 src_type == TypeManager.short_type ||
4044 src_type == TypeManager.int32_type) {
4046 ec.ig.Emit (OpCodes.Ldc_I4_0);
4047 ec.ig.Emit (OpCodes.Cgt_Un);
4051 if (src_type == TypeManager.int64_type) {
4052 ec.ig.Emit (OpCodes.Ldc_I8, (long) 0);
4053 ec.ig.Emit (OpCodes.Cgt_Un);
4057 if (src_type == TypeManager.float_type) {
4058 ec.ig.Emit (OpCodes.Ldc_R4, (float) 0);
4059 ec.ig.Emit (OpCodes.Ceq);
4060 ec.ig.Emit (OpCodes.Ldc_I4_0);
4061 ec.ig.Emit (OpCodes.Ceq);
4065 if (src_type == TypeManager.double_type) {
4066 ec.ig.Emit (OpCodes.Ldc_R8, (double) 0);
4067 ec.ig.Emit (OpCodes.Ceq);
4068 ec.ig.Emit (OpCodes.Ldc_I4_0);
4069 ec.ig.Emit (OpCodes.Ceq);
4075 public class BoolToNumericCast : EmptyCast
4080 public BoolToNumericCast (Expression src, Type target_type)
4081 : base (src, target_type)
4084 this.target_type = target_type;
4087 public override Expression DoResolve (EmitContext ec)
4092 public override void Emit (EmitContext ec)
4096 if (target_type == TypeManager.byte_type) {
4097 conv = OpCodes.Conv_U1;
4098 } else if (target_type == TypeManager.short_type) {
4099 conv = OpCodes.Conv_I2;
4100 } else if (target_type == TypeManager.int32_type) {
4101 conv = OpCodes.Conv_I4;
4102 } else if (target_type == TypeManager.int64_type) {
4103 conv = OpCodes.Conv_I8;
4104 } else if (target_type == TypeManager.float_type) {
4105 conv = OpCodes.Conv_R4;
4106 } else if (target_type == TypeManager.double_type) {
4107 conv = OpCodes.Conv_R8;
4110 ec.ig.Emit (OpCodes.Ldc_I4_0);
4111 ec.ig.Emit (OpCodes.Cgt_Un);
4112 ec.ig.Emit (OpCodes.Neg);
4119 /// This kind of cast is used to encapsulate a child and cast it
4120 /// to the class requested
4122 public class ClassCast : EmptyCast {
4123 public ClassCast (Expression child, Type return_type)
4124 : base (child, return_type)
4129 public override Expression DoResolve (EmitContext ec)
4131 // This should never be invoked, we are born in fully
4132 // initialized state.
4137 public override void Emit (EmitContext ec)
4141 ec.ig.Emit (OpCodes.Castclass, type);
4147 /// SimpleName expressions are initially formed of a single
4148 /// word and it only happens at the beginning of the expression.
4152 /// The expression will try to be bound to a Field, a Method
4153 /// group or a Property. If those fail we pass the name to our
4154 /// caller and the SimpleName is compounded to perform a type
4155 /// lookup. The idea behind this process is that we want to avoid
4156 /// creating a namespace map from the assemblies, as that requires
4157 /// the GetExportedTypes function to be called and a hashtable to
4158 /// be constructed which reduces startup time. If later we find
4159 /// that this is slower, we should create a 'NamespaceExpr' expression
4160 /// that fully participates in the resolution process.
4162 /// For example 'System.Console.WriteLine' is decomposed into
4163 /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
4165 /// The first SimpleName wont produce a match on its own, so it will
4167 /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
4169 /// System.Console will produce a TypeExpr match.
4171 /// The downside of this is that we might be hitting 'LookupType' too many
4172 /// times with this scheme.
4174 public class SimpleName : Expression, ITypeExpression {
4175 public readonly string Name;
4176 bool is_invocation = false;
4177 bool is_addressof = false;
4179 public bool IsInvocation {
4181 is_invocation = value;
4185 public bool IsAddressOf {
4187 is_addressof = value;
4191 public SimpleName (string name, Location l)
4197 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
4199 if (ec.IsFieldInitializer)
4202 "A field initializer cannot reference the non-static field, " +
4203 "method or property '"+name+"'");
4207 "An object reference is required " +
4208 "for the non-static field '"+name+"'");
4212 // Checks whether we are trying to access an instance
4213 // property, method or field from a static body.
4215 Expression MemberStaticCheck (EmitContext ec, Expression e)
4217 if (e is IMemberExpr){
4218 IMemberExpr member = (IMemberExpr) e;
4220 if (!member.IsStatic){
4221 Error_ObjectRefRequired (ec, loc, Name);
4229 public override Expression DoResolve (EmitContext ec)
4231 return SimpleNameResolve (ec, null, false);
4234 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4236 return SimpleNameResolve (ec, right_side, false);
4240 public Expression DoResolveAllowStatic (EmitContext ec)
4242 return SimpleNameResolve (ec, null, true);
4245 public Expression DoResolveType (EmitContext ec)
4248 // Stage 3: Lookup symbol in the various namespaces.
4250 DeclSpace ds = ec.DeclSpace;
4254 if (ec.ResolvingTypeTree){
4255 int errors = Report.Errors;
4256 Type dt = ec.DeclSpace.FindType (loc, Name);
4257 if (Report.Errors != errors)
4261 return new TypeExpr (dt, loc);
4264 if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
4265 return new TypeExpr (t, loc);
4269 // Stage 2 part b: Lookup up if we are an alias to a type
4272 // Since we are cheating: we only do the Alias lookup for
4273 // namespaces if the name does not include any dots in it
4276 alias_value = ec.DeclSpace.LookupAlias (Name);
4278 if (Name.IndexOf ('.') == -1 && alias_value != null) {
4279 if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
4280 return new TypeExpr (t, loc);
4282 // we have alias value, but it isn't Type, so try if it's namespace
4283 return new SimpleName (alias_value, loc);
4286 // No match, maybe our parent can compose us
4287 // into something meaningful.
4292 /// 7.5.2: Simple Names.
4294 /// Local Variables and Parameters are handled at
4295 /// parse time, so they never occur as SimpleNames.
4297 /// The 'allow_static' flag is used by MemberAccess only
4298 /// and it is used to inform us that it is ok for us to
4299 /// avoid the static check, because MemberAccess might end
4300 /// up resolving the Name as a Type name and the access as
4301 /// a static type access.
4303 /// ie: Type Type; .... { Type.GetType (""); }
4305 /// Type is both an instance variable and a Type; Type.GetType
4306 /// is the static method not an instance method of type.
4308 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
4310 Expression e = null;
4313 // Stage 1: Performed by the parser (binding to locals or parameters).
4315 Block current_block = ec.CurrentBlock;
4316 if (ec.InvokingOwnOverload == false && current_block != null && current_block.IsVariableDefined (Name)){
4317 LocalVariableReference var;
4319 var = new LocalVariableReference (current_block, Name, loc);
4321 if (right_side != null)
4322 return var.ResolveLValue (ec, right_side);
4324 return var.Resolve (ec);
4327 if (current_block != null){
4329 Parameter par = null;
4330 Parameters pars = current_block.Parameters;
4332 par = pars.GetParameterByName (Name, out idx);
4335 ParameterReference param;
4337 param = new ParameterReference (pars, idx, Name, loc);
4339 if (right_side != null)
4340 return param.ResolveLValue (ec, right_side);
4342 return param.Resolve (ec);
4347 // Stage 2: Lookup members
4351 // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
4352 // Hence we have two different cases
4355 DeclSpace lookup_ds = ec.DeclSpace;
4357 if (lookup_ds.TypeBuilder == null)
4360 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
4365 // Classes/structs keep looking, enums break
4367 if (lookup_ds is TypeContainer)
4368 lookup_ds = ((TypeContainer) lookup_ds).Parent;
4371 } while (lookup_ds != null);
4373 if (e == null && ec.ContainerType != null)
4374 e = MemberLookup (ec, ec.ContainerType, Name, loc);
4376 // #52067 - Start - Trying to solve
4379 ArrayList lookups = new ArrayList();
4380 ArrayList typelookups = new ArrayList();
4382 int split = Name.LastIndexOf('.');
4384 String nameSpacePart = Name.Substring(0, split);
4385 String memberNamePart = Name.Substring(split + 1);
4386 foreach(Type type in TypeManager.GetPertinentStandardModules(nameSpacePart)) {
4387 e = MemberLookup(ec, type, memberNamePart, loc);
4390 typelookups.Add(type);
4395 string[] NamespacesInScope = RootContext.SourceBeingCompiled.GetNamespacesInScope(ec.DeclSpace.Namespace.Name);
4396 foreach(Type type in TypeManager.GetPertinentStandardModules(NamespacesInScope)) {
4397 e = MemberLookup(ec, type, Name, loc);
4400 typelookups.Add(type);
4403 if (lookups.Count == 1) {
4404 e = (Expression)lookups[0];
4406 if (lookups.Count > 1) {
4407 StringBuilder sb = new StringBuilder();
4408 foreach(Type type in typelookups)
4409 sb.Append("'" + type.FullName + "'");
4410 Error (-1, "The name '" + Name + "' can be resolved to a member of more than one standard module: " + sb.ToString() + ". Please fully qualify it.");
4420 /* preparing to support automatic definition of variables on first usage with Option Explicit Off
4422 Isn't good enough to enable just now (tries to define some internal links and breaks on emit)
4424 if (Name.IndexOf ('.') == -1 && current_block != null && !Mono.MonoBASIC.Parser.OptionExplicit) {
4426 // while looking for a real solution
4427 if (Name != "anything")
4428 return DoResolveType (ec);
4430 Console.WriteLine("Implicitly adding a variable named '{0}'", Name);
4432 // TODO: look at type-suffixes to correct name and type
4433 Expression type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", loc);
4435 current_block.AddVariable(ec, type, Name, loc);
4437 LocalVariableReference var = new LocalVariableReference (current_block, Name, loc);
4438 if (right_side != null)
4439 return var.ResolveLValue (ec, right_side);
4441 return var.Resolve (ec);
4444 return DoResolveType (ec);
4450 if (e is IMemberExpr) {
4451 if ((e is MethodGroupExpr) && !is_invocation && !is_addressof) {
4452 Expression inv = new Invocation (this, new ArrayList (), loc);
4453 return inv.Resolve (ec);
4455 e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
4459 if (e is PropertyGroupExpr && is_invocation) // We dont know the arguments yet
4462 IMemberExpr me = e as IMemberExpr;
4466 // This fails if ResolveMemberAccess() was unable to decide whether
4467 // it's a field or a type of the same name.
4468 if (!me.IsStatic && (me.InstanceExpression == null))
4471 /* FIXME If this is not commented out, it seems that it's not possible to reach class members in mBas.
4472 Maybe a grammar-related problem?
4475 TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
4476 Error (38, "Cannot access nonstatic member '" + me.Name + "' of " +
4477 "outer type '" + me.DeclaringType + "' via nested type '" +
4478 me.InstanceExpression.Type + "'");
4482 bool isPropertyGroup = (e is PropertyGroupExpr);
4483 if (right_side != null)
4484 e = e.DoResolveLValue (ec, right_side);
4486 e = e.DoResolve (ec);
4488 if (e == null && isPropertyGroup && !is_invocation)
4489 Error (30057, "Property '" + Name + "' cannot be invoked with given arguments");
4494 if (ec.IsStatic || ec.IsFieldInitializer) {
4498 return MemberStaticCheck (ec, e);
4504 public override void Emit (EmitContext ec)
4507 // If this is ever reached, then we failed to
4508 // find the name as a namespace
4511 Error (30451, "The name '" + Name +
4512 "' does not exist in the class '" +
4513 ec.DeclSpace.Name + "'");
4516 public override string ToString ()
4522 public class DecoratedIdentifier : Expression {
4526 public Expression Id
4534 public DecoratedIdentifier (Expression id, Type decoration)
4537 this.decoration = decoration;
4540 override public Expression DoResolve (EmitContext ec)
4542 if (id == null || decoration == null)
4545 Expression ret = id.DoResolve (ec);
4546 if (ret.Type != TypeManager.TypeToCoreType (decoration)) {
4547 Report.Error (30277, id.Location, "Type character '" + decoration + "' does not match declared type '" + ret.Type + "'.");
4554 override public void Emit (EmitContext ec)
4556 throw new InternalErrorException ("Should never be called");
4561 /// Fully resolved expression that evaluates to a type
4563 public class TypeExpr : Expression, ITypeExpression {
4564 public TypeExpr (Type t, Location l)
4567 eclass = ExprClass.Type;
4571 public virtual Expression DoResolveType (EmitContext ec)
4576 override public Expression DoResolve (EmitContext ec)
4581 override public void Emit (EmitContext ec)
4583 throw new Exception ("Should never be called");
4586 public override string ToString ()
4588 return Type.ToString ();
4593 /// Used to create types from a fully qualified name. These are just used
4594 /// by the parser to setup the core types. A TypeLookupExpression is always
4595 /// classified as a type.
4597 public class TypeLookupExpression : TypeExpr {
4600 public TypeLookupExpression (string name) : base (null, Location.Null)
4605 public override Expression DoResolveType (EmitContext ec)
4608 type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
4612 public override Expression DoResolve (EmitContext ec)
4614 return DoResolveType (ec);
4617 public override void Emit (EmitContext ec)
4619 throw new Exception ("Should never be called");
4622 public override string ToString ()
4629 /// MethodGroup Expression.
4631 /// This is a fully resolved expression that evaluates to a type
4633 public class MethodGroupExpr : Expression, IMemberExpr {
4634 public MethodBase [] Methods;
4635 Expression instance_expression = null;
4636 bool is_explicit_impl = false;
4638 public MethodGroupExpr (MemberInfo [] mi, Location l)
4640 Methods = new MethodBase [mi.Length];
4641 mi.CopyTo (Methods, 0);
4642 eclass = ExprClass.MethodGroup;
4643 type = TypeManager.object_type;
4647 public MethodGroupExpr (ArrayList list, Location l)
4649 Methods = new MethodBase [list.Count];
4652 list.CopyTo (Methods, 0);
4654 foreach (MemberInfo m in list){
4655 if (!(m is MethodBase)){
4656 Console.WriteLine ("Name " + m.Name);
4657 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4663 eclass = ExprClass.MethodGroup;
4664 type = TypeManager.object_type;
4667 public Type DeclaringType {
4669 return Methods [0].DeclaringType;
4674 // 'A method group may have associated an instance expression'
4676 public Expression InstanceExpression {
4678 return instance_expression;
4682 instance_expression = value;
4686 public bool IsExplicitImpl {
4688 return is_explicit_impl;
4692 is_explicit_impl = value;
4696 public string Name {
4698 return Methods [0].Name;
4702 public bool IsInstance {
4704 foreach (MethodBase mb in Methods)
4712 public bool IsStatic {
4714 foreach (MethodBase mb in Methods)
4722 override public Expression DoResolve (EmitContext ec)
4724 if (instance_expression != null) {
4725 instance_expression = instance_expression.DoResolve (ec);
4726 if (instance_expression == null)
4733 public void ReportUsageError ()
4735 Report.Error (654, loc, "Method '" + Methods [0].DeclaringType + "." +
4736 Methods [0].Name + "()' is referenced without parentheses");
4739 override public void Emit (EmitContext ec)
4741 ReportUsageError ();
4744 bool RemoveMethods (bool keep_static)
4746 ArrayList smethods = new ArrayList ();
4748 foreach (MethodBase mb in Methods){
4749 if (mb.IsStatic == keep_static)
4753 if (smethods.Count == 0)
4756 Methods = new MethodBase [smethods.Count];
4757 smethods.CopyTo (Methods, 0);
4763 /// Removes any instance methods from the MethodGroup, returns
4764 /// false if the resulting set is empty.
4766 public bool RemoveInstanceMethods ()
4768 return RemoveMethods (true);
4772 /// Removes any static methods from the MethodGroup, returns
4773 /// false if the resulting set is empty.
4775 public bool RemoveStaticMethods ()
4777 return RemoveMethods (false);
4782 /// Property Group Expression.
4785 public class PropertyGroupExpr : ExpressionStatement, IMemberExpr {
4786 public PropertyInfo [] Properties;
4787 Expression instance_expression = null;
4788 bool is_explicit_impl = false;
4789 MethodBase method = null;
4790 bool indexer_access_req = false;
4791 ArrayList arguments = null;
4793 public PropertyGroupExpr (MemberInfo [] mi, Location l)
4795 Properties = new PropertyInfo [mi.Length];
4796 mi.CopyTo (Properties, 0);
4797 eclass = ExprClass.PropertyAccess;
4798 type = TypeManager.object_type;
4802 public PropertyGroupExpr (MemberInfo [] mi, ArrayList args, Expression expr, Location l)
4806 instance_expression = expr;
4809 public PropertyGroupExpr (ArrayList list, Location l)
4811 Properties = new PropertyInfo [list.Count];
4814 list.CopyTo (Properties, 0);
4816 foreach (MemberInfo m in list){
4817 if (!(m is PropertyInfo)){
4818 Console.WriteLine ("Name " + m.Name);
4819 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4825 eclass = ExprClass.PropertyAccess;
4826 type = TypeManager.object_type;
4829 public ArrayList Arguments {
4838 public Type DeclaringType {
4840 return Properties [0].DeclaringType;
4844 public bool IndexerAccessRequired {
4846 return indexer_access_req;
4851 // 'A method group may have associated an instance expression'
4853 public Expression InstanceExpression {
4855 return instance_expression;
4859 instance_expression = value;
4863 public bool IsExplicitImpl {
4865 return is_explicit_impl;
4869 is_explicit_impl = value;
4873 public string Name {
4875 return Properties [0].Name;
4879 public bool IsInstance {
4881 foreach (PropertyInfo pi in Properties) {
4882 MethodInfo mi = pi.GetGetMethod ();
4883 if (mi != null && !mi.IsStatic)
4885 mi = pi.GetSetMethod ();
4886 if (mi != null && !mi.IsStatic)
4893 public bool IsStatic {
4895 return (!IsInstance);
4899 public ArrayList GetAccessors () {
4900 ArrayList GetAccessors = new ArrayList ();
4901 foreach (PropertyInfo pi in Properties) {
4902 if (pi.GetGetMethod () != null)
4903 GetAccessors.Add (pi.GetGetMethod ());
4905 else if (pi.GetGetMethod (true) != null)
4906 GetAccessors.Add (pi.GetGetMethod (true));
4910 return GetAccessors;
4913 public ArrayList SetAccessors () {
4914 ArrayList SetAccessors = new ArrayList ();
4915 foreach (PropertyInfo pi in Properties) {
4916 if (pi.GetSetMethod () != null)
4917 SetAccessors.Add (pi.GetSetMethod ());
4919 else if (pi.GetSetMethod (true) != null)
4920 SetAccessors.Add (pi.GetSetMethod (true));
4923 return SetAccessors;
4926 override public Expression DoResolve (EmitContext ec)
4928 if (instance_expression != null) {
4929 instance_expression = instance_expression.DoResolve (ec);
4930 if (instance_expression == null)
4934 ArrayList members = GetAccessors ();
4935 if (members == null || members.Count == 0) {
4936 Report.Error (30524, loc, "Property '" + Name + "' lacks a 'get' accesor");
4940 MethodGroupExpr m_expr = new MethodGroupExpr (members, loc);
4941 method = Invocation.OverloadResolve (ec, m_expr, ref arguments, loc);
4942 if ((method as MethodInfo) != null) {
4943 MethodInfo mi = method as MethodInfo;
4944 type = TypeManager.TypeToCoreType (mi.ReturnType);
4945 indexer_access_req = false;
4946 eclass = ExprClass.Value;
4949 // find a get method that doesnt take any arguments. Check the return type of
4950 // that method to find out if indexer access is required. Leave the rest to
4951 // 'Invocation's Resolve'
4952 method = Invocation.OverloadResolve (ec, m_expr, null, loc);
4953 if (method != null) {
4954 MethodInfo mi = method as MethodInfo;
4955 Type ret_type = mi.ReturnType;
4956 if (ret_type.IsArray)
4957 indexer_access_req = true;
4959 Indexers list = Indexers.GetIndexersForType (ec.ContainerType, ret_type, loc);
4960 if (list != null && list.getters.Count > 0)
4961 indexer_access_req = true;
4966 type = mi.ReturnType;
4974 override public Expression DoResolveLValue (EmitContext ec, Expression right_side) {
4975 if (instance_expression != null) {
4976 instance_expression = instance_expression.DoResolve (ec);
4977 if (instance_expression == null)
4981 ArrayList members = SetAccessors ();
4982 if (members == null || members.Count == 0) {
4983 Report.Error (30524, loc, "Property '" + Name + "' lacks a 'set' accesor");
4987 MethodGroupExpr m_expr = new MethodGroupExpr (members, loc);
4988 if (arguments == null)
4989 arguments = new ArrayList ();
4990 arguments.Add (new Argument (right_side, Argument.AType.Expression));
4991 method = Invocation.OverloadResolve (ec, m_expr, ref arguments, loc);
4992 if (method != null) {
4993 //MethodInfo mi = method as MethodInfo;
4994 type = TypeManager.void_type; //TypeManager.TypeToCoreType (mi.ReturnType);
4995 eclass = ExprClass.Value;
4996 indexer_access_req = false;
4999 // Look for properties that do not take any arguments.
5000 // Check if the return type has any indexers
5003 if (method != null) {
5004 MethodInfo mi = method as MethodInfo;
5005 Type ret_type = mi.ReturnType;
5006 if (ret_type.IsArray)
5007 indexer_access_req = true;
5010 Indexers list = Indexers.GetIndexersForType (ec.ContainerType,
5012 if (list != null && list.setters.Count > 0)
5013 indexer_access_req = true;
5017 type = mi.ReturnType;
5025 override public void Emit (EmitContext ec)
5027 if (Arguments == null)
5028 Arguments = new ArrayList ();
5029 Invocation.EmitCall (ec, false, IsStatic, instance_expression, method, null, Arguments, loc);
5032 override public void EmitStatement (EmitContext ec)
5040 /// Fully resolved expression that evaluates to a Field
5042 public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr {
5043 public readonly FieldInfo FieldInfo;
5044 Expression instance_expr;
5046 public FieldExpr (FieldInfo fi, Location l)
5049 eclass = ExprClass.Variable;
5050 type = fi.FieldType;
5054 public string Name {
5056 return FieldInfo.Name;
5060 public bool IsInstance {
5062 return !FieldInfo.IsStatic;
5066 public bool IsStatic {
5068 return FieldInfo.IsStatic;
5072 public Type DeclaringType {
5074 return FieldInfo.DeclaringType;
5078 public Expression InstanceExpression {
5080 return instance_expr;
5084 instance_expr = value;
5088 override public Expression DoResolve (EmitContext ec)
5090 if (!FieldInfo.IsStatic){
5091 if (instance_expr == null){
5092 throw new Exception ("non-static FieldExpr without instance var\n" +
5093 "You have to assign the Instance variable\n" +
5094 "Of the FieldExpr to set this\n");
5097 // Resolve the field's instance expression while flow analysis is turned
5098 // off: when accessing a field "a.b", we must check whether the field
5099 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5100 instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
5101 ResolveFlags.DisableFlowAnalysis);
5102 if (instance_expr == null)
5106 // If the instance expression is a local variable or parameter.
5107 IVariable var = instance_expr as IVariable;
5108 if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc))
5114 void Report_AssignToReadonly (bool is_instance)
5119 msg = "Readonly field can not be assigned outside " +
5120 "of constructor or variable initializer";
5122 msg = "A static readonly field can only be assigned in " +
5123 "a static constructor";
5125 Report.Error (is_instance ? 191 : 198, loc, msg);
5128 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5130 IVariable var = instance_expr as IVariable;
5132 var.SetFieldAssigned (ec, FieldInfo.Name);
5134 Expression e = DoResolve (ec);
5139 if (!FieldInfo.IsInitOnly)
5143 // InitOnly fields can only be assigned in constructors
5146 if (ec.IsConstructor)
5149 Report_AssignToReadonly (true);
5154 override public void Emit (EmitContext ec)
5156 ILGenerator ig = ec.ig;
5157 bool is_volatile = false;
5159 if (FieldInfo is FieldBuilder){
5160 FieldBase f = TypeManager.GetField (FieldInfo);
5162 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5165 f.status |= Field.Status.USED;
5168 if (FieldInfo.IsStatic){
5170 ig.Emit (OpCodes.Volatile);
5172 ig.Emit (OpCodes.Ldsfld, FieldInfo);
5174 if (instance_expr.Type.IsValueType){
5176 LocalTemporary tempo = null;
5178 if (!(instance_expr is IMemoryLocation)){
5179 tempo = new LocalTemporary (
5180 ec, instance_expr.Type);
5182 InstanceExpression.Emit (ec);
5186 ml = (IMemoryLocation) instance_expr;
5188 ml.AddressOf (ec, AddressOp.Load);
5190 instance_expr.Emit (ec);
5193 ig.Emit (OpCodes.Volatile);
5195 ig.Emit (OpCodes.Ldfld, FieldInfo);
5199 public void EmitAssign (EmitContext ec, Expression source)
5201 FieldAttributes fa = FieldInfo.Attributes;
5202 bool is_static = (fa & FieldAttributes.Static) != 0;
5203 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5204 ILGenerator ig = ec.ig;
5206 if (is_readonly && !ec.IsConstructor){
5207 Report_AssignToReadonly (!is_static);
5212 Expression instance = instance_expr;
5214 if (instance.Type.IsValueType){
5215 if (instance is IMemoryLocation){
5216 IMemoryLocation ml = (IMemoryLocation) instance;
5218 ml.AddressOf (ec, AddressOp.Store);
5220 throw new Exception ("The " + instance + " of type " +
5222 " represents a ValueType and does " +
5223 "not implement IMemoryLocation");
5229 if (FieldInfo is FieldBuilder){
5230 FieldBase f = TypeManager.GetField (FieldInfo);
5232 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5233 ig.Emit (OpCodes.Volatile);
5237 ig.Emit (OpCodes.Stsfld, FieldInfo);
5239 ig.Emit (OpCodes.Stfld, FieldInfo);
5241 if (FieldInfo is FieldBuilder){
5242 FieldBase f = TypeManager.GetField (FieldInfo);
5244 f.status |= Field.Status.ASSIGNED;
5248 public void AddressOf (EmitContext ec, AddressOp mode)
5250 ILGenerator ig = ec.ig;
5252 if (FieldInfo is FieldBuilder){
5253 FieldBase f = TypeManager.GetField (FieldInfo);
5254 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5255 ig.Emit (OpCodes.Volatile);
5258 if (FieldInfo is FieldBuilder){
5259 FieldBase f = TypeManager.GetField (FieldInfo);
5261 if ((mode & AddressOp.Store) != 0)
5262 f.status |= Field.Status.ASSIGNED;
5263 if ((mode & AddressOp.Load) != 0)
5264 f.status |= Field.Status.USED;
5268 // Handle initonly fields specially: make a copy and then
5269 // get the address of the copy.
5271 if (FieldInfo.IsInitOnly && !ec.IsConstructor){
5275 local = ig.DeclareLocal (type);
5276 ig.Emit (OpCodes.Stloc, local);
5277 ig.Emit (OpCodes.Ldloca, local);
5281 if (FieldInfo.IsStatic)
5282 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5284 if (instance_expr is IMemoryLocation)
5285 ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
5287 instance_expr.Emit (ec);
5288 ig.Emit (OpCodes.Ldflda, FieldInfo);
5294 /// Expression that evaluates to a Property. The Assign class
5295 /// might set the 'Value' expression if we are in an assignment.
5297 /// This is not an LValue because we need to re-write the expression, we
5298 /// can not take data from the stack and store it.
5300 public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
5301 public readonly PropertyInfo PropertyInfo;
5303 MethodInfo getter, setter;
5305 public ArrayList PropertyArgs;
5307 Expression instance_expr;
5309 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
5312 eclass = ExprClass.PropertyAccess;
5313 PropertyArgs = null;
5317 type = TypeManager.TypeToCoreType (pi.PropertyType);
5319 ResolveAccessors (ec);
5322 public string Name {
5324 return PropertyInfo.Name;
5328 public bool IsInstance {
5334 public bool IsStatic {
5340 public Type DeclaringType {
5342 return PropertyInfo.DeclaringType;
5347 // The instance expression associated with this expression
5349 public Expression InstanceExpression {
5351 instance_expr = value;
5355 return instance_expr;
5359 public bool VerifyAssignable ()
5361 if (!PropertyInfo.CanWrite){
5362 Report.Error (200, loc,
5363 "The property '" + PropertyInfo.Name +
5364 "' can not be assigned to, as it has not set accessor");
5371 void ResolveAccessors (EmitContext ec)
5373 BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
5374 MemberInfo [] group;
5376 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5377 MemberTypes.Method, flags, "get_" + PropertyInfo.Name);
5380 // The first method is the closest to us
5382 if (group != null && group.Length > 0){
5383 getter = (MethodInfo) group [0];
5385 if (getter.IsStatic)
5390 // The first method is the closest to us
5392 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5393 MemberTypes.Method, flags, "set_" + PropertyInfo.Name);
5394 if (group != null && group.Length > 0){
5395 setter = (MethodInfo) group [0];
5396 if (setter.IsStatic)
5401 override public Expression DoResolve (EmitContext ec)
5403 if (getter == null){
5404 Report.Error (30524, loc,
5405 "The property '" + PropertyInfo.Name +
5406 "' can not be used in " +
5407 "this context because it lacks a get accessor");
5411 if ((instance_expr == null) && ec.IsStatic && !is_static) {
5412 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
5416 if (instance_expr != null) {
5417 instance_expr = instance_expr.DoResolve (ec);
5418 if (instance_expr == null)
5425 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5427 if (setter == null){
5428 Report.Error (30526, loc,
5429 "The property '" + PropertyInfo.Name +
5430 "' can not be used in " +
5431 "this context because it lacks a set accessor");
5435 if (instance_expr != null) {
5436 instance_expr = instance_expr.DoResolve (ec);
5437 if (instance_expr == null)
5444 override public void Emit (EmitContext ec)
5447 // Special case: length of single dimension array property is turned into ldlen
5449 if ((getter == TypeManager.system_int_array_get_length) ||
5450 (getter == TypeManager.int_array_get_length)){
5451 Type iet = instance_expr.Type;
5454 // System.Array.Length can be called, but the Type does not
5455 // support invoking GetArrayRank, so test for that case first
5457 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
5458 instance_expr.Emit (ec);
5459 ec.ig.Emit (OpCodes.Ldlen);
5463 if (PropertyArgs == null)
5464 PropertyArgs = new ArrayList ();
5465 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, PropertyArgs, loc);
5469 // Implements the IAssignMethod interface for assignments
5471 public void EmitAssign (EmitContext ec, Expression source)
5473 Argument arg = new Argument (source, Argument.AType.Expression);
5474 ArrayList args = new ArrayList ();
5477 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, PropertyArgs,loc);
5480 override public void EmitStatement (EmitContext ec)
5483 ec.ig.Emit (OpCodes.Pop);
5488 /// Fully resolved expression that evaluates to an Event
5490 public class EventExpr : Expression, IMemberExpr {
5491 public readonly EventInfo EventInfo;
5492 public Expression instance_expr;
5495 MethodInfo add_accessor, remove_accessor;
5497 public EventExpr (EventInfo ei, Location loc)
5501 eclass = ExprClass.EventAccess;
5503 add_accessor = TypeManager.GetAddMethod (ei);
5504 remove_accessor = TypeManager.GetRemoveMethod (ei);
5506 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5509 if (EventInfo is MyEventBuilder)
5510 type = ((MyEventBuilder) EventInfo).EventType;
5512 type = EventInfo.EventHandlerType;
5515 public string Name {
5517 return EventInfo.Name;
5521 public bool IsInstance {
5527 public bool IsStatic {
5533 public Type DeclaringType {
5535 return EventInfo.DeclaringType;
5539 public Expression InstanceExpression {
5541 return instance_expr;
5545 instance_expr = value;
5549 Expression field_expr = null;
5551 public override Expression DoResolve (EmitContext ec)
5553 if (instance_expr != null) {
5554 instance_expr = instance_expr.DoResolve (ec);
5555 if (instance_expr == null)
5559 if (this.DeclaringType == ec.ContainerType) {
5560 MemberInfo mi = GetFieldFromEvent (this);
5563 field_expr = ExprClassFromMemberInfo (ec, mi, loc);
5564 ((FieldExpr) field_expr).InstanceExpression = instance_expr;
5565 field_expr = field_expr.DoResolve (ec);
5566 if (field_expr == null)
5573 public override void Emit (EmitContext ec)
5575 if (field_expr != null)
5576 field_expr.Emit (ec);
5579 public void EmitAddOrRemove (EmitContext ec, Expression source)
5581 Expression handler = ((Binary) source).Right;
5583 Argument arg = new Argument (handler, Argument.AType.Expression);
5584 ArrayList args = new ArrayList ();
5588 if (((Binary) source).Oper == Binary.Operator.Addition)
5589 Invocation.EmitCall (
5590 ec, false, IsStatic, instance_expr, add_accessor, args, loc);
5592 Invocation.EmitCall (
5593 ec, false, IsStatic, instance_expr, remove_accessor, args, loc);