2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
13 using System.Collections;
14 using System.Diagnostics;
15 using System.Reflection;
16 using System.Reflection.Emit;
20 // The ExprClass class contains the is used to pass the
21 // classification of an expression (value, variable, namespace,
22 // type, method group, property access, event access, indexer access,
25 public enum ExprClass {
40 // An interface provided by expressions that can be used as
41 // LValues and can store the value on the top of the stack on
44 public interface IStackStore {
47 // The Store method should store the contents of the top
48 // of the stack into the storage that is implemented by
49 // the particular implementation of LValue
51 void Store (EmitContext ec);
55 // This interface is implemented by variables
57 public interface IMemoryLocation {
59 // The AddressOf method should generate code that loads
60 // the address of the object and leaves it on the stack
62 void AddressOf (EmitContext ec);
66 // Base class for expressions
68 public abstract class Expression {
69 protected ExprClass eclass;
82 public ExprClass ExprClass {
93 // Utility wrapper routine for Error, just to beautify the code
95 static protected void Error (int error, string s)
97 Report.Error (error, s);
100 static protected void Error (int error, Location loc, string s)
102 Report.Error (error, loc, s);
106 // Utility wrapper routine for Warning, just to beautify the code
108 static protected void Warning (int warning, string s)
110 Report.Warning (warning, s);
114 // Performs semantic analysis on the Expression
118 // The Resolve method is invoked to perform the semantic analysis
121 // The return value is an expression (it can be the
122 // same expression in some cases) or a new
123 // expression that better represents this node.
125 // For example, optimizations of Unary (LiteralInt)
126 // would return a new LiteralInt with a negated
129 // If there is an error during semantic analysis,
130 // then an error should be reported (using Report)
131 // and a null value should be returned.
133 // There are two side effects expected from calling
134 // Resolve(): the the field variable "eclass" should
135 // be set to any value of the enumeration
136 // `ExprClass' and the type variable should be set
137 // to a valid type (this is the type of the
141 public abstract Expression DoResolve (EmitContext ec);
143 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
145 return DoResolve (ec);
149 // Currently Resolve wraps DoResolve to perform sanity
150 // checking and assertion checking on what we expect from Resolve
152 public Expression Resolve (EmitContext ec)
154 Expression e = DoResolve (ec);
157 if (e is SimpleName){
158 SimpleName s = (SimpleName) e;
162 "The name `" + s.Name + "' could not be found in `" +
163 ec.TypeContainer.Name + "'");
167 if (e.ExprClass == ExprClass.Invalid)
168 throw new Exception ("Expression " + e +
169 " ExprClass is Invalid after resolve");
171 if (e.ExprClass != ExprClass.MethodGroup)
173 throw new Exception ("Expression " + e +
174 " did not set its type after Resolve");
181 // Just like `Resolve' above, but this allows SimpleNames to be returned.
182 // This is used by MemberAccess to construct long names that can not be
183 // partially resolved (namespace-qualified names for example).
185 public Expression ResolveWithSimpleName (EmitContext ec)
187 Expression e = DoResolve (ec);
193 if (e.ExprClass == ExprClass.Invalid)
194 throw new Exception ("Expression " + e +
195 " ExprClass is Invalid after resolve");
197 if (e.ExprClass != ExprClass.MethodGroup)
199 throw new Exception ("Expression " + e +
200 " did not set its type after Resolve");
207 // Currently ResolveLValue wraps DoResolveLValue to perform sanity
208 // checking and assertion checking on what we expect from Resolve
210 public Expression ResolveLValue (EmitContext ec, Expression right_side)
212 Expression e = DoResolveLValue (ec, right_side);
215 if (e is SimpleName){
216 SimpleName s = (SimpleName) e;
220 "The name `" + s.Name + "' could not be found in `" +
221 ec.TypeContainer.Name + "'");
225 if (e.ExprClass == ExprClass.Invalid)
226 throw new Exception ("Expression " + e +
227 " ExprClass is Invalid after resolve");
229 if (e.ExprClass != ExprClass.MethodGroup)
231 throw new Exception ("Expression " + e +
232 " did not set its type after Resolve");
239 // Emits the code for the expression
244 // The Emit method is invoked to generate the code
245 // for the expression.
248 public abstract void Emit (EmitContext ec);
251 // This method should perform a reduction of the expression. This should
252 // never return null.
254 public virtual Expression Reduce (EmitContext ec)
260 // Protected constructor. Only derivate types should
261 // be able to be created
264 protected Expression ()
266 eclass = ExprClass.Invalid;
271 // Returns a literalized version of a literal FieldInfo
273 public static Expression Literalize (object v, Type t)
275 if (t == TypeManager.int32_type)
276 return new IntLiteral ((int) v);
277 else if (t == TypeManager.uint32_type)
278 return new UIntLiteral ((uint) v);
279 else if (t == TypeManager.int64_type)
280 return new LongLiteral ((long) v);
281 else if (t == TypeManager.uint64_type)
282 return new ULongLiteral ((ulong) v);
283 else if (t == TypeManager.float_type)
284 return new FloatLiteral ((float) v);
285 else if (t == TypeManager.double_type)
286 return new DoubleLiteral ((double) v);
287 else if (t == TypeManager.string_type)
288 return new StringLiteral ((string) v);
289 else if (t == TypeManager.short_type)
290 return new IntLiteral ((int) ((short)v));
291 else if (t == TypeManager.ushort_type)
292 return new IntLiteral ((int) ((ushort)v));
293 else if (t == TypeManager.sbyte_type)
294 return new IntLiteral ((int) ((sbyte)v));
295 else if (t == TypeManager.byte_type)
296 return new IntLiteral ((int) ((byte)v));
297 else if (t == TypeManager.char_type)
298 return new IntLiteral ((int) ((char)v));
300 throw new Exception ("Unknown type for literal (" + t +
305 // Returns a fully formed expression after a MemberLookup
307 static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
310 return new EventExpr ((EventInfo) mi, loc);
311 else if (mi is FieldInfo)
312 return new FieldExpr ((FieldInfo) mi, loc);
313 else if (mi is PropertyInfo)
314 return new PropertyExpr ((PropertyInfo) mi, loc);
316 return new TypeExpr ((Type) mi);
322 // FIXME: Probably implement a cache for (t,name,current_access_set)?
324 // FIXME: We need to cope with access permissions here, or this wont
327 // This code could use some optimizations, but we need to do some
328 // measurements. For example, we could use a delegate to `flag' when
329 // something can not any longer be a method-group (because it is something
333 // If the return value is an Array, then it is an array of
336 // If the return value is an MemberInfo, it is anything, but a Method
340 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
341 // the arguments here and have MemberLookup return only the methods that
342 // match the argument count/type, unlike we are doing now (we delay this
345 // This is so we can catch correctly attempts to invoke instance methods
346 // from a static body (scan for error 120 in ResolveSimpleName).
348 public static Expression MemberLookup (EmitContext ec, Type t, string name,
349 bool same_type, MemberTypes mt,
350 BindingFlags bf, Location loc)
353 bf |= BindingFlags.NonPublic;
355 MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers (
356 t, mt, bf, Type.FilterName, name);
366 if (mi.Length == 1 && !(mi [0] is MethodBase))
367 return Expression.ExprClassFromMemberInfo (ec, mi [0], loc);
369 for (int i = 0; i < mi.Length; i++)
370 if (!(mi [i] is MethodBase)){
371 Error (-5, "Do not know how to reproduce this case: " +
372 "Methods and non-Method with the same name, " +
373 "report this please");
375 for (i = 0; i < mi.Length; i++){
376 Type tt = mi [i].GetType ();
378 Console.WriteLine (i + ": " + mi [i]);
379 while (tt != TypeManager.object_type){
380 Console.WriteLine (tt);
386 return new MethodGroupExpr (mi);
389 public const MemberTypes AllMemberTypes =
390 MemberTypes.Constructor |
394 MemberTypes.NestedType |
395 MemberTypes.Property;
397 public const BindingFlags AllBindingsFlags =
398 BindingFlags.Public |
399 BindingFlags.Static |
400 BindingFlags.Instance;
402 public static Expression MemberLookup (EmitContext ec, Type t, string name,
403 bool same_type, Location loc)
405 return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags, loc);
408 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
410 Type expr_type = expr.Type;
412 if (target_type == TypeManager.object_type) {
413 if (expr_type.IsClass)
414 return new EmptyCast (expr, target_type);
415 if (expr_type.IsValueType)
416 return new BoxedCast (expr);
417 } else if (expr_type.IsSubclassOf (target_type)) {
418 return new EmptyCast (expr, target_type);
420 // from any class-type S to any interface-type T.
421 if (expr_type.IsClass && target_type.IsInterface) {
423 if (TypeManager.ImplementsInterface (expr_type, target_type))
424 return new EmptyCast (expr, target_type);
429 // from any interface type S to interface-type T.
430 if (expr_type.IsInterface && target_type.IsInterface) {
432 if (TypeManager.ImplementsInterface (expr_type, target_type))
433 return new EmptyCast (expr, target_type);
438 // from an array-type S to an array-type of type T
439 if (expr_type.IsArray && target_type.IsArray) {
440 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
442 Type expr_element_type = expr_type.GetElementType ();
443 Type target_element_type = target_type.GetElementType ();
445 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
446 if (StandardConversionExists (expr_element_type,
447 target_element_type))
448 return new EmptyCast (expr, target_type);
453 // from an array-type to System.Array
454 if (expr_type.IsArray && target_type == TypeManager.array_type)
455 return new EmptyCast (expr, target_type);
457 // from any delegate type to System.Delegate
458 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
459 target_type == TypeManager.delegate_type)
460 return new EmptyCast (expr, target_type);
462 // from any array-type or delegate type into System.ICloneable.
463 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
464 if (target_type == TypeManager.icloneable_type)
465 return new EmptyCast (expr, target_type);
467 // from the null type to any reference-type.
468 if (expr is NullLiteral)
469 return new EmptyCast (expr, target_type);
479 // Handles expressions like this: decimal d; d = 1;
480 // and changes them into: decimal d; d = new System.Decimal (1);
482 static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target)
484 ArrayList args = new ArrayList ();
486 args.Add (new Argument (expr, Argument.AType.Expression));
488 Expression ne = new New (target.FullName, args,
491 return ne.Resolve (ec);
495 // Implicit Numeric Conversions.
497 // expr is the expression to convert, returns a new expression of type
498 // target_type or null if an implicit conversion is not possible.
501 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
502 Type target_type, Location loc)
504 Type expr_type = expr.Type;
507 // Attempt to do the implicit constant expression conversions
509 if (expr is IntLiteral){
512 e = TryImplicitIntConversion (target_type, (IntLiteral) expr);
515 } else if (expr is LongLiteral){
517 // Try the implicit constant expression conversion
518 // from long to ulong, instead of a nice routine,
521 if (((LongLiteral) expr).Value > 0)
522 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
525 if (expr_type == TypeManager.sbyte_type){
527 // From sbyte to short, int, long, float, double.
529 if (target_type == TypeManager.int32_type)
530 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
531 if (target_type == TypeManager.int64_type)
532 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
533 if (target_type == TypeManager.double_type)
534 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
535 if (target_type == TypeManager.float_type)
536 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
537 if (target_type == TypeManager.short_type)
538 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
539 if (target_type == TypeManager.decimal_type)
540 return InternalTypeConstructor (ec, expr, target_type);
541 } else if (expr_type == TypeManager.byte_type){
543 // From byte to short, ushort, int, uint, long, ulong, float, double
545 if ((target_type == TypeManager.short_type) ||
546 (target_type == TypeManager.ushort_type) ||
547 (target_type == TypeManager.int32_type) ||
548 (target_type == TypeManager.uint32_type))
549 return new EmptyCast (expr, target_type);
551 if (target_type == TypeManager.uint64_type)
552 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
553 if (target_type == TypeManager.int64_type)
554 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
556 if (target_type == TypeManager.float_type)
557 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
558 if (target_type == TypeManager.double_type)
559 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
560 if (target_type == TypeManager.decimal_type)
561 return InternalTypeConstructor (ec, expr, target_type);
562 } else if (expr_type == TypeManager.short_type){
564 // From short to int, long, float, double
566 if (target_type == TypeManager.int32_type)
567 return new EmptyCast (expr, target_type);
568 if (target_type == TypeManager.int64_type)
569 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
570 if (target_type == TypeManager.double_type)
571 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
572 if (target_type == TypeManager.float_type)
573 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
574 if (target_type == TypeManager.decimal_type)
575 return InternalTypeConstructor (ec, expr, target_type);
576 } else if (expr_type == TypeManager.ushort_type){
578 // From ushort to int, uint, long, ulong, float, double
580 if (target_type == TypeManager.uint32_type)
581 return new EmptyCast (expr, target_type);
583 if (target_type == TypeManager.uint64_type)
584 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
585 if (target_type == TypeManager.int32_type)
586 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
587 if (target_type == TypeManager.int64_type)
588 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
589 if (target_type == TypeManager.double_type)
590 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
591 if (target_type == TypeManager.float_type)
592 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
593 if (target_type == TypeManager.decimal_type)
594 return InternalTypeConstructor (ec, expr, target_type);
595 } else if (expr_type == TypeManager.int32_type){
597 // From int to long, float, double
599 if (target_type == TypeManager.int64_type)
600 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
601 if (target_type == TypeManager.double_type)
602 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
603 if (target_type == TypeManager.float_type)
604 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
605 if (target_type == TypeManager.decimal_type)
606 return InternalTypeConstructor (ec, expr, target_type);
607 } else if (expr_type == TypeManager.uint32_type){
609 // From uint to long, ulong, float, double
611 if (target_type == TypeManager.int64_type)
612 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
613 if (target_type == TypeManager.uint64_type)
614 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
615 if (target_type == TypeManager.double_type)
616 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
618 if (target_type == TypeManager.float_type)
619 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
621 if (target_type == TypeManager.decimal_type)
622 return InternalTypeConstructor (ec, expr, target_type);
623 } else if ((expr_type == TypeManager.uint64_type) ||
624 (expr_type == TypeManager.int64_type)){
626 // From long/ulong to float, double
628 if (target_type == TypeManager.double_type)
629 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
631 if (target_type == TypeManager.float_type)
632 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
634 if (target_type == TypeManager.decimal_type)
635 return InternalTypeConstructor (ec, expr, target_type);
636 } else if (expr_type == TypeManager.char_type){
638 // From char to ushort, int, uint, long, ulong, float, double
640 if ((target_type == TypeManager.ushort_type) ||
641 (target_type == TypeManager.int32_type) ||
642 (target_type == TypeManager.uint32_type))
643 return new EmptyCast (expr, target_type);
644 if (target_type == TypeManager.uint64_type)
645 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
646 if (target_type == TypeManager.int64_type)
647 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
648 if (target_type == TypeManager.float_type)
649 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
650 if (target_type == TypeManager.double_type)
651 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
652 if (target_type == TypeManager.decimal_type)
653 return InternalTypeConstructor (ec, expr, target_type);
654 } else if (expr_type == TypeManager.float_type){
658 if (target_type == TypeManager.double_type)
659 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
666 // Determines if a standard implicit conversion exists from
667 // expr_type to target_type
669 public static bool StandardConversionExists (Type expr_type, Type target_type)
671 if (expr_type == target_type)
674 // First numeric conversions
676 if (expr_type == TypeManager.sbyte_type){
678 // From sbyte to short, int, long, float, double.
680 if ((target_type == TypeManager.int32_type) ||
681 (target_type == TypeManager.int64_type) ||
682 (target_type == TypeManager.double_type) ||
683 (target_type == TypeManager.float_type) ||
684 (target_type == TypeManager.short_type) ||
685 (target_type == TypeManager.decimal_type))
688 } else if (expr_type == TypeManager.byte_type){
690 // From byte to short, ushort, int, uint, long, ulong, float, double
692 if ((target_type == TypeManager.short_type) ||
693 (target_type == TypeManager.ushort_type) ||
694 (target_type == TypeManager.int32_type) ||
695 (target_type == TypeManager.uint32_type) ||
696 (target_type == TypeManager.uint64_type) ||
697 (target_type == TypeManager.int64_type) ||
698 (target_type == TypeManager.float_type) ||
699 (target_type == TypeManager.double_type) ||
700 (target_type == TypeManager.decimal_type))
703 } else if (expr_type == TypeManager.short_type){
705 // From short to int, long, float, double
707 if ((target_type == TypeManager.int32_type) ||
708 (target_type == TypeManager.int64_type) ||
709 (target_type == TypeManager.double_type) ||
710 (target_type == TypeManager.float_type) ||
711 (target_type == TypeManager.decimal_type))
714 } else if (expr_type == TypeManager.ushort_type){
716 // From ushort to int, uint, long, ulong, float, double
718 if ((target_type == TypeManager.uint32_type) ||
719 (target_type == TypeManager.uint64_type) ||
720 (target_type == TypeManager.int32_type) ||
721 (target_type == TypeManager.int64_type) ||
722 (target_type == TypeManager.double_type) ||
723 (target_type == TypeManager.float_type) ||
724 (target_type == TypeManager.decimal_type))
727 } else if (expr_type == TypeManager.int32_type){
729 // From int to long, float, double
731 if ((target_type == TypeManager.int64_type) ||
732 (target_type == TypeManager.double_type) ||
733 (target_type == TypeManager.float_type) ||
734 (target_type == TypeManager.decimal_type))
737 } else if (expr_type == TypeManager.uint32_type){
739 // From uint to long, ulong, float, double
741 if ((target_type == TypeManager.int64_type) ||
742 (target_type == TypeManager.uint64_type) ||
743 (target_type == TypeManager.double_type) ||
744 (target_type == TypeManager.float_type) ||
745 (target_type == TypeManager.decimal_type))
748 } else if ((expr_type == TypeManager.uint64_type) ||
749 (expr_type == TypeManager.int64_type)) {
751 // From long/ulong to float, double
753 if ((target_type == TypeManager.double_type) ||
754 (target_type == TypeManager.float_type) ||
755 (target_type == TypeManager.decimal_type))
758 } else if (expr_type == TypeManager.char_type){
760 // From char to ushort, int, uint, long, ulong, float, double
762 if ((target_type == TypeManager.ushort_type) ||
763 (target_type == TypeManager.int32_type) ||
764 (target_type == TypeManager.uint32_type) ||
765 (target_type == TypeManager.uint64_type) ||
766 (target_type == TypeManager.int64_type) ||
767 (target_type == TypeManager.float_type) ||
768 (target_type == TypeManager.double_type) ||
769 (target_type == TypeManager.decimal_type))
772 } else if (expr_type == TypeManager.float_type){
776 if (target_type == TypeManager.double_type)
780 // Next reference conversions
782 if (target_type == TypeManager.object_type) {
783 if ((expr_type.IsClass) ||
784 (expr_type.IsValueType))
787 } else if (expr_type.IsSubclassOf (target_type)) {
791 // from any class-type S to any interface-type T.
792 if (expr_type.IsClass && target_type.IsInterface)
795 // from any interface type S to interface-type T.
796 // FIXME : Is it right to use IsAssignableFrom ?
797 if (expr_type.IsInterface && target_type.IsInterface)
798 if (target_type.IsAssignableFrom (expr_type))
801 // from an array-type S to an array-type of type T
802 if (expr_type.IsArray && target_type.IsArray) {
803 if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
805 Type expr_element_type = expr_type.GetElementType ();
806 Type target_element_type = target_type.GetElementType ();
808 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
809 if (StandardConversionExists (expr_element_type,
810 target_element_type))
815 // from an array-type to System.Array
816 if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type))
819 // from any delegate type to System.Delegate
820 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
821 target_type == TypeManager.delegate_type)
822 if (target_type.IsAssignableFrom (expr_type))
825 // from any array-type or delegate type into System.ICloneable.
826 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
827 if (target_type == TypeManager.icloneable_type)
830 // from the null type to any reference-type.
831 // FIXME : How do we do this ?
839 // Finds "most encompassed type" according to the spec (13.4.2)
840 // amongst the methods in the MethodGroupExpr which convert from a
841 // type encompassing source_type
843 static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type)
847 for (int i = me.Methods.Length; i > 0; ) {
850 MethodBase mb = me.Methods [i];
851 ParameterData pd = Invocation.GetParameterData (mb);
852 Type param_type = pd.ParameterType (0);
854 if (StandardConversionExists (source_type, param_type)) {
858 if (StandardConversionExists (param_type, best))
867 // Finds "most encompassing type" according to the spec (13.4.2)
868 // amongst the methods in the MethodGroupExpr which convert to a
869 // type encompassed by target_type
871 static Type FindMostEncompassingType (MethodGroupExpr me, Type target)
875 for (int i = me.Methods.Length; i > 0; ) {
878 MethodInfo mi = (MethodInfo) me.Methods [i];
879 Type ret_type = mi.ReturnType;
881 if (StandardConversionExists (ret_type, target)) {
885 if (!StandardConversionExists (ret_type, best))
897 // User-defined Implicit conversions
899 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
900 Type target, Location loc)
902 return UserDefinedConversion (ec, source, target, loc, false);
906 // User-defined Explicit conversions
908 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
909 Type target, Location loc)
911 return UserDefinedConversion (ec, source, target, loc, true);
915 // User-defined conversions
917 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
918 Type target, Location loc,
919 bool look_for_explicit)
921 Expression mg1 = null, mg2 = null, mg3 = null, mg4 = null;
922 Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
924 MethodBase method = null;
925 Type source_type = source.Type;
929 // If we have a boolean type, we need to check for the True operator
931 // FIXME : How does the False operator come into the picture ?
932 // FIXME : This doesn't look complete and very correct !
933 if (target == TypeManager.bool_type)
936 op_name = "op_Implicit";
938 mg1 = MemberLookup (ec, source_type, op_name, false, loc);
940 if (source_type.BaseType != null)
941 mg2 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
943 mg3 = MemberLookup (ec, target, op_name, false, loc);
945 if (target.BaseType != null)
946 mg4 = MemberLookup (ec, target.BaseType, op_name, false, loc);
948 MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2);
949 MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4);
951 MethodGroupExpr union3 = Invocation.MakeUnionSet (union1, union2);
953 MethodGroupExpr union4 = null;
955 if (look_for_explicit) {
957 op_name = "op_Explicit";
959 mg5 = MemberLookup (ec, source_type, op_name, false, loc);
961 if (source_type.BaseType != null)
962 mg6 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
964 mg7 = MemberLookup (ec, target, op_name, false, loc);
966 if (target.BaseType != null)
967 mg8 = MemberLookup (ec, target.BaseType, op_name, false, loc);
969 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6);
970 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8);
972 union4 = Invocation.MakeUnionSet (union5, union6);
975 MethodGroupExpr union = Invocation.MakeUnionSet (union3, union4);
979 Type most_specific_source, most_specific_target;
981 most_specific_source = FindMostEncompassedType (union, source_type);
982 if (most_specific_source == null)
985 most_specific_target = FindMostEncompassingType (union, target);
986 if (most_specific_target == null)
991 for (int i = union.Methods.Length; i > 0;) {
994 MethodBase mb = union.Methods [i];
995 ParameterData pd = Invocation.GetParameterData (mb);
996 MethodInfo mi = (MethodInfo) union.Methods [i];
998 if (pd.ParameterType (0) == most_specific_source &&
999 mi.ReturnType == most_specific_target) {
1005 if (method == null || count > 1) {
1006 Report.Error (-11, loc, "Ambiguous user defined conversion");
1011 // This will do the conversion to the best match that we
1012 // found. Now we need to perform an implict standard conversion
1013 // if the best match was not the type that we were requested
1016 if (look_for_explicit)
1017 source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1019 source = ConvertImplicitStandard (ec, source,
1020 most_specific_source, loc);
1025 e = new UserCast ((MethodInfo) method, source);
1027 if (e.Type != target){
1028 if (!look_for_explicit)
1029 e = ConvertImplicitStandard (ec, e, target, loc);
1031 e = ConvertExplicitStandard (ec, e, target, loc);
1042 // Converts implicitly the resolved expression `expr' into the
1043 // `target_type'. It returns a new expression that can be used
1044 // in a context that expects a `target_type'.
1046 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1047 Type target_type, Location loc)
1049 Type expr_type = expr.Type;
1052 if (expr_type == target_type)
1055 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1059 e = ImplicitReferenceConversion (expr, target_type);
1063 e = ImplicitUserConversion (ec, expr, target_type, loc);
1067 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1068 IntLiteral i = (IntLiteral) expr;
1071 return new EmptyCast (expr, target_type);
1079 // Attempts to apply the `Standard Implicit
1080 // Conversion' rules to the expression `expr' into
1081 // the `target_type'. It returns a new expression
1082 // that can be used in a context that expects a
1085 // This is different from `ConvertImplicit' in that the
1086 // user defined implicit conversions are excluded.
1088 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
1089 Type target_type, Location loc)
1091 Type expr_type = expr.Type;
1094 if (expr_type == target_type)
1097 e = ImplicitNumericConversion (ec, expr, target_type, loc);
1101 e = ImplicitReferenceConversion (expr, target_type);
1105 if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1106 IntLiteral i = (IntLiteral) expr;
1109 return new EmptyCast (expr, target_type);
1114 // Attemps to perform an implict constant conversion of the IntLiteral
1115 // into a different data type using casts (See Implicit Constant
1116 // Expression Conversions)
1118 static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il)
1120 int value = il.Value;
1122 if (target_type == TypeManager.sbyte_type){
1123 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1125 } else if (target_type == TypeManager.byte_type){
1126 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1128 } else if (target_type == TypeManager.short_type){
1129 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1131 } else if (target_type == TypeManager.ushort_type){
1132 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1134 } else if (target_type == TypeManager.uint32_type){
1136 // we can optimize this case: a positive int32
1137 // always fits on a uint32
1141 } else if (target_type == TypeManager.uint64_type){
1143 // we can optimize this case: a positive int32
1144 // always fits on a uint64. But we need an opcode
1148 return new OpcodeCast (il, target_type, OpCodes.Conv_I8);
1155 // Attemptes to implicityly convert `target' into `type', using
1156 // ConvertImplicit. If there is no implicit conversion, then
1157 // an error is signaled
1159 static public Expression ConvertImplicitRequired (EmitContext ec, Expression target,
1160 Type type, Location loc)
1164 e = ConvertImplicit (ec, target, type, loc);
1168 string msg = "Can not convert implicitly from `"+
1169 TypeManager.CSharpName (target.Type) + "' to `" +
1170 TypeManager.CSharpName (type) + "'";
1172 Error (29, loc, msg);
1178 // Performs the explicit numeric conversions
1180 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr,
1183 Type expr_type = expr.Type;
1185 if (expr_type == TypeManager.sbyte_type){
1187 // From sbyte to byte, ushort, uint, ulong, char
1189 if (target_type == TypeManager.byte_type)
1190 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1191 if (target_type == TypeManager.ushort_type)
1192 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1193 if (target_type == TypeManager.uint32_type)
1194 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1195 if (target_type == TypeManager.uint64_type)
1196 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1197 if (target_type == TypeManager.char_type)
1198 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1199 } else if (expr_type == TypeManager.byte_type){
1201 // From byte to sbyte and char
1203 if (target_type == TypeManager.sbyte_type)
1204 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1205 if (target_type == TypeManager.char_type)
1206 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1207 } else if (expr_type == TypeManager.short_type){
1209 // From short to sbyte, byte, ushort, uint, ulong, char
1211 if (target_type == TypeManager.sbyte_type)
1212 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1213 if (target_type == TypeManager.byte_type)
1214 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1215 if (target_type == TypeManager.ushort_type)
1216 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1217 if (target_type == TypeManager.uint32_type)
1218 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1219 if (target_type == TypeManager.uint64_type)
1220 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1221 if (target_type == TypeManager.char_type)
1222 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1223 } else if (expr_type == TypeManager.ushort_type){
1225 // From ushort to sbyte, byte, short, char
1227 if (target_type == TypeManager.sbyte_type)
1228 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1229 if (target_type == TypeManager.byte_type)
1230 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1231 if (target_type == TypeManager.short_type)
1232 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1233 if (target_type == TypeManager.char_type)
1234 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1235 } else if (expr_type == TypeManager.int32_type){
1237 // From int to sbyte, byte, short, ushort, uint, ulong, char
1239 if (target_type == TypeManager.sbyte_type)
1240 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1241 if (target_type == TypeManager.byte_type)
1242 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1243 if (target_type == TypeManager.short_type)
1244 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1245 if (target_type == TypeManager.ushort_type)
1246 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1247 if (target_type == TypeManager.uint32_type)
1248 return new EmptyCast (expr, target_type);
1249 if (target_type == TypeManager.uint64_type)
1250 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1251 if (target_type == TypeManager.char_type)
1252 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1253 } else if (expr_type == TypeManager.uint32_type){
1255 // From uint to sbyte, byte, short, ushort, int, char
1257 if (target_type == TypeManager.sbyte_type)
1258 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1259 if (target_type == TypeManager.byte_type)
1260 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1261 if (target_type == TypeManager.short_type)
1262 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1263 if (target_type == TypeManager.ushort_type)
1264 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1265 if (target_type == TypeManager.int32_type)
1266 return new EmptyCast (expr, target_type);
1267 if (target_type == TypeManager.char_type)
1268 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1269 } else if (expr_type == TypeManager.int64_type){
1271 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1273 if (target_type == TypeManager.sbyte_type)
1274 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1275 if (target_type == TypeManager.byte_type)
1276 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1277 if (target_type == TypeManager.short_type)
1278 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1279 if (target_type == TypeManager.ushort_type)
1280 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1281 if (target_type == TypeManager.int32_type)
1282 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1283 if (target_type == TypeManager.uint32_type)
1284 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1285 if (target_type == TypeManager.uint64_type)
1286 return new EmptyCast (expr, target_type);
1287 if (target_type == TypeManager.char_type)
1288 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1289 } else if (expr_type == TypeManager.uint64_type){
1291 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1293 if (target_type == TypeManager.sbyte_type)
1294 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1295 if (target_type == TypeManager.byte_type)
1296 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1297 if (target_type == TypeManager.short_type)
1298 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1299 if (target_type == TypeManager.ushort_type)
1300 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1301 if (target_type == TypeManager.int32_type)
1302 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1303 if (target_type == TypeManager.uint32_type)
1304 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1305 if (target_type == TypeManager.int64_type)
1306 return new EmptyCast (expr, target_type);
1307 if (target_type == TypeManager.char_type)
1308 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1309 } else if (expr_type == TypeManager.char_type){
1311 // From char to sbyte, byte, short
1313 if (target_type == TypeManager.sbyte_type)
1314 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1315 if (target_type == TypeManager.byte_type)
1316 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1317 if (target_type == TypeManager.short_type)
1318 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1319 } else if (expr_type == TypeManager.float_type){
1321 // From float to sbyte, byte, short,
1322 // ushort, int, uint, long, ulong, char
1325 if (target_type == TypeManager.sbyte_type)
1326 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1327 if (target_type == TypeManager.byte_type)
1328 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1329 if (target_type == TypeManager.short_type)
1330 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1331 if (target_type == TypeManager.ushort_type)
1332 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1333 if (target_type == TypeManager.int32_type)
1334 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1335 if (target_type == TypeManager.uint32_type)
1336 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1337 if (target_type == TypeManager.int64_type)
1338 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1339 if (target_type == TypeManager.uint64_type)
1340 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1341 if (target_type == TypeManager.char_type)
1342 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1343 if (target_type == TypeManager.decimal_type)
1344 return InternalTypeConstructor (ec, expr, target_type);
1345 } else if (expr_type == TypeManager.double_type){
1347 // From double to byte, byte, short,
1348 // ushort, int, uint, long, ulong,
1349 // char, float or decimal
1351 if (target_type == TypeManager.sbyte_type)
1352 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1353 if (target_type == TypeManager.byte_type)
1354 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1355 if (target_type == TypeManager.short_type)
1356 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1357 if (target_type == TypeManager.ushort_type)
1358 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1359 if (target_type == TypeManager.int32_type)
1360 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1361 if (target_type == TypeManager.uint32_type)
1362 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1363 if (target_type == TypeManager.int64_type)
1364 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1365 if (target_type == TypeManager.uint64_type)
1366 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1367 if (target_type == TypeManager.char_type)
1368 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1369 if (target_type == TypeManager.float_type)
1370 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
1371 if (target_type == TypeManager.decimal_type)
1372 return InternalTypeConstructor (ec, expr, target_type);
1375 // decimal is taken care of by the op_Explicit methods.
1381 // Returns whether an explicit reference conversion can be performed
1382 // from source_type to target_type
1384 static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1386 bool target_is_value_type = target_type.IsValueType;
1388 if (source_type == target_type)
1392 // From object to any reference type
1394 if (source_type == TypeManager.object_type && !target_is_value_type)
1398 // From any class S to any class-type T, provided S is a base class of T
1400 if (target_type.IsSubclassOf (source_type))
1404 // From any interface type S to any interface T provided S is not derived from T
1406 if (source_type.IsInterface && target_type.IsInterface){
1407 if (!target_type.IsSubclassOf (source_type))
1412 // From any class type S to any interface T, provides S is not sealed
1413 // and provided S does not implement T.
1415 if (target_type.IsInterface && !source_type.IsSealed &&
1416 !target_type.IsAssignableFrom (source_type))
1420 // From any interface-type S to to any class type T, provided T is not
1421 // sealed, or provided T implements S.
1423 if (source_type.IsInterface &&
1424 (!target_type.IsSealed || source_type.IsAssignableFrom (target_type)))
1427 // From an array type S with an element type Se to an array type T with an
1428 // element type Te provided all the following are true:
1429 // * S and T differe only in element type, in other words, S and T
1430 // have the same number of dimensions.
1431 // * Both Se and Te are reference types
1432 // * An explicit referenc conversions exist from Se to Te
1434 if (source_type.IsArray && target_type.IsArray) {
1435 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1437 Type source_element_type = source_type.GetElementType ();
1438 Type target_element_type = target_type.GetElementType ();
1440 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1441 if (ExplicitReferenceConversionExists (source_element_type,
1442 target_element_type))
1448 // From System.Array to any array-type
1449 if (source_type == TypeManager.array_type &&
1450 target_type.IsSubclassOf (TypeManager.array_type)){
1455 // From System delegate to any delegate-type
1457 if (source_type == TypeManager.delegate_type &&
1458 target_type.IsSubclassOf (TypeManager.delegate_type))
1462 // From ICloneable to Array or Delegate types
1464 if (source_type == TypeManager.icloneable_type &&
1465 (target_type == TypeManager.array_type ||
1466 target_type == TypeManager.delegate_type))
1473 // Implements Explicit Reference conversions
1475 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
1477 Type source_type = source.Type;
1478 bool target_is_value_type = target_type.IsValueType;
1481 // From object to any reference type
1483 if (source_type == TypeManager.object_type && !target_is_value_type)
1484 return new ClassCast (source, target_type);
1488 // From any class S to any class-type T, provided S is a base class of T
1490 if (target_type.IsSubclassOf (source_type))
1491 return new ClassCast (source, target_type);
1494 // From any interface type S to any interface T provided S is not derived from T
1496 if (source_type.IsInterface && target_type.IsInterface){
1498 Type [] ifaces = source_type.GetInterfaces ();
1500 if (TypeManager.ImplementsInterface (source_type, target_type))
1503 return new ClassCast (source, target_type);
1507 // From any class type S to any interface T, provides S is not sealed
1508 // and provided S does not implement T.
1510 if (target_type.IsInterface && !source_type.IsSealed) {
1512 if (TypeManager.ImplementsInterface (source_type, target_type))
1515 return new ClassCast (source, target_type);
1520 // From any interface-type S to to any class type T, provided T is not
1521 // sealed, or provided T implements S.
1523 if (source_type.IsInterface) {
1525 if (target_type.IsSealed)
1528 if (TypeManager.ImplementsInterface (target_type, source_type))
1529 return new ClassCast (source, target_type);
1534 // From an array type S with an element type Se to an array type T with an
1535 // element type Te provided all the following are true:
1536 // * S and T differe only in element type, in other words, S and T
1537 // have the same number of dimensions.
1538 // * Both Se and Te are reference types
1539 // * An explicit referenc conversions exist from Se to Te
1541 if (source_type.IsArray && target_type.IsArray) {
1542 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1544 Type source_element_type = source_type.GetElementType ();
1545 Type target_element_type = target_type.GetElementType ();
1547 if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1548 if (ExplicitReferenceConversionExists (source_element_type,
1549 target_element_type))
1550 return new ClassCast (source, target_type);
1555 // From System.Array to any array-type
1556 if (source_type == TypeManager.array_type &&
1557 target_type.IsSubclassOf (TypeManager.array_type)){
1558 return new ClassCast (source, target_type);
1562 // From System delegate to any delegate-type
1564 if (source_type == TypeManager.delegate_type &&
1565 target_type.IsSubclassOf (TypeManager.delegate_type))
1566 return new ClassCast (source, target_type);
1569 // From ICloneable to Array or Delegate types
1571 if (source_type == TypeManager.icloneable_type &&
1572 (target_type == TypeManager.array_type ||
1573 target_type == TypeManager.delegate_type))
1574 return new ClassCast (source, target_type);
1580 // Performs an explicit conversion of the expression `expr' whose
1581 // type is expr.Type to `target_type'.
1583 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
1584 Type target_type, Location loc)
1586 Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
1591 ne = ConvertNumericExplicit (ec, expr, target_type);
1595 ne = ConvertReferenceExplicit (expr, target_type);
1599 ne = ExplicitUserConversion (ec, expr, target_type, loc);
1603 Report.Error (30, loc, "Cannot convert type '" + TypeManager.CSharpName (expr.Type) + "' to '"
1604 + TypeManager.CSharpName (target_type) + "'");
1609 // Same as ConverExplicit, only it doesn't include user defined conversions
1611 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
1612 Type target_type, Location l)
1614 Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
1619 ne = ConvertNumericExplicit (ec, expr, target_type);
1623 ne = ConvertReferenceExplicit (expr, target_type);
1627 Report.Error (30, l, "Cannot convert type '" +
1628 TypeManager.CSharpName (expr.Type) + "' to '" +
1629 TypeManager.CSharpName (target_type) + "'");
1633 static string ExprClassName (ExprClass c)
1636 case ExprClass.Invalid:
1638 case ExprClass.Value:
1640 case ExprClass.Variable:
1642 case ExprClass.Namespace:
1644 case ExprClass.Type:
1646 case ExprClass.MethodGroup:
1647 return "method group";
1648 case ExprClass.PropertyAccess:
1649 return "property access";
1650 case ExprClass.EventAccess:
1651 return "event access";
1652 case ExprClass.IndexerAccess:
1653 return "indexer access";
1654 case ExprClass.Nothing:
1657 throw new Exception ("Should not happen");
1661 // Reports that we were expecting `expr' to be of class `expected'
1663 protected void report118 (Location loc, Expression expr, string expected)
1665 string kind = "Unknown";
1668 kind = ExprClassName (expr.ExprClass);
1670 Error (118, loc, "Expression denotes a '" + kind +
1671 "' where an " + expected + " was expected");
1675 // This function tries to reduce the expression performing
1676 // constant folding and common subexpression elimination
1678 static public Expression Reduce (EmitContext ec, Expression e)
1680 //Console.WriteLine ("Calling reduce");
1681 return e.Reduce (ec);
1686 // This is just a base class for expressions that can
1687 // appear on statements (invocations, object creation,
1688 // assignments, post/pre increment and decrement). The idea
1689 // being that they would support an extra Emition interface that
1690 // does not leave a result on the stack.
1693 public abstract class ExpressionStatement : Expression {
1696 // Requests the expression to be emitted in a `statement'
1697 // context. This means that no new value is left on the
1698 // stack after invoking this method (constrasted with
1699 // Emit that will always leave a value on the stack).
1701 public abstract void EmitStatement (EmitContext ec);
1705 // This kind of cast is used to encapsulate the child
1706 // whose type is child.Type into an expression that is
1707 // reported to return "return_type". This is used to encapsulate
1708 // expressions which have compatible types, but need to be dealt
1709 // at higher levels with.
1711 // For example, a "byte" expression could be encapsulated in one
1712 // of these as an "unsigned int". The type for the expression
1713 // would be "unsigned int".
1717 public class EmptyCast : Expression {
1718 protected Expression child;
1720 public EmptyCast (Expression child, Type return_type)
1722 ExprClass = child.ExprClass;
1727 public override Expression DoResolve (EmitContext ec)
1729 // This should never be invoked, we are born in fully
1730 // initialized state.
1735 public override void Emit (EmitContext ec)
1743 // This class is used to wrap literals which belong inside Enums
1746 public class EnumLiteral : Literal {
1749 public EnumLiteral (Expression child, Type enum_type)
1751 ExprClass = child.ExprClass;
1756 public override Expression DoResolve (EmitContext ec)
1758 // This should never be invoked, we are born in fully
1759 // initialized state.
1764 public override void Emit (EmitContext ec)
1769 public override object GetValue ()
1771 return ((Literal) child).GetValue ();
1774 public override string AsString ()
1776 return ((Literal) child).AsString ();
1781 // This kind of cast is used to encapsulate Value Types in objects.
1783 // The effect of it is to box the value type emitted by the previous
1786 public class BoxedCast : EmptyCast {
1788 public BoxedCast (Expression expr)
1789 : base (expr, TypeManager.object_type)
1793 public override Expression DoResolve (EmitContext ec)
1795 // This should never be invoked, we are born in fully
1796 // initialized state.
1801 public override void Emit (EmitContext ec)
1804 ec.ig.Emit (OpCodes.Box, child.Type);
1809 // This kind of cast is used to encapsulate a child expression
1810 // that can be trivially converted to a target type using one or
1811 // two opcodes. The opcodes are passed as arguments.
1813 public class OpcodeCast : EmptyCast {
1817 public OpcodeCast (Expression child, Type return_type, OpCode op)
1818 : base (child, return_type)
1822 second_valid = false;
1825 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1826 : base (child, return_type)
1831 second_valid = true;
1834 public override Expression DoResolve (EmitContext ec)
1836 // This should never be invoked, we are born in fully
1837 // initialized state.
1842 public override void Emit (EmitContext ec)
1854 // This kind of cast is used to encapsulate a child and cast it
1855 // to the class requested
1857 public class ClassCast : EmptyCast {
1858 public ClassCast (Expression child, Type return_type)
1859 : base (child, return_type)
1864 public override Expression DoResolve (EmitContext ec)
1866 // This should never be invoked, we are born in fully
1867 // initialized state.
1872 public override void Emit (EmitContext ec)
1876 ec.ig.Emit (OpCodes.Castclass, type);
1882 // SimpleName expressions are initially formed of a single
1883 // word and it only happens at the beginning of the expression.
1885 // The expression will try to be bound to a Field, a Method
1886 // group or a Property. If those fail we pass the name to our
1887 // caller and the SimpleName is compounded to perform a type
1888 // lookup. The idea behind this process is that we want to avoid
1889 // creating a namespace map from the assemblies, as that requires
1890 // the GetExportedTypes function to be called and a hashtable to
1891 // be constructed which reduces startup time. If later we find
1892 // that this is slower, we should create a `NamespaceExpr' expression
1893 // that fully participates in the resolution process.
1895 // For example `System.Console.WriteLine' is decomposed into
1896 // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
1898 // The first SimpleName wont produce a match on its own, so it will
1900 // MemberAccess (SimpleName ("System.Console"), "WriteLine").
1902 // System.Console will produce a TypeExpr match.
1904 // The downside of this is that we might be hitting `LookupType' too many
1905 // times with this scheme.
1907 public class SimpleName : Expression {
1908 public readonly string Name;
1909 public readonly Location Location;
1911 public SimpleName (string name, Location l)
1917 public static void Error120 (Location l, string name)
1921 "An object reference is required " +
1922 "for the non-static field `"+name+"'");
1926 // Checks whether we are trying to access an instance
1927 // property, method or field from a static body.
1929 Expression MemberStaticCheck (Expression e)
1931 if (e is FieldExpr){
1932 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1935 Error120 (Location, Name);
1938 } else if (e is MethodGroupExpr){
1939 MethodGroupExpr mg = (MethodGroupExpr) e;
1941 if (!mg.RemoveInstanceMethods ()){
1942 Error120 (Location, mg.Methods [0].Name);
1946 } else if (e is PropertyExpr){
1947 if (!((PropertyExpr) e).IsStatic){
1948 Error120 (Location, Name);
1957 // 7.5.2: Simple Names.
1959 // Local Variables and Parameters are handled at
1960 // parse time, so they never occur as SimpleNames.
1962 public override Expression DoResolve (EmitContext ec)
1967 // Stage 1: Performed by the parser (binding to local or parameters).
1971 // Stage 2: Lookup members
1973 e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true, Location);
1976 // Stage 3: Lookup symbol in the various namespaces.
1980 if ((t = ec.TypeContainer.LookupType (Name, true)) != null)
1981 return new TypeExpr (t);
1984 // Stage 3 part b: Lookup up if we are an alias to a type
1987 // Since we are cheating: we only do the Alias lookup for
1988 // namespaces if the name does not include any dots in it
1991 // IMPLEMENT ME. Read mcs/mcs/TODO for ideas, or rewrite
1992 // using NamespaceExprs (dunno how that fixes the alias
1993 // per-file though).
1995 // No match, maybe our parent can compose us
1996 // into something meaningful.
2001 // Step 2, continues here.
2005 if (e is FieldExpr){
2006 FieldExpr fe = (FieldExpr) e;
2008 if (!fe.FieldInfo.IsStatic)
2009 fe.InstanceExpression = new This (Location.Null);
2013 return MemberStaticCheck (e);
2018 public override void Emit (EmitContext ec)
2021 // If this is ever reached, then we failed to
2022 // find the name as a namespace
2025 Error (103, Location, "The name `" + Name +
2026 "' does not exist in the class `" +
2027 ec.TypeContainer.Name + "'");
2032 // Fully resolved expression that evaluates to a type
2034 public class TypeExpr : Expression {
2035 public TypeExpr (Type t)
2038 eclass = ExprClass.Type;
2041 override public Expression DoResolve (EmitContext ec)
2046 override public void Emit (EmitContext ec)
2048 throw new Exception ("Implement me");
2053 // MethodGroup Expression.
2055 // This is a fully resolved expression that evaluates to a type
2057 public class MethodGroupExpr : Expression {
2058 public MethodBase [] Methods;
2059 Expression instance_expression = null;
2061 public MethodGroupExpr (MemberInfo [] mi)
2063 Methods = new MethodBase [mi.Length];
2064 mi.CopyTo (Methods, 0);
2065 eclass = ExprClass.MethodGroup;
2068 public MethodGroupExpr (ArrayList l)
2070 Methods = new MethodBase [l.Count];
2072 l.CopyTo (Methods, 0);
2073 eclass = ExprClass.MethodGroup;
2077 // `A method group may have associated an instance expression'
2079 public Expression InstanceExpression {
2081 return instance_expression;
2085 instance_expression = value;
2089 override public Expression DoResolve (EmitContext ec)
2094 override public void Emit (EmitContext ec)
2096 throw new Exception ("This should never be reached");
2099 bool RemoveMethods (bool keep_static)
2101 ArrayList smethods = new ArrayList ();
2102 int top = Methods.Length;
2105 for (i = 0; i < top; i++){
2106 MethodBase mb = Methods [i];
2108 if (mb.IsStatic == keep_static)
2112 if (smethods.Count == 0)
2115 Methods = new MethodBase [smethods.Count];
2116 smethods.CopyTo (Methods, 0);
2122 // Removes any instance methods from the MethodGroup, returns
2123 // false if the resulting set is empty.
2125 public bool RemoveInstanceMethods ()
2127 return RemoveMethods (true);
2131 // Removes any static methods from the MethodGroup, returns
2132 // false if the resulting set is empty.
2134 public bool RemoveStaticMethods ()
2136 return RemoveMethods (false);
2141 // Fully resolved expression that evaluates to a Field
2143 public class FieldExpr : Expression, IStackStore, IMemoryLocation {
2144 public readonly FieldInfo FieldInfo;
2145 public Expression InstanceExpression;
2148 public FieldExpr (FieldInfo fi, Location l)
2151 eclass = ExprClass.Variable;
2152 type = fi.FieldType;
2156 override public Expression DoResolve (EmitContext ec)
2158 if (!FieldInfo.IsStatic){
2159 if (InstanceExpression == null){
2160 throw new Exception ("non-static FieldExpr without instance var\n" +
2161 "You have to assign the Instance variable\n" +
2162 "Of the FieldExpr to set this\n");
2165 InstanceExpression = InstanceExpression.Resolve (ec);
2166 if (InstanceExpression == null)
2173 public Expression DoResolveLValue (EmitContext ec)
2175 if (!FieldInfo.IsInitOnly)
2179 // InitOnly fields can only be assigned in constructors
2182 if (ec.IsConstructor)
2185 Report.Error (191, loc,
2186 "Readonly field can not be assigned outside " +
2187 "of constructor or variable initializer");
2192 override public void Emit (EmitContext ec)
2194 ILGenerator ig = ec.ig;
2196 if (FieldInfo.IsStatic)
2197 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2199 InstanceExpression.Emit (ec);
2201 ig.Emit (OpCodes.Ldfld, FieldInfo);
2205 public void Store (EmitContext ec)
2207 if (FieldInfo.IsStatic)
2208 ec.ig.Emit (OpCodes.Stsfld, FieldInfo);
2210 ec.ig.Emit (OpCodes.Stfld, FieldInfo);
2213 public void AddressOf (EmitContext ec)
2215 if (FieldInfo.IsStatic)
2216 ec.ig.Emit (OpCodes.Ldsflda, FieldInfo);
2218 InstanceExpression.Emit (ec);
2219 ec.ig.Emit (OpCodes.Ldflda, FieldInfo);
2225 // Expression that evaluates to a Property. The Assign class
2226 // might set the `Value' expression if we are in an assignment.
2228 // This is not an LValue because we need to re-write the expression, we
2229 // can not take data from the stack and store it.
2231 public class PropertyExpr : ExpressionStatement, IAssignMethod {
2232 public readonly PropertyInfo PropertyInfo;
2233 public readonly bool IsStatic;
2234 MethodInfo [] Accessors;
2237 Expression instance_expr;
2239 public PropertyExpr (PropertyInfo pi, Location l)
2242 eclass = ExprClass.PropertyAccess;
2245 Accessors = TypeManager.GetAccessors (pi);
2247 if (Accessors != null)
2248 for (int i = 0; i < Accessors.Length; i++){
2249 if (Accessors [i] != null)
2250 if (Accessors [i].IsStatic)
2254 Accessors = new MethodInfo [2];
2256 type = pi.PropertyType;
2260 // The instance expression associated with this expression
2262 public Expression InstanceExpression {
2264 instance_expr = value;
2268 return instance_expr;
2272 public bool VerifyAssignable ()
2274 if (!PropertyInfo.CanWrite){
2275 Report.Error (200, loc,
2276 "The property `" + PropertyInfo.Name +
2277 "' can not be assigned to, as it has not set accessor");
2284 override public Expression DoResolve (EmitContext ec)
2286 if (!PropertyInfo.CanRead){
2287 Report.Error (154, loc,
2288 "The property `" + PropertyInfo.Name +
2289 "' can not be used in " +
2290 "this context because it lacks a get accessor");
2297 override public void Emit (EmitContext ec)
2299 Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null);
2304 // Implements the IAssignMethod interface for assignments
2306 public void EmitAssign (EmitContext ec, Expression source)
2308 Argument arg = new Argument (source, Argument.AType.Expression);
2309 ArrayList args = new ArrayList ();
2312 Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args);
2315 override public void EmitStatement (EmitContext ec)
2318 ec.ig.Emit (OpCodes.Pop);
2323 // Fully resolved expression that evaluates to a Expression
2325 public class EventExpr : Expression {
2326 public readonly EventInfo EventInfo;
2329 public EventExpr (EventInfo ei, Location loc)
2333 eclass = ExprClass.EventAccess;
2336 override public Expression DoResolve (EmitContext ec)
2338 // We are born in resolved state.
2342 override public void Emit (EmitContext ec)
2344 throw new Exception ("Implement me");
2345 // FIXME: Implement.