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 (TypeManager.IsEnumType (t)){
508 Constant e = Constantify (v, TypeManager.TypeToCoreType (v.GetType ()));
510 return new EnumConstant (e, t);
512 throw new Exception ("Unknown type for constant (" + t +
517 /// Returns a fully formed expression after a MemberLookup
519 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
522 return new EventExpr ((EventInfo) mi, loc);
523 else if (mi is FieldInfo)
524 return new FieldExpr ((FieldInfo) mi, loc);
525 else if (mi is PropertyInfo)
526 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
527 else if (mi is Type){
528 return new TypeExpr ((System.Type) mi, loc);
535 // FIXME: Probably implement a cache for (t,name,current_access_set)?
537 // This code could use some optimizations, but we need to do some
538 // measurements. For example, we could use a delegate to 'flag' when
539 // something can not any longer be a method-group (because it is something
543 // If the return value is an Array, then it is an array of
546 // If the return value is an MemberInfo, it is anything, but a Method
550 // FIXME: When calling MemberLookup inside an 'Invocation', we should pass
551 // the arguments here and have MemberLookup return only the methods that
552 // match the argument count/type, unlike we are doing now (we delay this
555 // This is so we can catch correctly attempts to invoke instance methods
556 // from a static body (scan for error 120 in ResolveSimpleName).
559 // FIXME: Potential optimization, have a static ArrayList
562 public static Expression MemberLookup (EmitContext ec, Type t, string name,
563 MemberTypes mt, BindingFlags bf, Location loc)
565 return MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
569 // Lookup type 't' for code in class 'invocation_type'. Note that it's important
570 // to set 'invocation_type' correctly since this method also checks whether the
571 // invoking class is allowed to access the member in class 't'. When you want to
572 // explicitly do a lookup in the base class, you must set both 't' and 'invocation_type'
573 // to the base class (although a derived class can access protected members of its base
574 // class it cannot do so through an instance of the base class (error CS1540)).
577 public static Expression MemberLookup (EmitContext ec, Type invocation_type, Type t,
578 string name, MemberTypes mt, BindingFlags bf,
581 MemberInfo [] mi = TypeManager.MemberLookup (invocation_type, t, mt, bf, name);
586 int count = mi.Length;
589 return new MethodGroupExpr (mi, loc);
591 if (mi [0] is MethodBase)
592 return new MethodGroupExpr (mi, loc);
594 return ExprClassFromMemberInfo (ec, mi [0], loc);
597 public const MemberTypes AllMemberTypes =
598 MemberTypes.Constructor |
602 MemberTypes.NestedType |
603 MemberTypes.Property;
605 public const BindingFlags AllBindingFlags =
606 BindingFlags.Public |
607 BindingFlags.Static |
608 BindingFlags.Instance |
609 BindingFlags.IgnoreCase;
611 public static Expression MemberLookup (EmitContext ec, Type t, string name, Location loc)
613 return MemberLookup (ec, ec.ContainerType, t, name, AllMemberTypes, AllBindingFlags, loc);
616 public static Expression MethodLookup (EmitContext ec, Type t, string name, Location loc)
618 return MemberLookup (ec, ec.ContainerType, t, name,
619 MemberTypes.Method, AllBindingFlags, loc);
623 /// This is a wrapper for MemberLookup that is not used to "probe", but
624 /// to find a final definition. If the final definition is not found, we
625 /// look for private members and display a useful debugging message if we
628 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
631 return MemberLookupFinal (ec, t, name, MemberTypes.Method, AllBindingFlags, loc);
634 public static Expression MemberLookupFinal (EmitContext ec, Type t, string name,
635 MemberTypes mt, BindingFlags bf, Location loc)
639 int errors = Report.Errors;
641 e = MemberLookup (ec, ec.ContainerType, t, name, mt, bf, loc);
646 // Error has already been reported.
647 if (errors < Report.Errors)
650 e = MemberLookup (ec, t, name, AllMemberTypes,
651 AllBindingFlags | BindingFlags.NonPublic, loc);
654 30456, loc, "'" + t + "' does not contain a definition " +
655 "for '" + name + "'");
658 30390, loc, "'" + t + "." + name +
659 "' is inaccessible due to its protection level");
665 static public MemberInfo GetFieldFromEvent (EventExpr event_expr)
667 EventInfo ei = event_expr.EventInfo;
669 return TypeManager.GetPrivateFieldOfEvent (ei);
672 static EmptyExpression MyEmptyExpr;
673 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
675 Type expr_type = expr.Type;
677 if (expr_type == null && expr.eclass == ExprClass.MethodGroup){
678 // if we are a method group, emit a warning
684 // notice that it is possible to write "ValueType v = 1", the ValueType here
685 // is an abstract class, and not really a value type, so we apply the same rules.
687 if (target_type == TypeManager.object_type || target_type == TypeManager.value_type) {
689 // A pointer type cannot be converted to object
691 if (expr_type.IsPointer)
694 if (expr_type.IsValueType)
695 return new BoxedCast (expr);
696 if (expr_type.IsClass || expr_type.IsInterface)
697 return new EmptyCast (expr, target_type);
698 } else if (expr_type.IsSubclassOf (target_type)) {
700 // Special case: enumeration to System.Enum.
701 // System.Enum is not a value type, it is a class, so we need
702 // a boxing conversion
704 if (expr_type.IsEnum)
705 return new BoxedCast (expr);
707 return new EmptyCast (expr, target_type);
710 // This code is kind of mirrored inside StandardConversionExists
711 // with the small distinction that we only probe there
713 // Always ensure that the code here and there is in sync
715 // from the null type to any reference-type.
716 if (expr is NullLiteral && !target_type.IsValueType)
717 return new EmptyCast (expr, target_type);
719 // from any class-type S to any interface-type T.
720 if (target_type.IsInterface) {
721 if (TypeManager.ImplementsInterface (expr_type, target_type)){
722 if (expr_type.IsClass)
723 return new EmptyCast (expr, target_type);
724 else if (expr_type.IsValueType)
725 return new BoxedCast (expr);
729 // from any interface type S to interface-type T.
730 if (expr_type.IsInterface && target_type.IsInterface) {
731 if (TypeManager.ImplementsInterface (expr_type, target_type))
732 return new EmptyCast (expr, target_type);
737 // from an array-type S to an array-type of type T
738 if (expr_type.IsArray && target_type.IsArray) {
739 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
741 Type expr_element_type = expr_type.GetElementType ();
743 if (MyEmptyExpr == null)
744 MyEmptyExpr = new EmptyExpression ();
746 MyEmptyExpr.SetType (expr_element_type);
747 Type target_element_type = target_type.GetElementType ();
749 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
750 if (StandardConversionExists (MyEmptyExpr,
751 target_element_type))
752 return new EmptyCast (expr, target_type);
757 // from an array-type to System.Array
758 if (expr_type.IsArray && target_type == TypeManager.array_type)
759 return new EmptyCast (expr, target_type);
761 // from any delegate type to System.Delegate
762 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
763 target_type == TypeManager.delegate_type)
764 return new EmptyCast (expr, target_type);
766 // from any array-type or delegate type into System.ICloneable.
767 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
768 if (target_type == TypeManager.icloneable_type)
769 return new EmptyCast (expr, target_type);
779 /// Implicit Numeric Conversions.
781 /// expr is the expression to convert, returns a new expression of type
782 /// target_type or null if an implicit conversion is not possible.
784 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
785 Type target_type, Location loc)
787 Type expr_type = expr.Type;
790 // Attempt to do the implicit constant expression conversions
792 if (expr is BoolConstant || expr is IntConstant || expr is LongConstant || expr is DoubleConstant || expr is FloatConstant){
795 e = TryImplicitNumericConversion (target_type, (Constant) expr);
799 if (target_type == TypeManager.byte_type ||
800 target_type == TypeManager.short_type ||
801 target_type == TypeManager.int32_type ||
802 target_type == TypeManager.int64_type ||
803 target_type == TypeManager.float_type) {
806 if (expr is IntConstant)
807 val = ((IntConstant) expr).Value.ToString();
808 if (expr is LongConstant)
809 val = ((LongConstant) expr).Value.ToString();
810 if (expr is FloatConstant)
811 val = ((FloatConstant) expr).Value.ToString();
812 if (expr is DoubleConstant)
813 val = ((DoubleConstant) expr).Value.ToString();
814 Error_ConstantValueCannotBeConverted(loc, val, target_type);
817 } else if (expr is LongConstant && target_type == TypeManager.uint64_type) {
819 // Try the implicit constant expression conversion
820 // from long to ulong, instead of a nice routine,
823 long v = ((LongConstant) expr).Value;
825 return new ULongConstant ((ulong) v);
828 Type real_target_type = target_type;
830 if (target_type == TypeManager.bool_type) {
832 if (expr_type == TypeManager.decimal_type) {
833 return RTConversionExpression (ec, "System.Convert",".ToBoolean" , expr, loc);
836 if ((expr_type != TypeManager.char_type) &&
837 (expr_type != TypeManager.string_type) &&
838 (expr_type != TypeManager.object_type))
839 return new NumericToBoolCast (expr, expr.Type);
842 if (expr_type == TypeManager.bool_type){
844 if (real_target_type == TypeManager.sbyte_type)
845 return new BoolToNumericCast (expr, target_type);
846 if (real_target_type == TypeManager.byte_type)
847 return new BoolToNumericCast (expr, target_type);
848 if (real_target_type == TypeManager.int32_type)
849 return new BoolToNumericCast (expr, target_type);
850 if (real_target_type == TypeManager.int64_type)
851 return new BoolToNumericCast (expr, target_type);
852 if (real_target_type == TypeManager.double_type)
853 return new BoolToNumericCast (expr, target_type);
854 if (real_target_type == TypeManager.float_type)
855 return new BoolToNumericCast (expr, target_type);
856 if (real_target_type == TypeManager.short_type)
857 return new BoolToNumericCast (expr, target_type);
858 if (real_target_type == TypeManager.decimal_type)
859 return RTConversionExpression(ec, "DecimalType.FromBoolean", expr, loc);
860 } else if (expr_type == TypeManager.sbyte_type){
862 // From sbyte to short, int, long, float, double.
864 if (real_target_type == TypeManager.int32_type)
865 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
866 if (real_target_type == TypeManager.int64_type)
867 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
868 if (real_target_type == TypeManager.double_type)
869 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
870 if (real_target_type == TypeManager.float_type)
871 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
872 if (real_target_type == TypeManager.short_type)
873 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
874 } else if (expr_type == TypeManager.byte_type){
876 // From byte to short, ushort, int, uint, long, ulong, float, double
878 if ((real_target_type == TypeManager.short_type) ||
879 (real_target_type == TypeManager.ushort_type) ||
880 (real_target_type == TypeManager.int32_type) ||
881 (real_target_type == TypeManager.uint32_type))
882 return new EmptyCast (expr, target_type);
884 if (real_target_type == TypeManager.uint64_type)
885 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
886 if (real_target_type == TypeManager.int64_type)
887 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
888 if (real_target_type == TypeManager.float_type)
889 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
890 if (real_target_type == TypeManager.double_type)
891 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
892 } else if (expr_type == TypeManager.short_type){
894 // From short to int, long, float, double
896 if (real_target_type == TypeManager.int32_type)
897 return new EmptyCast (expr, target_type);
898 if (real_target_type == TypeManager.int64_type)
899 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
900 if (real_target_type == TypeManager.double_type)
901 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
902 if (real_target_type == TypeManager.float_type)
903 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
904 } else if (expr_type == TypeManager.ushort_type){
906 // From ushort to int, uint, long, ulong, float, double
908 if (real_target_type == TypeManager.uint32_type)
909 return new EmptyCast (expr, target_type);
911 if (real_target_type == TypeManager.uint64_type)
912 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
913 if (real_target_type == TypeManager.int32_type)
914 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
915 if (real_target_type == TypeManager.int64_type)
916 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
917 if (real_target_type == TypeManager.double_type)
918 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
919 if (real_target_type == TypeManager.float_type)
920 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
921 } else if (expr_type == TypeManager.int32_type){
923 // From int to long, float, double
925 if (real_target_type == TypeManager.int64_type)
926 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
927 if (real_target_type == TypeManager.double_type)
928 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
929 if (real_target_type == TypeManager.float_type)
930 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
931 } else if (expr_type == TypeManager.uint32_type){
933 // From uint to long, ulong, float, double
935 if (real_target_type == TypeManager.int64_type)
936 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
937 if (real_target_type == TypeManager.uint64_type)
938 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
939 if (real_target_type == TypeManager.double_type)
940 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
942 if (real_target_type == TypeManager.float_type)
943 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
945 } else if (expr_type == TypeManager.int64_type){
947 // From long/ulong to float, double
949 if (real_target_type == TypeManager.double_type)
950 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
951 if (real_target_type == TypeManager.float_type)
952 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
953 } else if (expr_type == TypeManager.uint64_type){
955 // From ulong to float, double
957 if (real_target_type == TypeManager.double_type)
958 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
960 if (real_target_type == TypeManager.float_type)
961 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
963 } else if (expr_type == TypeManager.char_type){
965 // From char to ushort, int, uint, long, ulong, float, double
967 if ((real_target_type == TypeManager.ushort_type) ||
968 (real_target_type == TypeManager.int32_type) ||
969 (real_target_type == TypeManager.uint32_type))
970 return new EmptyCast (expr, target_type);
971 if (real_target_type == TypeManager.uint64_type)
972 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
973 if (real_target_type == TypeManager.int64_type)
974 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
975 if (real_target_type == TypeManager.float_type)
976 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
977 if (real_target_type == TypeManager.double_type)
978 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
979 } else if (expr_type == TypeManager.string_type){
981 if (real_target_type == TypeManager.bool_type)
982 return RTConversionExpression (ec, "BooleanType.FromString" , expr, loc);
983 if (real_target_type == TypeManager.decimal_type)
984 return RTConversionExpression (ec, "DecimalType.FromString" , expr, loc);
985 if (real_target_type == TypeManager.float_type)
986 return RTConversionExpression (ec, "SingleType.FromString" , expr, loc);
987 if (real_target_type == TypeManager.short_type)
988 return RTConversionExpression (ec, "ShortType.FromString" , expr, loc);
989 if (real_target_type == TypeManager.int64_type)
990 return RTConversionExpression (ec, "LongType.FromString" , expr, loc);
991 if (real_target_type == TypeManager.int32_type)
992 return RTConversionExpression (ec, "IntegerType.FromString" , expr, loc);
993 if (real_target_type == TypeManager.double_type)
994 return RTConversionExpression (ec, "DoubleType.FromString" , expr, loc);
995 if (real_target_type == TypeManager.byte_type)
996 return RTConversionExpression (ec, "ByteType.FromString" , expr, loc);
997 } else if (expr_type == TypeManager.float_type){
1001 if (real_target_type == TypeManager.decimal_type)
1002 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
1003 if (real_target_type == TypeManager.double_type)
1004 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
1006 } else if (expr_type == TypeManager.double_type){
1008 if (real_target_type == TypeManager.decimal_type)
1009 return RTConversionExpression (ec, "System.Convert", ".ToDecimal" , expr, loc);
1010 } else if (expr_type == TypeManager.decimal_type){
1012 if (real_target_type == TypeManager.bool_type)
1013 return RTConversionExpression (ec, "BooleanType.FromDecimal" , expr, loc);
1014 if (real_target_type == TypeManager.short_type)
1015 return RTConversionExpression(ec, "System.Convert", ".ToInt16", expr, loc);
1016 if (real_target_type == TypeManager.byte_type)
1017 return RTConversionExpression(ec, "System.Convert", ".ToByte", expr, loc);
1018 if (real_target_type == TypeManager.int32_type)
1019 return RTConversionExpression(ec, "System.Convert", ".ToInt32", expr, loc);
1020 if (real_target_type == TypeManager.int64_type)
1021 return RTConversionExpression(ec, "System.Convert", ".ToInt64", expr, loc);
1022 if (real_target_type == TypeManager.float_type)
1023 return RTConversionExpression(ec, "System.Convert", ".ToSingle", expr, loc);
1024 if (real_target_type == TypeManager.double_type)
1025 return RTConversionExpression(ec, "System.Convert", ".ToDouble", expr, loc);
1026 if (real_target_type == TypeManager.char_type)
1027 return RTConversionExpression(ec, "System.Convert", ".ToChar", expr, loc);
1034 // Tests whether an implicit reference conversion exists between expr_type
1037 public static bool ImplicitReferenceConversionExists (Expression expr, Type expr_type, Type target_type)
1040 // This is the boxed case.
1042 if (target_type == TypeManager.object_type) {
1043 if ((expr_type.IsClass) ||
1044 (expr_type.IsValueType) ||
1045 (expr_type.IsInterface))
1048 } else if (expr_type.IsSubclassOf (target_type)) {
1051 // Please remember that all code below actually comes
1052 // from ImplicitReferenceConversion so make sure code remains in sync
1054 // from any class-type S to any interface-type T.
1055 if (target_type.IsInterface) {
1056 if (TypeManager.ImplementsInterface (expr_type, target_type))
1060 // from any interface type S to interface-type T.
1061 if (expr_type.IsInterface && target_type.IsInterface)
1062 if (TypeManager.ImplementsInterface (expr_type, target_type))
1065 // from an array-type S to an array-type of type T
1066 if (expr_type.IsArray && target_type.IsArray) {
1067 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
1069 Type expr_element_type = expr_type.GetElementType ();
1071 if (MyEmptyExpr == null)
1072 MyEmptyExpr = new EmptyExpression ();
1074 MyEmptyExpr.SetType (expr_element_type);
1075 Type target_element_type = target_type.GetElementType ();
1077 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
1078 if (StandardConversionExists (MyEmptyExpr,
1079 target_element_type))
1084 // from an array-type to System.Array
1085 if (expr_type.IsArray && (target_type == TypeManager.array_type))
1088 // from any delegate type to System.Delegate
1089 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
1090 target_type == TypeManager.delegate_type)
1091 if (target_type.IsAssignableFrom (expr_type))
1094 // from any array-type or delegate type into System.ICloneable.
1095 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
1096 if (target_type == TypeManager.icloneable_type)
1099 // from the null type to any reference-type.
1100 if (expr is NullLiteral && !target_type.IsValueType &&
1101 !TypeManager.IsEnumType (target_type))
1110 /// Same as StandardConversionExists except that it also looks at
1111 /// implicit user defined conversions - needed for overload resolution
1113 public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
1115 if (StandardConversionExists (expr, target_type) == true)
1119 Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
1129 /// Determines if a standard implicit conversion exists from
1130 /// expr_type to target_type
1132 public static bool StandardConversionExists (Expression expr, Type target_type)
1134 return WideningConversionExists (expr, expr.type, target_type);
1137 public static bool WideningConversionExists (Type expr_type, Type target_type)
1139 return WideningConversionExists (null, expr_type, target_type);
1142 public static bool WideningConversionExists (Expression expr, Type target_type)
1144 return WideningConversionExists (expr, expr.Type, target_type);
1147 public static bool WideningConversionExists (Expression expr, Type expr_type, Type target_type)
1150 if (expr_type == null || expr_type == TypeManager.void_type)
1153 if (expr_type == target_type)
1156 // Conversions from enum to underlying type are widening.
1157 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1158 expr_type = TypeManager.EnumToUnderlying (expr_type);
1160 if (expr_type == target_type)
1163 // First numeric conversions
1165 if (expr_type == TypeManager.sbyte_type){
1167 // From sbyte to short, int, long, float, double.
1169 if ((target_type == TypeManager.int32_type) ||
1170 (target_type == TypeManager.int64_type) ||
1171 (target_type == TypeManager.double_type) ||
1172 (target_type == TypeManager.float_type) ||
1173 (target_type == TypeManager.short_type) ||
1174 (target_type == TypeManager.decimal_type))
1177 } else if (expr_type == TypeManager.byte_type){
1179 // From byte to short, ushort, int, uint, long, ulong, float, double
1181 if ((target_type == TypeManager.short_type) ||
1182 (target_type == TypeManager.bool_type) ||
1183 (target_type == TypeManager.ushort_type) ||
1184 (target_type == TypeManager.int32_type) ||
1185 (target_type == TypeManager.uint32_type) ||
1186 (target_type == TypeManager.uint64_type) ||
1187 (target_type == TypeManager.int64_type) ||
1188 (target_type == TypeManager.float_type) ||
1189 (target_type == TypeManager.double_type) ||
1190 (target_type == TypeManager.decimal_type))
1193 } else if (expr_type == TypeManager.short_type){
1195 // From short to int, long, float, double
1197 if ((target_type == TypeManager.int32_type) ||
1198 (target_type == TypeManager.bool_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.ushort_type){
1207 // From ushort to int, uint, long, ulong, float, double
1209 if ((target_type == TypeManager.uint32_type) ||
1210 (target_type == TypeManager.uint64_type) ||
1211 (target_type == TypeManager.int32_type) ||
1212 (target_type == TypeManager.int64_type) ||
1213 (target_type == TypeManager.double_type) ||
1214 (target_type == TypeManager.float_type) ||
1215 (target_type == TypeManager.decimal_type))
1218 } else if (expr_type == TypeManager.int32_type){
1220 // From int to long, float, double
1222 if ((target_type == TypeManager.int64_type) ||
1223 (target_type == TypeManager.bool_type) ||
1224 (target_type == TypeManager.double_type) ||
1225 (target_type == TypeManager.float_type) ||
1226 (target_type == TypeManager.decimal_type))
1229 } else if (expr_type == TypeManager.uint32_type){
1231 // From uint to long, ulong, float, double
1233 if ((target_type == TypeManager.int64_type) ||
1234 (target_type == TypeManager.bool_type) ||
1235 (target_type == TypeManager.uint64_type) ||
1236 (target_type == TypeManager.double_type) ||
1237 (target_type == TypeManager.float_type) ||
1238 (target_type == TypeManager.decimal_type))
1241 } else if ((expr_type == TypeManager.uint64_type) ||
1242 (expr_type == TypeManager.int64_type)) {
1244 // From long/ulong to float, double
1246 if ((target_type == TypeManager.double_type) ||
1247 (target_type == TypeManager.bool_type) ||
1248 (target_type == TypeManager.float_type) ||
1249 (target_type == TypeManager.decimal_type))
1252 } else if (expr_type == TypeManager.char_type){
1254 // From char to ushort, int, uint, long, ulong, float, double
1256 if ((target_type == TypeManager.ushort_type) ||
1257 (target_type == TypeManager.int32_type) ||
1258 (target_type == TypeManager.uint32_type) ||
1259 (target_type == TypeManager.uint64_type) ||
1260 (target_type == TypeManager.int64_type) ||
1261 (target_type == TypeManager.float_type) ||
1262 (target_type == TypeManager.double_type) ||
1263 (target_type == TypeManager.string_type) ||
1264 (target_type == TypeManager.decimal_type))
1267 } else if (expr_type == TypeManager.decimal_type) {
1268 if (target_type == TypeManager.float_type ||
1269 target_type == TypeManager.double_type)
1271 } else if (expr_type == TypeManager.float_type){
1273 // float to double, decimal
1275 if (target_type == TypeManager.double_type)
1277 } else if (expr_type == TypeManager.double_type){
1279 if ((target_type == TypeManager.bool_type))
1283 if (ImplicitReferenceConversionExists (expr, expr_type, target_type))
1286 if (expr is IntConstant){
1287 int value = ((IntConstant) expr).Value;
1289 if (target_type == TypeManager.sbyte_type){
1290 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1292 } else if (target_type == TypeManager.byte_type){
1293 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1295 } else if (target_type == TypeManager.short_type){
1296 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1298 } else if (target_type == TypeManager.ushort_type){
1299 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1301 } else if (target_type == TypeManager.uint32_type){
1304 } else if (target_type == TypeManager.uint64_type){
1306 // we can optimize this case: a positive int32
1307 // always fits on a uint64. But we need an opcode
1314 if (value == 0 && expr is IntLiteral && TypeManager.IsEnumType (target_type))
1318 if (expr is LongConstant && target_type == TypeManager.uint64_type){
1320 // Try the implicit constant expression conversion
1321 // from long to ulong, instead of a nice routine,
1322 // we just inline it
1324 long v = ((LongConstant) expr).Value;
1329 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1330 IntLiteral i = (IntLiteral) expr;
1336 if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
1343 // Used internally by FindMostEncompassedType, this is used
1344 // to avoid creating lots of objects in the tight loop inside
1345 // FindMostEncompassedType
1347 static EmptyExpression priv_fmet_param;
1350 /// Finds "most encompassed type" according to the spec (13.4.2)
1351 /// amongst the methods in the MethodGroupExpr
1353 static Type FindMostEncompassedType (ArrayList types)
1357 if (priv_fmet_param == null)
1358 priv_fmet_param = new EmptyExpression ();
1360 foreach (Type t in types){
1361 priv_fmet_param.SetType (t);
1368 if (StandardConversionExists (priv_fmet_param, best))
1376 // Used internally by FindMostEncompassingType, this is used
1377 // to avoid creating lots of objects in the tight loop inside
1378 // FindMostEncompassingType
1380 static EmptyExpression priv_fmee_ret;
1383 /// Finds "most encompassing type" according to the spec (13.4.2)
1384 /// amongst the types in the given set
1386 static Type FindMostEncompassingType (ArrayList types)
1390 if (priv_fmee_ret == null)
1391 priv_fmee_ret = new EmptyExpression ();
1393 foreach (Type t in types){
1394 priv_fmee_ret.SetType (best);
1401 if (StandardConversionExists (priv_fmee_ret, t))
1409 // Used to avoid creating too many objects
1411 static EmptyExpression priv_fms_expr;
1414 /// Finds the most specific source Sx according to the rules of the spec (13.4.4)
1415 /// by making use of FindMostEncomp* methods. Applies the correct rules separately
1416 /// for explicit and implicit conversion operators.
1418 static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source,
1419 bool apply_explicit_conv_rules,
1422 ArrayList src_types_set = new ArrayList ();
1424 if (priv_fms_expr == null)
1425 priv_fms_expr = new EmptyExpression ();
1428 // If any operator converts from S then Sx = S
1430 Type source_type= source.Type;
1431 foreach (MethodBase mb in me.Methods){
1432 ParameterData pd = Invocation.GetParameterData (mb);
1433 Type param_type = pd.ParameterType (0);
1435 if (param_type == source_type)
1438 if (apply_explicit_conv_rules) {
1441 // Find the set of applicable user-defined conversion operators, U. This set
1443 // user-defined implicit or explicit conversion operators declared by
1444 // the classes or structs in D that convert from a type encompassing
1445 // or encompassed by S to a type encompassing or encompassed by T
1447 priv_fms_expr.SetType (param_type);
1448 if (StandardConversionExists (priv_fms_expr, source_type))
1449 src_types_set.Add (param_type);
1451 if (StandardConversionExists (source, param_type))
1452 src_types_set.Add (param_type);
1456 // Only if S is encompassed by param_type
1458 if (StandardConversionExists (source, param_type))
1459 src_types_set.Add (param_type);
1464 // Explicit Conv rules
1466 if (apply_explicit_conv_rules) {
1467 ArrayList candidate_set = new ArrayList ();
1469 foreach (Type param_type in src_types_set){
1470 if (StandardConversionExists (source, param_type))
1471 candidate_set.Add (param_type);
1474 if (candidate_set.Count != 0)
1475 return FindMostEncompassedType (candidate_set);
1481 if (apply_explicit_conv_rules)
1482 return FindMostEncompassingType (src_types_set);
1484 return FindMostEncompassedType (src_types_set);
1488 // Useful in avoiding proliferation of objects
1490 static EmptyExpression priv_fmt_expr;
1493 /// Finds the most specific target Tx according to section 13.4.4
1495 static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target,
1496 bool apply_explicit_conv_rules,
1499 ArrayList tgt_types_set = new ArrayList ();
1501 if (priv_fmt_expr == null)
1502 priv_fmt_expr = new EmptyExpression ();
1505 // If any operator converts to T then Tx = T
1507 foreach (MethodInfo mi in me.Methods){
1508 Type ret_type = mi.ReturnType;
1510 if (ret_type == target)
1513 if (apply_explicit_conv_rules) {
1516 // Find the set of applicable user-defined conversion operators, U.
1518 // This set consists of the
1519 // user-defined implicit or explicit conversion operators declared by
1520 // the classes or structs in D that convert from a type encompassing
1521 // or encompassed by S to a type encompassing or encompassed by T
1523 priv_fms_expr.SetType (ret_type);
1524 if (StandardConversionExists (priv_fms_expr, target))
1525 tgt_types_set.Add (ret_type);
1527 priv_fms_expr.SetType (target);
1528 if (StandardConversionExists (priv_fms_expr, ret_type))
1529 tgt_types_set.Add (ret_type);
1533 // Only if T is encompassed by param_type
1535 priv_fms_expr.SetType (ret_type);
1536 if (StandardConversionExists (priv_fms_expr, target))
1537 tgt_types_set.Add (ret_type);
1542 // Explicit conv rules
1544 if (apply_explicit_conv_rules) {
1545 ArrayList candidate_set = new ArrayList ();
1547 foreach (Type ret_type in tgt_types_set){
1548 priv_fmt_expr.SetType (ret_type);
1550 if (StandardConversionExists (priv_fmt_expr, target))
1551 candidate_set.Add (ret_type);
1554 if (candidate_set.Count != 0)
1555 return FindMostEncompassingType (candidate_set);
1559 // Okay, final case !
1561 if (apply_explicit_conv_rules)
1562 return FindMostEncompassedType (tgt_types_set);
1564 return FindMostEncompassingType (tgt_types_set);
1568 /// User-defined Implicit conversions
1570 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
1571 Type target, Location loc)
1573 return UserDefinedConversion (ec, source, target, loc, false);
1577 /// User-defined Explicit conversions
1579 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
1580 Type target, Location loc)
1582 return UserDefinedConversion (ec, source, target, loc, true);
1586 /// Computes the MethodGroup for the user-defined conversion
1587 /// operators from source_type to target_type. 'look_for_explicit'
1588 /// controls whether we should also include the list of explicit
1591 static MethodGroupExpr GetConversionOperators (EmitContext ec,
1592 Type source_type, Type target_type,
1593 Location loc, bool look_for_explicit)
1595 Expression mg1 = null, mg2 = null;
1596 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
1600 // FIXME : How does the False operator come into the picture ?
1601 // This doesn't look complete and very correct !
1603 if (target_type == TypeManager.bool_type && !look_for_explicit)
1604 op_name = "op_True";
1606 op_name = "op_Implicit";
1608 MethodGroupExpr union3;
1610 mg1 = MethodLookup (ec, source_type, op_name, loc);
1611 if (source_type.BaseType != null)
1612 mg2 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1615 union3 = (MethodGroupExpr) mg2;
1616 else if (mg2 == null)
1617 union3 = (MethodGroupExpr) mg1;
1619 union3 = Invocation.MakeUnionSet (mg1, mg2, loc);
1621 mg1 = MethodLookup (ec, target_type, op_name, loc);
1624 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1626 union3 = (MethodGroupExpr) mg1;
1629 if (target_type.BaseType != null)
1630 mg1 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1634 union3 = Invocation.MakeUnionSet (union3, mg1, loc);
1636 union3 = (MethodGroupExpr) mg1;
1639 MethodGroupExpr union4 = null;
1641 if (look_for_explicit) {
1642 op_name = "op_Explicit";
1644 mg5 = MemberLookup (ec, source_type, op_name, loc);
1645 if (source_type.BaseType != null)
1646 mg6 = MethodLookup (ec, source_type.BaseType, op_name, loc);
1648 mg7 = MemberLookup (ec, target_type, op_name, loc);
1649 if (target_type.BaseType != null)
1650 mg8 = MethodLookup (ec, target_type.BaseType, op_name, loc);
1652 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc);
1653 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc);
1655 union4 = Invocation.MakeUnionSet (union5, union6, loc);
1658 return Invocation.MakeUnionSet (union3, union4, loc);
1662 /// User-defined conversions
1664 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
1665 Type target, Location loc,
1666 bool look_for_explicit)
1668 MethodGroupExpr union;
1669 Type source_type = source.Type;
1670 MethodBase method = null;
1672 union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
1676 Type most_specific_source, most_specific_target;
1679 foreach (MethodBase m in union.Methods){
1680 Console.WriteLine ("Name: " + m.Name);
1681 Console.WriteLine (" : " + ((MethodInfo)m).ReturnType);
1685 most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc);
1686 if (most_specific_source == null)
1689 most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc);
1690 if (most_specific_target == null)
1695 foreach (MethodBase mb in union.Methods){
1696 ParameterData pd = Invocation.GetParameterData (mb);
1697 MethodInfo mi = (MethodInfo) mb;
1699 if (pd.ParameterType (0) == most_specific_source &&
1700 mi.ReturnType == most_specific_target) {
1706 if (method == null || count > 1)
1711 // This will do the conversion to the best match that we
1712 // found. Now we need to perform an implict standard conversion
1713 // if the best match was not the type that we were requested
1716 if (look_for_explicit)
1717 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1719 source = ConvertImplicitStandard (ec, source, most_specific_source, loc);
1725 e = new UserCast ((MethodInfo) method, source, loc);
1726 if (e.Type != target){
1727 if (!look_for_explicit)
1728 e = ConvertImplicitStandard (ec, e, target, loc);
1730 e = ConvertExplicitStandard (ec, e, target, loc);
1736 /// Converts implicitly the resolved expression 'expr' into the
1737 /// 'target_type'. It returns a new expression that can be used
1738 /// in a context that expects a 'target_type'.
1740 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1741 Type target_type, Location loc)
1743 Type expr_type = expr.Type;
1747 if (expr_type == target_type)
1750 if (target_type == null)
1751 throw new Exception ("Target type is null");
1753 e = ConvertImplicitStandard (ec, expr, target_type, loc);
1757 e = ImplicitUserConversion (ec, expr, target_type, loc);
1762 e = NarrowingConversion (ec, expr, target_type, loc);
1770 /// Converts the resolved expression 'expr' into the
1771 /// 'target_type' using the Microsoft.VisualBasic runtime.
1772 /// It returns a new expression that can be used
1773 /// in a context that expects a 'target_type'.
1775 static private Expression RTConversionExpression (EmitContext ec, string s, Expression expr, Location loc)
1781 etmp = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices." + s, loc);
1782 args = new ArrayList();
1783 arg = new Argument (expr, Argument.AType.Expression);
1785 e = (Expression) new Invocation (etmp, args, loc);
1790 static private Expression RTConversionExpression (EmitContext ec, string ns, string method, Expression expr, Location loc)
1796 etmp = Mono.MonoBASIC.Parser.DecomposeQI(ns+method, loc);
1797 args = new ArrayList();
1798 arg = new Argument (expr, Argument.AType.Expression);
1800 e = (Expression) new Invocation (etmp, args, loc);
1806 static public bool NarrowingConversionExists (EmitContext ec, Expression expr, Type target_type)
1808 Type expr_type = expr.Type;
1809 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1810 expr_type = TypeManager.EnumToUnderlying (expr_type);
1812 if (target_type.IsSubclassOf (TypeManager.enum_type))
1813 target_type = TypeManager.EnumToUnderlying (target_type);
1816 if (expr_type == target_type)
1819 if (target_type == TypeManager.sbyte_type){
1821 // To sbyte from short, int, long, float, double.
1823 if ((expr_type == TypeManager.int32_type) ||
1824 (expr_type == TypeManager.int64_type) ||
1825 (expr_type == TypeManager.double_type) ||
1826 (expr_type == TypeManager.float_type) ||
1827 (expr_type == TypeManager.short_type) ||
1828 (expr_type == TypeManager.decimal_type))
1831 } else if (target_type == TypeManager.byte_type){
1833 // To byte from short, ushort, int, uint, long, ulong, float, double
1835 if ((expr_type == TypeManager.short_type) ||
1836 (expr_type == TypeManager.ushort_type) ||
1837 (expr_type == TypeManager.int32_type) ||
1838 (expr_type == TypeManager.uint32_type) ||
1839 (expr_type == TypeManager.uint64_type) ||
1840 (expr_type == TypeManager.int64_type) ||
1841 (expr_type == TypeManager.float_type) ||
1842 (expr_type == TypeManager.double_type) ||
1843 (expr_type == TypeManager.decimal_type))
1846 } else if (target_type == TypeManager.short_type){
1848 // To short from int, long, float, double
1850 if ((expr_type == TypeManager.int32_type) ||
1851 (expr_type == TypeManager.int64_type) ||
1852 (expr_type == TypeManager.double_type) ||
1853 (expr_type == TypeManager.float_type) ||
1854 (expr_type == TypeManager.decimal_type))
1857 } else if (target_type == TypeManager.ushort_type){
1859 // To ushort from int, uint, long, ulong, float, double
1861 if ((expr_type == TypeManager.uint32_type) ||
1862 (expr_type == TypeManager.uint64_type) ||
1863 (expr_type == TypeManager.int32_type) ||
1864 (expr_type == TypeManager.int64_type) ||
1865 (expr_type == TypeManager.double_type) ||
1866 (expr_type == TypeManager.float_type) ||
1867 (expr_type == TypeManager.decimal_type))
1870 } else if (target_type == TypeManager.int32_type){
1872 // To int from long, float, double
1874 if ((expr_type == TypeManager.int64_type) ||
1875 (expr_type == TypeManager.double_type) ||
1876 (expr_type == TypeManager.float_type) ||
1877 (expr_type == TypeManager.decimal_type))
1880 } else if (target_type == TypeManager.uint32_type){
1882 // To uint from long, ulong, float, double
1884 if ((expr_type == TypeManager.int64_type) ||
1885 (expr_type == TypeManager.uint64_type) ||
1886 (expr_type == TypeManager.double_type) ||
1887 (expr_type == TypeManager.float_type) ||
1888 (expr_type == TypeManager.decimal_type))
1891 } else if ((target_type == TypeManager.uint64_type) ||
1892 (target_type == TypeManager.int64_type)) {
1894 // To long/ulong from float, double
1896 if ((expr_type == TypeManager.double_type) ||
1897 (expr_type == TypeManager.float_type) ||
1898 (expr_type == TypeManager.decimal_type))
1901 } else if (target_type == TypeManager.char_type){
1903 // To char from ushort, int, uint, long, ulong, float, double, decimal,string
1905 if ((expr_type == TypeManager.ushort_type) ||
1906 (expr_type == TypeManager.int32_type) ||
1907 (expr_type == TypeManager.uint32_type) ||
1908 (expr_type == TypeManager.uint64_type) ||
1909 (expr_type == TypeManager.int64_type) ||
1910 (expr_type == TypeManager.float_type) ||
1911 (expr_type == TypeManager.double_type) ||
1912 (expr_type == TypeManager.decimal_type) ||
1913 (expr_type == TypeManager.string_type))
1917 } else if (target_type == TypeManager.decimal_type){
1918 if (expr_type == TypeManager.float_type ||
1919 expr_type == TypeManager.double_type)
1921 } else if (target_type == TypeManager.float_type){
1923 // To float from double
1925 if (expr_type == TypeManager.double_type)
1929 return (NarrowingConversion (ec, expr, target_type,Location.Null)) != null;
1932 static public Expression NarrowingConversion (EmitContext ec, Expression expr,
1933 Type target_type, Location loc)
1935 Type expr_type = expr.Type;
1937 if (expr_type.IsSubclassOf (TypeManager.enum_type))
1938 expr_type = TypeManager.EnumToUnderlying (expr_type);
1940 if (target_type.IsSubclassOf (TypeManager.enum_type))
1941 target_type = TypeManager.EnumToUnderlying (target_type);
1943 if (expr_type == target_type)
1946 if (target_type == TypeManager.sbyte_type){
1948 // To sbyte from short, int, long, float, double.
1950 if (expr_type == TypeManager.int32_type)
1951 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
1952 if (expr_type == TypeManager.int64_type)
1953 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
1954 if (expr_type == TypeManager.short_type)
1955 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
1957 if (expr_type == TypeManager.float_type) {
1958 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1959 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
1961 if (expr_type == TypeManager.double_type) {
1962 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1963 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
1966 } else if (target_type == TypeManager.byte_type){
1968 // To byte from short, ushort, int, uint, long, ulong, float, double
1970 if (expr_type == TypeManager.short_type)
1971 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
1972 if (expr_type == TypeManager.ushort_type)
1973 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
1974 if (expr_type == TypeManager.int32_type)
1975 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
1976 if (expr_type == TypeManager.uint32_type)
1977 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
1978 if (expr_type == TypeManager.uint64_type)
1979 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
1980 if (expr_type == TypeManager.int64_type)
1981 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
1983 if (expr_type == TypeManager.float_type) {
1984 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1985 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
1987 if (expr_type == TypeManager.double_type) {
1988 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
1989 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
1992 } else if (target_type == TypeManager.short_type) {
1994 // To short from int, long, float, double
1996 if (expr_type == TypeManager.int32_type)
1997 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
1998 if (expr_type == TypeManager.int64_type)
1999 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
2001 if (expr_type == TypeManager.float_type) {
2002 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2003 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
2005 if (expr_type == TypeManager.double_type) {
2006 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2007 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
2010 } else if (target_type == TypeManager.ushort_type) {
2012 // To ushort from int, uint, long, ulong, float, double
2014 if (expr_type == TypeManager.uint32_type)
2015 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
2016 if (expr_type == TypeManager.uint64_type)
2017 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
2018 if (expr_type == TypeManager.int32_type)
2019 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
2020 if (expr_type == TypeManager.int64_type)
2021 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2023 if (expr_type == TypeManager.float_type) {
2024 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2025 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2028 if (expr_type == TypeManager.double_type) {
2029 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2030 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
2033 } else if (target_type == TypeManager.int32_type){
2035 // To int from long, float, double
2037 if (expr_type == TypeManager.int64_type)
2038 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2040 if (expr_type == TypeManager.float_type) {
2041 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2042 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2044 if (expr_type == TypeManager.double_type) {
2045 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2046 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2049 } else if (target_type == TypeManager.uint32_type){
2051 // To uint from long, ulong, float, double
2053 if (expr_type == TypeManager.int64_type)
2054 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2055 if (expr_type == TypeManager.uint64_type)
2056 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2057 if (expr_type == TypeManager.float_type) {
2058 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2059 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2061 if (expr_type == TypeManager.double_type) {
2062 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2063 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2066 } else if (target_type == TypeManager.uint64_type) {
2068 // To long/ulong from float, double
2070 if (expr_type == TypeManager.float_type) {
2071 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2072 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2074 if (expr_type == TypeManager.double_type) {
2075 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2076 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2079 } else if (target_type == TypeManager.int64_type) {
2081 // To long/ulong from float, double
2083 if (expr_type == TypeManager.float_type) {
2084 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2085 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2087 if (expr_type == TypeManager.double_type) {
2088 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2089 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2092 } else if (target_type == TypeManager.char_type){
2094 // To char from ushort, int, uint, long, ulong, float, double
2096 if (expr_type == TypeManager.ushort_type)
2097 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
2098 if (expr_type == TypeManager.int32_type)
2099 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
2100 if (expr_type == TypeManager.uint32_type)
2101 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
2102 if (expr_type == TypeManager.uint64_type)
2103 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
2104 if (expr_type == TypeManager.int64_type)
2105 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
2107 if (expr_type == TypeManager.float_type) {
2108 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2109 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_CH);
2111 if (expr_type == TypeManager.double_type) {
2112 Expression rounded_expr = RTConversionExpression(ec, "System.Math", ".Round", expr, loc);
2113 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_CH);
2116 } else if (target_type == TypeManager.float_type){
2118 // To float from double
2120 if (expr_type == TypeManager.double_type)
2121 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2124 TypeCode dest_type = Type.GetTypeCode (target_type);
2125 TypeCode src_type = Type.GetTypeCode (expr_type);
2126 Expression e = null;
2128 switch (dest_type) {
2129 case TypeCode.String:
2131 case TypeCode.SByte:
2133 e = RTConversionExpression(ec, "StringType.FromByte", expr, loc);
2135 case TypeCode.UInt16:
2136 case TypeCode.Int16:
2137 e = RTConversionExpression(ec, "StringType.FromShort", expr, loc);
2139 case TypeCode.UInt32:
2140 case TypeCode.Int32:
2141 e = RTConversionExpression(ec, "StringType.FromInteger", expr, loc);
2143 case TypeCode.UInt64:
2144 case TypeCode.Int64:
2145 e = RTConversionExpression(ec, "StringType.FromLong", expr, loc);
2148 e = RTConversionExpression(ec, "StringType.FromChar", expr, loc);
2150 case TypeCode.Single:
2151 e = RTConversionExpression(ec, "StringType.FromSingle", expr, loc);
2153 case TypeCode.Double:
2154 e = RTConversionExpression(ec, "StringType.FromDouble", expr, loc);
2156 case TypeCode.Boolean:
2157 e = RTConversionExpression(ec, "StringType.FromBoolean", expr, loc);
2159 case TypeCode.DateTime:
2160 e = RTConversionExpression(ec, "StringType.FromDate", expr, loc);
2162 case TypeCode.Decimal:
2163 e = RTConversionExpression(ec, "StringType.FromDecimal", expr, loc);
2165 case TypeCode.Object:
2166 e = RTConversionExpression(ec, "StringType.FromObject", expr, loc);
2171 case TypeCode.Double:
2173 case TypeCode.String:
2174 e = RTConversionExpression(ec, "DoubleType.FromString", expr, loc);
2176 case TypeCode.Object:
2177 e = RTConversionExpression(ec, "DoubleType.FromObject", expr, loc);
2182 case TypeCode.Single:
2184 case TypeCode.String:
2185 e = RTConversionExpression(ec, "SingleType.FromString", expr, loc);
2187 case TypeCode.Object:
2188 e = RTConversionExpression(ec, "SingleType.FromObject", expr, loc);
2193 case TypeCode.Decimal:
2195 case TypeCode.String:
2196 e = RTConversionExpression(ec, "DecimalType.FromString", expr, loc);
2198 case TypeCode.Object:
2199 e = RTConversionExpression(ec, "DecimalType.FromObject", expr, loc);
2204 case TypeCode.Int64:
2205 case TypeCode.UInt64:
2207 case TypeCode.String:
2208 e = RTConversionExpression(ec, "LongType.FromString", expr, loc);
2210 case TypeCode.Object:
2211 e = RTConversionExpression(ec, "LongType.FromObject", expr, loc);
2215 case TypeCode.Int32:
2216 case TypeCode.UInt32:
2218 case TypeCode.String:
2219 e = RTConversionExpression(ec, "IntegerType.FromString", expr, loc);
2221 case TypeCode.Object:
2222 e = RTConversionExpression(ec, "IntegerType.FromObject", expr, loc);
2227 case TypeCode.Int16:
2228 case TypeCode.UInt16:
2230 case TypeCode.String:
2231 e = RTConversionExpression(ec, "ShortType.FromString", expr, loc);
2233 case TypeCode.Object:
2234 e = RTConversionExpression(ec, "ShortType.FromObject", expr, loc);
2239 // Ok, this *is* broken
2240 e = RTConversionExpression(ec, "ByteType.FromObject", expr, loc);
2242 case TypeCode.Boolean:
2244 case TypeCode.String:
2245 e = RTConversionExpression(ec, "BooleanType.FromString", expr, loc);
2247 case TypeCode.Object:
2248 e = RTConversionExpression(ec, "BooleanType.FromObject", expr, loc);
2252 case TypeCode.DateTime:
2254 case TypeCode.String:
2255 e = RTConversionExpression(ec, "DateType.FromString", expr, loc);
2257 case TypeCode.Object:
2258 e = RTConversionExpression(ec, "DateType.FromObject", expr, loc);
2265 case TypeCode.String:
2266 e = RTConversionExpression(ec, "CharType.FromString", expr, loc);
2273 // We must examine separately some types that
2274 // don't have a TypeCode but are supported
2276 if (expr_type == typeof(System.String) && target_type == typeof (System.Char[])) {
2277 e = RTConversionExpression(ec, "CharArrayType.FromString", expr, loc);
2281 // VB.NET Objects can be converted to anything by default
2282 // unless, that is, an exception at runtime blows it all
2283 if (src_type == TypeCode.Object) {
2284 Expression cast_type = Mono.MonoBASIC.Parser.DecomposeQI(target_type.ToString(), loc);
2285 Cast ce = new Cast (cast_type, expr, loc);
2286 ce.IsRuntimeCast = true;
2287 return ce.Resolve (ec);
2292 static public Expression ConvertNothingToDefaultValues (EmitContext ec, Expression expr,
2293 Type target_type, Location loc)
2295 switch (Type.GetTypeCode (target_type)) {
2296 case TypeCode.Boolean :
2297 return new BoolConstant (false);
2298 case TypeCode.Byte :
2299 return new ByteConstant (0);
2300 case TypeCode.Char :
2301 return new CharConstant ((char)0);
2302 case TypeCode.SByte :
2303 return new SByteConstant (0);
2304 case TypeCode.Int16 :
2305 return new ShortConstant (0);
2306 case TypeCode.Int32 :
2307 return new IntConstant (0);
2308 case TypeCode.Int64 :
2309 return new LongConstant (0);
2310 case TypeCode.Decimal :
2311 return new DecimalConstant (System.Decimal.Zero);
2312 case TypeCode.Single :
2313 return new FloatConstant (0.0F);
2314 case TypeCode.Double :
2315 return new DoubleConstant (0.0);
2322 /// Attempts to apply the 'Standard Implicit
2323 /// Conversion' rules to the expression 'expr' into
2324 /// the 'target_type'. It returns a new expression
2325 /// that can be used in a context that expects a
2328 /// This is different from 'ConvertImplicit' in that the
2329 /// user defined implicit conversions are excluded.
2331 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
2332 Type target_type, Location loc)
2334 Type expr_type = expr.Type;
2336 if (expr_type.IsSubclassOf (TypeManager.enum_type))
2337 expr_type = TypeManager.EnumToUnderlying (expr_type);
2341 if (expr is NullLiteral) {
2342 if (target_type == TypeManager.string_type)
2344 e = ConvertNothingToDefaultValues (ec, expr, target_type, loc);
2349 if (expr_type == target_type)
2352 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2357 e = ImplicitReferenceConversion (expr, target_type);
2361 if (expr.Type.IsSubclassOf (TypeManager.enum_type)) {
2362 expr_type = TypeManager.EnumToUnderlying (expr.Type);
2363 expr = new EmptyCast (expr, expr_type);
2364 if (expr_type == target_type)
2366 e = ImplicitNumericConversion (ec, expr, target_type, loc);
2372 if (expr_type.IsPointer){
2373 if (target_type == TypeManager.void_ptr_type)
2374 return new EmptyCast (expr, target_type);
2377 // yep, comparing pointer types cant be done with
2378 // t1 == t2, we have to compare their element types.
2380 if (target_type.IsPointer){
2381 if (target_type.GetElementType()==expr_type.GetElementType())
2386 if (target_type.IsPointer){
2387 if (expr is NullLiteral)
2388 return new EmptyCast (expr, target_type);
2396 /// Attemps to perform an implict constant conversion of the any Numeric Constant
2397 /// into a different data type using casts (See Implicit Constant
2398 /// Expression Conversions)
2400 static protected Expression TryImplicitNumericConversion (Type target_type, Constant ic)
2403 if (ic is BoolConstant) {
2404 bool val = (bool) ((BoolConstant)ic).Value;
2406 if (target_type == TypeManager.byte_type)
2407 value = Byte.MaxValue;
2412 if (ic is IntConstant)
2413 value = (double)((IntConstant)ic).Value;
2415 if (ic is LongConstant)
2416 value = (double) ((LongConstant)ic).Value;
2418 if (ic is FloatConstant) {
2419 value = (double) ((FloatConstant)ic).Value;
2422 if (ic is DoubleConstant) {
2423 value = ((DoubleConstant)ic).Value;
2427 // FIXME: This could return constants instead of EmptyCasts
2429 if (target_type == TypeManager.bool_type){
2431 return new BoolConstant (true);
2432 return new BoolConstant (false);
2433 } else if (target_type == TypeManager.sbyte_type){
2434 if (value >= SByte.MinValue && value <= SByte.MaxValue)
2435 return new SByteConstant ((sbyte) System.Math.Round (value));
2436 } else if (target_type == TypeManager.byte_type){
2437 if (value >= Byte.MinValue && value <= Byte.MaxValue)
2438 return new ByteConstant ((byte) System.Math.Round (value));
2439 } else if (target_type == TypeManager.short_type){
2440 if (value >= Int16.MinValue && value <= Int16.MaxValue)
2441 return new ShortConstant ((short) System.Math.Round (value));
2442 } else if (target_type == TypeManager.ushort_type){
2443 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
2444 return new UShortConstant ((ushort) System.Math.Round (value));
2445 } else if (target_type == TypeManager.int32_type){
2446 if (value >= Int32.MinValue && value <= Int32.MaxValue)
2447 return new IntConstant ((int) System.Math.Round (value));
2448 } else if (target_type == TypeManager.uint32_type){
2450 return new UIntConstant ((uint) System.Math.Round (value));
2451 } else if (target_type == TypeManager.int64_type){
2452 return new LongConstant ((long) System.Math.Round (value));
2453 } else if (target_type == TypeManager.uint64_type){
2455 // we can optimize this case: a positive int32
2456 // always fits on a uint64. But we need an opcode
2460 return new ULongConstant ((ulong)System.Math.Round ( value));
2461 } else if (target_type == TypeManager.float_type){
2462 return new FloatConstant ((float) value);
2463 } else if (target_type == TypeManager.double_type){
2464 return new DoubleConstant ((double) value);
2467 if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
2468 Type underlying = TypeManager.EnumToUnderlying (target_type);
2469 Constant e = (Constant) ic;
2472 // Possibly, we need to create a different 0 literal before passing
2475 if (underlying == TypeManager.int64_type)
2476 e = new LongLiteral (0);
2477 else if (underlying == TypeManager.uint64_type)
2478 e = new ULongLiteral (0);
2480 return new EnumConstant (e, target_type);
2485 static public void Error_CannotConvertImplicit (Location loc, Type source, Type target)
2487 string msg = "Cannot convert implicitly from '"+
2488 TypeManager.MonoBASIC_Name (source) + "' to '" +
2489 TypeManager.MonoBASIC_Name (target) + "'";
2491 throw new Exception (msg);
2493 // Report.Error (30512, loc, msg);
2497 /// Attemptes to implicityly convert 'target' into 'type', using
2498 /// ConvertImplicit. If there is no implicit conversion, then
2499 /// an error is signaled
2501 static public Expression ConvertImplicitRequired (EmitContext ec, Expression source,
2502 Type target_type, Location loc)
2506 e = ConvertImplicit (ec, source, target_type, loc);
2512 if (source is DoubleLiteral && target_type == TypeManager.float_type){
2513 Report.Error (664, loc,
2514 "Double literal cannot be implicitly converted to " +
2515 "float type, use F suffix to create a float literal");
2518 Error_CannotConvertImplicit (loc, source.Type, target_type);
2524 /// Performs the explicit numeric conversions
2526 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr, Type target_type, Location loc)
2528 Type expr_type = expr.Type;
2531 // If we have an enumeration, extract the underlying type,
2532 // use this during the comparison, but wrap around the original
2535 Type real_target_type = target_type;
2537 if (TypeManager.IsEnumType (real_target_type))
2538 real_target_type = TypeManager.EnumToUnderlying (real_target_type);
2540 if (StandardConversionExists (expr, real_target_type)){
2541 Expression ce = ConvertImplicitStandard (ec, expr, real_target_type, loc);
2543 if (real_target_type != target_type)
2544 return new EmptyCast (ce, target_type);
2548 if (expr_type == TypeManager.sbyte_type){
2550 // From sbyte to byte, ushort, uint, ulong, char
2552 if (real_target_type == TypeManager.byte_type)
2553 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1);
2554 if (real_target_type == TypeManager.ushort_type)
2555 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2);
2556 if (real_target_type == TypeManager.uint32_type)
2557 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4);
2558 if (real_target_type == TypeManager.uint64_type)
2559 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8);
2560 if (real_target_type == TypeManager.char_type)
2561 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH);
2562 } else if (expr_type == TypeManager.byte_type){
2564 // From byte to sbyte and char
2566 if (real_target_type == TypeManager.sbyte_type)
2567 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1);
2568 if (real_target_type == TypeManager.char_type)
2569 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH);
2570 } else if (expr_type == TypeManager.short_type){
2572 // From short to sbyte, byte, ushort, uint, ulong, char
2574 if (real_target_type == TypeManager.sbyte_type)
2575 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
2576 if (real_target_type == TypeManager.byte_type)
2577 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1);
2578 if (real_target_type == TypeManager.ushort_type)
2579 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2);
2580 if (real_target_type == TypeManager.uint32_type)
2581 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4);
2582 if (real_target_type == TypeManager.uint64_type)
2583 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8);
2584 if (real_target_type == TypeManager.char_type)
2585 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
2586 } else if (expr_type == TypeManager.ushort_type){
2588 // From ushort to sbyte, byte, short, char
2590 if (real_target_type == TypeManager.sbyte_type)
2591 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1);
2592 if (real_target_type == TypeManager.byte_type)
2593 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1);
2594 if (real_target_type == TypeManager.short_type)
2595 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2);
2596 if (real_target_type == TypeManager.char_type)
2597 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
2598 } else if (expr_type == TypeManager.int32_type){
2600 // From int to sbyte, byte, short, ushort, uint, ulong, char
2602 if (real_target_type == TypeManager.sbyte_type)
2603 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
2604 if (real_target_type == TypeManager.byte_type)
2605 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1);
2606 if (real_target_type == TypeManager.short_type)
2607 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2);
2608 if (real_target_type == TypeManager.ushort_type)
2609 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2);
2610 if (real_target_type == TypeManager.uint32_type)
2611 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4);
2612 if (real_target_type == TypeManager.uint64_type)
2613 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8);
2614 if (real_target_type == TypeManager.char_type)
2615 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
2616 } else if (expr_type == TypeManager.uint32_type){
2618 // From uint to sbyte, byte, short, ushort, int, char
2620 if (real_target_type == TypeManager.sbyte_type)
2621 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1);
2622 if (real_target_type == TypeManager.byte_type)
2623 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1);
2624 if (real_target_type == TypeManager.short_type)
2625 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2);
2626 if (real_target_type == TypeManager.ushort_type)
2627 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2);
2628 if (real_target_type == TypeManager.int32_type)
2629 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4);
2630 if (real_target_type == TypeManager.char_type)
2631 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH);
2632 } else if (expr_type == TypeManager.int64_type){
2634 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
2636 if (real_target_type == TypeManager.sbyte_type)
2637 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
2638 if (real_target_type == TypeManager.byte_type)
2639 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1);
2640 if (real_target_type == TypeManager.short_type)
2641 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2);
2642 if (real_target_type == TypeManager.ushort_type)
2643 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2);
2644 if (real_target_type == TypeManager.int32_type)
2645 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4);
2646 if (real_target_type == TypeManager.uint32_type)
2647 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4);
2648 if (real_target_type == TypeManager.uint64_type)
2649 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8);
2650 if (real_target_type == TypeManager.char_type)
2651 return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH);
2652 } else if (expr_type == TypeManager.uint64_type){
2654 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
2656 if (real_target_type == TypeManager.sbyte_type)
2657 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1);
2658 if (real_target_type == TypeManager.byte_type)
2659 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1);
2660 if (real_target_type == TypeManager.short_type)
2661 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2);
2662 if (real_target_type == TypeManager.ushort_type)
2663 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2);
2664 if (real_target_type == TypeManager.int32_type)
2665 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4);
2666 if (real_target_type == TypeManager.uint32_type)
2667 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4);
2668 if (real_target_type == TypeManager.int64_type)
2669 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8);
2670 if (real_target_type == TypeManager.char_type)
2671 return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH);
2672 } else if (expr_type == TypeManager.char_type){
2674 // From char to sbyte, byte, short
2676 if (real_target_type == TypeManager.sbyte_type)
2677 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1);
2678 if (real_target_type == TypeManager.byte_type)
2679 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1);
2680 if (real_target_type == TypeManager.short_type)
2681 return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2);
2682 } else if (expr_type == TypeManager.float_type){
2684 // From float to sbyte, byte, short,
2685 // ushort, int, uint, long, ulong, char
2688 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2689 if (real_target_type == TypeManager.sbyte_type)
2690 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I1);
2691 if (real_target_type == TypeManager.byte_type)
2692 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U1);
2693 if (real_target_type == TypeManager.short_type)
2694 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I2);
2695 if (real_target_type == TypeManager.ushort_type)
2696 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U2);
2697 if (real_target_type == TypeManager.int32_type)
2698 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I4);
2699 if (real_target_type == TypeManager.uint32_type)
2700 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U4);
2701 if (real_target_type == TypeManager.int64_type)
2702 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_I8);
2703 if (real_target_type == TypeManager.uint64_type)
2704 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_U8);
2705 if (real_target_type == TypeManager.char_type)
2706 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R4_CH);
2707 } else if (expr_type == TypeManager.double_type){
2709 // From double to byte, byte, short,
2710 // ushort, int, uint, long, ulong,
2711 // char, float or decimal
2713 Expression rounded_expr = RTConversionExpression(ec, "System.Math",".Round" , expr, loc);
2714 if (real_target_type == TypeManager.sbyte_type)
2715 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I1);
2716 if (real_target_type == TypeManager.byte_type)
2717 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U1);
2718 if (real_target_type == TypeManager.short_type)
2719 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I2);
2720 if (real_target_type == TypeManager.ushort_type)
2721 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U2);
2722 if (real_target_type == TypeManager.int32_type)
2723 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I4);
2724 if (real_target_type == TypeManager.uint32_type)
2725 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U4);
2726 if (real_target_type == TypeManager.int64_type)
2727 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_I8);
2728 if (real_target_type == TypeManager.uint64_type)
2729 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_U8);
2730 if (real_target_type == TypeManager.char_type)
2731 return new ConvCast (ec, rounded_expr, target_type, ConvCast.Mode.R8_CH);
2732 if (real_target_type == TypeManager.float_type)
2733 return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4);
2736 // decimal is taken care of by the op_Explicit methods.
2742 /// Returns whether an explicit reference conversion can be performed
2743 /// from source_type to target_type
2745 public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
2747 bool target_is_value_type = target_type.IsValueType;
2749 if (source_type == target_type)
2753 // From object to any reference type
2755 if (source_type == TypeManager.object_type && !target_is_value_type)
2759 // From any class S to any class-type T, provided S is a base class of T
2761 if (target_type.IsSubclassOf (source_type))
2765 // From any interface type S to any interface T provided S is not derived from T
2767 if (source_type.IsInterface && target_type.IsInterface){
2768 if (!target_type.IsSubclassOf (source_type))
2773 // From any class type S to any interface T, provided S is not sealed
2774 // and provided S does not implement T.
2776 if (target_type.IsInterface && !source_type.IsSealed &&
2777 !TypeManager.ImplementsInterface (source_type, target_type))
2781 // From any interface-type S to to any class type T, provided T is not
2782 // sealed, or provided T implements S.
2784 if (source_type.IsInterface &&
2785 (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type)))
2789 // From an array type S with an element type Se to an array type T with an
2790 // element type Te provided all the following are true:
2791 // * S and T differe only in element type, in other words, S and T
2792 // have the same number of dimensions.
2793 // * Both Se and Te are reference types
2794 // * An explicit referenc conversions exist from Se to Te
2796 if (source_type.IsArray && target_type.IsArray) {
2797 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2799 Type source_element_type = source_type.GetElementType ();
2800 Type target_element_type = target_type.GetElementType ();
2802 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2803 if (ExplicitReferenceConversionExists (source_element_type,
2804 target_element_type))
2810 // From System.Array to any array-type
2811 if (source_type == TypeManager.array_type &&
2812 target_type.IsArray){
2817 // From System delegate to any delegate-type
2819 if (source_type == TypeManager.delegate_type &&
2820 target_type.IsSubclassOf (TypeManager.delegate_type))
2824 // From ICloneable to Array or Delegate types
2826 if (source_type == TypeManager.icloneable_type &&
2827 (target_type == TypeManager.array_type ||
2828 target_type == TypeManager.delegate_type))
2835 /// Implements Explicit Reference conversions
2837 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
2839 Type source_type = source.Type;
2840 bool target_is_value_type = target_type.IsValueType;
2843 // From object to any reference type
2845 if (source_type == TypeManager.object_type && !target_is_value_type)
2846 return new ClassCast (source, target_type);
2850 // From any class S to any class-type T, provided S is a base class of T
2852 if (target_type.IsSubclassOf (source_type))
2853 return new ClassCast (source, target_type);
2856 // From any interface type S to any interface T provided S is not derived from T
2858 if (source_type.IsInterface && target_type.IsInterface){
2859 if (TypeManager.ImplementsInterface (source_type, target_type))
2862 return new ClassCast (source, target_type);
2866 // From any class type S to any interface T, provides S is not sealed
2867 // and provided S does not implement T.
2869 if (target_type.IsInterface && !source_type.IsSealed) {
2870 if (TypeManager.ImplementsInterface (source_type, target_type))
2873 return new ClassCast (source, target_type);
2878 // From any interface-type S to to any class type T, provided T is not
2879 // sealed, or provided T implements S.
2881 if (source_type.IsInterface) {
2882 if (!target_type.IsSealed || TypeManager.ImplementsInterface (target_type, source_type))
2883 return new ClassCast (source, target_type);
2888 // From an array type S with an element type Se to an array type T with an
2889 // element type Te provided all the following are true:
2890 // * S and T differe only in element type, in other words, S and T
2891 // have the same number of dimensions.
2892 // * Both Se and Te are reference types
2893 // * An explicit referenc conversions exist from Se to Te
2895 if (source_type.IsArray && target_type.IsArray) {
2896 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
2898 Type source_element_type = source_type.GetElementType ();
2899 Type target_element_type = target_type.GetElementType ();
2901 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
2902 if (ExplicitReferenceConversionExists (source_element_type,
2903 target_element_type))
2904 return new ClassCast (source, target_type);
2909 // From System.Array to any array-type
2910 if (source_type == TypeManager.array_type &&
2911 target_type.IsArray) {
2912 return new ClassCast (source, target_type);
2916 // From System delegate to any delegate-type
2918 if (source_type == TypeManager.delegate_type &&
2919 target_type.IsSubclassOf (TypeManager.delegate_type))
2920 return new ClassCast (source, target_type);
2923 // From ICloneable to Array or Delegate types
2925 if (source_type == TypeManager.icloneable_type &&
2926 (target_type == TypeManager.array_type ||
2927 target_type == TypeManager.delegate_type))
2928 return new ClassCast (source, target_type);
2934 /// Performs an explicit conversion of the expression 'expr' whose
2935 /// type is expr.Type to 'target_type'.
2937 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
2938 Type target_type, bool runtimeconv, Location loc)
2940 Type expr_type = expr.Type;
2941 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
2946 ne = ConvertNumericExplicit (ec, expr, target_type, loc);
2951 // Unboxing conversion.
2953 if (expr_type == TypeManager.object_type && target_type.IsValueType)
2954 return new UnboxCast (expr, target_type);
2959 if (expr_type.IsSubclassOf (TypeManager.enum_type)) {
2963 // FIXME: Is there any reason we should have EnumConstant
2964 // dealt with here instead of just using always the
2965 // UnderlyingSystemType to wrap the type?
2967 if (expr is EnumConstant)
2968 e = ((EnumConstant) expr).Child;
2970 e = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type));
2973 Expression t = ConvertImplicit (ec, e, target_type, loc);
2977 t = ConvertNumericExplicit (ec, e, target_type, loc);
2981 t = NarrowingConversion (ec, e, target_type, loc);
2985 Error_CannotConvertType (loc, expr_type, target_type);
2989 ne = ConvertReferenceExplicit (expr, target_type);
2994 if (target_type.IsPointer){
2995 if (expr_type.IsPointer)
2996 return new EmptyCast (expr, target_type);
2998 if (expr_type == TypeManager.sbyte_type ||
2999 expr_type == TypeManager.byte_type ||
3000 expr_type == TypeManager.short_type ||
3001 expr_type == TypeManager.ushort_type ||
3002 expr_type == TypeManager.int32_type ||
3003 expr_type == TypeManager.uint32_type ||
3004 expr_type == TypeManager.uint64_type ||
3005 expr_type == TypeManager.int64_type)
3006 return new OpcodeCast (expr, target_type, OpCodes.Conv_U);
3008 if (expr_type.IsPointer){
3009 if (target_type == TypeManager.sbyte_type ||
3010 target_type == TypeManager.byte_type ||
3011 target_type == TypeManager.short_type ||
3012 target_type == TypeManager.ushort_type ||
3013 target_type == TypeManager.int32_type ||
3014 target_type == TypeManager.uint32_type ||
3015 target_type == TypeManager.uint64_type ||
3016 target_type == TypeManager.int64_type){
3017 Expression e = new EmptyCast (expr, TypeManager.uint32_type);
3020 ci = ConvertImplicitStandard (ec, e, target_type, loc);
3025 ce = ConvertNumericExplicit (ec, e, target_type, loc);
3029 // We should always be able to go from an uint32
3030 // implicitly or explicitly to the other integral
3033 throw new Exception ("Internal compiler error");
3038 ne = ExplicitUserConversion (ec, expr, target_type, loc);
3042 if (!(runtimeconv)) {
3043 ne = NarrowingConversion (ec, expr, target_type, loc);
3047 Error_CannotConvertType (loc, expr_type, target_type);
3053 /// Same as ConvertExplicit, only it doesn't include user defined conversions
3055 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
3056 Type target_type, Location l)
3058 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
3063 ne = ConvertNumericExplicit (ec, expr, target_type, l);
3067 ne = ConvertReferenceExplicit (expr, target_type);
3071 ne = NarrowingConversion (ec, expr, target_type, l);
3075 Error_CannotConvertType (l, expr.Type, target_type);
3079 static string ExprClassName (ExprClass c)
3082 case ExprClass.Invalid:
3084 case ExprClass.Value:
3086 case ExprClass.Variable:
3088 case ExprClass.Namespace:
3090 case ExprClass.Type:
3092 case ExprClass.MethodGroup:
3093 return "method group";
3094 case ExprClass.PropertyAccess:
3095 return "property access";
3096 case ExprClass.EventAccess:
3097 return "event access";
3098 case ExprClass.IndexerAccess:
3099 return "indexer access";
3100 case ExprClass.Nothing:
3103 throw new Exception ("Should not happen");
3107 /// Reports that we were expecting 'expr' to be of class 'expected'
3109 public void Error118 (string expected)
3111 string kind = "Unknown";
3113 kind = ExprClassName (eclass);
3115 Error (118, "Expression denotes a '" + kind +
3116 "' where a '" + expected + "' was expected");
3119 public void Error118 (ResolveFlags flags)
3121 ArrayList valid = new ArrayList (10);
3123 if ((flags & ResolveFlags.VariableOrValue) != 0) {
3124 valid.Add ("variable");
3125 valid.Add ("value");
3128 if ((flags & ResolveFlags.Type) != 0)
3131 if ((flags & ResolveFlags.MethodGroup) != 0)
3132 valid.Add ("method group");
3134 if ((flags & ResolveFlags.SimpleName) != 0)
3135 valid.Add ("simple name");
3137 if (valid.Count == 0)
3138 valid.Add ("unknown");
3140 StringBuilder sb = new StringBuilder ();
3141 for (int i = 0; i < valid.Count; i++) {
3144 else if (i == valid.Count)
3146 sb.Append (valid [i]);
3149 string kind = ExprClassName (eclass);
3151 Error (119, "Expression denotes a '" + kind + "' where " +
3152 "a '" + sb.ToString () + "' was expected");
3155 static void Error_ConstantValueCannotBeConverted (Location l, string val, Type t)
3157 Report.Error (31, l, "Constant value '" + val + "' cannot be converted to " +
3158 TypeManager.MonoBASIC_Name (t));
3161 public static void UnsafeError (Location loc)
3163 Report.Error (214, loc, "Pointers may only be used in an unsafe context");
3167 /// Converts the IntConstant, UIntConstant, LongConstant or
3168 /// ULongConstant,Double into the integral target_type. Notice
3169 /// that we do not return an 'Expression' we do return
3170 /// a boxed integral type.
3172 /// FIXME: Since I added the new constants, we need to
3173 /// also support conversions from CharConstant, ByteConstant,
3174 /// SByteConstant, UShortConstant, ShortConstant
3176 /// This is used by the switch statement, so the domain
3177 /// of work is restricted to the literals above, and the
3178 /// targets are int32, uint32, char, byte, sbyte, ushort,
3179 /// short, uint64 and int64
3181 public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
3185 if (c.Type == target_type)
3186 return ((Constant) c).GetValue ();
3189 // Make into one of the literals we handle, we dont really care
3190 // about this value as we will just return a few limited types
3192 if (c is EnumConstant)
3193 c = ((EnumConstant)c).WidenToCompilerConstant ();
3195 if (c is IntConstant){
3196 int v = ((IntConstant) c).Value;
3198 if (target_type == TypeManager.uint32_type){
3201 } else if (target_type == TypeManager.char_type){
3202 if (v >= Char.MinValue && v <= Char.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 >= SByte.MinValue && v <= SByte.MaxValue)
3210 } else if (target_type == TypeManager.short_type){
3211 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3213 } else if (target_type == TypeManager.ushort_type){
3214 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3216 } else if (target_type == TypeManager.int64_type)
3218 else if (target_type == TypeManager.uint64_type){
3224 } else if (c is UIntConstant){
3225 uint v = ((UIntConstant) c).Value;
3227 if (target_type == TypeManager.int32_type){
3228 if (v <= Int32.MaxValue)
3230 } else if (target_type == TypeManager.char_type){
3231 if (v >= Char.MinValue && v <= Char.MaxValue)
3233 } else if (target_type == TypeManager.byte_type){
3234 if (v <= Byte.MaxValue)
3236 } else if (target_type == TypeManager.sbyte_type){
3237 if (v <= SByte.MaxValue)
3239 } else if (target_type == TypeManager.short_type){
3240 if (v <= UInt16.MaxValue)
3242 } else if (target_type == TypeManager.ushort_type){
3243 if (v <= UInt16.MaxValue)
3245 } else if (target_type == TypeManager.int64_type)
3247 else if (target_type == TypeManager.uint64_type)
3250 } else if (c is LongConstant){
3251 long v = ((LongConstant) c).Value;
3253 if (target_type == TypeManager.int32_type){
3254 if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
3256 } else if (target_type == TypeManager.uint32_type){
3257 if (v >= 0 && v <= UInt32.MaxValue)
3259 } else if (target_type == TypeManager.char_type){
3260 if (v >= Char.MinValue && v <= Char.MaxValue)
3262 } else if (target_type == TypeManager.byte_type){
3263 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3265 } else if (target_type == TypeManager.sbyte_type){
3266 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3268 } else if (target_type == TypeManager.short_type){
3269 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
3271 } else if (target_type == TypeManager.ushort_type){
3272 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3274 } else if (target_type == TypeManager.uint64_type){
3279 } else if (c is ULongConstant){
3280 ulong v = ((ULongConstant) c).Value;
3282 if (target_type == TypeManager.int32_type){
3283 if (v <= Int32.MaxValue)
3285 } else if (target_type == TypeManager.uint32_type){
3286 if (v <= UInt32.MaxValue)
3288 } else if (target_type == TypeManager.char_type){
3289 if (v >= Char.MinValue && v <= Char.MaxValue)
3291 } else if (target_type == TypeManager.byte_type){
3292 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3294 } else if (target_type == TypeManager.sbyte_type){
3295 if (v <= (int) SByte.MaxValue)
3297 } else if (target_type == TypeManager.short_type){
3298 if (v <= UInt16.MaxValue)
3300 } else if (target_type == TypeManager.ushort_type){
3301 if (v <= UInt16.MaxValue)
3303 } else if (target_type == TypeManager.int64_type){
3304 if (v <= Int64.MaxValue)
3308 } else if (c is ByteConstant){
3309 byte v = ((ByteConstant) c).Value;
3311 if (target_type == TypeManager.int32_type)
3313 else if (target_type == TypeManager.uint32_type)
3315 else if (target_type == TypeManager.char_type)
3317 else if (target_type == TypeManager.sbyte_type){
3318 if (v <= SByte.MaxValue)
3320 } else if (target_type == TypeManager.short_type)
3322 else if (target_type == TypeManager.ushort_type)
3324 else if (target_type == TypeManager.int64_type)
3326 else if (target_type == TypeManager.uint64_type)
3329 } else if (c is SByteConstant){
3330 sbyte v = ((SByteConstant) c).Value;
3332 if (target_type == TypeManager.int32_type)
3334 else if (target_type == TypeManager.uint32_type){
3337 } else if (target_type == TypeManager.char_type){
3340 } else if (target_type == TypeManager.byte_type){
3343 } else if (target_type == TypeManager.short_type)
3345 else if (target_type == TypeManager.ushort_type){
3348 } else if (target_type == TypeManager.int64_type)
3350 else if (target_type == TypeManager.uint64_type){
3355 } else if (c is ShortConstant){
3356 short v = ((ShortConstant) c).Value;
3358 if (target_type == TypeManager.int32_type){
3360 } else if (target_type == TypeManager.uint32_type){
3363 } else if (target_type == TypeManager.char_type){
3366 } else if (target_type == TypeManager.byte_type){
3367 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3369 } else if (target_type == TypeManager.sbyte_type){
3370 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3372 } else if (target_type == TypeManager.ushort_type){
3375 } else if (target_type == TypeManager.int64_type)
3377 else if (target_type == TypeManager.uint64_type)
3381 } else if (c is UShortConstant){
3382 ushort v = ((UShortConstant) c).Value;
3384 if (target_type == TypeManager.int32_type)
3386 else if (target_type == TypeManager.uint32_type)
3388 else if (target_type == TypeManager.char_type){
3389 if (v >= Char.MinValue && v <= Char.MaxValue)
3391 } else if (target_type == TypeManager.byte_type){
3392 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3394 } else if (target_type == TypeManager.sbyte_type){
3395 if (v <= SByte.MaxValue)
3397 } else if (target_type == TypeManager.short_type){
3398 if (v <= Int16.MaxValue)
3400 } else if (target_type == TypeManager.int64_type)
3402 else if (target_type == TypeManager.uint64_type)
3406 } else if (c is CharConstant){
3407 char v = ((CharConstant) c).Value;
3409 if (target_type == TypeManager.int32_type)
3411 else if (target_type == TypeManager.uint32_type)
3413 else if (target_type == TypeManager.byte_type){
3414 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3416 } else if (target_type == TypeManager.sbyte_type){
3417 if (v <= SByte.MaxValue)
3419 } else if (target_type == TypeManager.short_type){
3420 if (v <= Int16.MaxValue)
3422 } else if (target_type == TypeManager.ushort_type)
3424 else if (target_type == TypeManager.int64_type)
3426 else if (target_type == TypeManager.uint64_type)
3431 } else if (c is DoubleConstant){
3432 double v = ((DoubleConstant) c).Value;
3434 if (target_type == TypeManager.sbyte_type){
3435 if (v >= SByte.MinValue && v <= SByte.MaxValue)
3436 return new SByteConstant ((sbyte) System.Math.Round (v));
3437 } else if (target_type == TypeManager.byte_type){
3438 if (v >= Byte.MinValue && v <= Byte.MaxValue)
3439 return new ByteConstant ((byte) System.Math.Round (v));
3440 } else if (target_type == TypeManager.char_type){
3441 if (v >= Char.MinValue && v <= Char.MaxValue)
3443 } else if (target_type == TypeManager.short_type){
3444 if (v >= Int16.MinValue && v <= Int16.MaxValue)
3445 return new ShortConstant ((short) System.Math.Round (v));
3446 } else if (target_type == TypeManager.ushort_type){
3447 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
3448 return new UShortConstant ((ushort) System.Math.Round (v));
3449 } else if (target_type == TypeManager.int32_type){
3450 if (v >= Int32.MinValue && v <= Int32.MaxValue)
3451 return new IntConstant ((int) System.Math.Round (v));
3452 } else if (target_type == TypeManager.uint32_type){
3453 if (v >= 0 && v <= UInt32.MaxValue)
3454 return new UIntConstant ((uint) System.Math.Round (v));
3455 } else if (target_type == TypeManager.uint64_type){
3457 return new ULongConstant ((ulong) System.Math.Round (v));
3462 Error_ConstantValueCannotBeConverted (loc, s, target_type);
3467 // Load the object from the pointer.
3469 public static void LoadFromPtr (ILGenerator ig, Type t)
3471 if (t == TypeManager.int32_type)
3472 ig.Emit (OpCodes.Ldind_I4);
3473 else if (t == TypeManager.uint32_type)
3474 ig.Emit (OpCodes.Ldind_U4);
3475 else if (t == TypeManager.short_type)
3476 ig.Emit (OpCodes.Ldind_I2);
3477 else if (t == TypeManager.ushort_type)
3478 ig.Emit (OpCodes.Ldind_U2);
3479 else if (t == TypeManager.char_type)
3480 ig.Emit (OpCodes.Ldind_U2);
3481 else if (t == TypeManager.byte_type)
3482 ig.Emit (OpCodes.Ldind_U1);
3483 else if (t == TypeManager.sbyte_type)
3484 ig.Emit (OpCodes.Ldind_I1);
3485 else if (t == TypeManager.uint64_type)
3486 ig.Emit (OpCodes.Ldind_I8);
3487 else if (t == TypeManager.int64_type)
3488 ig.Emit (OpCodes.Ldind_I8);
3489 else if (t == TypeManager.float_type)
3490 ig.Emit (OpCodes.Ldind_R4);
3491 else if (t == TypeManager.double_type)
3492 ig.Emit (OpCodes.Ldind_R8);
3493 else if (t == TypeManager.bool_type)
3494 ig.Emit (OpCodes.Ldind_I1);
3495 else if (t == TypeManager.intptr_type)
3496 ig.Emit (OpCodes.Ldind_I);
3497 else if (TypeManager.IsEnumType (t)) {
3498 if (t == TypeManager.enum_type)
3499 ig.Emit (OpCodes.Ldind_Ref);
3501 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
3502 } else if (t.IsValueType)
3503 ig.Emit (OpCodes.Ldobj, t);
3505 ig.Emit (OpCodes.Ldind_Ref);
3509 // The stack contains the pointer and the value of type 'type'
3511 public static void StoreFromPtr (ILGenerator ig, Type type)
3513 if (TypeManager.IsEnumType (type))
3514 type = TypeManager.EnumToUnderlying (type);
3515 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
3516 ig.Emit (OpCodes.Stind_I4);
3517 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
3518 ig.Emit (OpCodes.Stind_I8);
3519 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
3520 type == TypeManager.ushort_type)
3521 ig.Emit (OpCodes.Stind_I2);
3522 else if (type == TypeManager.float_type)
3523 ig.Emit (OpCodes.Stind_R4);
3524 else if (type == TypeManager.double_type)
3525 ig.Emit (OpCodes.Stind_R8);
3526 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
3527 type == TypeManager.bool_type)
3528 ig.Emit (OpCodes.Stind_I1);
3529 else if (type == TypeManager.intptr_type)
3530 ig.Emit (OpCodes.Stind_I);
3531 else if (type.IsValueType)
3532 ig.Emit (OpCodes.Stobj, type);
3534 ig.Emit (OpCodes.Stind_Ref);
3538 // Returns the size of type 't' if known, otherwise, 0
3540 public static int GetTypeSize (Type t)
3542 t = TypeManager.TypeToCoreType (t);
3543 if (t == TypeManager.int32_type ||
3544 t == TypeManager.uint32_type ||
3545 t == TypeManager.float_type)
3547 else if (t == TypeManager.int64_type ||
3548 t == TypeManager.uint64_type ||
3549 t == TypeManager.double_type)
3551 else if (t == TypeManager.byte_type ||
3552 t == TypeManager.sbyte_type ||
3553 t == TypeManager.bool_type)
3555 else if (t == TypeManager.short_type ||
3556 t == TypeManager.char_type ||
3557 t == TypeManager.ushort_type)
3559 else if (t == TypeManager.decimal_type)
3566 // Default implementation of IAssignMethod.CacheTemporaries
3568 public void CacheTemporaries (EmitContext ec)
3572 static void Error_NegativeArrayIndex (Location loc)
3574 Report.Error (284, loc, "Can not create array with a negative size");
3578 // Converts 'source' to an int, uint, long or ulong.
3580 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
3584 bool old_checked = ec.CheckState;
3585 ec.CheckState = true;
3587 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
3588 if (target == null){
3589 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
3590 if (target == null){
3591 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
3592 if (target == null){
3593 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
3595 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
3599 ec.CheckState = old_checked;
3602 // Only positive constants are allowed at compile time
3604 if (target is Constant){
3605 if (target is IntConstant){
3606 if (((IntConstant) target).Value < 0){
3607 Error_NegativeArrayIndex (loc);
3612 if (target is LongConstant){
3613 if (((LongConstant) target).Value < 0){
3614 Error_NegativeArrayIndex (loc);
3627 /// This is just a base class for expressions that can
3628 /// appear on statements (invocations, object creation,
3629 /// assignments, post/pre increment and decrement). The idea
3630 /// being that they would support an extra Emition interface that
3631 /// does not leave a result on the stack.
3633 public abstract class ExpressionStatement : Expression {
3636 /// Requests the expression to be emitted in a 'statement'
3637 /// context. This means that no new value is left on the
3638 /// stack after invoking this method (constrasted with
3639 /// Emit that will always leave a value on the stack).
3641 public abstract void EmitStatement (EmitContext ec);
3645 /// This kind of cast is used to encapsulate the child
3646 /// whose type is child.Type into an expression that is
3647 /// reported to return "return_type". This is used to encapsulate
3648 /// expressions which have compatible types, but need to be dealt
3649 /// at higher levels with.
3651 /// For example, a "byte" expression could be encapsulated in one
3652 /// of these as an "unsigned int". The type for the expression
3653 /// would be "unsigned int".
3656 public class EmptyCast : Expression {
3657 protected Expression child;
3659 public EmptyCast (Expression child, Type return_type)
3661 eclass = child.eclass;
3666 public override Expression DoResolve (EmitContext ec)
3668 // This should never be invoked, we are born in fully
3669 // initialized state.
3674 public override void Emit (EmitContext ec)
3681 /// This class is used to wrap literals which belong inside Enums
3683 public class EnumConstant : Constant {
3684 public Constant Child;
3686 public EnumConstant (Constant child, Type enum_type)
3688 eclass = child.eclass;
3693 public override Expression DoResolve (EmitContext ec)
3695 // This should never be invoked, we are born in fully
3696 // initialized state.
3701 public override void Emit (EmitContext ec)
3706 public override object GetValue ()
3708 return Child.GetValue ();
3712 // Converts from one of the valid underlying types for an enumeration
3713 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
3714 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
3716 public Constant WidenToCompilerConstant ()
3718 Type t = TypeManager.EnumToUnderlying (Child.Type);
3719 object v = ((Constant) Child).GetValue ();;
3721 if (t == TypeManager.int32_type)
3722 return new IntConstant ((int) v);
3723 if (t == TypeManager.uint32_type)
3724 return new UIntConstant ((uint) v);
3725 if (t == TypeManager.int64_type)
3726 return new LongConstant ((long) v);
3727 if (t == TypeManager.uint64_type)
3728 return new ULongConstant ((ulong) v);
3729 if (t == TypeManager.short_type)
3730 return new ShortConstant ((short) v);
3731 if (t == TypeManager.ushort_type)
3732 return new UShortConstant ((ushort) v);
3733 if (t == TypeManager.byte_type)
3734 return new ByteConstant ((byte) v);
3735 if (t == TypeManager.sbyte_type)
3736 return new SByteConstant ((sbyte) v);
3738 throw new Exception ("Invalid enumeration underlying type: " + t);
3742 // Extracts the value in the enumeration on its native representation
3744 public object GetPlainValue ()
3746 Type t = TypeManager.EnumToUnderlying (Child.Type);
3747 object v = ((Constant) Child).GetValue ();;
3749 if (t == TypeManager.int32_type)
3751 if (t == TypeManager.uint32_type)
3753 if (t == TypeManager.int64_type)
3755 if (t == TypeManager.uint64_type)
3757 if (t == TypeManager.short_type)
3759 if (t == TypeManager.ushort_type)
3761 if (t == TypeManager.byte_type)
3763 if (t == TypeManager.sbyte_type)
3769 public override string AsString ()
3771 return Child.AsString ();
3774 public override DoubleConstant ConvertToDouble ()
3776 return Child.ConvertToDouble ();
3779 public override FloatConstant ConvertToFloat ()
3781 return Child.ConvertToFloat ();
3784 public override ULongConstant ConvertToULong ()
3786 return Child.ConvertToULong ();
3789 public override LongConstant ConvertToLong ()
3791 return Child.ConvertToLong ();
3794 public override UIntConstant ConvertToUInt ()
3796 return Child.ConvertToUInt ();
3799 public override IntConstant ConvertToInt ()
3801 return Child.ConvertToInt ();
3806 /// This kind of cast is used to encapsulate Value Types in objects.
3808 /// The effect of it is to box the value type emitted by the previous
3811 public class BoxedCast : EmptyCast {
3813 public BoxedCast (Expression expr)
3814 : base (expr, TypeManager.object_type)
3818 public override Expression DoResolve (EmitContext ec)
3820 // This should never be invoked, we are born in fully
3821 // initialized state.
3826 public override void Emit (EmitContext ec)
3830 ec.ig.Emit (OpCodes.Box, child.Type);
3834 public class UnboxCast : EmptyCast {
3835 public UnboxCast (Expression expr, Type return_type)
3836 : base (expr, return_type)
3840 public override Expression DoResolve (EmitContext ec)
3842 // This should never be invoked, we are born in fully
3843 // initialized state.
3848 public override void Emit (EmitContext ec)
3851 ILGenerator ig = ec.ig;
3854 ig.Emit (OpCodes.Unbox, t);
3856 LoadFromPtr (ig, t);
3861 /// This is used to perform explicit numeric conversions.
3863 /// Explicit numeric conversions might trigger exceptions in a checked
3864 /// context, so they should generate the conv.ovf opcodes instead of
3867 public class ConvCast : EmptyCast {
3868 public enum Mode : byte {
3869 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
3871 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
3872 U2_I1, U2_U1, U2_I2, U2_CH,
3873 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
3874 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
3875 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
3876 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
3877 CH_I1, CH_U1, CH_I2,
3878 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
3879 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
3885 public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
3886 : base (child, return_type)
3888 checked_state = ec.CheckState;
3892 public override Expression DoResolve (EmitContext ec)
3894 // This should never be invoked, we are born in fully
3895 // initialized state.
3900 public override void Emit (EmitContext ec)
3902 ILGenerator ig = ec.ig;
3908 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3909 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3910 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3911 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3912 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3914 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3915 case Mode.U1_CH: /* nothing */ break;
3917 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3918 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3919 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3920 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3921 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3922 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3924 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3925 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3926 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3927 case Mode.U2_CH: /* nothing */ break;
3929 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3930 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3931 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3932 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3933 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3934 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3935 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3937 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3938 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3939 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3940 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3941 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3942 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3944 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3945 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3946 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3947 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3948 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3949 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3950 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3951 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3953 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3954 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3955 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3956 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3957 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
3958 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
3959 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
3960 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
3962 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
3963 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
3964 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
3966 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3967 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3968 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3969 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3970 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3971 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3972 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3973 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3974 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3976 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
3977 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
3978 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
3979 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3980 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
3981 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
3982 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
3983 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
3984 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
3985 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
3989 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
3990 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
3991 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
3992 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
3993 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
3995 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
3996 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
3998 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
3999 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
4000 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
4001 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
4002 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
4003 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
4005 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
4006 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
4007 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
4008 case Mode.U2_CH: /* nothing */ break;
4010 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
4011 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
4012 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
4013 case Mode.I4_U4: /* nothing */ break;
4014 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
4015 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
4016 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
4018 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
4019 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
4020 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
4021 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
4022 case Mode.U4_I4: /* nothing */ break;
4023 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
4025 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
4026 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
4027 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
4028 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
4029 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
4030 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
4031 case Mode.I8_U8: /* nothing */ break;
4032 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
4034 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
4035 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
4036 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
4037 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
4038 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
4039 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
4040 case Mode.U8_I8: /* nothing */ break;
4041 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
4043 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
4044 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
4045 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
4047 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
4048 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
4049 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
4050 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
4051 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
4052 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
4053 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
4054 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
4055 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
4057 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
4058 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
4059 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
4060 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
4061 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
4062 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
4063 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
4064 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
4065 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
4066 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
4072 public class OpcodeCast : EmptyCast {
4076 public OpcodeCast (Expression child, Type return_type, OpCode op)
4077 : base (child, return_type)
4081 second_valid = false;
4084 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
4085 : base (child, return_type)
4090 second_valid = true;
4093 public override Expression DoResolve (EmitContext ec)
4095 // This should never be invoked, we are born in fully
4096 // initialized state.
4101 public override void Emit (EmitContext ec)
4112 public class NumericToBoolCast : EmptyCast
4116 public NumericToBoolCast (Expression src, Type src_type)
4117 : base (src, TypeManager.bool_type)
4120 this.src_type = src_type;
4123 public override Expression DoResolve (EmitContext ec)
4128 public override void Emit (EmitContext ec)
4132 if (src_type == TypeManager.byte_type ||
4133 src_type == TypeManager.short_type ||
4134 src_type == TypeManager.int32_type) {
4136 ec.ig.Emit (OpCodes.Ldc_I4_0);
4137 ec.ig.Emit (OpCodes.Cgt_Un);
4141 if (src_type == TypeManager.int64_type) {
4142 ec.ig.Emit (OpCodes.Ldc_I8, (long) 0);
4143 ec.ig.Emit (OpCodes.Cgt_Un);
4147 if (src_type == TypeManager.float_type) {
4148 ec.ig.Emit (OpCodes.Ldc_R4, (float) 0);
4149 ec.ig.Emit (OpCodes.Ceq);
4150 ec.ig.Emit (OpCodes.Ldc_I4_0);
4151 ec.ig.Emit (OpCodes.Ceq);
4155 if (src_type == TypeManager.double_type) {
4156 ec.ig.Emit (OpCodes.Ldc_R8, (double) 0);
4157 ec.ig.Emit (OpCodes.Ceq);
4158 ec.ig.Emit (OpCodes.Ldc_I4_0);
4159 ec.ig.Emit (OpCodes.Ceq);
4165 public class BoolToNumericCast : EmptyCast
4170 public BoolToNumericCast (Expression src, Type target_type)
4171 : base (src, target_type)
4174 this.target_type = target_type;
4177 public override Expression DoResolve (EmitContext ec)
4182 public override void Emit (EmitContext ec)
4186 if (target_type == TypeManager.byte_type) {
4187 conv = OpCodes.Conv_U1;
4188 } else if (target_type == TypeManager.short_type) {
4189 conv = OpCodes.Conv_I2;
4190 } else if (target_type == TypeManager.int32_type) {
4191 conv = OpCodes.Conv_I4;
4192 } else if (target_type == TypeManager.int64_type) {
4193 conv = OpCodes.Conv_I8;
4194 } else if (target_type == TypeManager.float_type) {
4195 conv = OpCodes.Conv_R4;
4196 } else if (target_type == TypeManager.double_type) {
4197 conv = OpCodes.Conv_R8;
4200 ec.ig.Emit (OpCodes.Ldc_I4_0);
4201 ec.ig.Emit (OpCodes.Cgt_Un);
4202 ec.ig.Emit (OpCodes.Neg);
4209 /// This kind of cast is used to encapsulate a child and cast it
4210 /// to the class requested
4212 public class ClassCast : EmptyCast {
4213 public ClassCast (Expression child, Type return_type)
4214 : base (child, return_type)
4219 public override Expression DoResolve (EmitContext ec)
4221 // This should never be invoked, we are born in fully
4222 // initialized state.
4227 public override void Emit (EmitContext ec)
4231 ec.ig.Emit (OpCodes.Castclass, type);
4237 /// SimpleName expressions are initially formed of a single
4238 /// word and it only happens at the beginning of the expression.
4242 /// The expression will try to be bound to a Field, a Method
4243 /// group or a Property. If those fail we pass the name to our
4244 /// caller and the SimpleName is compounded to perform a type
4245 /// lookup. The idea behind this process is that we want to avoid
4246 /// creating a namespace map from the assemblies, as that requires
4247 /// the GetExportedTypes function to be called and a hashtable to
4248 /// be constructed which reduces startup time. If later we find
4249 /// that this is slower, we should create a 'NamespaceExpr' expression
4250 /// that fully participates in the resolution process.
4252 /// For example 'System.Console.WriteLine' is decomposed into
4253 /// MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
4255 /// The first SimpleName wont produce a match on its own, so it will
4257 /// MemberAccess (SimpleName ("System.Console"), "WriteLine").
4259 /// System.Console will produce a TypeExpr match.
4261 /// The downside of this is that we might be hitting 'LookupType' too many
4262 /// times with this scheme.
4264 public class SimpleName : Expression, ITypeExpression {
4265 public readonly string Name;
4267 public SimpleName (string name, Location l)
4273 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
4275 if (ec.IsFieldInitializer)
4278 "A field initializer cannot reference the non-static field, " +
4279 "method or property '"+name+"'");
4283 "An object reference is required " +
4284 "for the non-static field '"+name+"'");
4288 // Checks whether we are trying to access an instance
4289 // property, method or field from a static body.
4291 Expression MemberStaticCheck (EmitContext ec, Expression e)
4293 if (e is IMemberExpr){
4294 IMemberExpr member = (IMemberExpr) e;
4296 if (!member.IsStatic){
4297 Error_ObjectRefRequired (ec, loc, Name);
4305 public override Expression DoResolve (EmitContext ec)
4307 return SimpleNameResolve (ec, null, false);
4310 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4312 return SimpleNameResolve (ec, right_side, false);
4316 public Expression DoResolveAllowStatic (EmitContext ec)
4318 return SimpleNameResolve (ec, null, true);
4321 public Expression DoResolveType (EmitContext ec)
4324 // Stage 3: Lookup symbol in the various namespaces.
4326 DeclSpace ds = ec.DeclSpace;
4330 if (ec.ResolvingTypeTree){
4331 int errors = Report.Errors;
4332 Type dt = ec.DeclSpace.FindType (loc, Name);
4333 if (Report.Errors != errors)
4337 return new TypeExpr (dt, loc);
4340 if ((t = RootContext.LookupType (ds, Name, true, loc)) != null)
4341 return new TypeExpr (t, loc);
4345 // Stage 2 part b: Lookup up if we are an alias to a type
4348 // Since we are cheating: we only do the Alias lookup for
4349 // namespaces if the name does not include any dots in it
4352 alias_value = ec.DeclSpace.LookupAlias (Name);
4354 if (Name.IndexOf ('.') == -1 && alias_value != null) {
4355 if ((t = RootContext.LookupType (ds, alias_value, true, loc)) != null)
4356 return new TypeExpr (t, loc);
4358 // we have alias value, but it isn't Type, so try if it's namespace
4359 return new SimpleName (alias_value, loc);
4362 // No match, maybe our parent can compose us
4363 // into something meaningful.
4368 /// 7.5.2: Simple Names.
4370 /// Local Variables and Parameters are handled at
4371 /// parse time, so they never occur as SimpleNames.
4373 /// The 'allow_static' flag is used by MemberAccess only
4374 /// and it is used to inform us that it is ok for us to
4375 /// avoid the static check, because MemberAccess might end
4376 /// up resolving the Name as a Type name and the access as
4377 /// a static type access.
4379 /// ie: Type Type; .... { Type.GetType (""); }
4381 /// Type is both an instance variable and a Type; Type.GetType
4382 /// is the static method not an instance method of type.
4384 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool allow_static)
4386 Expression e = null;
4389 // Stage 1: Performed by the parser (binding to locals or parameters).
4391 Block current_block = ec.CurrentBlock;
4392 if (ec.InvokingOwnOverload == false && current_block != null && current_block.IsVariableDefined (Name)){
4393 LocalVariableReference var;
4395 var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
4397 if (right_side != null)
4398 return var.ResolveLValue (ec, right_side);
4400 return var.Resolve (ec);
4403 if (current_block != null){
4405 Parameter par = null;
4406 Parameters pars = current_block.Parameters;
4408 par = pars.GetParameterByName (Name, out idx);
4411 ParameterReference param;
4413 param = new ParameterReference (pars, idx, Name, loc);
4415 if (right_side != null)
4416 return param.ResolveLValue (ec, right_side);
4418 return param.Resolve (ec);
4423 // Stage 2: Lookup members
4427 // For enums, the TypeBuilder is not ec.DeclSpace.TypeBuilder
4428 // Hence we have two different cases
4431 DeclSpace lookup_ds = ec.DeclSpace;
4433 if (lookup_ds.TypeBuilder == null)
4436 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
4441 // Classes/structs keep looking, enums break
4443 if (lookup_ds is TypeContainer)
4444 lookup_ds = ((TypeContainer) lookup_ds).Parent;
4447 } while (lookup_ds != null);
4449 if (e == null && ec.ContainerType != null)
4450 e = MemberLookup (ec, ec.ContainerType, Name, loc);
4452 // #52067 - Start - Trying to solve
4456 ArrayList lookups = new ArrayList();
4457 ArrayList typelookups = new ArrayList();
4459 int split = Name.LastIndexOf('.');
4461 String nameSpacePart = Name.Substring(0, split);
4462 String memberNamePart = Name.Substring(split + 1);
4463 foreach(Type type in TypeManager.GetPertinentStandardModules(nameSpacePart)) {
4464 e = MemberLookup(ec, type, memberNamePart, loc);
4467 typelookups.Add(type);
4472 string[] NamespacesInScope = RootContext.SourceBeingCompiled.GetNamespacesInScope(ec.DeclSpace.Namespace.Name);
4473 foreach(Type type in TypeManager.GetPertinentStandardModules(NamespacesInScope)) {
4474 e = MemberLookup(ec, type, Name, loc);
4477 typelookups.Add(type);
4480 if (lookups.Count == 1) {
4481 e = (Expression)lookups[0];
4483 if (lookups.Count > 1) {
4484 StringBuilder sb = new StringBuilder();
4485 foreach(Type type in typelookups)
4486 sb.Append("'" + type.FullName + "'");
4487 Error (-1, "The name '" + Name + "' can be resolved to a member of more than one standard module: " + sb.ToString() + ". Please fully qualify it.");
4496 return DoResolveType (ec);
4501 if (e is IMemberExpr) {
4502 e = MemberAccess.ResolveMemberAccess (ec, e, null, loc, this);
4506 IMemberExpr me = e as IMemberExpr;
4510 // This fails if ResolveMemberAccess() was unable to decide whether
4511 // it's a field or a type of the same name.
4512 if (!me.IsStatic && (me.InstanceExpression == null))
4515 /* FIXME If this is not commented out, it seems that it's not possible to reach class members in mBas.
4516 Maybe a grammar-related problem?
4519 TypeManager.IsNestedChildOf (me.InstanceExpression.Type, me.DeclaringType)) {
4520 Error (38, "Cannot access nonstatic member '" + me.Name + "' of " +
4521 "outer type '" + me.DeclaringType + "' via nested type '" +
4522 me.InstanceExpression.Type + "'");
4526 if (right_side != null)
4527 e = e.DoResolveLValue (ec, right_side);
4529 e = e.DoResolve (ec);
4534 if (ec.IsStatic || ec.IsFieldInitializer){
4538 return MemberStaticCheck (ec, e);
4543 public override void Emit (EmitContext ec)
4546 // If this is ever reached, then we failed to
4547 // find the name as a namespace
4550 Error (30451, "The name '" + Name +
4551 "' does not exist in the class '" +
4552 ec.DeclSpace.Name + "'");
4555 public override string ToString ()
4562 /// Fully resolved expression that evaluates to a type
4564 public class TypeExpr : Expression, ITypeExpression {
4565 public TypeExpr (Type t, Location l)
4568 eclass = ExprClass.Type;
4572 public virtual Expression DoResolveType (EmitContext ec)
4577 override public Expression DoResolve (EmitContext ec)
4582 override public void Emit (EmitContext ec)
4584 throw new Exception ("Should never be called");
4587 public override string ToString ()
4589 return Type.ToString ();
4594 /// Used to create types from a fully qualified name. These are just used
4595 /// by the parser to setup the core types. A TypeLookupExpression is always
4596 /// classified as a type.
4598 public class TypeLookupExpression : TypeExpr {
4601 public TypeLookupExpression (string name) : base (null, Location.Null)
4606 public override Expression DoResolveType (EmitContext ec)
4609 type = RootContext.LookupType (ec.DeclSpace, name, false, Location.Null);
4613 public override Expression DoResolve (EmitContext ec)
4615 return DoResolveType (ec);
4618 public override void Emit (EmitContext ec)
4620 throw new Exception ("Should never be called");
4623 public override string ToString ()
4630 /// MethodGroup Expression.
4632 /// This is a fully resolved expression that evaluates to a type
4634 public class MethodGroupExpr : Expression, IMemberExpr {
4635 public MethodBase [] Methods;
4636 Expression instance_expression = null;
4637 bool is_explicit_impl = false;
4639 public MethodGroupExpr (MemberInfo [] mi, Location l)
4641 Methods = new MethodBase [mi.Length];
4642 mi.CopyTo (Methods, 0);
4643 eclass = ExprClass.MethodGroup;
4644 type = TypeManager.object_type;
4648 public MethodGroupExpr (ArrayList list, Location l)
4650 Methods = new MethodBase [list.Count];
4653 list.CopyTo (Methods, 0);
4655 foreach (MemberInfo m in list){
4656 if (!(m is MethodBase)){
4657 Console.WriteLine ("Name " + m.Name);
4658 Console.WriteLine ("Found a: " + m.GetType ().FullName);
4664 eclass = ExprClass.MethodGroup;
4665 type = TypeManager.object_type;
4668 public Type DeclaringType {
4670 return Methods [0].DeclaringType;
4675 // 'A method group may have associated an instance expression'
4677 public Expression InstanceExpression {
4679 return instance_expression;
4683 instance_expression = value;
4687 public bool IsExplicitImpl {
4689 return is_explicit_impl;
4693 is_explicit_impl = value;
4697 public string Name {
4699 return Methods [0].Name;
4703 public bool IsInstance {
4705 foreach (MethodBase mb in Methods)
4713 public bool IsStatic {
4715 foreach (MethodBase mb in Methods)
4723 override public Expression DoResolve (EmitContext ec)
4725 if (instance_expression != null) {
4726 instance_expression = instance_expression.DoResolve (ec);
4727 if (instance_expression == null)
4734 public void ReportUsageError ()
4736 Report.Error (654, loc, "Method '" + Methods [0].DeclaringType + "." +
4737 Methods [0].Name + "()' is referenced without parentheses");
4740 override public void Emit (EmitContext ec)
4742 ReportUsageError ();
4745 bool RemoveMethods (bool keep_static)
4747 ArrayList smethods = new ArrayList ();
4749 foreach (MethodBase mb in Methods){
4750 if (mb.IsStatic == keep_static)
4754 if (smethods.Count == 0)
4757 Methods = new MethodBase [smethods.Count];
4758 smethods.CopyTo (Methods, 0);
4764 /// Removes any instance methods from the MethodGroup, returns
4765 /// false if the resulting set is empty.
4767 public bool RemoveInstanceMethods ()
4769 return RemoveMethods (true);
4773 /// Removes any static methods from the MethodGroup, returns
4774 /// false if the resulting set is empty.
4776 public bool RemoveStaticMethods ()
4778 return RemoveMethods (false);
4783 /// Fully resolved expression that evaluates to a Field
4785 public class FieldExpr : Expression, IAssignMethod, IMemoryLocation, IMemberExpr {
4786 public readonly FieldInfo FieldInfo;
4787 Expression instance_expr;
4789 public FieldExpr (FieldInfo fi, Location l)
4792 eclass = ExprClass.Variable;
4793 type = fi.FieldType;
4797 public string Name {
4799 return FieldInfo.Name;
4803 public bool IsInstance {
4805 return !FieldInfo.IsStatic;
4809 public bool IsStatic {
4811 return FieldInfo.IsStatic;
4815 public Type DeclaringType {
4817 return FieldInfo.DeclaringType;
4821 public Expression InstanceExpression {
4823 return instance_expr;
4827 instance_expr = value;
4831 override public Expression DoResolve (EmitContext ec)
4833 if (!FieldInfo.IsStatic){
4834 if (instance_expr == null){
4835 throw new Exception ("non-static FieldExpr without instance var\n" +
4836 "You have to assign the Instance variable\n" +
4837 "Of the FieldExpr to set this\n");
4840 // Resolve the field's instance expression while flow analysis is turned
4841 // off: when accessing a field "a.b", we must check whether the field
4842 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4843 instance_expr = instance_expr.Resolve (ec, ResolveFlags.VariableOrValue |
4844 ResolveFlags.DisableFlowAnalysis);
4845 if (instance_expr == null)
4849 // If the instance expression is a local variable or parameter.
4850 IVariable var = instance_expr as IVariable;
4851 if ((var != null) && !var.IsFieldAssigned (ec, FieldInfo.Name, loc))
4857 void Report_AssignToReadonly (bool is_instance)
4862 msg = "Readonly field can not be assigned outside " +
4863 "of constructor or variable initializer";
4865 msg = "A static readonly field can only be assigned in " +
4866 "a static constructor";
4868 Report.Error (is_instance ? 191 : 198, loc, msg);
4871 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4873 IVariable var = instance_expr as IVariable;
4875 var.SetFieldAssigned (ec, FieldInfo.Name);
4877 Expression e = DoResolve (ec);
4882 if (!FieldInfo.IsInitOnly)
4886 // InitOnly fields can only be assigned in constructors
4889 if (ec.IsConstructor)
4892 Report_AssignToReadonly (true);
4897 override public void Emit (EmitContext ec)
4899 ILGenerator ig = ec.ig;
4900 bool is_volatile = false;
4902 if (FieldInfo is FieldBuilder){
4903 FieldBase f = TypeManager.GetField (FieldInfo);
4905 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4908 f.status |= Field.Status.USED;
4911 if (FieldInfo.IsStatic){
4913 ig.Emit (OpCodes.Volatile);
4915 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4917 if (instance_expr.Type.IsValueType){
4919 LocalTemporary tempo = null;
4921 if (!(instance_expr is IMemoryLocation)){
4922 tempo = new LocalTemporary (
4923 ec, instance_expr.Type);
4925 InstanceExpression.Emit (ec);
4929 ml = (IMemoryLocation) instance_expr;
4931 ml.AddressOf (ec, AddressOp.Load);
4933 instance_expr.Emit (ec);
4936 ig.Emit (OpCodes.Volatile);
4938 ig.Emit (OpCodes.Ldfld, FieldInfo);
4942 public void EmitAssign (EmitContext ec, Expression source)
4944 FieldAttributes fa = FieldInfo.Attributes;
4945 bool is_static = (fa & FieldAttributes.Static) != 0;
4946 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
4947 ILGenerator ig = ec.ig;
4949 if (is_readonly && !ec.IsConstructor){
4950 Report_AssignToReadonly (!is_static);
4955 Expression instance = instance_expr;
4957 if (instance.Type.IsValueType){
4958 if (instance is IMemoryLocation){
4959 IMemoryLocation ml = (IMemoryLocation) instance;
4961 ml.AddressOf (ec, AddressOp.Store);
4963 throw new Exception ("The " + instance + " of type " +
4965 " represents a ValueType and does " +
4966 "not implement IMemoryLocation");
4972 if (FieldInfo is FieldBuilder){
4973 FieldBase f = TypeManager.GetField (FieldInfo);
4975 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4976 ig.Emit (OpCodes.Volatile);
4980 ig.Emit (OpCodes.Stsfld, FieldInfo);
4982 ig.Emit (OpCodes.Stfld, FieldInfo);
4984 if (FieldInfo is FieldBuilder){
4985 FieldBase f = TypeManager.GetField (FieldInfo);
4987 f.status |= Field.Status.ASSIGNED;
4991 public void AddressOf (EmitContext ec, AddressOp mode)
4993 ILGenerator ig = ec.ig;
4995 if (FieldInfo is FieldBuilder){
4996 FieldBase f = TypeManager.GetField (FieldInfo);
4997 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
4998 ig.Emit (OpCodes.Volatile);
5001 if (FieldInfo is FieldBuilder){
5002 FieldBase f = TypeManager.GetField (FieldInfo);
5004 if ((mode & AddressOp.Store) != 0)
5005 f.status |= Field.Status.ASSIGNED;
5006 if ((mode & AddressOp.Load) != 0)
5007 f.status |= Field.Status.USED;
5011 // Handle initonly fields specially: make a copy and then
5012 // get the address of the copy.
5014 if (FieldInfo.IsInitOnly && !ec.IsConstructor){
5018 local = ig.DeclareLocal (type);
5019 ig.Emit (OpCodes.Stloc, local);
5020 ig.Emit (OpCodes.Ldloca, local);
5024 if (FieldInfo.IsStatic)
5025 ig.Emit (OpCodes.Ldsflda, FieldInfo);
5027 if (instance_expr is IMemoryLocation)
5028 ((IMemoryLocation)instance_expr).AddressOf (ec, AddressOp.LoadStore);
5030 instance_expr.Emit (ec);
5031 ig.Emit (OpCodes.Ldflda, FieldInfo);
5037 /// Expression that evaluates to a Property. The Assign class
5038 /// might set the 'Value' expression if we are in an assignment.
5040 /// This is not an LValue because we need to re-write the expression, we
5041 /// can not take data from the stack and store it.
5043 public class PropertyExpr : ExpressionStatement, IAssignMethod, IMemberExpr {
5044 public readonly PropertyInfo PropertyInfo;
5046 MethodInfo getter, setter;
5048 public ArrayList PropertyArgs;
5050 Expression instance_expr;
5052 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
5055 eclass = ExprClass.PropertyAccess;
5056 PropertyArgs = null;
5060 type = TypeManager.TypeToCoreType (pi.PropertyType);
5062 ResolveAccessors (ec);
5065 public string Name {
5067 return PropertyInfo.Name;
5071 public bool IsInstance {
5077 public bool IsStatic {
5083 public Type DeclaringType {
5085 return PropertyInfo.DeclaringType;
5090 // The instance expression associated with this expression
5092 public Expression InstanceExpression {
5094 instance_expr = value;
5098 return instance_expr;
5102 public bool VerifyAssignable ()
5104 if (!PropertyInfo.CanWrite){
5105 Report.Error (200, loc,
5106 "The property '" + PropertyInfo.Name +
5107 "' can not be assigned to, as it has not set accessor");
5114 void ResolveAccessors (EmitContext ec)
5116 BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
5117 MemberInfo [] group;
5119 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5120 MemberTypes.Method, flags, "get_" + PropertyInfo.Name);
5123 // The first method is the closest to us
5125 if (group != null && group.Length > 0){
5126 getter = (MethodInfo) group [0];
5128 if (getter.IsStatic)
5133 // The first method is the closest to us
5135 group = TypeManager.MemberLookup (ec.ContainerType, PropertyInfo.DeclaringType,
5136 MemberTypes.Method, flags, "set_" + PropertyInfo.Name);
5137 if (group != null && group.Length > 0){
5138 setter = (MethodInfo) group [0];
5139 if (setter.IsStatic)
5144 override public Expression DoResolve (EmitContext ec)
5146 if (getter == null){
5147 Report.Error (30524, loc,
5148 "The property '" + PropertyInfo.Name +
5149 "' can not be used in " +
5150 "this context because it lacks a get accessor");
5154 if ((instance_expr == null) && ec.IsStatic && !is_static) {
5155 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
5159 if (instance_expr != null) {
5160 instance_expr = instance_expr.DoResolve (ec);
5161 if (instance_expr == null)
5168 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5170 if (setter == null){
5171 Report.Error (30526, loc,
5172 "The property '" + PropertyInfo.Name +
5173 "' can not be used in " +
5174 "this context because it lacks a set accessor");
5178 if (instance_expr != null) {
5179 instance_expr = instance_expr.DoResolve (ec);
5180 if (instance_expr == null)
5187 override public void Emit (EmitContext ec)
5190 // Special case: length of single dimension array property is turned into ldlen
5192 if ((getter == TypeManager.system_int_array_get_length) ||
5193 (getter == TypeManager.int_array_get_length)){
5194 Type iet = instance_expr.Type;
5197 // System.Array.Length can be called, but the Type does not
5198 // support invoking GetArrayRank, so test for that case first
5200 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)){
5201 instance_expr.Emit (ec);
5202 ec.ig.Emit (OpCodes.Ldlen);
5206 if (PropertyArgs == null)
5207 PropertyArgs = new ArrayList ();
5208 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, getter, null, PropertyArgs, loc);
5212 // Implements the IAssignMethod interface for assignments
5214 public void EmitAssign (EmitContext ec, Expression source)
5216 Argument arg = new Argument (source, Argument.AType.Expression);
5217 ArrayList args = new ArrayList ();
5220 Invocation.EmitCall (ec, IsBase, IsStatic, instance_expr, setter, args, PropertyArgs,loc);
5223 override public void EmitStatement (EmitContext ec)
5226 ec.ig.Emit (OpCodes.Pop);
5231 /// Fully resolved expression that evaluates to an Event
5233 public class EventExpr : Expression, IMemberExpr {
5234 public readonly EventInfo EventInfo;
5235 public Expression instance_expr;
5238 MethodInfo add_accessor, remove_accessor;
5240 public EventExpr (EventInfo ei, Location loc)
5244 eclass = ExprClass.EventAccess;
5246 add_accessor = TypeManager.GetAddMethod (ei);
5247 remove_accessor = TypeManager.GetRemoveMethod (ei);
5249 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5252 if (EventInfo is MyEventBuilder)
5253 type = ((MyEventBuilder) EventInfo).EventType;
5255 type = EventInfo.EventHandlerType;
5258 public string Name {
5260 return EventInfo.Name;
5264 public bool IsInstance {
5270 public bool IsStatic {
5276 public Type DeclaringType {
5278 return EventInfo.DeclaringType;
5282 public Expression InstanceExpression {
5284 return instance_expr;
5288 instance_expr = value;
5292 Expression field_expr = null;
5294 public override Expression DoResolve (EmitContext ec)
5296 if (instance_expr != null) {
5297 instance_expr = instance_expr.DoResolve (ec);
5298 if (instance_expr == null)
5302 if (this.DeclaringType == ec.ContainerType) {
5303 MemberInfo mi = GetFieldFromEvent (this);
5306 field_expr = ExprClassFromMemberInfo (ec, mi, loc);
5307 ((FieldExpr) field_expr).InstanceExpression = instance_expr;
5308 field_expr = field_expr.DoResolve (ec);
5309 if (field_expr == null)
5316 public override void Emit (EmitContext ec)
5318 if (field_expr != null)
5319 field_expr.Emit (ec);
5322 public void EmitAddOrRemove (EmitContext ec, Expression source)
5324 Expression handler = ((Binary) source).Right;
5326 Argument arg = new Argument (handler, Argument.AType.Expression);
5327 ArrayList args = new ArrayList ();
5331 if (((Binary) source).Oper == Binary.Operator.Addition)
5332 Invocation.EmitCall (
5333 ec, false, IsStatic, instance_expr, add_accessor, args, loc);
5335 Invocation.EmitCall (
5336 ec, false, IsStatic, instance_expr, remove_accessor, args, loc);