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.
64 // Disable control flow analysis _of struct_ while resolving the expression.
65 // This is used when resolving the instance expression of a field expression.
66 DisableStructFlowAnalysis = 32,
71 // This is just as a hint to AddressOf of what will be done with the
74 public enum AddressOp {
81 /// This interface is implemented by variables
83 public interface IMemoryLocation {
85 /// The AddressOf method should generate code that loads
86 /// the address of the object and leaves it on the stack.
88 /// The `mode' argument is used to notify the expression
89 /// of whether this will be used to read from the address or
90 /// write to the address.
92 /// This is just a hint that can be used to provide good error
93 /// reporting, and should have no other side effects.
95 void AddressOf (EmitContext ec, AddressOp mode);
99 /// This interface is implemented by variables
101 public interface IVariable {
102 VariableInfo VariableInfo {
110 /// Base class for expressions
112 public abstract class Expression {
113 public ExprClass eclass;
115 protected Location loc;
119 set { type = value; }
122 public virtual Location Location {
127 /// Utility wrapper routine for Error, just to beautify the code
129 public void Error (int error, string s)
132 Report.Error (error, s);
134 Report.Error (error, loc, s);
137 // Not nice but we have broken hierarchy
138 public virtual void CheckMarshallByRefAccess (Type container) {}
140 public virtual bool GetAttributableValue (out object value)
142 Attribute.Error_AttributeArgumentNotValid (loc);
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
154 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == MethodAttributes.Public)
162 // If only accessible to the current class or children
164 if (ma == MethodAttributes.Private)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if (mi.DeclaringType.Assembly == invocation_type.Assembly ||
169 TypeManager.IsFriendAssembly (mi.DeclaringType.Assembly)) {
170 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
173 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
177 // Family and FamANDAssem require that we derive.
178 // FamORAssem requires that we derive if in different assemblies.
179 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
182 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
183 must_do_cs1540_check = true;
189 /// Performs semantic analysis on the Expression
193 /// The Resolve method is invoked to perform the semantic analysis
196 /// The return value is an expression (it can be the
197 /// same expression in some cases) or a new
198 /// expression that better represents this node.
200 /// For example, optimizations of Unary (LiteralInt)
201 /// would return a new LiteralInt with a negated
204 /// If there is an error during semantic analysis,
205 /// then an error should be reported (using Report)
206 /// and a null value should be returned.
208 /// There are two side effects expected from calling
209 /// Resolve(): the the field variable "eclass" should
210 /// be set to any value of the enumeration
211 /// `ExprClass' and the type variable should be set
212 /// to a valid type (this is the type of the
215 public abstract Expression DoResolve (EmitContext ec);
217 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
223 // This is used if the expression should be resolved as a type or namespace name.
224 // the default implementation fails.
226 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
232 // This is used to resolve the expression as a type, a null
233 // value will be returned if the expression is not a type
236 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
238 int errors = Report.Errors;
240 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
243 if (!silent && errors == Report.Errors)
244 Report.Error (118, loc, "Expecting a type.");
248 if (fne.eclass != ExprClass.Type) {
249 if (!silent && errors == Report.Errors)
250 fne.Error_UnexpectedKind (null, "type", loc);
254 TypeExpr te = fne as TypeExpr;
256 if (!te.CheckAccessLevel (ec.DeclContainer)) {
257 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
261 // Constrains don't need to be checked for overrides
262 GenericMethod gm = ec.DeclContainer as GenericMethod;
263 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
268 ConstructedType ct = te as ConstructedType;
269 if ((ct != null) && !ct.CheckConstraints (ec))
276 public static void ErrorIsInaccesible (Location loc, string name)
278 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
281 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
283 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
284 + " the qualifier must be of type `{2}' (or derived from it)",
285 TypeManager.GetFullNameSignature (m),
286 TypeManager.CSharpName (qualifier),
287 TypeManager.CSharpName (container));
291 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
293 if (Type.Name == target.Name){
294 Report.ExtraInformation (loc,
296 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
297 Type.Name, Type.Assembly.FullName, target.Assembly.FullName));
302 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
303 GetSignatureForError (), TypeManager.CSharpName (target));
307 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
308 bool b = Convert.ExplicitNumericConversion (e, target) != null;
310 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
311 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
312 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
316 if (Type != TypeManager.string_type && this is Constant && !(this is NullCast)) {
317 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
318 GetSignatureForError (), TypeManager.CSharpName (target));
322 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
323 Type == TypeManager.anonymous_method_type ?
324 "anonymous method" : "`" + GetSignatureForError () + "'",
325 TypeManager.CSharpName (target));
328 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
330 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
331 TypeManager.CSharpName (type), name);
334 ResolveFlags ExprClassToResolveFlags
339 case ExprClass.Namespace:
340 return ResolveFlags.Type;
342 case ExprClass.MethodGroup:
343 return ResolveFlags.MethodGroup;
345 case ExprClass.Value:
346 case ExprClass.Variable:
347 case ExprClass.PropertyAccess:
348 case ExprClass.EventAccess:
349 case ExprClass.IndexerAccess:
350 return ResolveFlags.VariableOrValue;
353 throw new Exception ("Expression " + GetType () +
354 " ExprClass is Invalid after resolve");
360 /// Resolves an expression and performs semantic analysis on it.
364 /// Currently Resolve wraps DoResolve to perform sanity
365 /// checking and assertion checking on what we expect from Resolve.
367 public Expression Resolve (EmitContext ec, ResolveFlags flags)
369 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
370 return ResolveAsTypeStep (ec, false);
372 bool old_do_flow_analysis = ec.DoFlowAnalysis;
373 bool old_omit_struct_analysis = ec.OmitStructFlowAnalysis;
374 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
375 ec.DoFlowAnalysis = false;
376 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
377 ec.OmitStructFlowAnalysis = true;
380 if (this is SimpleName) {
381 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
382 e = ((SimpleName) this).DoResolve (ec, intermediate);
387 ec.DoFlowAnalysis = old_do_flow_analysis;
388 ec.OmitStructFlowAnalysis = old_omit_struct_analysis;
393 if ((flags & e.ExprClassToResolveFlags) == 0) {
394 e.Error_UnexpectedKind (flags, loc);
398 if (e.type == null && !(e is Namespace)) {
399 throw new Exception (
400 "Expression " + e.GetType () +
401 " did not set its type after Resolve\n" +
402 "called from: " + this.GetType ());
409 /// Resolves an expression and performs semantic analysis on it.
411 public Expression Resolve (EmitContext ec)
413 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
415 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
416 ((MethodGroupExpr) e).ReportUsageError ();
422 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
424 Expression e = Resolve (ec);
428 Constant c = e as Constant;
432 EmptyCast empty = e as EmptyCast;
434 c = empty.Child as Constant;
436 // TODO: not sure about this maybe there is easier way how to use EmptyCast
443 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
448 /// Resolves an expression for LValue assignment
452 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
453 /// checking and assertion checking on what we expect from Resolve
455 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
457 int errors = Report.Errors;
458 Expression e = DoResolveLValue (ec, right_side);
461 if (errors == Report.Errors)
462 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
467 if (e.eclass == ExprClass.Invalid)
468 throw new Exception ("Expression " + e +
469 " ExprClass is Invalid after resolve");
471 if (e.eclass == ExprClass.MethodGroup) {
472 ((MethodGroupExpr) e).ReportUsageError ();
476 if ((e.type == null) && !(e is ConstructedType))
477 throw new Exception ("Expression " + e +
478 " did not set its type after Resolve");
485 /// Emits the code for the expression
489 /// The Emit method is invoked to generate the code
490 /// for the expression.
492 public abstract void Emit (EmitContext ec);
494 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
497 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
501 /// Protected constructor. Only derivate types should
502 /// be able to be created
505 protected Expression ()
507 eclass = ExprClass.Invalid;
512 /// Returns a literalized version of a literal FieldInfo
516 /// The possible return values are:
517 /// IntConstant, UIntConstant
518 /// LongLiteral, ULongConstant
519 /// FloatConstant, DoubleConstant
522 /// The value returned is already resolved.
524 public static Constant Constantify (object v, Type t)
526 if (t == TypeManager.int32_type)
527 return new IntConstant ((int) v, Location.Null);
528 else if (t == TypeManager.uint32_type)
529 return new UIntConstant ((uint) v, Location.Null);
530 else if (t == TypeManager.int64_type)
531 return new LongConstant ((long) v, Location.Null);
532 else if (t == TypeManager.uint64_type)
533 return new ULongConstant ((ulong) v, Location.Null);
534 else if (t == TypeManager.float_type)
535 return new FloatConstant ((float) v, Location.Null);
536 else if (t == TypeManager.double_type)
537 return new DoubleConstant ((double) v, Location.Null);
538 else if (t == TypeManager.string_type)
539 return new StringConstant ((string) v, Location.Null);
540 else if (t == TypeManager.short_type)
541 return new ShortConstant ((short)v, Location.Null);
542 else if (t == TypeManager.ushort_type)
543 return new UShortConstant ((ushort)v, Location.Null);
544 else if (t == TypeManager.sbyte_type)
545 return new SByteConstant ((sbyte)v, Location.Null);
546 else if (t == TypeManager.byte_type)
547 return new ByteConstant ((byte)v, Location.Null);
548 else if (t == TypeManager.char_type)
549 return new CharConstant ((char)v, Location.Null);
550 else if (t == TypeManager.bool_type)
551 return new BoolConstant ((bool) v, Location.Null);
552 else if (t == TypeManager.decimal_type)
553 return new DecimalConstant ((decimal) v, Location.Null);
554 else if (TypeManager.IsEnumType (t)){
555 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
557 real_type = System.Enum.GetUnderlyingType (real_type);
559 Constant e = Constantify (v, real_type);
561 return new EnumConstant (e, t);
562 } else if (v == null && !TypeManager.IsValueType (t))
563 return new NullLiteral (Location.Null);
565 throw new Exception ("Unknown type for constant (" + t +
570 /// Returns a fully formed expression after a MemberLookup
573 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
576 return new EventExpr ((EventInfo) mi, loc);
577 else if (mi is FieldInfo)
578 return new FieldExpr ((FieldInfo) mi, loc);
579 else if (mi is PropertyInfo)
580 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
581 else if (mi is Type){
582 return new TypeExpression ((System.Type) mi, loc);
588 protected static ArrayList almostMatchedMembers = new ArrayList (4);
591 // FIXME: Probably implement a cache for (t,name,current_access_set)?
593 // This code could use some optimizations, but we need to do some
594 // measurements. For example, we could use a delegate to `flag' when
595 // something can not any longer be a method-group (because it is something
599 // If the return value is an Array, then it is an array of
602 // If the return value is an MemberInfo, it is anything, but a Method
606 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
607 // the arguments here and have MemberLookup return only the methods that
608 // match the argument count/type, unlike we are doing now (we delay this
611 // This is so we can catch correctly attempts to invoke instance methods
612 // from a static body (scan for error 120 in ResolveSimpleName).
615 // FIXME: Potential optimization, have a static ArrayList
618 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
619 MemberTypes mt, BindingFlags bf, Location loc)
621 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
625 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
626 // `qualifier_type' or null to lookup members in the current class.
629 public static Expression MemberLookup (Type container_type,
630 Type qualifier_type, Type queried_type,
631 string name, MemberTypes mt,
632 BindingFlags bf, Location loc)
634 almostMatchedMembers.Clear ();
636 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
637 queried_type, mt, bf, name, almostMatchedMembers);
642 int count = mi.Length;
644 if (mi [0] is MethodBase)
645 return new MethodGroupExpr (mi, loc);
650 return ExprClassFromMemberInfo (container_type, mi [0], loc);
653 public const MemberTypes AllMemberTypes =
654 MemberTypes.Constructor |
658 MemberTypes.NestedType |
659 MemberTypes.Property;
661 public const BindingFlags AllBindingFlags =
662 BindingFlags.Public |
663 BindingFlags.Static |
664 BindingFlags.Instance;
666 public static Expression MemberLookup (EmitContext ec, Type queried_type,
667 string name, Location loc)
669 return MemberLookup (ec.ContainerType, null, queried_type, name,
670 AllMemberTypes, AllBindingFlags, loc);
673 public static Expression MemberLookup (Type container_type, Type qualifier_type,
674 Type queried_type, string name, Location loc)
676 return MemberLookup (container_type, qualifier_type, queried_type,
677 name, AllMemberTypes, AllBindingFlags, loc);
680 public static Expression MethodLookup (EmitContext ec, Type queried_type,
681 string name, Location loc)
683 return MemberLookup (ec.ContainerType, null, queried_type, name,
684 MemberTypes.Method, AllBindingFlags, loc);
688 /// This is a wrapper for MemberLookup that is not used to "probe", but
689 /// to find a final definition. If the final definition is not found, we
690 /// look for private members and display a useful debugging message if we
693 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
694 Type queried_type, string name, Location loc)
696 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
697 AllMemberTypes, AllBindingFlags, loc);
700 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
701 Type queried_type, string name,
702 MemberTypes mt, BindingFlags bf,
707 int errors = Report.Errors;
709 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
711 if (e == null && errors == Report.Errors)
712 // No errors were reported by MemberLookup, but there was an error.
713 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
718 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
719 Type queried_type, string name,
720 string class_name, bool complain_if_none_found,
723 if (almostMatchedMembers.Count != 0) {
724 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
725 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
726 for (int j = 0; j < i; ++j) {
727 if (m == almostMatchedMembers [j]) {
735 Type declaring_type = m.DeclaringType;
737 Report.SymbolRelatedToPreviousError (m);
738 if (qualifier_type == null) {
739 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
740 TypeManager.CSharpName (m.DeclaringType),
741 TypeManager.CSharpName (container_type));
743 } else if (qualifier_type != container_type &&
744 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
745 // Although a derived class can access protected members of
746 // its base class it cannot do so through an instance of the
747 // base class (CS1540). If the qualifier_type is a base of the
748 // ec.ContainerType and the lookup succeeds with the latter one,
749 // then we are in this situation.
750 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
752 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
755 almostMatchedMembers.Clear ();
759 MemberInfo[] lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
760 AllMemberTypes, AllBindingFlags |
761 BindingFlags.NonPublic, name, null);
763 if (lookup == null) {
764 if (!complain_if_none_found)
767 if (class_name != null)
768 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
771 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
775 if (TypeManager.MemberLookup (queried_type, null, queried_type,
776 AllMemberTypes, AllBindingFlags |
777 BindingFlags.NonPublic, name, null) == null) {
778 if ((lookup.Length == 1) && (lookup [0] is Type)) {
779 Type t = (Type) lookup [0];
781 Report.Error (305, loc,
782 "Using the generic type `{0}' " +
783 "requires {1} type arguments",
784 TypeManager.CSharpName (t),
785 TypeManager.GetNumberOfTypeArguments (t).ToString ());
790 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
791 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
792 if (name == ".ctor" && ml.Count == 0)
794 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
798 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
802 /// Returns an expression that can be used to invoke operator true
803 /// on the expression if it exists.
805 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
807 return GetOperatorTrueOrFalse (ec, e, true, loc);
811 /// Returns an expression that can be used to invoke operator false
812 /// on the expression if it exists.
814 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
816 return GetOperatorTrueOrFalse (ec, e, false, loc);
819 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
822 Expression operator_group;
824 if (TypeManager.IsNullableType (e.Type))
825 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
827 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
828 if (operator_group == null)
831 ArrayList arguments = new ArrayList ();
832 arguments.Add (new Argument (e, Argument.AType.Expression));
833 method = Invocation.OverloadResolve (
834 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
839 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
843 /// Resolves the expression `e' into a boolean expression: either through
844 /// an implicit conversion, or through an `operator true' invocation
846 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
852 if (e.Type == TypeManager.bool_type)
855 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
857 if (converted != null)
861 // If no implicit conversion to bool exists, try using `operator true'
863 converted = Expression.GetOperatorTrue (ec, e, loc);
864 if (converted == null){
865 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
871 public virtual string ExprClassName
875 case ExprClass.Invalid:
877 case ExprClass.Value:
879 case ExprClass.Variable:
881 case ExprClass.Namespace:
885 case ExprClass.MethodGroup:
886 return "method group";
887 case ExprClass.PropertyAccess:
888 return "property access";
889 case ExprClass.EventAccess:
890 return "event access";
891 case ExprClass.IndexerAccess:
892 return "indexer access";
893 case ExprClass.Nothing:
896 throw new Exception ("Should not happen");
901 /// Reports that we were expecting `expr' to be of class `expected'
903 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
905 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
908 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
910 string name = GetSignatureForError ();
912 name = ds.GetSignatureForError () + '.' + name;
914 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
915 name, was, expected);
918 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
920 string [] valid = new string [4];
923 if ((flags & ResolveFlags.VariableOrValue) != 0) {
924 valid [count++] = "variable";
925 valid [count++] = "value";
928 if ((flags & ResolveFlags.Type) != 0)
929 valid [count++] = "type";
931 if ((flags & ResolveFlags.MethodGroup) != 0)
932 valid [count++] = "method group";
935 valid [count++] = "unknown";
937 StringBuilder sb = new StringBuilder (valid [0]);
938 for (int i = 1; i < count - 1; i++) {
940 sb.Append (valid [i]);
943 sb.Append ("' or `");
944 sb.Append (valid [count - 1]);
947 Report.Error (119, loc,
948 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
951 public static void UnsafeError (Location loc)
953 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
957 // Load the object from the pointer.
959 public static void LoadFromPtr (ILGenerator ig, Type t)
961 if (t == TypeManager.int32_type)
962 ig.Emit (OpCodes.Ldind_I4);
963 else if (t == TypeManager.uint32_type)
964 ig.Emit (OpCodes.Ldind_U4);
965 else if (t == TypeManager.short_type)
966 ig.Emit (OpCodes.Ldind_I2);
967 else if (t == TypeManager.ushort_type)
968 ig.Emit (OpCodes.Ldind_U2);
969 else if (t == TypeManager.char_type)
970 ig.Emit (OpCodes.Ldind_U2);
971 else if (t == TypeManager.byte_type)
972 ig.Emit (OpCodes.Ldind_U1);
973 else if (t == TypeManager.sbyte_type)
974 ig.Emit (OpCodes.Ldind_I1);
975 else if (t == TypeManager.uint64_type)
976 ig.Emit (OpCodes.Ldind_I8);
977 else if (t == TypeManager.int64_type)
978 ig.Emit (OpCodes.Ldind_I8);
979 else if (t == TypeManager.float_type)
980 ig.Emit (OpCodes.Ldind_R4);
981 else if (t == TypeManager.double_type)
982 ig.Emit (OpCodes.Ldind_R8);
983 else if (t == TypeManager.bool_type)
984 ig.Emit (OpCodes.Ldind_I1);
985 else if (t == TypeManager.intptr_type)
986 ig.Emit (OpCodes.Ldind_I);
987 else if (TypeManager.IsEnumType (t)) {
988 if (t == TypeManager.enum_type)
989 ig.Emit (OpCodes.Ldind_Ref);
991 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
992 } else if (t.IsValueType || t.IsGenericParameter)
993 ig.Emit (OpCodes.Ldobj, t);
994 else if (t.IsPointer)
995 ig.Emit (OpCodes.Ldind_I);
997 ig.Emit (OpCodes.Ldind_Ref);
1001 // The stack contains the pointer and the value of type `type'
1003 public static void StoreFromPtr (ILGenerator ig, Type type)
1005 if (TypeManager.IsEnumType (type))
1006 type = TypeManager.EnumToUnderlying (type);
1007 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1008 ig.Emit (OpCodes.Stind_I4);
1009 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1010 ig.Emit (OpCodes.Stind_I8);
1011 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1012 type == TypeManager.ushort_type)
1013 ig.Emit (OpCodes.Stind_I2);
1014 else if (type == TypeManager.float_type)
1015 ig.Emit (OpCodes.Stind_R4);
1016 else if (type == TypeManager.double_type)
1017 ig.Emit (OpCodes.Stind_R8);
1018 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1019 type == TypeManager.bool_type)
1020 ig.Emit (OpCodes.Stind_I1);
1021 else if (type == TypeManager.intptr_type)
1022 ig.Emit (OpCodes.Stind_I);
1023 else if (type.IsValueType || type.IsGenericParameter)
1024 ig.Emit (OpCodes.Stobj, type);
1026 ig.Emit (OpCodes.Stind_Ref);
1030 // Returns the size of type `t' if known, otherwise, 0
1032 public static int GetTypeSize (Type t)
1034 t = TypeManager.TypeToCoreType (t);
1035 if (t == TypeManager.int32_type ||
1036 t == TypeManager.uint32_type ||
1037 t == TypeManager.float_type)
1039 else if (t == TypeManager.int64_type ||
1040 t == TypeManager.uint64_type ||
1041 t == TypeManager.double_type)
1043 else if (t == TypeManager.byte_type ||
1044 t == TypeManager.sbyte_type ||
1045 t == TypeManager.bool_type)
1047 else if (t == TypeManager.short_type ||
1048 t == TypeManager.char_type ||
1049 t == TypeManager.ushort_type)
1051 else if (t == TypeManager.decimal_type)
1057 public static void Error_NegativeArrayIndex (Location loc)
1059 Report.Error (248, loc, "Cannot create an array with a negative size");
1062 protected void Error_CannotCallAbstractBase (string name)
1064 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1068 // Converts `source' to an int, uint, long or ulong.
1070 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1074 bool old_checked = ec.CheckState;
1075 ec.CheckState = true;
1077 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1078 if (target == null){
1079 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1080 if (target == null){
1081 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1082 if (target == null){
1083 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1085 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1089 ec.CheckState = old_checked;
1092 // Only positive constants are allowed at compile time
1094 if (target is Constant){
1095 if (target is IntConstant){
1096 if (((IntConstant) target).Value < 0){
1097 Error_NegativeArrayIndex (loc);
1102 if (target is LongConstant){
1103 if (((LongConstant) target).Value < 0){
1104 Error_NegativeArrayIndex (loc);
1117 /// This is just a base class for expressions that can
1118 /// appear on statements (invocations, object creation,
1119 /// assignments, post/pre increment and decrement). The idea
1120 /// being that they would support an extra Emition interface that
1121 /// does not leave a result on the stack.
1123 public abstract class ExpressionStatement : Expression {
1125 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1127 Expression e = Resolve (ec);
1131 ExpressionStatement es = e as ExpressionStatement;
1133 Error (201, "Only assignment, call, increment, decrement and new object " +
1134 "expressions can be used as a statement");
1140 /// Requests the expression to be emitted in a `statement'
1141 /// context. This means that no new value is left on the
1142 /// stack after invoking this method (constrasted with
1143 /// Emit that will always leave a value on the stack).
1145 public abstract void EmitStatement (EmitContext ec);
1149 /// This kind of cast is used to encapsulate the child
1150 /// whose type is child.Type into an expression that is
1151 /// reported to return "return_type". This is used to encapsulate
1152 /// expressions which have compatible types, but need to be dealt
1153 /// at higher levels with.
1155 /// For example, a "byte" expression could be encapsulated in one
1156 /// of these as an "unsigned int". The type for the expression
1157 /// would be "unsigned int".
1160 public class EmptyCast : Expression {
1161 protected readonly Expression child;
1163 public Expression Child {
1169 public EmptyCast (Expression child, Type return_type)
1171 eclass = child.eclass;
1172 loc = child.Location;
1177 public override Expression DoResolve (EmitContext ec)
1179 // This should never be invoked, we are born in fully
1180 // initialized state.
1185 public override void Emit (EmitContext ec)
1190 public override bool GetAttributableValue (out object value)
1192 return child.GetAttributableValue (out value);
1197 /// This is a numeric cast to a Decimal
1199 public class CastToDecimal : EmptyCast {
1201 MethodInfo conversion_operator;
1203 public CastToDecimal (Expression child)
1204 : this (child, false)
1208 public CastToDecimal (Expression child, bool find_explicit)
1209 : base (child, TypeManager.decimal_type)
1211 conversion_operator = GetConversionOperator (find_explicit);
1213 if (conversion_operator == null)
1214 throw new InternalErrorException ("Outer conversion routine is out of sync");
1217 // Returns the implicit operator that converts from
1218 // 'child.Type' to System.Decimal.
1219 MethodInfo GetConversionOperator (bool find_explicit)
1221 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1223 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1224 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1226 foreach (MethodInfo oper in mi) {
1227 ParameterData pd = TypeManager.GetParameterData (oper);
1229 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1235 public override void Emit (EmitContext ec)
1237 ILGenerator ig = ec.ig;
1240 ig.Emit (OpCodes.Call, conversion_operator);
1245 /// This is an explicit numeric cast from a Decimal
1247 public class CastFromDecimal : EmptyCast
1249 static IDictionary operators;
1251 public CastFromDecimal (Expression child, Type return_type)
1252 : base (child, return_type)
1254 if (child.Type != TypeManager.decimal_type)
1255 throw new InternalErrorException (
1256 "The expected type is Decimal, instead it is " + child.Type.FullName);
1259 // Returns the explicit operator that converts from an
1260 // express of type System.Decimal to 'type'.
1261 public Expression Resolve ()
1263 if (operators == null) {
1264 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1265 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1266 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1268 operators = new System.Collections.Specialized.HybridDictionary ();
1269 foreach (MethodInfo oper in all_oper) {
1270 ParameterData pd = TypeManager.GetParameterData (oper);
1271 if (pd.ParameterType (0) == TypeManager.decimal_type)
1272 operators.Add (oper.ReturnType, oper);
1276 return operators.Contains (type) ? this : null;
1279 public override void Emit (EmitContext ec)
1281 ILGenerator ig = ec.ig;
1284 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1289 // We need to special case this since an empty cast of
1290 // a NullLiteral is still a Constant
1292 public class NullCast : Constant {
1293 public Constant child;
1295 public NullCast (Constant child, Type return_type):
1296 base (Location.Null)
1298 eclass = child.eclass;
1303 override public string AsString ()
1308 public override object GetValue ()
1313 public override Expression DoResolve (EmitContext ec)
1315 // This should never be invoked, we are born in fully
1316 // initialized state.
1321 public override void Emit (EmitContext ec)
1326 public override Constant Increment ()
1328 throw new NotSupportedException ();
1331 public override bool IsDefaultValue {
1337 public override bool IsNegative {
1343 public override Constant Reduce (EmitContext ec, Type target_type)
1345 if (type == target_type)
1346 return child.Reduce (ec, target_type);
1355 /// This class is used to wrap literals which belong inside Enums
1357 public class EnumConstant : Constant {
1358 public Constant Child;
1360 public EnumConstant (Constant child, Type enum_type):
1361 base (child.Location)
1363 eclass = child.eclass;
1368 public override Expression DoResolve (EmitContext ec)
1370 // This should never be invoked, we are born in fully
1371 // initialized state.
1376 public override void Emit (EmitContext ec)
1381 public override string GetSignatureForError()
1383 return TypeManager.CSharpName (Type);
1386 public override object GetValue ()
1388 return Child.GetValue ();
1391 public override object GetTypedValue ()
1393 // FIXME: runtime is not ready to work with just emited enums
1394 if (!RootContext.StdLib) {
1395 return Child.GetValue ();
1398 return System.Enum.ToObject (type, Child.GetValue ());
1401 public override string AsString ()
1403 return Child.AsString ();
1406 public override DoubleConstant ConvertToDouble ()
1408 return Child.ConvertToDouble ();
1411 public override FloatConstant ConvertToFloat ()
1413 return Child.ConvertToFloat ();
1416 public override ULongConstant ConvertToULong ()
1418 return Child.ConvertToULong ();
1421 public override LongConstant ConvertToLong ()
1423 return Child.ConvertToLong ();
1426 public override UIntConstant ConvertToUInt ()
1428 return Child.ConvertToUInt ();
1431 public override IntConstant ConvertToInt ()
1433 return Child.ConvertToInt ();
1436 public override Constant Increment()
1438 return new EnumConstant (Child.Increment (), type);
1441 public override bool IsDefaultValue {
1443 return Child.IsDefaultValue;
1447 public override bool IsZeroInteger {
1448 get { return Child.IsZeroInteger; }
1451 public override bool IsNegative {
1453 return Child.IsNegative;
1457 public override Constant Reduce(EmitContext ec, Type target_type)
1459 if (Child.Type == target_type)
1462 return Child.Reduce (ec, target_type);
1465 public override Constant ToType (Type type, Location loc)
1468 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1469 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1472 if (type.UnderlyingSystemType != Child.Type)
1473 Child = Child.ToType (type.UnderlyingSystemType, loc);
1477 if (!Convert.ImplicitStandardConversionExists (this, type)){
1478 Error_ValueCannotBeConverted (loc, type, false);
1482 return Child.ToType (type, loc);
1488 /// This kind of cast is used to encapsulate Value Types in objects.
1490 /// The effect of it is to box the value type emitted by the previous
1493 public class BoxedCast : EmptyCast {
1495 public BoxedCast (Expression expr, Type target_type)
1496 : base (expr, target_type)
1498 eclass = ExprClass.Value;
1501 public override Expression DoResolve (EmitContext ec)
1503 // This should never be invoked, we are born in fully
1504 // initialized state.
1509 public override void Emit (EmitContext ec)
1513 ec.ig.Emit (OpCodes.Box, child.Type);
1517 public class UnboxCast : EmptyCast {
1518 public UnboxCast (Expression expr, Type return_type)
1519 : base (expr, return_type)
1523 public override Expression DoResolve (EmitContext ec)
1525 // This should never be invoked, we are born in fully
1526 // initialized state.
1531 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1533 if (right_side == EmptyExpression.LValueMemberAccess)
1534 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1535 return base.DoResolveLValue (ec, right_side);
1538 public override void Emit (EmitContext ec)
1541 ILGenerator ig = ec.ig;
1544 if (t.IsGenericParameter)
1545 ig.Emit (OpCodes.Unbox_Any, t);
1547 ig.Emit (OpCodes.Unbox, t);
1549 LoadFromPtr (ig, t);
1555 /// This is used to perform explicit numeric conversions.
1557 /// Explicit numeric conversions might trigger exceptions in a checked
1558 /// context, so they should generate the conv.ovf opcodes instead of
1561 public class ConvCast : EmptyCast {
1562 public enum Mode : byte {
1563 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1565 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1566 U2_I1, U2_U1, U2_I2, U2_CH,
1567 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1568 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1569 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1570 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1571 CH_I1, CH_U1, CH_I2,
1572 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1573 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1578 public ConvCast (Expression child, Type return_type, Mode m)
1579 : base (child, return_type)
1584 public override Expression DoResolve (EmitContext ec)
1586 // This should never be invoked, we are born in fully
1587 // initialized state.
1592 public override string ToString ()
1594 return String.Format ("ConvCast ({0}, {1})", mode, child);
1597 public override void Emit (EmitContext ec)
1599 ILGenerator ig = ec.ig;
1605 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1606 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1607 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1608 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1609 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1611 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1612 case Mode.U1_CH: /* nothing */ break;
1614 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1615 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1616 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1618 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1619 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1622 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1623 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1624 case Mode.U2_CH: /* nothing */ break;
1626 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1627 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1628 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1629 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1630 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1631 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1632 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1634 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1635 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1636 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1637 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1638 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1639 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1641 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1642 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1643 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1644 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1645 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1646 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1647 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1648 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1650 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1651 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1652 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1653 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1654 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1655 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1656 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1657 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1659 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1660 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1661 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1663 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1664 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1665 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1666 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1667 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1668 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1669 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1670 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1671 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1673 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1674 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1675 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1676 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1677 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1678 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1679 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1680 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1681 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1682 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1686 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1687 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1688 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1689 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1690 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1692 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1693 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1695 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1696 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1697 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1698 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1699 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1700 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1702 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1703 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1704 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1705 case Mode.U2_CH: /* nothing */ break;
1707 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1708 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1709 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1710 case Mode.I4_U4: /* nothing */ break;
1711 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1712 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1713 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1715 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1716 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1717 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1718 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1719 case Mode.U4_I4: /* nothing */ break;
1720 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1722 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1723 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1724 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1725 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1726 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1727 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1728 case Mode.I8_U8: /* nothing */ break;
1729 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1731 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1732 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1733 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1734 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1735 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1736 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1737 case Mode.U8_I8: /* nothing */ break;
1738 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1740 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1741 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1742 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1744 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1745 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1746 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1747 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1748 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1749 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1750 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1751 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1752 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1754 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1755 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1756 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1757 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1758 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1759 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1760 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1761 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1762 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1763 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1769 public class OpcodeCast : EmptyCast {
1773 public OpcodeCast (Expression child, Type return_type, OpCode op)
1774 : base (child, return_type)
1778 second_valid = false;
1781 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1782 : base (child, return_type)
1787 second_valid = true;
1790 public override Expression DoResolve (EmitContext ec)
1792 // This should never be invoked, we are born in fully
1793 // initialized state.
1798 public override void Emit (EmitContext ec)
1809 /// This kind of cast is used to encapsulate a child and cast it
1810 /// to the class requested
1812 public class ClassCast : EmptyCast {
1813 public ClassCast (Expression child, Type return_type)
1814 : base (child, return_type)
1819 public override Expression DoResolve (EmitContext ec)
1821 // This should never be invoked, we are born in fully
1822 // initialized state.
1827 public override void Emit (EmitContext ec)
1831 if (child.Type.IsGenericParameter)
1832 ec.ig.Emit (OpCodes.Box, child.Type);
1834 if (type.IsGenericParameter)
1835 ec.ig.Emit (OpCodes.Unbox_Any, type);
1837 ec.ig.Emit (OpCodes.Castclass, type);
1842 /// SimpleName expressions are formed of a single word and only happen at the beginning
1843 /// of a dotted-name.
1845 public class SimpleName : Expression {
1847 public readonly TypeArguments Arguments;
1850 public SimpleName (string name, Location l)
1856 public SimpleName (string name, TypeArguments args, Location l)
1863 public SimpleName (string name, TypeParameter[] type_params, Location l)
1868 Arguments = new TypeArguments (l);
1869 foreach (TypeParameter type_param in type_params)
1870 Arguments.Add (new TypeParameterExpr (type_param, l));
1873 public static string RemoveGenericArity (string name)
1876 StringBuilder sb = new StringBuilder ();
1877 while (start < name.Length) {
1878 int pos = name.IndexOf ('`', start);
1880 sb.Append (name.Substring (start));
1884 sb.Append (name.Substring (start, pos-start));
1887 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1893 return sb.ToString ();
1896 public SimpleName GetMethodGroup ()
1898 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1901 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1903 if (ec.IsFieldInitializer)
1904 Report.Error (236, l,
1905 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1908 if (name.LastIndexOf ('.') > 0)
1909 name = name.Substring (name.LastIndexOf ('.') + 1);
1912 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1917 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1919 return resolved_to != null && resolved_to.Type != null &&
1920 resolved_to.Type.Name == Name &&
1921 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1924 public override Expression DoResolve (EmitContext ec)
1926 return SimpleNameResolve (ec, null, false);
1929 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1931 return SimpleNameResolve (ec, right_side, false);
1935 public Expression DoResolve (EmitContext ec, bool intermediate)
1937 return SimpleNameResolve (ec, null, intermediate);
1940 private bool IsNestedChild (Type t, Type parent)
1945 while (parent != null) {
1946 parent = TypeManager.DropGenericTypeArguments (parent);
1947 if (TypeManager.IsNestedChildOf (t, parent))
1950 parent = parent.BaseType;
1956 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
1958 if (!t.IsGenericTypeDefinition)
1961 DeclSpace ds = ec.DeclContainer;
1962 while (ds != null) {
1963 if (IsNestedChild (t, ds.TypeBuilder))
1972 Type[] gen_params = t.GetGenericArguments ();
1974 int arg_count = Arguments != null ? Arguments.Count : 0;
1976 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
1977 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
1978 TypeArguments new_args = new TypeArguments (loc);
1979 foreach (TypeParameter param in ds.TypeParameters)
1980 new_args.Add (new TypeParameterExpr (param, loc));
1982 if (Arguments != null)
1983 new_args.Add (Arguments);
1985 return new ConstructedType (t, new_args, loc);
1992 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
1994 FullNamedExpression fne = ec.DeclContainer.LookupGeneric (Name, loc);
1996 return fne.ResolveAsTypeStep (ec, silent);
1998 int errors = Report.Errors;
1999 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2002 if (fne.Type == null)
2005 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2007 return nested.ResolveAsTypeStep (ec, false);
2009 if (Arguments != null) {
2010 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2011 return ct.ResolveAsTypeStep (ec, false);
2017 if (silent || errors != Report.Errors)
2020 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2022 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2024 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2030 // TODO: I am still not convinced about this. If someone else will need it
2031 // implement this as virtual property in MemberCore hierarchy
2032 string GetMemberType (MemberCore mc)
2034 if (mc is PropertyBase)
2038 if (mc is FieldBase)
2040 if (mc is MethodCore)
2042 if (mc is EnumMember)
2048 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2054 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2058 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2065 /// 7.5.2: Simple Names.
2067 /// Local Variables and Parameters are handled at
2068 /// parse time, so they never occur as SimpleNames.
2070 /// The `intermediate' flag is used by MemberAccess only
2071 /// and it is used to inform us that it is ok for us to
2072 /// avoid the static check, because MemberAccess might end
2073 /// up resolving the Name as a Type name and the access as
2074 /// a static type access.
2076 /// ie: Type Type; .... { Type.GetType (""); }
2078 /// Type is both an instance variable and a Type; Type.GetType
2079 /// is the static method not an instance method of type.
2081 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2083 Expression e = null;
2086 // Stage 1: Performed by the parser (binding to locals or parameters).
2088 Block current_block = ec.CurrentBlock;
2089 if (current_block != null){
2090 LocalInfo vi = current_block.GetLocalInfo (Name);
2092 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2093 if (right_side != null) {
2094 return var.ResolveLValue (ec, right_side, loc);
2096 ResolveFlags rf = ResolveFlags.VariableOrValue;
2098 rf |= ResolveFlags.DisableFlowAnalysis;
2099 return var.Resolve (ec, rf);
2103 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2105 if (right_side != null)
2106 return pref.ResolveLValue (ec, right_side, loc);
2108 return pref.Resolve (ec);
2113 // Stage 2: Lookup members
2116 DeclSpace lookup_ds = ec.DeclContainer;
2117 Type almost_matched_type = null;
2118 ArrayList almost_matched = null;
2120 if (lookup_ds.TypeBuilder == null)
2123 e = MemberLookup (ec, lookup_ds.TypeBuilder, Name, loc);
2127 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2128 almost_matched_type = lookup_ds.TypeBuilder;
2129 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2132 lookup_ds =lookup_ds.Parent;
2133 } while (lookup_ds != null);
2135 if (e == null && ec.ContainerType != null)
2136 e = MemberLookup (ec, ec.ContainerType, Name, loc);
2139 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2140 almost_matched_type = ec.ContainerType;
2141 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2143 e = ResolveAsTypeStep (ec, true);
2147 if (almost_matched != null)
2148 almostMatchedMembers = almost_matched;
2149 if (almost_matched_type == null)
2150 almost_matched_type = ec.ContainerType;
2151 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2158 if (e is MemberExpr) {
2159 MemberExpr me = (MemberExpr) e;
2162 if (me.IsInstance) {
2163 if (ec.IsStatic || ec.IsFieldInitializer) {
2165 // Note that an MemberExpr can be both IsInstance and IsStatic.
2166 // An unresolved MethodGroupExpr can contain both kinds of methods
2167 // and each predicate is true if the MethodGroupExpr contains
2168 // at least one of that kind of method.
2172 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2173 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2174 return EmptyExpression.Null;
2178 // Pass the buck to MemberAccess and Invocation.
2180 left = EmptyExpression.Null;
2182 left = ec.GetThis (loc);
2185 left = new TypeExpression (ec.ContainerType, loc);
2188 e = me.ResolveMemberAccess (ec, left, loc, null);
2192 me = e as MemberExpr;
2196 if (Arguments != null) {
2197 MethodGroupExpr mg = me as MethodGroupExpr;
2201 return mg.ResolveGeneric (ec, Arguments);
2205 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2206 me.InstanceExpression.Type != me.DeclaringType &&
2207 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2208 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2209 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2210 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2214 return (right_side != null)
2215 ? me.DoResolveLValue (ec, right_side)
2216 : me.DoResolve (ec);
2222 public override void Emit (EmitContext ec)
2225 // If this is ever reached, then we failed to
2226 // find the name as a namespace
2229 Error (103, "The name `" + Name +
2230 "' does not exist in the class `" +
2231 ec.DeclContainer.Name + "'");
2234 public override string ToString ()
2239 public override string GetSignatureForError ()
2246 /// Represents a namespace or a type. The name of the class was inspired by
2247 /// section 10.8.1 (Fully Qualified Names).
2249 public abstract class FullNamedExpression : Expression {
2250 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2255 public abstract string FullName {
2261 /// Expression that evaluates to a type
2263 public abstract class TypeExpr : FullNamedExpression {
2264 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2266 TypeExpr t = DoResolveAsTypeStep (ec);
2270 eclass = ExprClass.Type;
2274 override public Expression DoResolve (EmitContext ec)
2276 return ResolveAsTypeTerminal (ec, false);
2279 override public void Emit (EmitContext ec)
2281 throw new Exception ("Should never be called");
2284 public virtual bool CheckAccessLevel (DeclSpace ds)
2286 return ds.CheckAccessLevel (Type);
2289 public virtual bool AsAccessible (DeclSpace ds, int flags)
2291 return ds.AsAccessible (Type, flags);
2294 public virtual bool IsClass {
2295 get { return Type.IsClass; }
2298 public virtual bool IsValueType {
2299 get { return Type.IsValueType; }
2302 public virtual bool IsInterface {
2303 get { return Type.IsInterface; }
2306 public virtual bool IsSealed {
2307 get { return Type.IsSealed; }
2310 public virtual bool CanInheritFrom ()
2312 if (Type == TypeManager.enum_type ||
2313 (Type == TypeManager.value_type && RootContext.StdLib) ||
2314 Type == TypeManager.multicast_delegate_type ||
2315 Type == TypeManager.delegate_type ||
2316 Type == TypeManager.array_type)
2322 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2324 public Type ResolveType (IResolveContext ec)
2326 TypeExpr t = ResolveAsTypeTerminal (ec, false);
2330 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (t.Type);
2331 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
2332 AttributeTester.Report_ObsoleteMessage (obsolete_attr, Name, Location);
2338 public abstract string Name {
2342 public override bool Equals (object obj)
2344 TypeExpr tobj = obj as TypeExpr;
2348 return Type == tobj.Type;
2351 public override int GetHashCode ()
2353 return Type.GetHashCode ();
2356 public override string ToString ()
2363 /// Fully resolved Expression that already evaluated to a type
2365 public class TypeExpression : TypeExpr {
2366 public TypeExpression (Type t, Location l)
2369 eclass = ExprClass.Type;
2373 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2378 public override string Name {
2379 get { return Type.ToString (); }
2382 public override string FullName {
2383 get { return Type.FullName; }
2388 /// Used to create types from a fully qualified name. These are just used
2389 /// by the parser to setup the core types. A TypeLookupExpression is always
2390 /// classified as a type.
2392 public class TypeLookupExpression : TypeExpr {
2395 public TypeLookupExpression (string name)
2400 static readonly char [] dot_array = { '.' };
2401 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2406 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2408 string lookup_name = name;
2409 int pos = name.IndexOf ('.');
2411 rest = name.Substring (pos + 1);
2412 lookup_name = name.Substring (0, pos);
2415 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2417 if (resolved != null && rest != null) {
2418 // Now handle the rest of the the name.
2419 string [] elements = rest.Split (dot_array);
2421 int count = elements.Length;
2423 while (i < count && resolved != null && resolved is Namespace) {
2424 Namespace ns = resolved as Namespace;
2425 element = elements [i++];
2426 lookup_name += "." + element;
2427 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2430 if (resolved != null && resolved is TypeExpr) {
2431 Type t = ((TypeExpr) resolved).Type;
2433 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2435 lookup_name = t.FullName;
2442 t = TypeManager.GetNestedType (t, elements [i++]);
2447 if (resolved == null) {
2448 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2452 if (!(resolved is TypeExpr)) {
2453 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2457 type = ((TypeExpr) resolved).ResolveType (ec);
2461 public override string Name {
2462 get { return name; }
2465 public override string FullName {
2466 get { return name; }
2471 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2474 public class UnboundTypeExpression : TypeExpr
2478 public UnboundTypeExpression (MemberName name, Location l)
2484 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2487 if (name.Left != null) {
2488 Expression lexpr = name.Left.GetTypeExpression ();
2489 expr = new MemberAccess (lexpr, name.Basename, loc);
2491 expr = new SimpleName (name.Basename, loc);
2494 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2499 return new TypeExpression (type, loc);
2502 public override string Name {
2503 get { return name.FullName; }
2506 public override string FullName {
2507 get { return name.FullName; }
2511 public class TypeAliasExpression : TypeExpr {
2512 FullNamedExpression alias;
2517 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2523 eclass = ExprClass.Type;
2525 name = alias.FullName + "<" + args.ToString () + ">";
2527 name = alias.FullName;
2530 public override string Name {
2531 get { return alias.FullName; }
2534 public override string FullName {
2535 get { return name; }
2538 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2540 texpr = alias.ResolveAsTypeTerminal (ec, false);
2544 Type type = texpr.ResolveType (ec);
2545 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2548 if (num_args == 0) {
2549 Report.Error (308, loc,
2550 "The non-generic type `{0}' cannot " +
2551 "be used with type arguments.",
2552 TypeManager.CSharpName (type));
2556 ConstructedType ctype = new ConstructedType (type, args, loc);
2557 return ctype.ResolveAsTypeTerminal (ec, false);
2558 } else if (num_args > 0) {
2559 Report.Error (305, loc,
2560 "Using the generic type `{0}' " +
2561 "requires {1} type arguments",
2562 TypeManager.CSharpName (type), num_args.ToString ());
2566 return new TypeExpression (type, loc);
2569 public override bool CheckAccessLevel (DeclSpace ds)
2571 return texpr.CheckAccessLevel (ds);
2574 public override bool AsAccessible (DeclSpace ds, int flags)
2576 return texpr.AsAccessible (ds, flags);
2579 public override bool IsClass {
2580 get { return texpr.IsClass; }
2583 public override bool IsValueType {
2584 get { return texpr.IsValueType; }
2587 public override bool IsInterface {
2588 get { return texpr.IsInterface; }
2591 public override bool IsSealed {
2592 get { return texpr.IsSealed; }
2597 /// This class denotes an expression which evaluates to a member
2598 /// of a struct or a class.
2600 public abstract class MemberExpr : Expression
2603 /// The name of this member.
2605 public abstract string Name {
2610 /// Whether this is an instance member.
2612 public abstract bool IsInstance {
2617 /// Whether this is a static member.
2619 public abstract bool IsStatic {
2624 /// The type which declares this member.
2626 public abstract Type DeclaringType {
2631 /// The instance expression associated with this member, if it's a
2632 /// non-static member.
2634 public Expression InstanceExpression;
2636 public static void error176 (Location loc, string name)
2638 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2639 "with an instance reference, qualify it with a type name instead", name);
2642 // TODO: possible optimalization
2643 // Cache resolved constant result in FieldBuilder <-> expression map
2644 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2645 SimpleName original)
2649 // original == null || original.Resolve (...) ==> left
2652 if (left is TypeExpr) {
2654 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2662 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2665 error176 (loc, GetSignatureForError ());
2669 InstanceExpression = left;
2674 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2679 if (InstanceExpression == EmptyExpression.Null) {
2680 SimpleName.Error_ObjectRefRequired (ec, loc, Name);
2684 if (InstanceExpression.Type.IsValueType) {
2685 if (InstanceExpression is IMemoryLocation) {
2686 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2688 LocalTemporary t = new LocalTemporary (ec, InstanceExpression.Type);
2689 InstanceExpression.Emit (ec);
2691 t.AddressOf (ec, AddressOp.Store);
2694 InstanceExpression.Emit (ec);
2696 if (prepare_for_load)
2697 ec.ig.Emit (OpCodes.Dup);
2702 /// MethodGroup Expression.
2704 /// This is a fully resolved expression that evaluates to a type
2706 public class MethodGroupExpr : MemberExpr {
2707 public MethodBase [] Methods;
2708 bool has_type_arguments = false;
2709 bool identical_type_name = false;
2712 public MethodGroupExpr (MemberInfo [] mi, Location l)
2714 Methods = new MethodBase [mi.Length];
2715 mi.CopyTo (Methods, 0);
2716 eclass = ExprClass.MethodGroup;
2717 type = TypeManager.object_type;
2721 public MethodGroupExpr (ArrayList list, Location l)
2723 Methods = new MethodBase [list.Count];
2726 list.CopyTo (Methods, 0);
2728 foreach (MemberInfo m in list){
2729 if (!(m is MethodBase)){
2730 Console.WriteLine ("Name " + m.Name);
2731 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2738 eclass = ExprClass.MethodGroup;
2739 type = TypeManager.object_type;
2742 public override Type DeclaringType {
2745 // We assume that the top-level type is in the end
2747 return Methods [Methods.Length - 1].DeclaringType;
2748 //return Methods [0].DeclaringType;
2752 public bool HasTypeArguments {
2754 return has_type_arguments;
2758 has_type_arguments = value;
2762 public bool IdenticalTypeName {
2764 return identical_type_name;
2768 identical_type_name = value;
2772 public bool IsBase {
2781 public override string GetSignatureForError ()
2783 return TypeManager.CSharpSignature (Methods [0]);
2786 public override string Name {
2788 return Methods [0].Name;
2792 public override bool IsInstance {
2794 foreach (MethodBase mb in Methods)
2802 public override bool IsStatic {
2804 foreach (MethodBase mb in Methods)
2812 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2813 SimpleName original)
2815 if (!(left is TypeExpr) &&
2816 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2817 IdenticalTypeName = true;
2819 return base.ResolveMemberAccess (ec, left, loc, original);
2822 override public Expression DoResolve (EmitContext ec)
2825 InstanceExpression = null;
2827 if (InstanceExpression != null) {
2828 InstanceExpression = InstanceExpression.DoResolve (ec);
2829 if (InstanceExpression == null)
2836 public void ReportUsageError ()
2838 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2839 Name + "()' is referenced without parentheses");
2842 override public void Emit (EmitContext ec)
2844 ReportUsageError ();
2847 bool RemoveMethods (bool keep_static)
2849 ArrayList smethods = new ArrayList ();
2851 foreach (MethodBase mb in Methods){
2852 if (mb.IsStatic == keep_static)
2856 if (smethods.Count == 0)
2859 Methods = new MethodBase [smethods.Count];
2860 smethods.CopyTo (Methods, 0);
2866 /// Removes any instance methods from the MethodGroup, returns
2867 /// false if the resulting set is empty.
2869 public bool RemoveInstanceMethods ()
2871 return RemoveMethods (true);
2875 /// Removes any static methods from the MethodGroup, returns
2876 /// false if the resulting set is empty.
2878 public bool RemoveStaticMethods ()
2880 return RemoveMethods (false);
2883 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2885 if (args.Resolve (ec) == false)
2888 Type[] atypes = args.Arguments;
2890 int first_count = 0;
2891 MethodInfo first = null;
2893 ArrayList list = new ArrayList ();
2894 foreach (MethodBase mb in Methods) {
2895 MethodInfo mi = mb as MethodInfo;
2896 if ((mi == null) || !mi.IsGenericMethod)
2899 Type[] gen_params = mi.GetGenericArguments ();
2901 if (first == null) {
2903 first_count = gen_params.Length;
2906 if (gen_params.Length != atypes.Length)
2909 list.Add (mi.MakeGenericMethod (atypes));
2912 if (list.Count > 0) {
2913 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
2914 new_mg.InstanceExpression = InstanceExpression;
2915 new_mg.HasTypeArguments = true;
2916 new_mg.IsBase = IsBase;
2922 305, loc, "Using the generic method `{0}' " +
2923 "requires {1} type arguments", Name,
2924 first_count.ToString ());
2927 308, loc, "The non-generic method `{0}' " +
2928 "cannot be used with type arguments", Name);
2935 /// Fully resolved expression that evaluates to a Field
2937 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
2938 public readonly FieldInfo FieldInfo;
2939 VariableInfo variable_info;
2941 LocalTemporary temp;
2943 bool in_initializer;
2945 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
2948 this.in_initializer = in_initializer;
2951 public FieldExpr (FieldInfo fi, Location l)
2954 eclass = ExprClass.Variable;
2955 type = TypeManager.TypeToCoreType (fi.FieldType);
2959 public override string Name {
2961 return FieldInfo.Name;
2965 public override bool IsInstance {
2967 return !FieldInfo.IsStatic;
2971 public override bool IsStatic {
2973 return FieldInfo.IsStatic;
2977 public override Type DeclaringType {
2979 return FieldInfo.DeclaringType;
2983 public override string GetSignatureForError ()
2985 return TypeManager.GetFullNameSignature (FieldInfo);
2988 public VariableInfo VariableInfo {
2990 return variable_info;
2994 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2995 SimpleName original)
2997 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
2999 Type t = fi.FieldType;
3001 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3002 IConstant ic = TypeManager.GetConstant (fi);
3005 ic = new ExternalConstant (fi);
3007 ic = ExternalConstant.CreateDecimal (fi);
3009 return base.ResolveMemberAccess (ec, left, loc, original);
3012 TypeManager.RegisterConstant (fi, ic);
3015 bool left_is_type = left is TypeExpr;
3016 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3017 Report.SymbolRelatedToPreviousError (FieldInfo);
3018 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3022 if (ic.ResolveValue ()) {
3023 if (!ec.IsInObsoleteScope)
3024 ic.CheckObsoleteness (loc);
3030 if (t.IsPointer && !ec.InUnsafe) {
3035 return base.ResolveMemberAccess (ec, left, loc, original);
3038 override public Expression DoResolve (EmitContext ec)
3040 return DoResolve (ec, false);
3043 Expression DoResolve (EmitContext ec, bool lvalue_instance)
3045 if (ec.InRefOutArgumentResolving && FieldInfo.IsInitOnly && !ec.IsConstructor && FieldInfo.FieldType.IsValueType) {
3046 if (FieldInfo.FieldType is TypeBuilder) {
3047 if (FieldInfo.IsStatic)
3048 Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3049 GetSignatureForError ());
3051 Report.Error (1649, loc, "Members of readonly field `{0}.{1}' cannot be passed ref or out (except in a constructor)",
3052 TypeManager.CSharpName (DeclaringType), Name);
3054 if (FieldInfo.IsStatic)
3055 Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3058 Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3064 if (!FieldInfo.IsStatic){
3065 if (InstanceExpression == null){
3067 // This can happen when referencing an instance field using
3068 // a fully qualified type expression: TypeName.InstanceField = xxx
3070 SimpleName.Error_ObjectRefRequired (ec, loc, FieldInfo.Name);
3074 // Resolve the field's instance expression while flow analysis is turned
3075 // off: when accessing a field "a.b", we must check whether the field
3076 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3078 if (lvalue_instance) {
3079 bool old_do_flow_analysis = ec.DoFlowAnalysis;
3080 ec.DoFlowAnalysis = false;
3081 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3082 ec.DoFlowAnalysis = old_do_flow_analysis;
3084 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3085 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3088 if (InstanceExpression == null)
3092 if (!in_initializer && !ec.IsFieldInitializer) {
3093 ObsoleteAttribute oa;
3094 FieldBase f = TypeManager.GetField (FieldInfo);
3096 if (!ec.IsInObsoleteScope)
3097 f.CheckObsoleteness (loc);
3099 // To be sure that type is external because we do not register generated fields
3100 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3101 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3103 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3107 AnonymousContainer am = ec.CurrentAnonymousMethod;
3109 if (!FieldInfo.IsStatic){
3110 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3111 Report.Error (1673, loc,
3112 "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",
3116 if ((am.ContainerAnonymousMethod == null) && (InstanceExpression is This))
3117 ec.CaptureField (this);
3121 // If the instance expression is a local variable or parameter.
3122 IVariable var = InstanceExpression as IVariable;
3123 if ((var == null) || (var.VariableInfo == null))
3126 VariableInfo vi = var.VariableInfo;
3127 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3130 variable_info = vi.GetSubStruct (FieldInfo.Name);
3134 void Report_AssignToReadonly (Expression right_side)
3138 bool need_error_sig = false;
3139 if (right_side == EmptyExpression.LValueMemberAccess) {
3142 msg = "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)";
3145 msg = "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)";
3147 need_error_sig = true;
3148 } else if (IsStatic) {
3150 msg = "A static readonly field cannot be assigned to (except in a static constructor or a variable initializer)";
3153 msg = "A readonly field cannot be assigned to (except in a constructor or a variable initializer)";
3157 Report.Error (code, loc, msg, GetSignatureForError ());
3159 Report.Error (code, loc, msg);
3162 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3164 IVariable var = InstanceExpression as IVariable;
3165 if ((var != null) && (var.VariableInfo != null))
3166 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3168 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3170 Expression e = DoResolve (ec, lvalue_instance);
3175 FieldBase fb = TypeManager.GetField (FieldInfo);
3179 if (!FieldInfo.IsInitOnly)
3183 // InitOnly fields can only be assigned in constructors
3186 if (ec.IsConstructor){
3187 if (IsStatic && !ec.IsStatic)
3188 Report_AssignToReadonly (right_side);
3191 if (ec.TypeContainer.CurrentType != null)
3192 ctype = ec.TypeContainer.CurrentType;
3194 ctype = ec.ContainerType;
3196 if (TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3200 Report_AssignToReadonly (right_side);
3205 public override void CheckMarshallByRefAccess (Type container)
3207 if (!IsStatic && Type.IsValueType && !container.IsSubclassOf (TypeManager.mbr_type) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3208 Report.SymbolRelatedToPreviousError (DeclaringType);
3209 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",
3210 GetSignatureForError ());
3214 public bool VerifyFixed ()
3216 IVariable variable = InstanceExpression as IVariable;
3217 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3218 // We defer the InstanceExpression check after the variable check to avoid a
3219 // separate null check on InstanceExpression.
3220 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3223 public override int GetHashCode()
3225 return FieldInfo.GetHashCode ();
3228 public override bool Equals (object obj)
3230 FieldExpr fe = obj as FieldExpr;
3234 if (FieldInfo != fe.FieldInfo)
3237 if (InstanceExpression == null || fe.InstanceExpression == null)
3240 return InstanceExpression.Equals (fe.InstanceExpression);
3243 public void Emit (EmitContext ec, bool leave_copy)
3245 ILGenerator ig = ec.ig;
3246 bool is_volatile = false;
3248 FieldBase f = TypeManager.GetField (FieldInfo);
3250 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3253 f.SetMemberIsUsed ();
3256 if (FieldInfo.IsStatic){
3258 ig.Emit (OpCodes.Volatile);
3260 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3263 EmitInstance (ec, false);
3266 ig.Emit (OpCodes.Volatile);
3268 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3271 ig.Emit (OpCodes.Ldflda, FieldInfo);
3272 ig.Emit (OpCodes.Ldflda, ff.Element);
3275 ig.Emit (OpCodes.Ldfld, FieldInfo);
3280 ec.ig.Emit (OpCodes.Dup);
3281 if (!FieldInfo.IsStatic) {
3282 temp = new LocalTemporary (ec, this.Type);
3288 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3290 FieldAttributes fa = FieldInfo.Attributes;
3291 bool is_static = (fa & FieldAttributes.Static) != 0;
3292 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3293 ILGenerator ig = ec.ig;
3294 prepared = prepare_for_load;
3296 if (is_readonly && !ec.IsConstructor){
3297 Report_AssignToReadonly (source);
3301 EmitInstance (ec, prepare_for_load);
3305 ec.ig.Emit (OpCodes.Dup);
3306 if (!FieldInfo.IsStatic) {
3307 temp = new LocalTemporary (ec, this.Type);
3312 if (FieldInfo is FieldBuilder){
3313 FieldBase f = TypeManager.GetField (FieldInfo);
3315 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3316 ig.Emit (OpCodes.Volatile);
3323 ig.Emit (OpCodes.Stsfld, FieldInfo);
3325 ig.Emit (OpCodes.Stfld, FieldInfo);
3331 public override void Emit (EmitContext ec)
3336 public void AddressOf (EmitContext ec, AddressOp mode)
3338 ILGenerator ig = ec.ig;
3340 if (FieldInfo is FieldBuilder){
3341 FieldBase f = TypeManager.GetField (FieldInfo);
3343 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3344 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3345 f.GetSignatureForError ());
3349 if ((mode & AddressOp.Store) != 0)
3351 if ((mode & AddressOp.Load) != 0)
3352 f.SetMemberIsUsed ();
3357 // Handle initonly fields specially: make a copy and then
3358 // get the address of the copy.
3361 if (FieldInfo.IsInitOnly){
3363 if (ec.IsConstructor){
3364 if (FieldInfo.IsStatic){
3376 local = ig.DeclareLocal (type);
3377 ig.Emit (OpCodes.Stloc, local);
3378 ig.Emit (OpCodes.Ldloca, local);
3383 if (FieldInfo.IsStatic){
3384 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3387 EmitInstance (ec, false);
3388 ig.Emit (OpCodes.Ldflda, FieldInfo);
3394 // A FieldExpr whose address can not be taken
3396 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3397 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3401 public new void AddressOf (EmitContext ec, AddressOp mode)
3403 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3408 /// Expression that evaluates to a Property. The Assign class
3409 /// might set the `Value' expression if we are in an assignment.
3411 /// This is not an LValue because we need to re-write the expression, we
3412 /// can not take data from the stack and store it.
3414 public class PropertyExpr : MemberExpr, IAssignMethod {
3415 public readonly PropertyInfo PropertyInfo;
3418 // This is set externally by the `BaseAccess' class
3421 MethodInfo getter, setter;
3426 LocalTemporary temp;
3429 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3431 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3434 eclass = ExprClass.PropertyAccess;
3438 type = TypeManager.TypeToCoreType (pi.PropertyType);
3440 ResolveAccessors (containerType);
3443 public override string Name {
3445 return PropertyInfo.Name;
3449 public override bool IsInstance {
3455 public override bool IsStatic {
3461 public override Type DeclaringType {
3463 return PropertyInfo.DeclaringType;
3467 public override string GetSignatureForError ()
3469 return TypeManager.GetFullNameSignature (PropertyInfo);
3472 void FindAccessors (Type invocation_type)
3474 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3475 BindingFlags.Static | BindingFlags.Instance |
3476 BindingFlags.DeclaredOnly;
3478 Type current = PropertyInfo.DeclaringType;
3479 for (; current != null; current = current.BaseType) {
3480 MemberInfo[] group = TypeManager.MemberLookup (
3481 invocation_type, invocation_type, current,
3482 MemberTypes.Property, flags, PropertyInfo.Name, null);
3487 if (group.Length != 1)
3488 // Oooops, can this ever happen ?
3491 PropertyInfo pi = (PropertyInfo) group [0];
3494 getter = pi.GetGetMethod (true);
3497 setter = pi.GetSetMethod (true);
3499 MethodInfo accessor = getter != null ? getter : setter;
3501 if (!accessor.IsVirtual)
3507 // We also perform the permission checking here, as the PropertyInfo does not
3508 // hold the information for the accessibility of its setter/getter
3510 // TODO: can use TypeManager.GetProperty to boost performance
3511 void ResolveAccessors (Type containerType)
3513 FindAccessors (containerType);
3515 if (getter != null) {
3516 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3517 IMethodData md = TypeManager.GetMethod (the_getter);
3519 md.SetMemberIsUsed ();
3521 AccessorTable [getter] = PropertyInfo;
3522 is_static = getter.IsStatic;
3525 if (setter != null) {
3526 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3527 IMethodData md = TypeManager.GetMethod (the_setter);
3529 md.SetMemberIsUsed ();
3531 AccessorTable [setter] = PropertyInfo;
3532 is_static = setter.IsStatic;
3536 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3539 InstanceExpression = null;
3543 if (InstanceExpression == null) {
3544 SimpleName.Error_ObjectRefRequired (ec, loc, PropertyInfo.Name);
3548 if (lvalue_instance)
3549 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3551 InstanceExpression = InstanceExpression.DoResolve (ec);
3552 if (InstanceExpression == null)
3555 InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
3557 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3558 InstanceExpression.Type != ec.ContainerType &&
3559 ec.ContainerType.IsSubclassOf (PropertyInfo.DeclaringType) &&
3560 !InstanceExpression.Type.IsSubclassOf (ec.ContainerType)) {
3561 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3568 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3570 // TODO: correctly we should compare arguments but it will lead to bigger changes
3571 if (mi is MethodBuilder) {
3572 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3576 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3578 ParameterData iparams = TypeManager.GetParameterData (mi);
3579 sig.Append (getter ? "get_" : "set_");
3581 sig.Append (iparams.GetSignatureForError ());
3583 Report.SymbolRelatedToPreviousError (mi);
3584 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3585 Name, sig.ToString ());
3588 override public Expression DoResolve (EmitContext ec)
3593 if (getter != null){
3594 if (TypeManager.GetParameterData (getter).Count != 0){
3595 Error_PropertyNotFound (getter, true);
3600 if (getter == null){
3602 // The following condition happens if the PropertyExpr was
3603 // created, but is invalid (ie, the property is inaccessible),
3604 // and we did not want to embed the knowledge about this in
3605 // the caller routine. This only avoids double error reporting.
3610 if (InstanceExpression != EmptyExpression.Null) {
3611 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3612 TypeManager.GetFullNameSignature (PropertyInfo));
3617 bool must_do_cs1540_check = false;
3618 if (getter != null &&
3619 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3620 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3621 if (pm != null && pm.HasCustomAccessModifier) {
3622 Report.SymbolRelatedToPreviousError (pm);
3623 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3624 TypeManager.CSharpSignature (getter));
3627 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3631 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3635 // Only base will allow this invocation to happen.
3637 if (IsBase && getter.IsAbstract) {
3638 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3642 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3652 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3654 if (right_side == EmptyExpression.OutAccess) {
3655 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3656 GetSignatureForError ());
3660 if (right_side == EmptyExpression.LValueMemberAccess) {
3661 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3662 GetSignatureForError ());
3666 if (setter == null){
3668 // The following condition happens if the PropertyExpr was
3669 // created, but is invalid (ie, the property is inaccessible),
3670 // and we did not want to embed the knowledge about this in
3671 // the caller routine. This only avoids double error reporting.
3675 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3676 GetSignatureForError ());
3680 if (TypeManager.GetParameterData (setter).Count != 1){
3681 Error_PropertyNotFound (setter, false);
3685 bool must_do_cs1540_check;
3686 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3687 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3688 if (pm != null && pm.HasCustomAccessModifier) {
3689 Report.SymbolRelatedToPreviousError (pm);
3690 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3691 TypeManager.CSharpSignature (setter));
3694 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3698 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3702 // Only base will allow this invocation to happen.
3704 if (IsBase && setter.IsAbstract){
3705 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3712 public override void Emit (EmitContext ec)
3717 public void Emit (EmitContext ec, bool leave_copy)
3720 // Special case: length of single dimension array property is turned into ldlen
3722 if ((getter == TypeManager.system_int_array_get_length) ||
3723 (getter == TypeManager.int_array_get_length)){
3724 Type iet = InstanceExpression.Type;
3727 // System.Array.Length can be called, but the Type does not
3728 // support invoking GetArrayRank, so test for that case first
3730 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3732 EmitInstance (ec, false);
3733 ec.ig.Emit (OpCodes.Ldlen);
3734 ec.ig.Emit (OpCodes.Conv_I4);
3739 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3742 ec.ig.Emit (OpCodes.Dup);
3744 temp = new LocalTemporary (ec, this.Type);
3751 // Implements the IAssignMethod interface for assignments
3753 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3755 Expression my_source = source;
3757 prepared = prepare_for_load;
3762 ec.ig.Emit (OpCodes.Dup);
3764 temp = new LocalTemporary (ec, this.Type);
3768 } else if (leave_copy) {
3771 temp = new LocalTemporary (ec, this.Type);
3777 ArrayList args = new ArrayList (1);
3778 args.Add (new Argument (my_source, Argument.AType.Expression));
3780 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3788 /// Fully resolved expression that evaluates to an Event
3790 public class EventExpr : MemberExpr {
3791 public readonly EventInfo EventInfo;
3794 MethodInfo add_accessor, remove_accessor;
3796 public EventExpr (EventInfo ei, Location loc)
3800 eclass = ExprClass.EventAccess;
3802 add_accessor = TypeManager.GetAddMethod (ei);
3803 remove_accessor = TypeManager.GetRemoveMethod (ei);
3805 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3808 if (EventInfo is MyEventBuilder){
3809 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3810 type = eb.EventType;
3813 type = EventInfo.EventHandlerType;
3816 public override string Name {
3818 return EventInfo.Name;
3822 public override bool IsInstance {
3828 public override bool IsStatic {
3834 public override Type DeclaringType {
3836 return EventInfo.DeclaringType;
3840 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3841 SimpleName original)
3844 // If the event is local to this class, we transform ourselves into a FieldExpr
3847 if (EventInfo.DeclaringType == ec.ContainerType ||
3848 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3849 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3852 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3855 Report.Error (-200, loc, "Internal error!!");
3859 InstanceExpression = null;
3861 return ml.ResolveMemberAccess (ec, left, loc, original);
3865 return base.ResolveMemberAccess (ec, left, loc, original);
3869 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3872 InstanceExpression = null;
3876 if (InstanceExpression == null) {
3877 SimpleName.Error_ObjectRefRequired (ec, loc, EventInfo.Name);
3881 InstanceExpression = InstanceExpression.DoResolve (ec);
3882 if (InstanceExpression == null)
3886 // This is using the same mechanism as the CS1540 check in PropertyExpr.
3887 // However, in the Event case, we reported a CS0122 instead.
3889 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
3890 InstanceExpression.Type != ec.ContainerType &&
3891 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
3892 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3899 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
3901 return DoResolve (ec);
3904 public override Expression DoResolve (EmitContext ec)
3906 bool must_do_cs1540_check;
3907 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
3908 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
3909 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
3913 if (!InstanceResolve (ec, must_do_cs1540_check))
3919 public override void Emit (EmitContext ec)
3921 if (InstanceExpression is This)
3922 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
3924 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
3925 "(except on the defining type)", Name);
3928 public override string GetSignatureForError ()
3930 return TypeManager.CSharpSignature (EventInfo);
3933 public void EmitAddOrRemove (EmitContext ec, Expression source)
3935 BinaryDelegate source_del = (BinaryDelegate) source;
3936 Expression handler = source_del.Right;
3938 Argument arg = new Argument (handler, Argument.AType.Expression);
3939 ArrayList args = new ArrayList ();
3943 if (source_del.IsAddition)
3944 Invocation.EmitCall (
3945 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
3947 Invocation.EmitCall (
3948 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
3953 public class TemporaryVariable : Expression, IMemoryLocation
3957 public TemporaryVariable (Type type, Location loc)
3961 eclass = ExprClass.Value;
3964 public override Expression DoResolve (EmitContext ec)
3969 TypeExpr te = new TypeExpression (type, loc);
3970 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
3971 if (!li.Resolve (ec))
3974 AnonymousContainer am = ec.CurrentAnonymousMethod;
3975 if ((am != null) && am.IsIterator)
3976 ec.CaptureVariable (li);
3981 public override void Emit (EmitContext ec)
3983 ILGenerator ig = ec.ig;
3985 if (li.FieldBuilder != null) {
3986 ig.Emit (OpCodes.Ldarg_0);
3987 ig.Emit (OpCodes.Ldfld, li.FieldBuilder);
3989 ig.Emit (OpCodes.Ldloc, li.LocalBuilder);
3993 public void EmitLoadAddress (EmitContext ec)
3995 ILGenerator ig = ec.ig;
3997 if (li.FieldBuilder != null) {
3998 ig.Emit (OpCodes.Ldarg_0);
3999 ig.Emit (OpCodes.Ldflda, li.FieldBuilder);
4001 ig.Emit (OpCodes.Ldloca, li.LocalBuilder);
4005 public void Store (EmitContext ec, Expression right_side)
4007 if (li.FieldBuilder != null)
4008 ec.ig.Emit (OpCodes.Ldarg_0);
4010 right_side.Emit (ec);
4011 if (li.FieldBuilder != null) {
4012 ec.ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4014 ec.ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4018 public void EmitThis (EmitContext ec)
4020 if (li.FieldBuilder != null) {
4021 ec.ig.Emit (OpCodes.Ldarg_0);
4025 public void EmitStore (ILGenerator ig)
4027 if (li.FieldBuilder != null)
4028 ig.Emit (OpCodes.Stfld, li.FieldBuilder);
4030 ig.Emit (OpCodes.Stloc, li.LocalBuilder);
4033 public void AddressOf (EmitContext ec, AddressOp mode)
4035 EmitLoadAddress (ec);