2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
11 namespace Mono.CSharp {
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 : byte {
40 /// This is used to tell Resolve in which types of expressions we're
44 public enum ResolveFlags {
45 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
48 // Returns a type expression.
51 // Returns a method group.
54 // Mask of all the expression class flags.
57 // Disable control flow analysis while resolving the expression.
58 // This is used when resolving the instance expression of a field expression.
59 DisableFlowAnalysis = 8,
61 // Set if this is resolving the first part of a MemberAccess.
66 // This is just as a hint to AddressOf of what will be done with the
69 public enum AddressOp {
76 /// This interface is implemented by variables
78 public interface IMemoryLocation {
80 /// The AddressOf method should generate code that loads
81 /// the address of the object and leaves it on the stack.
83 /// The `mode' argument is used to notify the expression
84 /// of whether this will be used to read from the address or
85 /// write to the address.
87 /// This is just a hint that can be used to provide good error
88 /// reporting, and should have no other side effects.
90 void AddressOf (EmitContext ec, AddressOp mode);
94 /// This interface is implemented by variables
96 public interface IVariable {
97 VariableInfo VariableInfo {
105 /// Base class for expressions
107 public abstract class Expression {
108 public ExprClass eclass;
110 protected Location loc;
114 set { type = value; }
117 public Location Location {
122 /// Utility wrapper routine for Error, just to beautify the code
124 public void Error (int error, string s)
127 Report.Error (error, loc, s);
129 Report.Error (error, s);
133 /// Utility wrapper routine for Warning, just to beautify the code
135 public void Warning (int code, string format, params object[] args)
137 Report.Warning (code, loc, format, args);
140 // Not nice but we have broken hierarchy
141 public virtual void CheckMarshallByRefAccess (Type container) {}
144 /// Tests presence of ObsoleteAttribute and report proper error
146 protected void CheckObsoleteAttribute (Type type)
148 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (type);
149 if (obsolete_attr == null)
152 AttributeTester.Report_ObsoleteMessage (obsolete_attr, type.FullName, loc);
155 public virtual string GetSignatureForError ()
157 return TypeManager.CSharpName (type);
160 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
162 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
164 must_do_cs1540_check = false; // by default we do not check for this
167 // If only accessible to the current class or children
169 if (ma == MethodAttributes.Private)
170 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
171 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
173 if (mi.DeclaringType.Assembly == invocation_type.Assembly) {
174 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
177 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
181 // Family and FamANDAssem require that we derive.
182 // FamORAssem requires that we derive if in different assemblies.
183 if (ma == MethodAttributes.Family ||
184 ma == MethodAttributes.FamANDAssem ||
185 ma == MethodAttributes.FamORAssem) {
186 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
189 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
190 must_do_cs1540_check = true;
199 /// Performs semantic analysis on the Expression
203 /// The Resolve method is invoked to perform the semantic analysis
206 /// The return value is an expression (it can be the
207 /// same expression in some cases) or a new
208 /// expression that better represents this node.
210 /// For example, optimizations of Unary (LiteralInt)
211 /// would return a new LiteralInt with a negated
214 /// If there is an error during semantic analysis,
215 /// then an error should be reported (using Report)
216 /// and a null value should be returned.
218 /// There are two side effects expected from calling
219 /// Resolve(): the the field variable "eclass" should
220 /// be set to any value of the enumeration
221 /// `ExprClass' and the type variable should be set
222 /// to a valid type (this is the type of the
225 public abstract Expression DoResolve (EmitContext ec);
227 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
233 // This is used if the expression should be resolved as a type or namespace name.
234 // the default implementation fails.
236 public FullNamedExpression ResolveAsTypeStep (EmitContext ec)
238 return ResolveAsTypeStep (ec, false);
241 public virtual FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
247 // This is used to resolve the expression as a type, a null
248 // value will be returned if the expression is not a type
251 public TypeExpr ResolveAsTypeTerminal (EmitContext ec)
253 return ResolveAsTypeTerminal (ec, false);
256 public virtual TypeExpr ResolveAsTypeTerminal (EmitContext ec, bool silent)
258 int errors = Report.Errors;
260 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
265 if (fne.eclass != ExprClass.Type) {
266 if (!silent && (errors == Report.Errors))
267 fne.Error_UnexpectedKind (null, "type", loc);
271 TypeExpr te = fne as TypeExpr;
273 if (!te.CheckAccessLevel (ec.DeclSpace)) {
274 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
278 ConstructedType ct = te as ConstructedType;
279 if ((ct != null) && !ec.ResolvingTypeTree && !ct.CheckConstraints (ec))
285 public static void ErrorIsInaccesible (Location loc, string name)
287 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
290 ResolveFlags ExprClassToResolveFlags ()
294 case ExprClass.Namespace:
295 return ResolveFlags.Type;
297 case ExprClass.MethodGroup:
298 return ResolveFlags.MethodGroup;
300 case ExprClass.Value:
301 case ExprClass.Variable:
302 case ExprClass.PropertyAccess:
303 case ExprClass.EventAccess:
304 case ExprClass.IndexerAccess:
305 return ResolveFlags.VariableOrValue;
308 throw new Exception ("Expression " + GetType () +
309 " ExprClass is Invalid after resolve");
315 /// Resolves an expression and performs semantic analysis on it.
319 /// Currently Resolve wraps DoResolve to perform sanity
320 /// checking and assertion checking on what we expect from Resolve.
322 public Expression Resolve (EmitContext ec, ResolveFlags flags)
324 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
325 return ResolveAsTypeStep (ec, false);
327 bool old_do_flow_analysis = ec.DoFlowAnalysis;
328 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
329 ec.DoFlowAnalysis = false;
332 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
333 if (this is SimpleName)
334 e = ((SimpleName) this).DoResolve (ec, intermediate);
339 ec.DoFlowAnalysis = old_do_flow_analysis;
344 if ((flags & e.ExprClassToResolveFlags ()) == 0) {
345 e.Error_UnexpectedKind (flags, loc);
349 if (e.type == null && !(e is Namespace)) {
350 throw new Exception (
351 "Expression " + e.GetType () +
352 " did not set its type after Resolve\n" +
353 "called from: " + this.GetType ());
360 /// Resolves an expression and performs semantic analysis on it.
362 public Expression Resolve (EmitContext ec)
364 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
366 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
367 ((MethodGroupExpr) e).ReportUsageError ();
374 /// Resolves an expression for LValue assignment
378 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
379 /// checking and assertion checking on what we expect from Resolve
381 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
383 int errors = Report.Errors;
384 Expression e = DoResolveLValue (ec, right_side);
387 if (errors == Report.Errors)
388 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
393 if (e.eclass == ExprClass.Invalid)
394 throw new Exception ("Expression " + e +
395 " ExprClass is Invalid after resolve");
397 if (e.eclass == ExprClass.MethodGroup) {
398 ((MethodGroupExpr) e).ReportUsageError ();
402 if ((e.type == null) && !(e is ConstructedType))
403 throw new Exception ("Expression " + e +
404 " did not set its type after Resolve");
411 /// Emits the code for the expression
415 /// The Emit method is invoked to generate the code
416 /// for the expression.
418 public abstract void Emit (EmitContext ec);
420 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
423 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
427 /// Protected constructor. Only derivate types should
428 /// be able to be created
431 protected Expression ()
433 eclass = ExprClass.Invalid;
438 /// Returns a literalized version of a literal FieldInfo
442 /// The possible return values are:
443 /// IntConstant, UIntConstant
444 /// LongLiteral, ULongConstant
445 /// FloatConstant, DoubleConstant
448 /// The value returned is already resolved.
450 public static Constant Constantify (object v, Type t)
452 if (t == TypeManager.int32_type)
453 return new IntConstant ((int) v);
454 else if (t == TypeManager.uint32_type)
455 return new UIntConstant ((uint) v);
456 else if (t == TypeManager.int64_type)
457 return new LongConstant ((long) v);
458 else if (t == TypeManager.uint64_type)
459 return new ULongConstant ((ulong) v);
460 else if (t == TypeManager.float_type)
461 return new FloatConstant ((float) v);
462 else if (t == TypeManager.double_type)
463 return new DoubleConstant ((double) v);
464 else if (t == TypeManager.string_type)
465 return new StringConstant ((string) v);
466 else if (t == TypeManager.short_type)
467 return new ShortConstant ((short)v);
468 else if (t == TypeManager.ushort_type)
469 return new UShortConstant ((ushort)v);
470 else if (t == TypeManager.sbyte_type)
471 return new SByteConstant (((sbyte)v));
472 else if (t == TypeManager.byte_type)
473 return new ByteConstant ((byte)v);
474 else if (t == TypeManager.char_type)
475 return new CharConstant ((char)v);
476 else if (t == TypeManager.bool_type)
477 return new BoolConstant ((bool) v);
478 else if (t == TypeManager.decimal_type)
479 return new DecimalConstant ((decimal) v);
480 else if (TypeManager.IsEnumType (t)){
481 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
483 real_type = System.Enum.GetUnderlyingType (real_type);
485 Constant e = Constantify (v, real_type);
487 return new EnumConstant (e, t);
488 } else if (v == null && !TypeManager.IsValueType (t))
489 return NullLiteral.Null;
491 throw new Exception ("Unknown type for constant (" + t +
496 /// Returns a fully formed expression after a MemberLookup
498 public static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
501 return new EventExpr ((EventInfo) mi, loc);
502 else if (mi is FieldInfo)
503 return new FieldExpr ((FieldInfo) mi, loc);
504 else if (mi is PropertyInfo)
505 return new PropertyExpr (ec, (PropertyInfo) mi, loc);
506 else if (mi is Type){
507 return new TypeExpression ((System.Type) mi, loc);
513 protected static ArrayList almostMatchedMembers = new ArrayList (4);
516 // FIXME: Probably implement a cache for (t,name,current_access_set)?
518 // This code could use some optimizations, but we need to do some
519 // measurements. For example, we could use a delegate to `flag' when
520 // something can not any longer be a method-group (because it is something
524 // If the return value is an Array, then it is an array of
527 // If the return value is an MemberInfo, it is anything, but a Method
531 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
532 // the arguments here and have MemberLookup return only the methods that
533 // match the argument count/type, unlike we are doing now (we delay this
536 // This is so we can catch correctly attempts to invoke instance methods
537 // from a static body (scan for error 120 in ResolveSimpleName).
540 // FIXME: Potential optimization, have a static ArrayList
543 public static Expression MemberLookup (EmitContext ec, Type queried_type, string name,
544 MemberTypes mt, BindingFlags bf, Location loc)
546 return MemberLookup (ec, ec.ContainerType, null, queried_type, name, mt, bf, loc);
550 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
551 // `qualifier_type' or null to lookup members in the current class.
554 public static Expression MemberLookup (EmitContext ec, Type container_type,
555 Type qualifier_type, Type queried_type,
556 string name, MemberTypes mt,
557 BindingFlags bf, Location loc)
559 almostMatchedMembers.Clear ();
561 MemberInfo [] mi = TypeManager.MemberLookup (
562 container_type, qualifier_type, queried_type, mt, bf, name,
563 almostMatchedMembers);
568 int count = mi.Length;
570 if (mi [0] is MethodBase)
571 return new MethodGroupExpr (mi, loc);
576 return ExprClassFromMemberInfo (ec, mi [0], loc);
579 public const MemberTypes AllMemberTypes =
580 MemberTypes.Constructor |
584 MemberTypes.NestedType |
585 MemberTypes.Property;
587 public const BindingFlags AllBindingFlags =
588 BindingFlags.Public |
589 BindingFlags.Static |
590 BindingFlags.Instance;
592 public static Expression MemberLookup (EmitContext ec, Type queried_type,
593 string name, Location loc)
595 return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
596 AllMemberTypes, AllBindingFlags, loc);
599 public static Expression MemberLookup (EmitContext ec, Type qualifier_type,
600 Type queried_type, string name, Location loc)
602 if (ec.ResolvingTypeTree)
603 return MemberLookup (ec, ec.ContainerType, qualifier_type,
604 queried_type, name, MemberTypes.NestedType,
605 AllBindingFlags, loc);
607 return MemberLookup (ec, ec.ContainerType, qualifier_type,
608 queried_type, name, AllMemberTypes,
609 AllBindingFlags, loc);
612 public static Expression MethodLookup (EmitContext ec, Type queried_type,
613 string name, Location loc)
615 return MemberLookup (ec, ec.ContainerType, null, queried_type, name,
616 MemberTypes.Method, AllBindingFlags, loc);
620 /// This is a wrapper for MemberLookup that is not used to "probe", but
621 /// to find a final definition. If the final definition is not found, we
622 /// look for private members and display a useful debugging message if we
625 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
626 Type queried_type, string name,
629 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
630 AllMemberTypes, AllBindingFlags, loc);
633 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
634 Type queried_type, string name,
635 MemberTypes mt, BindingFlags bf,
640 int errors = Report.Errors;
642 e = MemberLookup (ec, ec.ContainerType, qualifier_type, queried_type,
645 if (e == null && errors == Report.Errors)
646 // No errors were reported by MemberLookup, but there was an error.
647 MemberLookupFailed (ec, qualifier_type, queried_type, name, null, true, loc);
652 public static void MemberLookupFailed (EmitContext ec, Type qualifier_type,
653 Type queried_type, string name,
654 string class_name, bool complain_if_none_found,
657 if (almostMatchedMembers.Count != 0) {
658 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
659 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
660 for (int j = 0; j < i; ++j) {
661 if (m == almostMatchedMembers [j]) {
669 Type declaring_type = m.DeclaringType;
671 Report.SymbolRelatedToPreviousError (m);
672 if (qualifier_type == null) {
673 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
674 TypeManager.CSharpName (m.DeclaringType),
675 TypeManager.CSharpName (ec.ContainerType));
676 } else if (qualifier_type != ec.ContainerType &&
677 TypeManager.IsNestedFamilyAccessible (ec.ContainerType, declaring_type)) {
678 // Although a derived class can access protected members of
679 // its base class it cannot do so through an instance of the
680 // base class (CS1540). If the qualifier_type is a base of the
681 // ec.ContainerType and the lookup succeeds with the latter one,
682 // then we are in this situation.
683 Report.Error (1540, loc,
684 "Cannot access protected member `{0}' via a qualifier of type `{1}';"
685 + " the qualifier must be of type `{2}' (or derived from it)",
686 TypeManager.GetFullNameSignature (m),
687 TypeManager.CSharpName (qualifier_type),
688 TypeManager.CSharpName (ec.ContainerType));
690 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
693 almostMatchedMembers.Clear ();
697 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
698 AllMemberTypes, AllBindingFlags |
699 BindingFlags.NonPublic, name, null);
701 if (lookup == null) {
702 if (!complain_if_none_found)
705 if (class_name != null)
706 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
710 117, loc, "`" + TypeManager.CSharpName (queried_type) + "' does not contain a " +
711 "definition for `" + name + "'");
715 if (TypeManager.MemberLookup (queried_type, null, queried_type,
716 AllMemberTypes, AllBindingFlags |
717 BindingFlags.NonPublic, name, null) == null) {
718 if ((lookup.Length == 1) && (lookup [0] is Type)) {
719 Type t = (Type) lookup [0];
721 Report.Error (305, loc,
722 "Using the generic type `{0}' " +
723 "requires {1} type arguments",
724 TypeManager.GetFullName (t),
725 TypeManager.GetNumberOfTypeArguments (t));
730 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
731 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
732 if (name == ".ctor" && ml.Count == 0)
734 Report.Error (143, loc, String.Format ("The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type)));
738 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
742 /// Returns an expression that can be used to invoke operator true
743 /// on the expression if it exists.
745 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
747 return GetOperatorTrueOrFalse (ec, e, true, loc);
751 /// Returns an expression that can be used to invoke operator false
752 /// on the expression if it exists.
754 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
756 return GetOperatorTrueOrFalse (ec, e, false, loc);
759 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
762 Expression operator_group;
764 if (TypeManager.IsNullableType (e.Type))
765 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
767 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
768 if (operator_group == null)
771 ArrayList arguments = new ArrayList ();
772 arguments.Add (new Argument (e, Argument.AType.Expression));
773 method = Invocation.OverloadResolve (
774 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
779 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
783 /// Resolves the expression `e' into a boolean expression: either through
784 /// an implicit conversion, or through an `operator true' invocation
786 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
792 if (e.Type == TypeManager.bool_type)
795 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
797 if (converted != null)
801 // If no implicit conversion to bool exists, try using `operator true'
803 Expression operator_true = Expression.GetOperatorTrue (ec, e, loc);
804 if (operator_true == null){
805 Report.Error (31, loc, "Can not convert the expression to a boolean");
808 return operator_true;
811 string ExprClassName ()
814 case ExprClass.Invalid:
816 case ExprClass.Value:
818 case ExprClass.Variable:
820 case ExprClass.Namespace:
824 case ExprClass.MethodGroup:
825 return "method group";
826 case ExprClass.PropertyAccess:
827 return "property access";
828 case ExprClass.EventAccess:
829 return "event access";
830 case ExprClass.IndexerAccess:
831 return "indexer access";
832 case ExprClass.Nothing:
835 throw new Exception ("Should not happen");
839 /// Reports that we were expecting `expr' to be of class `expected'
841 public void Error_UnexpectedKind (EmitContext ec, string expected, Location loc)
843 Error_UnexpectedKind (ec, expected, ExprClassName (), loc);
846 public void Error_UnexpectedKind (EmitContext ec, string expected, string was, Location loc)
848 string name = GetSignatureForError ();
850 name = ec.DeclSpace.GetSignatureForError () + '.' + name;
852 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
853 name, was, expected);
856 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
858 string [] valid = new string [4];
861 if ((flags & ResolveFlags.VariableOrValue) != 0) {
862 valid [count++] = "variable";
863 valid [count++] = "value";
866 if ((flags & ResolveFlags.Type) != 0)
867 valid [count++] = "type";
869 if ((flags & ResolveFlags.MethodGroup) != 0)
870 valid [count++] = "method group";
873 valid [count++] = "unknown";
875 StringBuilder sb = new StringBuilder (valid [0]);
876 for (int i = 1; i < count - 1; i++) {
878 sb.Append (valid [i]);
881 sb.Append ("' or `");
882 sb.Append (valid [count - 1]);
885 Report.Error (119, loc,
886 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName (), sb);
889 public static void UnsafeError (Location loc)
891 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
895 /// Converts the IntConstant, UIntConstant, LongConstant or
896 /// ULongConstant into the integral target_type. Notice
897 /// that we do not return an `Expression' we do return
898 /// a boxed integral type.
900 /// FIXME: Since I added the new constants, we need to
901 /// also support conversions from CharConstant, ByteConstant,
902 /// SByteConstant, UShortConstant, ShortConstant
904 /// This is used by the switch statement, so the domain
905 /// of work is restricted to the literals above, and the
906 /// targets are int32, uint32, char, byte, sbyte, ushort,
907 /// short, uint64 and int64
909 public static object ConvertIntLiteral (Constant c, Type target_type, Location loc)
911 if (!Convert.ImplicitStandardConversionExists (Convert.ConstantEC, c, target_type)){
912 Convert.Error_CannotImplicitConversion (loc, c.Type, target_type);
916 if (c.Type == target_type)
917 return ((Constant) c).GetValue ();
920 // Make into one of the literals we handle, we dont really care
921 // about this value as we will just return a few limited types
923 if (c is EnumConstant)
924 c = ((EnumConstant)c).WidenToCompilerConstant ();
926 if (c is IntConstant){
927 int v = ((IntConstant) c).Value;
929 if (target_type == TypeManager.uint32_type){
932 } else if (target_type == TypeManager.char_type){
933 if (v >= Char.MinValue && v <= Char.MaxValue)
935 } else if (target_type == TypeManager.byte_type){
936 if (v >= Byte.MinValue && v <= Byte.MaxValue)
938 } else if (target_type == TypeManager.sbyte_type){
939 if (v >= SByte.MinValue && v <= SByte.MaxValue)
941 } else if (target_type == TypeManager.short_type){
942 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
944 } else if (target_type == TypeManager.ushort_type){
945 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
947 } else if (target_type == TypeManager.int64_type)
949 else if (target_type == TypeManager.uint64_type){
954 } else if (c is UIntConstant){
955 uint v = ((UIntConstant) c).Value;
957 if (target_type == TypeManager.int32_type){
958 if (v <= Int32.MaxValue)
960 } else if (target_type == TypeManager.char_type){
961 if (v >= Char.MinValue && v <= Char.MaxValue)
963 } else if (target_type == TypeManager.byte_type){
964 if (v <= Byte.MaxValue)
966 } else if (target_type == TypeManager.sbyte_type){
967 if (v <= SByte.MaxValue)
969 } else if (target_type == TypeManager.short_type){
970 if (v <= UInt16.MaxValue)
972 } else if (target_type == TypeManager.ushort_type){
973 if (v <= UInt16.MaxValue)
975 } else if (target_type == TypeManager.int64_type)
977 else if (target_type == TypeManager.uint64_type)
979 } else if (c is LongConstant){
980 long v = ((LongConstant) c).Value;
982 if (target_type == TypeManager.int32_type){
983 if (v >= UInt32.MinValue && v <= UInt32.MaxValue)
985 } else if (target_type == TypeManager.uint32_type){
986 if (v >= 0 && v <= UInt32.MaxValue)
988 } else if (target_type == TypeManager.char_type){
989 if (v >= Char.MinValue && v <= Char.MaxValue)
991 } else if (target_type == TypeManager.byte_type){
992 if (v >= Byte.MinValue && v <= Byte.MaxValue)
994 } else if (target_type == TypeManager.sbyte_type){
995 if (v >= SByte.MinValue && v <= SByte.MaxValue)
997 } else if (target_type == TypeManager.short_type){
998 if (v >= Int16.MinValue && v <= UInt16.MaxValue)
1000 } else if (target_type == TypeManager.ushort_type){
1001 if (v >= UInt16.MinValue && v <= UInt16.MaxValue)
1003 } else if (target_type == TypeManager.uint64_type){
1007 } else if (c is ULongConstant){
1008 ulong v = ((ULongConstant) c).Value;
1010 if (target_type == TypeManager.int32_type){
1011 if (v <= Int32.MaxValue)
1013 } else if (target_type == TypeManager.uint32_type){
1014 if (v <= UInt32.MaxValue)
1016 } else if (target_type == TypeManager.char_type){
1017 if (v >= Char.MinValue && v <= Char.MaxValue)
1019 } else if (target_type == TypeManager.byte_type){
1020 if (v >= Byte.MinValue && v <= Byte.MaxValue)
1022 } else if (target_type == TypeManager.sbyte_type){
1023 if (v <= (int) SByte.MaxValue)
1025 } else if (target_type == TypeManager.short_type){
1026 if (v <= UInt16.MaxValue)
1028 } else if (target_type == TypeManager.ushort_type){
1029 if (v <= UInt16.MaxValue)
1031 } else if (target_type == TypeManager.int64_type){
1032 if (v <= Int64.MaxValue)
1035 } else if (c is ByteConstant){
1036 byte v = ((ByteConstant) c).Value;
1038 if (target_type == TypeManager.int32_type)
1040 else if (target_type == TypeManager.uint32_type)
1042 else if (target_type == TypeManager.char_type)
1044 else if (target_type == TypeManager.sbyte_type){
1045 if (v <= SByte.MaxValue)
1047 } else if (target_type == TypeManager.short_type)
1049 else if (target_type == TypeManager.ushort_type)
1051 else if (target_type == TypeManager.int64_type)
1053 else if (target_type == TypeManager.uint64_type)
1055 } else if (c is SByteConstant){
1056 sbyte v = ((SByteConstant) c).Value;
1058 if (target_type == TypeManager.int32_type)
1060 else if (target_type == TypeManager.uint32_type){
1063 } else if (target_type == TypeManager.char_type){
1066 } else if (target_type == TypeManager.byte_type){
1069 } else if (target_type == TypeManager.short_type)
1071 else if (target_type == TypeManager.ushort_type){
1074 } else if (target_type == TypeManager.int64_type)
1076 else if (target_type == TypeManager.uint64_type){
1080 } else if (c is ShortConstant){
1081 short v = ((ShortConstant) c).Value;
1083 if (target_type == TypeManager.int32_type){
1085 } else if (target_type == TypeManager.uint32_type){
1088 } else if (target_type == TypeManager.char_type){
1091 } else if (target_type == TypeManager.byte_type){
1092 if (v >= Byte.MinValue && v <= Byte.MaxValue)
1094 } else if (target_type == TypeManager.sbyte_type){
1095 if (v >= SByte.MinValue && v <= SByte.MaxValue)
1097 } else if (target_type == TypeManager.ushort_type){
1100 } else if (target_type == TypeManager.int64_type)
1102 else if (target_type == TypeManager.uint64_type)
1104 } else if (c is UShortConstant){
1105 ushort v = ((UShortConstant) c).Value;
1107 if (target_type == TypeManager.int32_type)
1109 else if (target_type == TypeManager.uint32_type)
1111 else if (target_type == TypeManager.char_type){
1112 if (v >= Char.MinValue && v <= Char.MaxValue)
1114 } else if (target_type == TypeManager.byte_type){
1115 if (v >= Byte.MinValue && v <= Byte.MaxValue)
1117 } else if (target_type == TypeManager.sbyte_type){
1118 if (v <= SByte.MaxValue)
1120 } else if (target_type == TypeManager.short_type){
1121 if (v <= Int16.MaxValue)
1123 } else if (target_type == TypeManager.int64_type)
1125 else if (target_type == TypeManager.uint64_type)
1128 } else if (c is CharConstant){
1129 char v = ((CharConstant) c).Value;
1131 if (target_type == TypeManager.int32_type)
1133 else if (target_type == TypeManager.uint32_type)
1135 else if (target_type == TypeManager.byte_type){
1136 if (v >= Byte.MinValue && v <= Byte.MaxValue)
1138 } else if (target_type == TypeManager.sbyte_type){
1139 if (v <= SByte.MaxValue)
1141 } else if (target_type == TypeManager.short_type){
1142 if (v <= Int16.MaxValue)
1144 } else if (target_type == TypeManager.ushort_type)
1146 else if (target_type == TypeManager.int64_type)
1148 else if (target_type == TypeManager.uint64_type)
1152 c.Error_ConstantValueCannotBeConverted (loc, target_type);
1157 // Load the object from the pointer.
1159 public static void LoadFromPtr (ILGenerator ig, Type t)
1161 if (t == TypeManager.int32_type)
1162 ig.Emit (OpCodes.Ldind_I4);
1163 else if (t == TypeManager.uint32_type)
1164 ig.Emit (OpCodes.Ldind_U4);
1165 else if (t == TypeManager.short_type)
1166 ig.Emit (OpCodes.Ldind_I2);
1167 else if (t == TypeManager.ushort_type)
1168 ig.Emit (OpCodes.Ldind_U2);
1169 else if (t == TypeManager.char_type)
1170 ig.Emit (OpCodes.Ldind_U2);
1171 else if (t == TypeManager.byte_type)
1172 ig.Emit (OpCodes.Ldind_U1);
1173 else if (t == TypeManager.sbyte_type)
1174 ig.Emit (OpCodes.Ldind_I1);
1175 else if (t == TypeManager.uint64_type)
1176 ig.Emit (OpCodes.Ldind_I8);
1177 else if (t == TypeManager.int64_type)
1178 ig.Emit (OpCodes.Ldind_I8);
1179 else if (t == TypeManager.float_type)
1180 ig.Emit (OpCodes.Ldind_R4);
1181 else if (t == TypeManager.double_type)
1182 ig.Emit (OpCodes.Ldind_R8);
1183 else if (t == TypeManager.bool_type)
1184 ig.Emit (OpCodes.Ldind_I1);
1185 else if (t == TypeManager.intptr_type)
1186 ig.Emit (OpCodes.Ldind_I);
1187 else if (TypeManager.IsEnumType (t)) {
1188 if (t == TypeManager.enum_type)
1189 ig.Emit (OpCodes.Ldind_Ref);
1191 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1192 } else if (t.IsValueType || t.IsGenericParameter)
1193 ig.Emit (OpCodes.Ldobj, t);
1194 else if (t.IsPointer)
1195 ig.Emit (OpCodes.Ldind_I);
1197 ig.Emit (OpCodes.Ldind_Ref);
1201 // The stack contains the pointer and the value of type `type'
1203 public static void StoreFromPtr (ILGenerator ig, Type type)
1205 if (TypeManager.IsEnumType (type))
1206 type = TypeManager.EnumToUnderlying (type);
1207 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1208 ig.Emit (OpCodes.Stind_I4);
1209 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1210 ig.Emit (OpCodes.Stind_I8);
1211 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1212 type == TypeManager.ushort_type)
1213 ig.Emit (OpCodes.Stind_I2);
1214 else if (type == TypeManager.float_type)
1215 ig.Emit (OpCodes.Stind_R4);
1216 else if (type == TypeManager.double_type)
1217 ig.Emit (OpCodes.Stind_R8);
1218 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1219 type == TypeManager.bool_type)
1220 ig.Emit (OpCodes.Stind_I1);
1221 else if (type == TypeManager.intptr_type)
1222 ig.Emit (OpCodes.Stind_I);
1223 else if (type.IsValueType || type.IsGenericParameter)
1224 ig.Emit (OpCodes.Stobj, type);
1226 ig.Emit (OpCodes.Stind_Ref);
1230 // Returns the size of type `t' if known, otherwise, 0
1232 public static int GetTypeSize (Type t)
1234 t = TypeManager.TypeToCoreType (t);
1235 if (t == TypeManager.int32_type ||
1236 t == TypeManager.uint32_type ||
1237 t == TypeManager.float_type)
1239 else if (t == TypeManager.int64_type ||
1240 t == TypeManager.uint64_type ||
1241 t == TypeManager.double_type)
1243 else if (t == TypeManager.byte_type ||
1244 t == TypeManager.sbyte_type ||
1245 t == TypeManager.bool_type)
1247 else if (t == TypeManager.short_type ||
1248 t == TypeManager.char_type ||
1249 t == TypeManager.ushort_type)
1251 else if (t == TypeManager.decimal_type)
1257 public static void Error_NegativeArrayIndex (Location loc)
1259 Report.Error (248, loc, "Cannot create an array with a negative size");
1262 protected void Error_CannotCallAbstractBase (string name)
1264 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1268 // Converts `source' to an int, uint, long or ulong.
1270 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1274 bool old_checked = ec.CheckState;
1275 ec.CheckState = true;
1277 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1278 if (target == null){
1279 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1280 if (target == null){
1281 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1282 if (target == null){
1283 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1285 Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
1289 ec.CheckState = old_checked;
1292 // Only positive constants are allowed at compile time
1294 if (target is Constant){
1295 if (target is IntConstant){
1296 if (((IntConstant) target).Value < 0){
1297 Error_NegativeArrayIndex (loc);
1302 if (target is LongConstant){
1303 if (((LongConstant) target).Value < 0){
1304 Error_NegativeArrayIndex (loc);
1317 /// This is just a base class for expressions that can
1318 /// appear on statements (invocations, object creation,
1319 /// assignments, post/pre increment and decrement). The idea
1320 /// being that they would support an extra Emition interface that
1321 /// does not leave a result on the stack.
1323 public abstract class ExpressionStatement : Expression {
1325 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1327 Expression e = Resolve (ec);
1331 ExpressionStatement es = e as ExpressionStatement;
1333 Error (201, "Only assignment, call, increment, decrement and new object " +
1334 "expressions can be used as a statement");
1340 /// Requests the expression to be emitted in a `statement'
1341 /// context. This means that no new value is left on the
1342 /// stack after invoking this method (constrasted with
1343 /// Emit that will always leave a value on the stack).
1345 public abstract void EmitStatement (EmitContext ec);
1349 /// This kind of cast is used to encapsulate the child
1350 /// whose type is child.Type into an expression that is
1351 /// reported to return "return_type". This is used to encapsulate
1352 /// expressions which have compatible types, but need to be dealt
1353 /// at higher levels with.
1355 /// For example, a "byte" expression could be encapsulated in one
1356 /// of these as an "unsigned int". The type for the expression
1357 /// would be "unsigned int".
1360 public class EmptyCast : Expression {
1361 protected Expression child;
1363 public Expression Child {
1369 public EmptyCast (Expression child, Type return_type)
1371 eclass = child.eclass;
1372 loc = child.Location;
1377 public override Expression DoResolve (EmitContext ec)
1379 // This should never be invoked, we are born in fully
1380 // initialized state.
1385 public override void Emit (EmitContext ec)
1391 /// This is a numeric cast to a Decimal
1393 public class CastToDecimal : EmptyCast {
1395 MethodInfo conversion_operator;
1397 public CastToDecimal (EmitContext ec, Expression child)
1398 : this (ec, child, false)
1402 public CastToDecimal (EmitContext ec, Expression child, bool find_explicit)
1403 : base (child, TypeManager.decimal_type)
1405 conversion_operator = GetConversionOperator (ec, find_explicit);
1407 if (conversion_operator == null)
1408 Convert.Error_CannotImplicitConversion (loc, child.Type, type);
1411 // Returns the implicit operator that converts from
1412 // 'child.Type' to System.Decimal.
1413 MethodInfo GetConversionOperator (EmitContext ec, bool find_explicit)
1415 string operator_name = "op_Implicit";
1418 operator_name = "op_Explicit";
1420 MethodGroupExpr opers = Expression.MethodLookup (
1421 ec, type, operator_name, loc) as MethodGroupExpr;
1424 Convert.Error_CannotImplicitConversion (loc, child.Type, type);
1426 foreach (MethodInfo oper in opers.Methods) {
1427 ParameterData pd = TypeManager.GetParameterData (oper);
1429 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1435 public override void Emit (EmitContext ec)
1437 ILGenerator ig = ec.ig;
1440 ig.Emit (OpCodes.Call, conversion_operator);
1444 /// This is an explicit numeric cast from a Decimal
1446 public class CastFromDecimal : EmptyCast
1448 MethodInfo conversion_operator;
1449 public CastFromDecimal (EmitContext ec, Expression child, Type return_type)
1450 : base (child, return_type)
1452 if (child.Type != TypeManager.decimal_type)
1453 throw new InternalErrorException (
1454 "The expected type is Decimal, instead it is " + child.Type.FullName);
1456 conversion_operator = GetConversionOperator (ec);
1457 if (conversion_operator == null)
1458 Convert.Error_CannotImplicitConversion (loc, child.Type, type);
1461 // Returns the explicit operator that converts from an
1462 // express of type System.Decimal to 'type'.
1463 MethodInfo GetConversionOperator (EmitContext ec)
1465 MethodGroupExpr opers = Expression.MethodLookup (
1466 ec, child.Type, "op_Explicit", loc) as MethodGroupExpr;
1469 Convert.Error_CannotImplicitConversion (loc, child.Type, type);
1471 foreach (MethodInfo oper in opers.Methods) {
1472 ParameterData pd = TypeManager.GetParameterData (oper);
1474 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1480 public override void Emit (EmitContext ec)
1482 ILGenerator ig = ec.ig;
1485 ig.Emit (OpCodes.Call, conversion_operator);
1490 // We need to special case this since an empty cast of
1491 // a NullLiteral is still a Constant
1493 public class NullCast : Constant {
1494 protected Expression child;
1496 public NullCast (Expression child, Type return_type)
1498 eclass = child.eclass;
1503 override public string AsString ()
1508 public override object GetValue ()
1513 public override Expression DoResolve (EmitContext ec)
1515 // This should never be invoked, we are born in fully
1516 // initialized state.
1521 public override void Emit (EmitContext ec)
1526 public override bool IsDefaultValue {
1528 throw new NotImplementedException ();
1532 public override bool IsNegative {
1541 /// This class is used to wrap literals which belong inside Enums
1543 public class EnumConstant : Constant {
1544 public Constant Child;
1546 public EnumConstant (Constant child, Type enum_type)
1548 eclass = child.eclass;
1553 public override Expression DoResolve (EmitContext ec)
1555 // This should never be invoked, we are born in fully
1556 // initialized state.
1561 public override void Emit (EmitContext ec)
1566 public override object GetValue ()
1568 return Child.GetValue ();
1571 public object GetValueAsEnumType ()
1573 return System.Enum.ToObject (type, Child.GetValue ());
1577 // Converts from one of the valid underlying types for an enumeration
1578 // (int32, uint32, int64, uint64, short, ushort, byte, sbyte) to
1579 // one of the internal compiler literals: Int/UInt/Long/ULong Literals.
1581 public Constant WidenToCompilerConstant ()
1583 Type t = TypeManager.EnumToUnderlying (Child.Type);
1584 object v = ((Constant) Child).GetValue ();;
1586 if (t == TypeManager.int32_type)
1587 return new IntConstant ((int) v);
1588 if (t == TypeManager.uint32_type)
1589 return new UIntConstant ((uint) v);
1590 if (t == TypeManager.int64_type)
1591 return new LongConstant ((long) v);
1592 if (t == TypeManager.uint64_type)
1593 return new ULongConstant ((ulong) v);
1594 if (t == TypeManager.short_type)
1595 return new ShortConstant ((short) v);
1596 if (t == TypeManager.ushort_type)
1597 return new UShortConstant ((ushort) v);
1598 if (t == TypeManager.byte_type)
1599 return new ByteConstant ((byte) v);
1600 if (t == TypeManager.sbyte_type)
1601 return new SByteConstant ((sbyte) v);
1603 throw new Exception ("Invalid enumeration underlying type: " + t);
1607 // Extracts the value in the enumeration on its native representation
1609 public object GetPlainValue ()
1611 Type t = TypeManager.EnumToUnderlying (Child.Type);
1612 object v = ((Constant) Child).GetValue ();;
1614 if (t == TypeManager.int32_type)
1616 if (t == TypeManager.uint32_type)
1618 if (t == TypeManager.int64_type)
1620 if (t == TypeManager.uint64_type)
1622 if (t == TypeManager.short_type)
1624 if (t == TypeManager.ushort_type)
1626 if (t == TypeManager.byte_type)
1628 if (t == TypeManager.sbyte_type)
1634 public override string AsString ()
1636 return Child.AsString ();
1639 public override DoubleConstant ConvertToDouble ()
1641 return Child.ConvertToDouble ();
1644 public override FloatConstant ConvertToFloat ()
1646 return Child.ConvertToFloat ();
1649 public override ULongConstant ConvertToULong ()
1651 return Child.ConvertToULong ();
1654 public override LongConstant ConvertToLong ()
1656 return Child.ConvertToLong ();
1659 public override UIntConstant ConvertToUInt ()
1661 return Child.ConvertToUInt ();
1664 public override IntConstant ConvertToInt ()
1666 return Child.ConvertToInt ();
1669 public override bool IsDefaultValue {
1671 return Child.IsDefaultValue;
1675 public override bool IsZeroInteger {
1676 get { return Child.IsZeroInteger; }
1679 public override bool IsNegative {
1681 return Child.IsNegative;
1687 /// This kind of cast is used to encapsulate Value Types in objects.
1689 /// The effect of it is to box the value type emitted by the previous
1692 public class BoxedCast : EmptyCast {
1694 public BoxedCast (Expression expr)
1695 : base (expr, TypeManager.object_type)
1697 eclass = ExprClass.Value;
1700 public BoxedCast (Expression expr, Type target_type)
1701 : base (expr, target_type)
1703 eclass = ExprClass.Value;
1706 public override Expression DoResolve (EmitContext ec)
1708 // This should never be invoked, we are born in fully
1709 // initialized state.
1714 public override void Emit (EmitContext ec)
1718 ec.ig.Emit (OpCodes.Box, child.Type);
1722 public class UnboxCast : EmptyCast {
1723 public UnboxCast (Expression expr, Type return_type)
1724 : base (expr, return_type)
1728 public override Expression DoResolve (EmitContext ec)
1730 // This should never be invoked, we are born in fully
1731 // initialized state.
1736 public override void Emit (EmitContext ec)
1739 ILGenerator ig = ec.ig;
1742 if (t.IsGenericParameter)
1743 ig.Emit (OpCodes.Unbox_Any, t);
1745 ig.Emit (OpCodes.Unbox, t);
1747 LoadFromPtr (ig, t);
1753 /// This is used to perform explicit numeric conversions.
1755 /// Explicit numeric conversions might trigger exceptions in a checked
1756 /// context, so they should generate the conv.ovf opcodes instead of
1759 public class ConvCast : EmptyCast {
1760 public enum Mode : byte {
1761 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1763 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1764 U2_I1, U2_U1, U2_I2, U2_CH,
1765 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1766 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1767 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1768 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1769 CH_I1, CH_U1, CH_I2,
1770 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1771 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1777 public ConvCast (EmitContext ec, Expression child, Type return_type, Mode m)
1778 : base (child, return_type)
1780 checked_state = ec.CheckState;
1784 public override Expression DoResolve (EmitContext ec)
1786 // This should never be invoked, we are born in fully
1787 // initialized state.
1792 public override string ToString ()
1794 return String.Format ("ConvCast ({0}, {1})", mode, child);
1797 public override void Emit (EmitContext ec)
1799 ILGenerator ig = ec.ig;
1805 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1806 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1807 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1808 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1809 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1811 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1812 case Mode.U1_CH: /* nothing */ break;
1814 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1815 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1816 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1817 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1818 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1819 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1821 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1822 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1823 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1824 case Mode.U2_CH: /* nothing */ break;
1826 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1827 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1828 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1829 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1830 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1831 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1832 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1834 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1835 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1836 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1837 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1838 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1839 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1841 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1842 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1843 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1844 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1845 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1846 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1847 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1848 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1850 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1851 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1852 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1853 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1854 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1855 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1856 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1857 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1859 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1860 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1861 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1863 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1864 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1865 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1866 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1867 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1868 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1869 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1870 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1871 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1873 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1874 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1875 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1876 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1877 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1878 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1879 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1880 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1881 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1882 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1886 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1887 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1888 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1889 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1890 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1892 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1893 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1895 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1896 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1897 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1898 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1899 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1900 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1902 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1903 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1904 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1905 case Mode.U2_CH: /* nothing */ break;
1907 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1908 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1909 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1910 case Mode.I4_U4: /* nothing */ break;
1911 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1912 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1913 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1915 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1916 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1917 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1918 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1919 case Mode.U4_I4: /* nothing */ break;
1920 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1922 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1923 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1924 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1925 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1926 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1927 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1928 case Mode.I8_U8: /* nothing */ break;
1929 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1931 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1932 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1933 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1934 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1935 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1936 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1937 case Mode.U8_I8: /* nothing */ break;
1938 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1940 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1941 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1942 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1944 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1945 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1946 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1947 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1949 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1950 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1951 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1952 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1954 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1955 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1956 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1957 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1958 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1959 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1960 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1961 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1962 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1963 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1969 public class OpcodeCast : EmptyCast {
1973 public OpcodeCast (Expression child, Type return_type, OpCode op)
1974 : base (child, return_type)
1978 second_valid = false;
1981 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1982 : base (child, return_type)
1987 second_valid = true;
1990 public override Expression DoResolve (EmitContext ec)
1992 // This should never be invoked, we are born in fully
1993 // initialized state.
1998 public override void Emit (EmitContext ec)
2009 /// This kind of cast is used to encapsulate a child and cast it
2010 /// to the class requested
2012 public class ClassCast : EmptyCast {
2013 public ClassCast (Expression child, Type return_type)
2014 : base (child, return_type)
2019 public override Expression DoResolve (EmitContext ec)
2021 // This should never be invoked, we are born in fully
2022 // initialized state.
2027 public override void Emit (EmitContext ec)
2031 if (child.Type.IsGenericParameter)
2032 ec.ig.Emit (OpCodes.Box, child.Type);
2034 if (type.IsGenericParameter)
2035 ec.ig.Emit (OpCodes.Unbox_Any, type);
2037 ec.ig.Emit (OpCodes.Castclass, type);
2042 /// SimpleName expressions are formed of a single word and only happen at the beginning
2043 /// of a dotted-name.
2045 public class SimpleName : Expression {
2047 public readonly TypeArguments Arguments;
2050 public SimpleName (string name, Location l)
2056 public SimpleName (string name, TypeArguments args, Location l)
2063 public SimpleName (string name, TypeParameter[] type_params, Location l)
2068 Arguments = new TypeArguments (l);
2069 foreach (TypeParameter type_param in type_params)
2070 Arguments.Add (new TypeParameterExpr (type_param, l));
2073 public static string RemoveGenericArity (string name)
2076 StringBuilder sb = new StringBuilder ();
2077 while (start < name.Length) {
2078 int pos = name.IndexOf ('`', start);
2080 sb.Append (name.Substring (start));
2084 sb.Append (name.Substring (start, pos-start));
2087 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2093 return sb.ToString ();
2096 public SimpleName GetMethodGroup ()
2098 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
2101 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2103 if (ec.IsFieldInitializer)
2104 Report.Error (236, l,
2105 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2108 if (name.LastIndexOf ('.') > 0)
2109 name = name.Substring (name.LastIndexOf ('.') + 1);
2112 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
2117 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2119 return resolved_to != null && resolved_to.Type != null &&
2120 resolved_to.Type.Name == Name &&
2121 (ec.DeclSpace.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
2124 public override Expression DoResolve (EmitContext ec)
2126 return SimpleNameResolve (ec, null, false);
2129 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2131 return SimpleNameResolve (ec, right_side, false);
2135 public Expression DoResolve (EmitContext ec, bool intermediate)
2137 return SimpleNameResolve (ec, null, intermediate);
2140 private bool IsNestedChild (Type t, Type parent)
2145 while (parent != null) {
2146 if (parent.IsGenericInstance)
2147 parent = parent.GetGenericTypeDefinition ();
2149 if (TypeManager.IsNestedChildOf (t, parent))
2152 parent = parent.BaseType;
2158 FullNamedExpression ResolveNested (EmitContext ec, Type t)
2160 if (!t.IsGenericTypeDefinition)
2163 DeclSpace ds = ec.DeclSpace;
2164 while (ds != null) {
2165 if (IsNestedChild (t, ds.TypeBuilder))
2174 Type[] gen_params = t.GetGenericArguments ();
2176 int arg_count = Arguments != null ? Arguments.Count : 0;
2178 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2179 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2180 TypeArguments new_args = new TypeArguments (loc);
2181 foreach (TypeParameter param in ds.TypeParameters)
2182 new_args.Add (new TypeParameterExpr (param, loc));
2184 if (Arguments != null)
2185 new_args.Add (Arguments);
2187 return new ConstructedType (t, new_args, loc);
2194 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2196 FullNamedExpression fne = ec.DeclSpace.LookupGeneric (Name, loc);
2198 return fne.ResolveAsTypeStep (ec, silent);
2200 int errors = Report.Errors;
2201 fne = ec.DeclSpace.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2204 if (fne.Type == null)
2207 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2209 return nested.ResolveAsTypeStep (ec);
2211 if (Arguments != null) {
2212 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2213 return ct.ResolveAsTypeStep (ec);
2219 if (silent || errors != Report.Errors)
2222 MemberCore mc = ec.DeclSpace.GetDefinition (Name);
2224 Error_UnexpectedKind (ec, "type", GetMemberType (mc), loc);
2226 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2232 // TODO: I am still not convinced about this. If someone else will need it
2233 // implement this as virtual property in MemberCore hierarchy
2234 string GetMemberType (MemberCore mc)
2236 if (mc is PropertyBase)
2240 if (mc is FieldBase)
2246 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2252 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2256 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2263 /// 7.5.2: Simple Names.
2265 /// Local Variables and Parameters are handled at
2266 /// parse time, so they never occur as SimpleNames.
2268 /// The `intermediate' flag is used by MemberAccess only
2269 /// and it is used to inform us that it is ok for us to
2270 /// avoid the static check, because MemberAccess might end
2271 /// up resolving the Name as a Type name and the access as
2272 /// a static type access.
2274 /// ie: Type Type; .... { Type.GetType (""); }
2276 /// Type is both an instance variable and a Type; Type.GetType
2277 /// is the static method not an instance method of type.
2279 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2281 Expression e = null;
2284 // Stage 1: Performed by the parser (binding to locals or parameters).
2286 Block current_block = ec.CurrentBlock;
2287 if (current_block != null){
2288 LocalInfo vi = current_block.GetLocalInfo (Name);
2292 var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2294 if (right_side != null)
2295 return var.ResolveLValue (ec, right_side, loc);
2297 return var.Resolve (ec);
2300 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2302 if (right_side != null)
2303 return pref.ResolveLValue (ec, right_side, loc);
2305 return pref.Resolve (ec);
2310 // Stage 2: Lookup members
2313 DeclSpace lookup_ds = ec.DeclSpace;
2314 Type almost_matched_type = null;
2315 ArrayList almost_matched = null;
2317 if (lookup_ds.TypeBuilder == null)
2320 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
2324 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2325 almost_matched_type = lookup_ds.TypeBuilder;
2326 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2329 lookup_ds =lookup_ds.Parent;
2330 } while (lookup_ds != null);
2332 if (e == null && ec.ContainerType != null)
2333 e = MemberLookup (ec, ec.ContainerType, Name, loc);
2336 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2337 almost_matched_type = ec.ContainerType;
2338 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2340 e = ResolveAsTypeStep (ec, false);
2344 if (almost_matched != null)
2345 almostMatchedMembers = almost_matched;
2346 if (almost_matched_type == null)
2347 almost_matched_type = ec.ContainerType;
2348 MemberLookupFailed (ec, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclSpace.Name, true, loc);
2355 if (e is MemberExpr) {
2356 MemberExpr me = (MemberExpr) e;
2359 if (me.IsInstance) {
2360 if (ec.IsStatic || ec.IsFieldInitializer) {
2362 // Note that an MemberExpr can be both IsInstance and IsStatic.
2363 // An unresolved MethodGroupExpr can contain both kinds of methods
2364 // and each predicate is true if the MethodGroupExpr contains
2365 // at least one of that kind of method.
2369 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2370 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2375 // Pass the buck to MemberAccess and Invocation.
2377 left = EmptyExpression.Null;
2379 left = ec.GetThis (loc);
2382 left = new TypeExpression (ec.ContainerType, loc);
2385 e = me.ResolveMemberAccess (ec, left, loc, null);
2389 me = e as MemberExpr;
2393 if (Arguments != null) {
2394 MethodGroupExpr mg = me as MethodGroupExpr;
2398 return mg.ResolveGeneric (ec, Arguments);
2402 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2403 me.InstanceExpression.Type != me.DeclaringType &&
2404 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2405 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2406 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2407 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2411 return (right_side != null)
2412 ? me.DoResolveLValue (ec, right_side)
2413 : me.DoResolve (ec);
2419 public override void Emit (EmitContext ec)
2422 // If this is ever reached, then we failed to
2423 // find the name as a namespace
2426 Error (103, "The name `" + Name +
2427 "' does not exist in the class `" +
2428 ec.DeclSpace.Name + "'");
2431 public override string ToString ()
2436 public override string GetSignatureForError ()
2443 /// Represents a namespace or a type. The name of the class was inspired by
2444 /// section 10.8.1 (Fully Qualified Names).
2446 public abstract class FullNamedExpression : Expression {
2447 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2452 public abstract string FullName {
2458 /// Fully resolved expression that evaluates to a type
2460 public abstract class TypeExpr : FullNamedExpression {
2461 override public FullNamedExpression ResolveAsTypeStep (EmitContext ec, bool silent)
2463 TypeExpr t = DoResolveAsTypeStep (ec);
2467 eclass = ExprClass.Type;
2471 override public Expression DoResolve (EmitContext ec)
2473 return ResolveAsTypeTerminal (ec);
2476 override public void Emit (EmitContext ec)
2478 throw new Exception ("Should never be called");
2481 public virtual bool CheckAccessLevel (DeclSpace ds)
2483 return ds.CheckAccessLevel (Type);
2486 public virtual bool AsAccessible (DeclSpace ds, int flags)
2488 return ds.AsAccessible (Type, flags);
2491 public virtual bool IsClass {
2492 get { return Type.IsClass; }
2495 public virtual bool IsValueType {
2496 get { return Type.IsValueType; }
2499 public virtual bool IsInterface {
2500 get { return Type.IsInterface; }
2503 public virtual bool IsSealed {
2504 get { return Type.IsSealed; }
2507 public virtual bool CanInheritFrom ()
2509 if (Type == TypeManager.enum_type ||
2510 (Type == TypeManager.value_type && RootContext.StdLib) ||
2511 Type == TypeManager.multicast_delegate_type ||
2512 Type == TypeManager.delegate_type ||
2513 Type == TypeManager.array_type)
2519 protected abstract TypeExpr DoResolveAsTypeStep (EmitContext ec);
2521 public virtual Type ResolveType (EmitContext ec)
2523 TypeExpr t = ResolveAsTypeTerminal (ec);
2530 public abstract string Name {
2534 public override bool Equals (object obj)
2536 TypeExpr tobj = obj as TypeExpr;
2540 return Type == tobj.Type;
2543 public override int GetHashCode ()
2545 return Type.GetHashCode ();
2548 public override string ToString ()
2554 public class TypeExpression : TypeExpr {
2555 public TypeExpression (Type t, Location l)
2558 eclass = ExprClass.Type;
2562 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2567 public override string Name {
2568 get { return Type.ToString (); }
2571 public override string FullName {
2572 get { return Type.FullName; }
2577 /// Used to create types from a fully qualified name. These are just used
2578 /// by the parser to setup the core types. A TypeLookupExpression is always
2579 /// classified as a type.
2581 public class TypeLookupExpression : TypeExpr {
2584 public TypeLookupExpression (string name)
2589 static readonly char [] dot_array = { '.' };
2590 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2595 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2597 string lookup_name = name;
2598 int pos = name.IndexOf ('.');
2600 rest = name.Substring (pos + 1);
2601 lookup_name = name.Substring (0, pos);
2604 FullNamedExpression resolved = Namespace.Root.Lookup (ec.DeclSpace, lookup_name, Location.Null);
2606 if (resolved != null && rest != null) {
2607 // Now handle the rest of the the name.
2608 string [] elements = rest.Split (dot_array);
2610 int count = elements.Length;
2612 while (i < count && resolved != null && resolved is Namespace) {
2613 Namespace ns = resolved as Namespace;
2614 element = elements [i++];
2615 lookup_name += "." + element;
2616 resolved = ns.Lookup (ec.DeclSpace, element, Location.Null);
2619 if (resolved != null && resolved is TypeExpr) {
2620 Type t = ((TypeExpr) resolved).Type;
2622 if (!ec.DeclSpace.CheckAccessLevel (t)) {
2624 lookup_name = t.FullName;
2631 t = TypeManager.GetNestedType (t, elements [i++]);
2636 if (resolved == null) {
2637 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2641 if (!(resolved is TypeExpr)) {
2642 resolved.Error_UnexpectedKind (ec, "type", loc);
2646 type = ((TypeExpr) resolved).ResolveType (ec);
2650 public override string Name {
2651 get { return name; }
2654 public override string FullName {
2655 get { return name; }
2660 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2663 public class UnboundTypeExpression : TypeExpr
2667 public UnboundTypeExpression (MemberName name, Location l)
2673 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2676 if (name.Left != null) {
2677 Expression lexpr = name.Left.GetTypeExpression ();
2678 expr = new MemberAccess (lexpr, name.Basename, loc);
2680 expr = new SimpleName (name.Basename, loc);
2683 FullNamedExpression fne = expr.ResolveAsTypeStep (ec);
2688 return new TypeExpression (type, loc);
2691 public override string Name {
2692 get { return name.FullName; }
2695 public override string FullName {
2696 get { return name.FullName; }
2700 public class TypeAliasExpression : TypeExpr {
2701 FullNamedExpression alias;
2706 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2712 eclass = ExprClass.Type;
2714 name = alias.FullName + "<" + args.ToString () + ">";
2716 name = alias.FullName;
2719 public override string Name {
2720 get { return alias.FullName; }
2723 public override string FullName {
2724 get { return name; }
2727 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
2729 texpr = alias.ResolveAsTypeTerminal (ec);
2733 Type type = texpr.Type;
2734 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2737 if (num_args == 0) {
2738 Report.Error (308, loc,
2739 "The non-generic type `{0}' cannot " +
2740 "be used with type arguments.",
2741 TypeManager.CSharpName (type));
2745 ConstructedType ctype = new ConstructedType (type, args, loc);
2746 return ctype.ResolveAsTypeTerminal (ec);
2747 } else if (num_args > 0) {
2748 Report.Error (305, loc,
2749 "Using the generic type `{0}' " +
2750 "requires {1} type arguments",
2751 TypeManager.GetFullName (type), num_args);
2755 return new TypeExpression (type, loc);
2758 public override bool CheckAccessLevel (DeclSpace ds)
2760 return texpr.CheckAccessLevel (ds);
2763 public override bool AsAccessible (DeclSpace ds, int flags)
2765 return texpr.AsAccessible (ds, flags);
2768 public override bool IsClass {
2769 get { return texpr.IsClass; }
2772 public override bool IsValueType {
2773 get { return texpr.IsValueType; }
2776 public override bool IsInterface {
2777 get { return texpr.IsInterface; }
2780 public override bool IsSealed {
2781 get { return texpr.IsSealed; }
2786 /// This class denotes an expression which evaluates to a member
2787 /// of a struct or a class.
2789 public abstract class MemberExpr : Expression
2792 /// The name of this member.
2794 public abstract string Name {
2799 /// Whether this is an instance member.
2801 public abstract bool IsInstance {
2806 /// Whether this is a static member.
2808 public abstract bool IsStatic {
2813 /// The type which declares this member.
2815 public abstract Type DeclaringType {
2820 /// The instance expression associated with this member, if it's a
2821 /// non-static member.
2823 public Expression InstanceExpression;
2825 public static void error176 (Location loc, string name)
2827 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2828 "with an instance reference, qualify it with a type name instead", name);
2832 // TODO: possible optimalization
2833 // Cache resolved constant result in FieldBuilder <-> expression map
2834 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2835 SimpleName original)
2839 // original == null || original.Resolve (...) ==> left
2842 if (left is TypeExpr) {
2844 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2852 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2855 error176 (loc, GetSignatureForError ());
2859 InstanceExpression = left;
2864 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2869 if (InstanceExpression == EmptyExpression.Null) {
2870 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2874 if (InstanceExpression.Type.IsValueType) {
2875 if (InstanceExpression is IMemoryLocation) {
2876 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2878 LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
2879 InstanceExpression.Emit (ec);
2881 t.AddressOf (ec, AddressOp.Store);
2884 InstanceExpression.Emit (ec);
2886 if (prepare_for_load)
2887 ec.ig.Emit (OpCodes.Dup);
2892 /// MethodGroup Expression.
2894 /// This is a fully resolved expression that evaluates to a type
2896 public class MethodGroupExpr : MemberExpr {
2897 public MethodBase [] Methods;
2898 bool has_type_arguments = false;
2899 bool identical_type_name = false;
2902 public MethodGroupExpr (MemberInfo [] mi, Location l)
2904 Methods = new MethodBase [mi.Length];
2905 mi.CopyTo (Methods, 0);
2906 eclass = ExprClass.MethodGroup;
2907 type = TypeManager.object_type;
2911 public MethodGroupExpr (ArrayList list, Location l)
2913 Methods = new MethodBase [list.Count];
2916 list.CopyTo (Methods, 0);
2918 foreach (MemberInfo m in list){
2919 if (!(m is MethodBase)){
2920 Console.WriteLine ("Name " + m.Name);
2921 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2928 eclass = ExprClass.MethodGroup;
2929 type = TypeManager.object_type;
2932 public override Type DeclaringType {
2935 // We assume that the top-level type is in the end
2937 return Methods [Methods.Length - 1].DeclaringType;
2938 //return Methods [0].DeclaringType;
2942 public bool HasTypeArguments {
2944 return has_type_arguments;
2948 has_type_arguments = value;
2952 public bool IdenticalTypeName {
2954 return identical_type_name;
2958 identical_type_name = value;
2962 public bool IsBase {
2971 public override string GetSignatureForError ()
2973 return TypeManager.CSharpSignature (Methods [0]);
2976 public override string Name {
2978 return Methods [0].Name;
2982 public override bool IsInstance {
2984 foreach (MethodBase mb in Methods)
2992 public override bool IsStatic {
2994 foreach (MethodBase mb in Methods)
3002 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3003 SimpleName original)
3005 if (!(left is TypeExpr) &&
3006 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3007 IdenticalTypeName = true;
3009 return base.ResolveMemberAccess (ec, left, loc, original);
3012 override public Expression DoResolve (EmitContext ec)
3015 InstanceExpression = null;
3017 if (InstanceExpression != null) {
3018 InstanceExpression = InstanceExpression.DoResolve (ec);
3019 if (InstanceExpression == null)
3026 public void ReportUsageError ()
3028 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3029 Name + "()' is referenced without parentheses");
3032 override public void Emit (EmitContext ec)
3034 ReportUsageError ();
3037 bool RemoveMethods (bool keep_static)
3039 ArrayList smethods = new ArrayList ();
3041 foreach (MethodBase mb in Methods){
3042 if (mb.IsStatic == keep_static)
3046 if (smethods.Count == 0)
3049 Methods = new MethodBase [smethods.Count];
3050 smethods.CopyTo (Methods, 0);
3056 /// Removes any instance methods from the MethodGroup, returns
3057 /// false if the resulting set is empty.
3059 public bool RemoveInstanceMethods ()
3061 return RemoveMethods (true);
3065 /// Removes any static methods from the MethodGroup, returns
3066 /// false if the resulting set is empty.
3068 public bool RemoveStaticMethods ()
3070 return RemoveMethods (false);
3073 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
3075 if (args.Resolve (ec) == false)
3078 Type[] atypes = args.Arguments;
3080 int first_count = 0;
3081 MethodInfo first = null;
3083 ArrayList list = new ArrayList ();
3084 foreach (MethodBase mb in Methods) {
3085 MethodInfo mi = mb as MethodInfo;
3086 if ((mi == null) || !mi.HasGenericParameters)
3089 Type[] gen_params = mi.GetGenericArguments ();
3091 if (first == null) {
3093 first_count = gen_params.Length;
3096 if (gen_params.Length != atypes.Length)
3099 list.Add (mi.BindGenericParameters (atypes));
3102 if (list.Count > 0) {
3103 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3104 new_mg.InstanceExpression = InstanceExpression;
3105 new_mg.HasTypeArguments = true;
3111 305, loc, "Using the generic method `{0}' " +
3112 "requires {1} type arguments", Name,
3116 308, loc, "The non-generic method `{0}' " +
3117 "cannot be used with type arguments", Name);
3124 /// Fully resolved expression that evaluates to a Field
3126 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3127 public readonly FieldInfo FieldInfo;
3128 VariableInfo variable_info;
3130 LocalTemporary temp;
3132 bool in_initializer;
3134 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3137 this.in_initializer = in_initializer;
3140 public FieldExpr (FieldInfo fi, Location l)
3143 eclass = ExprClass.Variable;
3144 type = TypeManager.TypeToCoreType (fi.FieldType);
3148 public override string Name {
3150 return FieldInfo.Name;
3154 public override bool IsInstance {
3156 return !FieldInfo.IsStatic;
3160 public override bool IsStatic {
3162 return FieldInfo.IsStatic;
3166 public override Type DeclaringType {
3168 return FieldInfo.DeclaringType;
3172 public override string GetSignatureForError ()
3174 return TypeManager.GetFullNameSignature (FieldInfo);
3177 public VariableInfo VariableInfo {
3179 return variable_info;
3183 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3184 SimpleName original)
3186 bool left_is_type = left is TypeExpr;
3188 FieldInfo fi = FieldInfo.Mono_GetGenericFieldDefinition ();
3190 Type decl_type = fi.DeclaringType;
3192 bool is_emitted = fi is FieldBuilder;
3193 Type t = fi.FieldType;
3196 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
3200 if (!c.LookupConstantValue (out o))
3203 c.SetMemberIsUsed ();
3204 object real_value = ((Constant) c.Expr).GetValue ();
3206 Expression exp = Constantify (real_value, t);
3208 if (!left_is_type &&
3209 (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3210 Report.SymbolRelatedToPreviousError (c);
3211 error176 (loc, c.GetSignatureForError ());
3220 // Decimal constants cannot be encoded in the constant blob, and thus are marked
3221 // as IsInitOnly ('readonly' in C# parlance). We get its value from the
3222 // DecimalConstantAttribute metadata.
3224 if (fi.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
3225 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
3226 if (attrs.Length == 1)
3227 return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
3234 o = TypeManager.GetValue ((FieldBuilder) fi);
3236 o = fi.GetValue (fi);
3238 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
3239 if (!left_is_type &&
3240 (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3241 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3245 Expression enum_member = MemberLookup (
3246 ec, decl_type, "value__", MemberTypes.Field,
3247 AllBindingFlags | BindingFlags.NonPublic, loc);
3249 Enum en = TypeManager.LookupEnum (decl_type);
3253 c = Constantify (o, en.UnderlyingType);
3255 c = Constantify (o, enum_member.Type);
3257 return new EnumConstant (c, decl_type);
3260 Expression exp = Constantify (o, t);
3262 if (!left_is_type) {
3263 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3270 if (t.IsPointer && !ec.InUnsafe) {
3275 return base.ResolveMemberAccess (ec, left, loc, original);
3278 override public Expression DoResolve (EmitContext ec)
3280 if (ec.InRefOutArgumentResolving && FieldInfo.IsInitOnly && !ec.IsConstructor && FieldInfo.FieldType.IsValueType) {
3281 if (FieldInfo.FieldType is TypeBuilder) {
3282 if (FieldInfo.IsStatic)
3283 Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3284 GetSignatureForError ());
3286 Report.Error (1649, loc, "Members of readonly field `{0}.{1}' cannot be passed ref or out (except in a constructor)",
3287 TypeManager.CSharpName (DeclaringType), Name);
3289 if (FieldInfo.IsStatic)
3290 Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3293 Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3299 if (!FieldInfo.IsStatic){
3300 if (InstanceExpression == null){
3302 // This can happen when referencing an instance field using
3303 // a fully qualified type expression: TypeName.InstanceField = xxx
3305 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3309 // Resolve the field's instance expression while flow analysis is turned
3310 // off: when accessing a field "a.b", we must check whether the field
3311 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3312 InstanceExpression = InstanceExpression.Resolve (
3313 ec, ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis);
3314 if (InstanceExpression == null)
3318 if (!in_initializer) {
3319 ObsoleteAttribute oa;
3320 FieldBase f = TypeManager.GetField (FieldInfo);
3322 oa = f.GetObsoleteAttribute (f.Parent);
3324 AttributeTester.Report_ObsoleteMessage (oa, f.GetSignatureForError (), loc);
3325 // To be sure that type is external because we do not register generated fields
3326 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3327 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3329 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3333 AnonymousContainer am = ec.CurrentAnonymousMethod;
3335 if (!FieldInfo.IsStatic){
3336 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3337 Report.Error (1673, loc,
3338 "Anonymous methods inside structs cannot access instance members of `{0}'. Consider copying `{0}' to a local variable outside the anonymous method and using the local instead",
3342 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3343 ec.CaptureField (this);
3347 // If the instance expression is a local variable or parameter.
3348 IVariable var = InstanceExpression as IVariable;
3349 if ((var == null) || (var.VariableInfo == null))
3352 VariableInfo vi = var.VariableInfo;
3353 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3356 variable_info = vi.GetSubStruct (FieldInfo.Name);
3360 void Report_AssignToReadonly (bool is_instance)
3365 msg = "A readonly field cannot be assigned to (except in a constructor or a variable initializer)";
3367 msg = "A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)";
3369 Report.Error (is_instance ? 191 : 198, loc, msg);
3372 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3374 IVariable var = InstanceExpression as IVariable;
3375 if ((var != null) && (var.VariableInfo != null))
3376 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3378 Expression e = DoResolve (ec);
3383 if (!FieldInfo.IsStatic && (InstanceExpression.Type.IsValueType && !(InstanceExpression is IMemoryLocation))) {
3384 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3385 InstanceExpression.GetSignatureForError ());
3389 FieldBase fb = TypeManager.GetField (FieldInfo);
3393 if (!FieldInfo.IsInitOnly)
3397 // InitOnly fields can only be assigned in constructors
3400 if (ec.IsConstructor){
3401 if (IsStatic && !ec.IsStatic)
3402 Report_AssignToReadonly (false);
3405 if (ec.TypeContainer.CurrentType != null)
3406 ctype = ec.TypeContainer.CurrentType;
3408 ctype = ec.ContainerType;
3410 if (TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3414 Report_AssignToReadonly (!IsStatic);
3419 public override void CheckMarshallByRefAccess (Type container)
3421 if (!IsStatic && Type.IsValueType && !container.IsSubclassOf (TypeManager.mbr_type) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3422 Report.SymbolRelatedToPreviousError (DeclaringType);
3423 Report.Error (1690, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3424 GetSignatureForError ());
3428 public bool VerifyFixed ()
3430 IVariable variable = InstanceExpression as IVariable;
3431 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3432 // We defer the InstanceExpression check after the variable check to avoid a
3433 // separate null check on InstanceExpression.
3434 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3437 public override int GetHashCode()
3439 return FieldInfo.GetHashCode ();
3442 public override bool Equals (object obj)
3444 FieldExpr fe = obj as FieldExpr;
3448 if (FieldInfo != fe.FieldInfo)
3451 if (InstanceExpression == null || fe.InstanceExpression == null)
3454 return InstanceExpression.Equals (fe.InstanceExpression);
3457 public void Emit (EmitContext ec, bool leave_copy)
3459 ILGenerator ig = ec.ig;
3460 bool is_volatile = false;
3462 FieldInfo the_fi = FieldInfo.Mono_GetGenericFieldDefinition ();
3463 if (the_fi is FieldBuilder){
3464 FieldBase f = TypeManager.GetField (the_fi);
3466 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3469 f.SetMemberIsUsed ();
3473 if (FieldInfo.IsStatic){
3475 ig.Emit (OpCodes.Volatile);
3477 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3480 EmitInstance (ec, false);
3483 ig.Emit (OpCodes.Volatile);
3485 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3488 ig.Emit (OpCodes.Ldflda, FieldInfo);
3489 ig.Emit (OpCodes.Ldflda, ff.Element);
3492 ig.Emit (OpCodes.Ldfld, FieldInfo);
3497 ec.ig.Emit (OpCodes.Dup);
3498 if (!FieldInfo.IsStatic) {
3499 temp = new LocalTemporary (ec, this.Type);
3505 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3507 FieldAttributes fa = FieldInfo.Attributes;
3508 bool is_static = (fa & FieldAttributes.Static) != 0;
3509 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3510 ILGenerator ig = ec.ig;
3511 prepared = prepare_for_load;
3513 if (is_readonly && !ec.IsConstructor){
3514 Report_AssignToReadonly (!is_static);
3518 EmitInstance (ec, prepare_for_load);
3522 ec.ig.Emit (OpCodes.Dup);
3523 if (!FieldInfo.IsStatic) {
3524 temp = new LocalTemporary (ec, this.Type);
3529 if (FieldInfo is FieldBuilder){
3530 FieldBase f = TypeManager.GetField (FieldInfo);
3532 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3533 ig.Emit (OpCodes.Volatile);
3540 ig.Emit (OpCodes.Stsfld, FieldInfo);
3542 ig.Emit (OpCodes.Stfld, FieldInfo);
3548 public override void Emit (EmitContext ec)
3553 public void AddressOf (EmitContext ec, AddressOp mode)
3555 ILGenerator ig = ec.ig;
3557 if (FieldInfo is FieldBuilder){
3558 FieldBase f = TypeManager.GetField (FieldInfo);
3560 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3561 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3562 f.GetSignatureForError ());
3566 if ((mode & AddressOp.Store) != 0)
3568 if ((mode & AddressOp.Load) != 0)
3569 f.SetMemberIsUsed ();
3574 // Handle initonly fields specially: make a copy and then
3575 // get the address of the copy.
3578 if (FieldInfo.IsInitOnly){
3580 if (ec.IsConstructor){
3581 if (FieldInfo.IsStatic){
3593 local = ig.DeclareLocal (type);
3594 ig.Emit (OpCodes.Stloc, local);
3595 ig.Emit (OpCodes.Ldloca, local);
3600 if (FieldInfo.IsStatic){
3601 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3603 EmitInstance (ec, false);
3604 ig.Emit (OpCodes.Ldflda, FieldInfo);
3610 // A FieldExpr whose address can not be taken
3612 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3613 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3617 public new void AddressOf (EmitContext ec, AddressOp mode)
3619 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3624 /// Expression that evaluates to a Property. The Assign class
3625 /// might set the `Value' expression if we are in an assignment.
3627 /// This is not an LValue because we need to re-write the expression, we
3628 /// can not take data from the stack and store it.
3630 public class PropertyExpr : MemberExpr, IAssignMethod {
3631 public readonly PropertyInfo PropertyInfo;
3634 // This is set externally by the `BaseAccess' class
3637 MethodInfo getter, setter;
3642 LocalTemporary temp;
3645 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3647 public PropertyExpr (EmitContext ec, PropertyInfo pi, Location l)
3650 eclass = ExprClass.PropertyAccess;
3654 type = TypeManager.TypeToCoreType (pi.PropertyType);
3656 ResolveAccessors (ec);
3659 public override string Name {
3661 return PropertyInfo.Name;
3665 public override bool IsInstance {
3671 public override bool IsStatic {
3677 public override Type DeclaringType {
3679 return PropertyInfo.DeclaringType;
3683 public override string GetSignatureForError ()
3685 return TypeManager.GetFullNameSignature (PropertyInfo);
3688 void FindAccessors (Type invocation_type)
3690 BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3691 BindingFlags.Static | BindingFlags.Instance |
3692 BindingFlags.DeclaredOnly;
3694 Type current = PropertyInfo.DeclaringType;
3695 for (; current != null; current = current.BaseType) {
3696 MemberInfo[] group = TypeManager.MemberLookup (
3697 invocation_type, invocation_type, current,
3698 MemberTypes.Property, flags, PropertyInfo.Name, null);
3703 if (group.Length != 1)
3704 // Oooops, can this ever happen ?
3707 PropertyInfo pi = (PropertyInfo) group [0];
3710 getter = pi.GetGetMethod (true);
3713 setter = pi.GetSetMethod (true);
3715 MethodInfo accessor = getter != null ? getter : setter;
3717 if (!accessor.IsVirtual)
3723 // We also perform the permission checking here, as the PropertyInfo does not
3724 // hold the information for the accessibility of its setter/getter
3726 void ResolveAccessors (EmitContext ec)
3728 FindAccessors (ec.ContainerType);
3730 if (getter != null) {
3731 IMethodData md = TypeManager.GetMethod (getter);
3733 md.SetMemberIsUsed ();
3735 AccessorTable [getter] = PropertyInfo;
3736 is_static = getter.IsStatic;
3739 if (setter != null) {
3740 IMethodData md = TypeManager.GetMethod (setter);
3742 md.SetMemberIsUsed ();
3744 AccessorTable [setter] = PropertyInfo;
3745 is_static = setter.IsStatic;
3749 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3752 InstanceExpression = null;
3756 if (InstanceExpression == null) {
3757 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3761 InstanceExpression = InstanceExpression.DoResolve (ec);
3762 if (InstanceExpression == null)
3765 InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
3767 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null) {
3768 if ((InstanceExpression.Type != ec.ContainerType) &&
3769 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3770 Report.Error (1540, loc, "Cannot access protected member `" +
3771 PropertyInfo.DeclaringType + "." + PropertyInfo.Name +
3772 "' via a qualifier of type `" +
3773 TypeManager.CSharpName (InstanceExpression.Type) +
3774 "'; the qualifier must be of type `" +
3775 TypeManager.CSharpName (ec.ContainerType) +
3776 "' (or derived from it)");
3784 override public Expression DoResolve (EmitContext ec)
3789 if (getter != null){
3790 if (TypeManager.GetArgumentTypes (getter).Length != 0){
3792 117, loc, "`{0}' does not contain a " +
3793 "definition for `{1}'.", getter.DeclaringType,
3799 if (getter == null){
3801 // The following condition happens if the PropertyExpr was
3802 // created, but is invalid (ie, the property is inaccessible),
3803 // and we did not want to embed the knowledge about this in
3804 // the caller routine. This only avoids double error reporting.
3809 if (InstanceExpression != EmptyExpression.Null) {
3810 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3811 TypeManager.GetFullNameSignature (PropertyInfo));
3816 bool must_do_cs1540_check = false;
3817 if (getter != null &&
3818 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3819 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3820 if (pm != null && pm.HasCustomAccessModifier) {
3821 Report.SymbolRelatedToPreviousError (pm);
3822 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3823 TypeManager.CSharpSignature (getter));
3826 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3830 if (!InstanceResolve (ec, must_do_cs1540_check))
3834 // Only base will allow this invocation to happen.
3836 if (IsBase && getter.IsAbstract) {
3837 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3841 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3851 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3853 if (setter == null){
3855 // The following condition happens if the PropertyExpr was
3856 // created, but is invalid (ie, the property is inaccessible),
3857 // and we did not want to embed the knowledge about this in
3858 // the caller routine. This only avoids double error reporting.
3863 Report.Error (200, loc, " Property or indexer `{0}' cannot be assigned to (it is read only)",
3864 TypeManager.GetFullNameSignature (PropertyInfo));
3868 if (TypeManager.GetArgumentTypes (setter).Length != 1){
3870 117, loc, "`{0}' does not contain a " +
3871 "definition for `{1}'.", getter.DeclaringType,
3876 bool must_do_cs1540_check;
3877 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3878 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3879 if (pm != null && pm.HasCustomAccessModifier) {
3880 Report.SymbolRelatedToPreviousError (pm);
3881 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3882 TypeManager.CSharpSignature (setter));
3885 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3889 if (!InstanceResolve (ec, must_do_cs1540_check))
3893 // Only base will allow this invocation to happen.
3895 if (IsBase && setter.IsAbstract){
3896 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3901 // Check that we are not making changes to a temporary memory location
3903 if (InstanceExpression != null && InstanceExpression.Type.IsValueType && !(InstanceExpression is IMemoryLocation)) {
3904 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3905 InstanceExpression.GetSignatureForError ());
3912 public override void Emit (EmitContext ec)
3917 public void Emit (EmitContext ec, bool leave_copy)
3920 EmitInstance (ec, false);
3923 // Special case: length of single dimension array property is turned into ldlen
3925 if ((getter == TypeManager.system_int_array_get_length) ||
3926 (getter == TypeManager.int_array_get_length)){
3927 Type iet = InstanceExpression.Type;
3930 // System.Array.Length can be called, but the Type does not
3931 // support invoking GetArrayRank, so test for that case first
3933 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3934 ec.ig.Emit (OpCodes.Ldlen);
3935 ec.ig.Emit (OpCodes.Conv_I4);
3940 Invocation.EmitCall (ec, IsBase, IsStatic, new EmptyAddressOf (), getter, null, loc);
3945 ec.ig.Emit (OpCodes.Dup);
3947 temp = new LocalTemporary (ec, this.Type);
3953 // Implements the IAssignMethod interface for assignments
3955 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3957 prepared = prepare_for_load;
3959 EmitInstance (ec, prepare_for_load);
3963 ec.ig.Emit (OpCodes.Dup);
3965 temp = new LocalTemporary (ec, this.Type);
3970 ArrayList args = new ArrayList (1);
3971 args.Add (new Argument (new EmptyAddressOf (), Argument.AType.Expression));
3973 Invocation.EmitCall (ec, IsBase, IsStatic, new EmptyAddressOf (), setter, args, loc);
3981 /// Fully resolved expression that evaluates to an Event
3983 public class EventExpr : MemberExpr {
3984 public readonly EventInfo EventInfo;
3987 MethodInfo add_accessor, remove_accessor;
3989 public EventExpr (EventInfo ei, Location loc)
3993 eclass = ExprClass.EventAccess;
3995 add_accessor = TypeManager.GetAddMethod (ei);
3996 remove_accessor = TypeManager.GetRemoveMethod (ei);
3998 if (add_accessor.IsStatic || remove_accessor.IsStatic)
4001 if (EventInfo is MyEventBuilder){
4002 MyEventBuilder eb = (MyEventBuilder) EventInfo;
4003 type = eb.EventType;
4006 type = EventInfo.EventHandlerType;
4009 public override string Name {
4011 return EventInfo.Name;
4015 public override bool IsInstance {
4021 public override bool IsStatic {
4027 public override Type DeclaringType {
4029 return EventInfo.DeclaringType;
4033 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4034 SimpleName original)
4037 // If the event is local to this class, we transform ourselves into a FieldExpr
4040 if (EventInfo.DeclaringType == ec.ContainerType ||
4041 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
4042 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
4045 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec, mi, loc);
4048 Report.Error (-200, loc, "Internal error!!");
4052 InstanceExpression = null;
4054 return ml.ResolveMemberAccess (ec, left, loc, original);
4058 return base.ResolveMemberAccess (ec, left, loc, original);
4062 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
4065 InstanceExpression = null;
4069 if (InstanceExpression == null) {
4070 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
4074 InstanceExpression = InstanceExpression.DoResolve (ec);
4075 if (InstanceExpression == null)
4079 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4080 // However, in the Event case, we reported a CS0122 instead.
4082 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null) {
4083 if ((InstanceExpression.Type != ec.ContainerType) &&
4084 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4085 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4093 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4095 return DoResolve (ec);
4098 public override Expression DoResolve (EmitContext ec)
4100 bool must_do_cs1540_check;
4101 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4102 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4103 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4107 if (!InstanceResolve (ec, must_do_cs1540_check))
4113 public override void Emit (EmitContext ec)
4115 if (InstanceExpression is This)
4116 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4118 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4119 "(except on the defining type)", Name);
4122 public override string GetSignatureForError ()
4124 return TypeManager.CSharpSignature (EventInfo);
4127 public void EmitAddOrRemove (EmitContext ec, Expression source)
4129 BinaryDelegate source_del = (BinaryDelegate) source;
4130 Expression handler = source_del.Right;
4132 Argument arg = new Argument (handler, Argument.AType.Expression);
4133 ArrayList args = new ArrayList ();
4137 if (source_del.IsAddition)
4138 Invocation.EmitCall (
4139 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4141 Invocation.EmitCall (
4142 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);