2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // (C) 2001, 2002, 2003 Ximian, Inc.
12 namespace Mono.CSharp {
14 using System.Collections;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
21 /// The ExprClass class contains the is used to pass the
22 /// classification of an expression (value, variable, namespace,
23 /// type, method group, property access, event access, indexer access,
26 public enum ExprClass : byte {
41 /// This is used to tell Resolve in which types of expressions we're
45 public enum ResolveFlags {
46 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 // Returns a type expression.
52 // Returns a method group.
55 // Mask of all the expression class flags.
58 // Disable control flow analysis while resolving the expression.
59 // This is used when resolving the instance expression of a field expression.
60 DisableFlowAnalysis = 8,
62 // Set if this is resolving the first part of a MemberAccess.
65 // Disable control flow analysis _of struct_ while resolving the expression.
66 // This is used when resolving the instance expression of a field expression.
67 DisableStructFlowAnalysis = 32,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 /// This interface is implemented by variables
102 public interface IVariable {
103 VariableInfo VariableInfo {
111 /// Base class for expressions
113 public abstract class Expression {
114 public ExprClass eclass;
116 protected Location loc;
120 set { type = value; }
123 public virtual Location Location {
128 /// Utility wrapper routine for Error, just to beautify the code
130 public void Error (int error, string s)
132 Report.Error (error, loc, s);
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess ()
140 public virtual bool GetAttributableValue (Type valueType, 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 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
243 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
244 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
245 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
249 // Constrains don't need to be checked for overrides
250 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
251 if (gm != null && (gm.ModFlags & Modifiers.OVERRIDE) != 0) {
256 ConstructedType ct = te as ConstructedType;
257 if ((ct != null) && !ct.CheckConstraints (ec))
263 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
265 int errors = Report.Errors;
267 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
270 if (!silent && errors == Report.Errors)
271 Report.Error (118, loc, "Expecting a type.");
275 if (fne.eclass != ExprClass.Type) {
276 if (!silent && errors == Report.Errors)
277 fne.Error_UnexpectedKind (null, "type", loc);
281 TypeExpr te = fne as TypeExpr;
283 if (!te.CheckAccessLevel (ec.DeclContainer)) {
284 Report.SymbolRelatedToPreviousError (te.Type);
285 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
293 public static void ErrorIsInaccesible (Location loc, string name)
295 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
298 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
300 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}';"
301 + " the qualifier must be of type `{2}' (or derived from it)",
302 TypeManager.GetFullNameSignature (m),
303 TypeManager.CSharpName (qualifier),
304 TypeManager.CSharpName (container));
308 protected void Error_CannotAssign (string to, string roContext)
310 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
314 public static void Error_VoidInvalidInTheContext (Location loc)
316 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
319 public virtual void Error_ValueCannotBeConverted (Location loc, Type target, bool expl)
321 if (Type.FullName == target.FullName){
322 Report.ExtraInformation (loc,
324 "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}",
325 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
330 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
331 GetSignatureForError (), TypeManager.CSharpName (target));
335 Expression e = (this is EnumConstant) ? ((EnumConstant)this).Child : this;
336 bool b = Convert.ExplicitNumericConversion (e, target) != null;
338 if (b || Convert.ExplicitReferenceConversionExists (Type, target) || Convert.ExplicitUnsafe (e, target) != null) {
339 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
340 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
344 if (Type != TypeManager.string_type && this is Constant && !(this is EmptyConstantCast)) {
345 Report.Error (31, loc, "Constant value `{0}' cannot be converted to a `{1}'",
346 GetSignatureForError (), TypeManager.CSharpName (target));
350 Report.Error (29, loc, "Cannot implicitly convert type {0} to `{1}'",
351 Type == TypeManager.anonymous_method_type ?
352 "anonymous method" : "`" + GetSignatureForError () + "'",
353 TypeManager.CSharpName (target));
356 protected static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
358 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
359 TypeManager.CSharpName (type), name);
362 ResolveFlags ExprClassToResolveFlags
367 case ExprClass.Namespace:
368 return ResolveFlags.Type;
370 case ExprClass.MethodGroup:
371 return ResolveFlags.MethodGroup;
373 case ExprClass.Value:
374 case ExprClass.Variable:
375 case ExprClass.PropertyAccess:
376 case ExprClass.EventAccess:
377 case ExprClass.IndexerAccess:
378 return ResolveFlags.VariableOrValue;
381 throw new Exception ("Expression " + GetType () +
382 " ExprClass is Invalid after resolve");
388 /// Resolves an expression and performs semantic analysis on it.
392 /// Currently Resolve wraps DoResolve to perform sanity
393 /// checking and assertion checking on what we expect from Resolve.
395 public Expression Resolve (EmitContext ec, ResolveFlags flags)
397 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
398 return ResolveAsTypeStep (ec, false);
400 bool do_flow_analysis = ec.DoFlowAnalysis;
401 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
402 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
403 do_flow_analysis = false;
404 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
405 omit_struct_analysis = true;
408 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
409 if (this is SimpleName) {
410 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
411 e = ((SimpleName) this).DoResolve (ec, intermediate);
420 if ((flags & e.ExprClassToResolveFlags) == 0) {
421 e.Error_UnexpectedKind (flags, loc);
425 if (e.type == null && !(e is Namespace)) {
426 throw new Exception (
427 "Expression " + e.GetType () +
428 " did not set its type after Resolve\n" +
429 "called from: " + this.GetType ());
436 /// Resolves an expression and performs semantic analysis on it.
438 public Expression Resolve (EmitContext ec)
440 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
442 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
443 ((MethodGroupExpr) e).ReportUsageError ();
449 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
451 Expression e = Resolve (ec);
455 Constant c = e as Constant;
459 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
464 /// Resolves an expression for LValue assignment
468 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
469 /// checking and assertion checking on what we expect from Resolve
471 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
473 int errors = Report.Errors;
474 bool out_access = right_side == EmptyExpression.OutAccess;
476 Expression e = DoResolveLValue (ec, right_side);
478 if (e != null && out_access && !(e is IMemoryLocation)) {
479 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
480 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
482 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
483 // e.GetType () + " " + e.GetSignatureForError ());
488 if (errors == Report.Errors) {
490 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
492 Report.Error (131, loc, "The left-hand side of an assignment or mutating operation must be a variable, property or indexer");
497 if (e.eclass == ExprClass.Invalid)
498 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
500 if (e.eclass == ExprClass.MethodGroup) {
501 ((MethodGroupExpr) e).ReportUsageError ();
505 if ((e.type == null) && !(e is ConstructedType))
506 throw new Exception ("Expression " + e + " did not set its type after Resolve");
512 /// Emits the code for the expression
516 /// The Emit method is invoked to generate the code
517 /// for the expression.
519 public abstract void Emit (EmitContext ec);
521 public virtual void EmitBranchable (EmitContext ec, Label target, bool onTrue)
524 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
528 /// Protected constructor. Only derivate types should
529 /// be able to be created
532 protected Expression ()
534 eclass = ExprClass.Invalid;
539 /// Returns a literalized version of a literal FieldInfo
543 /// The possible return values are:
544 /// IntConstant, UIntConstant
545 /// LongLiteral, ULongConstant
546 /// FloatConstant, DoubleConstant
549 /// The value returned is already resolved.
551 public static Constant Constantify (object v, Type t)
553 if (t == TypeManager.int32_type)
554 return new IntConstant ((int) v, Location.Null);
555 else if (t == TypeManager.uint32_type)
556 return new UIntConstant ((uint) v, Location.Null);
557 else if (t == TypeManager.int64_type)
558 return new LongConstant ((long) v, Location.Null);
559 else if (t == TypeManager.uint64_type)
560 return new ULongConstant ((ulong) v, Location.Null);
561 else if (t == TypeManager.float_type)
562 return new FloatConstant ((float) v, Location.Null);
563 else if (t == TypeManager.double_type)
564 return new DoubleConstant ((double) v, Location.Null);
565 else if (t == TypeManager.string_type)
566 return new StringConstant ((string) v, Location.Null);
567 else if (t == TypeManager.short_type)
568 return new ShortConstant ((short)v, Location.Null);
569 else if (t == TypeManager.ushort_type)
570 return new UShortConstant ((ushort)v, Location.Null);
571 else if (t == TypeManager.sbyte_type)
572 return new SByteConstant ((sbyte)v, Location.Null);
573 else if (t == TypeManager.byte_type)
574 return new ByteConstant ((byte)v, Location.Null);
575 else if (t == TypeManager.char_type)
576 return new CharConstant ((char)v, Location.Null);
577 else if (t == TypeManager.bool_type)
578 return new BoolConstant ((bool) v, Location.Null);
579 else if (t == TypeManager.decimal_type)
580 return new DecimalConstant ((decimal) v, Location.Null);
581 else if (TypeManager.IsEnumType (t)){
582 Type real_type = TypeManager.TypeToCoreType (v.GetType ());
584 real_type = System.Enum.GetUnderlyingType (real_type);
586 Constant e = Constantify (v, real_type);
588 return new EnumConstant (e, t);
589 } else if (v == null && !TypeManager.IsValueType (t))
590 return new NullLiteral (Location.Null);
592 throw new Exception ("Unknown type for constant (" + t +
597 /// Returns a fully formed expression after a MemberLookup
600 public static Expression ExprClassFromMemberInfo (Type containerType, MemberInfo mi, Location loc)
603 return new EventExpr ((EventInfo) mi, loc);
604 else if (mi is FieldInfo)
605 return new FieldExpr ((FieldInfo) mi, loc);
606 else if (mi is PropertyInfo)
607 return new PropertyExpr (containerType, (PropertyInfo) mi, loc);
608 else if (mi is Type){
609 return new TypeExpression ((System.Type) mi, loc);
615 protected static ArrayList almostMatchedMembers = new ArrayList (4);
618 // FIXME: Probably implement a cache for (t,name,current_access_set)?
620 // This code could use some optimizations, but we need to do some
621 // measurements. For example, we could use a delegate to `flag' when
622 // something can not any longer be a method-group (because it is something
626 // If the return value is an Array, then it is an array of
629 // If the return value is an MemberInfo, it is anything, but a Method
633 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
634 // the arguments here and have MemberLookup return only the methods that
635 // match the argument count/type, unlike we are doing now (we delay this
638 // This is so we can catch correctly attempts to invoke instance methods
639 // from a static body (scan for error 120 in ResolveSimpleName).
642 // FIXME: Potential optimization, have a static ArrayList
645 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
646 MemberTypes mt, BindingFlags bf, Location loc)
648 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
652 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
653 // `qualifier_type' or null to lookup members in the current class.
656 public static Expression MemberLookup (Type container_type,
657 Type qualifier_type, Type queried_type,
658 string name, MemberTypes mt,
659 BindingFlags bf, Location loc)
661 almostMatchedMembers.Clear ();
663 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
664 queried_type, mt, bf, name, almostMatchedMembers);
670 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
671 MemberInfo non_method = null;
672 ArrayList methods = new ArrayList (2);
674 foreach (MemberInfo m in mi) {
675 if (m is MethodBase) {
680 if (non_method == null) {
685 Report.SymbolRelatedToPreviousError (m);
686 Report.SymbolRelatedToPreviousError (non_method);
687 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
688 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (non_method));
692 if (methods.Count == 0)
695 if (non_method != null) {
696 MethodBase method = (MethodBase) methods [0];
698 if (method.DeclaringType == non_method.DeclaringType) {
699 // Cannot happen with C# code, but is valid in IL
700 Report.SymbolRelatedToPreviousError (method);
701 Report.SymbolRelatedToPreviousError (non_method);
702 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
703 TypeManager.GetFullNameSignature (non_method),
704 TypeManager.CSharpSignature (method));
709 Report.SymbolRelatedToPreviousError (method);
710 Report.SymbolRelatedToPreviousError (non_method);
711 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
712 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
716 return new MethodGroupExpr (methods, loc);
719 if (mi [0] is MethodBase)
720 return new MethodGroupExpr (mi, loc);
722 return ExprClassFromMemberInfo (container_type, mi [0], loc);
725 public const MemberTypes AllMemberTypes =
726 MemberTypes.Constructor |
730 MemberTypes.NestedType |
731 MemberTypes.Property;
733 public const BindingFlags AllBindingFlags =
734 BindingFlags.Public |
735 BindingFlags.Static |
736 BindingFlags.Instance;
738 public static Expression MemberLookup (Type container_type, Type queried_type,
739 string name, Location loc)
741 return MemberLookup (container_type, null, queried_type, name,
742 AllMemberTypes, AllBindingFlags, loc);
745 public static Expression MemberLookup (Type container_type, Type qualifier_type,
746 Type queried_type, string name, Location loc)
748 return MemberLookup (container_type, qualifier_type, queried_type,
749 name, AllMemberTypes, AllBindingFlags, loc);
752 public static Expression MethodLookup (EmitContext ec, Type queried_type,
753 string name, Location loc)
755 return MemberLookup (ec.ContainerType, null, queried_type, name,
756 MemberTypes.Method, AllBindingFlags, loc);
760 /// This is a wrapper for MemberLookup that is not used to "probe", but
761 /// to find a final definition. If the final definition is not found, we
762 /// look for private members and display a useful debugging message if we
765 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
766 Type queried_type, string name, Location loc)
768 return MemberLookupFinal (ec, qualifier_type, queried_type, name,
769 AllMemberTypes, AllBindingFlags, loc);
772 public static Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
773 Type queried_type, string name,
774 MemberTypes mt, BindingFlags bf,
779 int errors = Report.Errors;
781 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
783 if (e == null && errors == Report.Errors)
784 // No errors were reported by MemberLookup, but there was an error.
785 MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type, name, null, true, loc);
790 public static void MemberLookupFailed (Type container_type, Type qualifier_type,
791 Type queried_type, string name,
792 string class_name, bool complain_if_none_found,
795 if (almostMatchedMembers.Count != 0) {
796 for (int i = 0; i < almostMatchedMembers.Count; ++i) {
797 MemberInfo m = (MemberInfo) almostMatchedMembers [i];
798 for (int j = 0; j < i; ++j) {
799 if (m == almostMatchedMembers [j]) {
807 Type declaring_type = m.DeclaringType;
809 Report.SymbolRelatedToPreviousError (m);
810 if (qualifier_type == null) {
811 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
812 TypeManager.CSharpName (m.DeclaringType),
813 TypeManager.CSharpName (container_type));
815 } else if (qualifier_type != container_type &&
816 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
817 // Although a derived class can access protected members of
818 // its base class it cannot do so through an instance of the
819 // base class (CS1540). If the qualifier_type is a base of the
820 // ec.ContainerType and the lookup succeeds with the latter one,
821 // then we are in this situation.
822 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
824 Report.SymbolRelatedToPreviousError (m);
825 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
828 almostMatchedMembers.Clear ();
832 MemberInfo[] lookup = null;
833 if (queried_type == null) {
834 class_name = "global::";
836 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
837 AllMemberTypes, AllBindingFlags |
838 BindingFlags.NonPublic, name, null);
841 if (lookup == null) {
842 if (!complain_if_none_found)
845 if (class_name != null)
846 Report.Error (103, loc, "The name `{0}' does not exist in the context of `{1}'",
849 Error_TypeDoesNotContainDefinition (loc, queried_type, name);
853 if (TypeManager.MemberLookup (queried_type, null, queried_type,
854 AllMemberTypes, AllBindingFlags |
855 BindingFlags.NonPublic, name, null) == null) {
856 if ((lookup.Length == 1) && (lookup [0] is Type)) {
857 Type t = (Type) lookup [0];
859 Report.Error (305, loc,
860 "Using the generic type `{0}' " +
861 "requires {1} type arguments",
862 TypeManager.CSharpName (t),
863 TypeManager.GetNumberOfTypeArguments (t).ToString ());
868 MemberList ml = TypeManager.FindMembers (queried_type, MemberTypes.Constructor,
869 BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly, null, null);
870 if (name == ".ctor" && ml.Count == 0)
872 Report.Error (143, loc, "The type `{0}' has no constructors defined", TypeManager.CSharpName (queried_type));
876 Report.SymbolRelatedToPreviousError (lookup [0]);
877 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
881 /// Returns an expression that can be used to invoke operator true
882 /// on the expression if it exists.
884 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
886 return GetOperatorTrueOrFalse (ec, e, true, loc);
890 /// Returns an expression that can be used to invoke operator false
891 /// on the expression if it exists.
893 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
895 return GetOperatorTrueOrFalse (ec, e, false, loc);
898 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
901 Expression operator_group;
904 if (TypeManager.IsNullableType (e.Type))
905 return new Nullable.OperatorTrueOrFalse (e, is_true, loc).Resolve (ec);
908 operator_group = MethodLookup (ec, e.Type, is_true ? "op_True" : "op_False", loc);
909 if (operator_group == null)
912 ArrayList arguments = new ArrayList ();
913 arguments.Add (new Argument (e, Argument.AType.Expression));
914 method = Invocation.OverloadResolve (
915 ec, (MethodGroupExpr) operator_group, arguments, false, loc);
920 return new StaticCallExpr ((MethodInfo) method, arguments, loc);
924 /// Resolves the expression `e' into a boolean expression: either through
925 /// an implicit conversion, or through an `operator true' invocation
927 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
933 if (e.Type == TypeManager.bool_type)
936 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
938 if (converted != null)
942 // If no implicit conversion to bool exists, try using `operator true'
944 converted = Expression.GetOperatorTrue (ec, e, loc);
945 if (converted == null){
946 e.Error_ValueCannotBeConverted (loc, TypeManager.bool_type, false);
952 public virtual string ExprClassName
956 case ExprClass.Invalid:
958 case ExprClass.Value:
960 case ExprClass.Variable:
962 case ExprClass.Namespace:
966 case ExprClass.MethodGroup:
967 return "method group";
968 case ExprClass.PropertyAccess:
969 return "property access";
970 case ExprClass.EventAccess:
971 return "event access";
972 case ExprClass.IndexerAccess:
973 return "indexer access";
974 case ExprClass.Nothing:
977 throw new Exception ("Should not happen");
982 /// Reports that we were expecting `expr' to be of class `expected'
984 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
986 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
989 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
991 string name = GetSignatureForError ();
993 name = ds.GetSignatureForError () + '.' + name;
995 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
996 name, was, expected);
999 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1001 string [] valid = new string [4];
1004 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1005 valid [count++] = "variable";
1006 valid [count++] = "value";
1009 if ((flags & ResolveFlags.Type) != 0)
1010 valid [count++] = "type";
1012 if ((flags & ResolveFlags.MethodGroup) != 0)
1013 valid [count++] = "method group";
1016 valid [count++] = "unknown";
1018 StringBuilder sb = new StringBuilder (valid [0]);
1019 for (int i = 1; i < count - 1; i++) {
1021 sb.Append (valid [i]);
1024 sb.Append ("' or `");
1025 sb.Append (valid [count - 1]);
1028 Report.Error (119, loc,
1029 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1032 public static void UnsafeError (Location loc)
1034 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1038 // Load the object from the pointer.
1040 public static void LoadFromPtr (ILGenerator ig, Type t)
1042 if (t == TypeManager.int32_type)
1043 ig.Emit (OpCodes.Ldind_I4);
1044 else if (t == TypeManager.uint32_type)
1045 ig.Emit (OpCodes.Ldind_U4);
1046 else if (t == TypeManager.short_type)
1047 ig.Emit (OpCodes.Ldind_I2);
1048 else if (t == TypeManager.ushort_type)
1049 ig.Emit (OpCodes.Ldind_U2);
1050 else if (t == TypeManager.char_type)
1051 ig.Emit (OpCodes.Ldind_U2);
1052 else if (t == TypeManager.byte_type)
1053 ig.Emit (OpCodes.Ldind_U1);
1054 else if (t == TypeManager.sbyte_type)
1055 ig.Emit (OpCodes.Ldind_I1);
1056 else if (t == TypeManager.uint64_type)
1057 ig.Emit (OpCodes.Ldind_I8);
1058 else if (t == TypeManager.int64_type)
1059 ig.Emit (OpCodes.Ldind_I8);
1060 else if (t == TypeManager.float_type)
1061 ig.Emit (OpCodes.Ldind_R4);
1062 else if (t == TypeManager.double_type)
1063 ig.Emit (OpCodes.Ldind_R8);
1064 else if (t == TypeManager.bool_type)
1065 ig.Emit (OpCodes.Ldind_I1);
1066 else if (t == TypeManager.intptr_type)
1067 ig.Emit (OpCodes.Ldind_I);
1068 else if (TypeManager.IsEnumType (t)) {
1069 if (t == TypeManager.enum_type)
1070 ig.Emit (OpCodes.Ldind_Ref);
1072 LoadFromPtr (ig, TypeManager.EnumToUnderlying (t));
1073 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1074 ig.Emit (OpCodes.Ldobj, t);
1075 else if (t.IsPointer)
1076 ig.Emit (OpCodes.Ldind_I);
1078 ig.Emit (OpCodes.Ldind_Ref);
1082 // The stack contains the pointer and the value of type `type'
1084 public static void StoreFromPtr (ILGenerator ig, Type type)
1086 if (TypeManager.IsEnumType (type))
1087 type = TypeManager.EnumToUnderlying (type);
1088 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1089 ig.Emit (OpCodes.Stind_I4);
1090 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1091 ig.Emit (OpCodes.Stind_I8);
1092 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1093 type == TypeManager.ushort_type)
1094 ig.Emit (OpCodes.Stind_I2);
1095 else if (type == TypeManager.float_type)
1096 ig.Emit (OpCodes.Stind_R4);
1097 else if (type == TypeManager.double_type)
1098 ig.Emit (OpCodes.Stind_R8);
1099 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1100 type == TypeManager.bool_type)
1101 ig.Emit (OpCodes.Stind_I1);
1102 else if (type == TypeManager.intptr_type)
1103 ig.Emit (OpCodes.Stind_I);
1104 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1105 ig.Emit (OpCodes.Stobj, type);
1107 ig.Emit (OpCodes.Stind_Ref);
1111 // Returns the size of type `t' if known, otherwise, 0
1113 public static int GetTypeSize (Type t)
1115 t = TypeManager.TypeToCoreType (t);
1116 if (t == TypeManager.int32_type ||
1117 t == TypeManager.uint32_type ||
1118 t == TypeManager.float_type)
1120 else if (t == TypeManager.int64_type ||
1121 t == TypeManager.uint64_type ||
1122 t == TypeManager.double_type)
1124 else if (t == TypeManager.byte_type ||
1125 t == TypeManager.sbyte_type ||
1126 t == TypeManager.bool_type)
1128 else if (t == TypeManager.short_type ||
1129 t == TypeManager.char_type ||
1130 t == TypeManager.ushort_type)
1132 else if (t == TypeManager.decimal_type)
1138 public static void Error_NegativeArrayIndex (Location loc)
1140 Report.Error (248, loc, "Cannot create an array with a negative size");
1143 protected void Error_CannotCallAbstractBase (string name)
1145 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1149 // Converts `source' to an int, uint, long or ulong.
1151 public Expression ExpressionToArrayArgument (EmitContext ec, Expression source, Location loc)
1155 using (ec.With (EmitContext.Flags.CheckState, true)) {
1156 target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
1158 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
1160 target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
1162 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
1164 if (target == null) {
1165 source.Error_ValueCannotBeConverted (loc, TypeManager.int32_type, false);
1171 // Only positive constants are allowed at compile time
1173 if (target is Constant){
1174 if (target is IntConstant){
1175 if (((IntConstant) target).Value < 0){
1176 Error_NegativeArrayIndex (loc);
1181 if (target is LongConstant){
1182 if (((LongConstant) target).Value < 0){
1183 Error_NegativeArrayIndex (loc);
1196 /// This is just a base class for expressions that can
1197 /// appear on statements (invocations, object creation,
1198 /// assignments, post/pre increment and decrement). The idea
1199 /// being that they would support an extra Emition interface that
1200 /// does not leave a result on the stack.
1202 public abstract class ExpressionStatement : Expression {
1204 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1206 Expression e = Resolve (ec);
1210 ExpressionStatement es = e as ExpressionStatement;
1212 Error (201, "Only assignment, call, increment, decrement and new object " +
1213 "expressions can be used as a statement");
1219 /// Requests the expression to be emitted in a `statement'
1220 /// context. This means that no new value is left on the
1221 /// stack after invoking this method (constrasted with
1222 /// Emit that will always leave a value on the stack).
1224 public abstract void EmitStatement (EmitContext ec);
1228 /// This kind of cast is used to encapsulate the child
1229 /// whose type is child.Type into an expression that is
1230 /// reported to return "return_type". This is used to encapsulate
1231 /// expressions which have compatible types, but need to be dealt
1232 /// at higher levels with.
1234 /// For example, a "byte" expression could be encapsulated in one
1235 /// of these as an "unsigned int". The type for the expression
1236 /// would be "unsigned int".
1239 public class EmptyCast : Expression {
1240 protected readonly Expression child;
1242 public EmptyCast (Expression child, Type return_type)
1244 eclass = child.eclass;
1245 loc = child.Location;
1250 public override Expression DoResolve (EmitContext ec)
1252 // This should never be invoked, we are born in fully
1253 // initialized state.
1258 public override void Emit (EmitContext ec)
1263 public override bool GetAttributableValue (Type valueType, out object value)
1265 return child.GetAttributableValue (valueType, out value);
1270 /// This is a numeric cast to a Decimal
1272 public class CastToDecimal : EmptyCast {
1274 MethodInfo conversion_operator;
1276 public CastToDecimal (Expression child)
1277 : this (child, false)
1281 public CastToDecimal (Expression child, bool find_explicit)
1282 : base (child, TypeManager.decimal_type)
1284 conversion_operator = GetConversionOperator (find_explicit);
1286 if (conversion_operator == null)
1287 throw new InternalErrorException ("Outer conversion routine is out of sync");
1290 // Returns the implicit operator that converts from
1291 // 'child.Type' to System.Decimal.
1292 MethodInfo GetConversionOperator (bool find_explicit)
1294 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1296 MemberInfo [] mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1297 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1299 foreach (MethodInfo oper in mi) {
1300 ParameterData pd = TypeManager.GetParameterData (oper);
1302 if (pd.ParameterType (0) == child.Type && oper.ReturnType == type)
1308 public override void Emit (EmitContext ec)
1310 ILGenerator ig = ec.ig;
1313 ig.Emit (OpCodes.Call, conversion_operator);
1318 /// This is an explicit numeric cast from a Decimal
1320 public class CastFromDecimal : EmptyCast
1322 static IDictionary operators;
1324 public CastFromDecimal (Expression child, Type return_type)
1325 : base (child, return_type)
1327 if (child.Type != TypeManager.decimal_type)
1328 throw new InternalErrorException (
1329 "The expected type is Decimal, instead it is " + child.Type.FullName);
1332 // Returns the explicit operator that converts from an
1333 // express of type System.Decimal to 'type'.
1334 public Expression Resolve ()
1336 if (operators == null) {
1337 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1338 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1339 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1341 operators = new System.Collections.Specialized.HybridDictionary ();
1342 foreach (MethodInfo oper in all_oper) {
1343 ParameterData pd = TypeManager.GetParameterData (oper);
1344 if (pd.ParameterType (0) == TypeManager.decimal_type)
1345 operators.Add (oper.ReturnType, oper);
1349 return operators.Contains (type) ? this : null;
1352 public override void Emit (EmitContext ec)
1354 ILGenerator ig = ec.ig;
1357 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1362 // Constant specialization of EmptyCast.
1363 // We need to special case this since an empty cast of
1364 // a constant is still a constant.
1366 public class EmptyConstantCast : Constant
1368 public readonly Constant child;
1370 public EmptyConstantCast(Constant child, Type type)
1371 : base (child.Location)
1373 eclass = child.eclass;
1378 public override string AsString ()
1380 return child.AsString ();
1383 public override object GetValue ()
1385 return child.GetValue ();
1388 public override Constant Reduce (bool inCheckedContext, Type target_type)
1390 return child.Reduce (inCheckedContext, target_type);
1393 public override Constant Increment ()
1395 return child.Increment ();
1398 public override bool IsDefaultValue
1400 get { return child.IsDefaultValue; }
1403 public override bool IsNegative
1405 get { return child.IsNegative; }
1408 public override void Emit (EmitContext ec)
1413 public override Constant ToType (Type type)
1415 return child.ToType (type);
1421 /// This class is used to wrap literals which belong inside Enums
1423 public class EnumConstant : Constant {
1424 public Constant Child;
1426 public EnumConstant (Constant child, Type enum_type):
1427 base (child.Location)
1429 eclass = child.eclass;
1434 public override Expression DoResolve (EmitContext ec)
1436 // This should never be invoked, we are born in fully
1437 // initialized state.
1442 public override void Emit (EmitContext ec)
1447 public override bool GetAttributableValue (Type valueType, out object value)
1449 value = GetTypedValue ();
1453 public override string GetSignatureForError()
1455 return TypeManager.CSharpName (Type);
1458 public override object GetValue ()
1460 return Child.GetValue ();
1463 public override object GetTypedValue ()
1465 // FIXME: runtime is not ready to work with just emited enums
1466 if (!RootContext.StdLib) {
1467 return Child.GetValue ();
1470 return System.Enum.ToObject (type, Child.GetValue ());
1473 public override string AsString ()
1475 return Child.AsString ();
1478 public override DoubleConstant ConvertToDouble ()
1480 return Child.ConvertToDouble ();
1483 public override FloatConstant ConvertToFloat ()
1485 return Child.ConvertToFloat ();
1488 public override ULongConstant ConvertToULong ()
1490 return Child.ConvertToULong ();
1493 public override LongConstant ConvertToLong ()
1495 return Child.ConvertToLong ();
1498 public override UIntConstant ConvertToUInt ()
1500 return Child.ConvertToUInt ();
1503 public override IntConstant ConvertToInt ()
1505 return Child.ConvertToInt ();
1508 public override Constant Increment()
1510 return new EnumConstant (Child.Increment (), type);
1513 public override bool IsDefaultValue {
1515 return Child.IsDefaultValue;
1519 public override bool IsZeroInteger {
1520 get { return Child.IsZeroInteger; }
1523 public override bool IsNegative {
1525 return Child.IsNegative;
1529 public override Constant Reduce(bool inCheckedContext, Type target_type)
1531 if (Child.Type == target_type)
1534 return Child.Reduce (inCheckedContext, target_type);
1537 public override Constant ToType (Type type)
1540 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1541 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1544 if (type.UnderlyingSystemType != Child.Type)
1545 Child = Child.ToType (type.UnderlyingSystemType);
1549 if (!Convert.ImplicitStandardConversionExists (this, type)){
1553 return Child.ToType (type);
1559 /// This kind of cast is used to encapsulate Value Types in objects.
1561 /// The effect of it is to box the value type emitted by the previous
1564 public class BoxedCast : EmptyCast {
1566 public BoxedCast (Expression expr, Type target_type)
1567 : base (expr, target_type)
1569 eclass = ExprClass.Value;
1572 public override Expression DoResolve (EmitContext ec)
1574 // This should never be invoked, we are born in fully
1575 // initialized state.
1580 public override void Emit (EmitContext ec)
1584 ec.ig.Emit (OpCodes.Box, child.Type);
1588 public class UnboxCast : EmptyCast {
1589 public UnboxCast (Expression expr, Type return_type)
1590 : base (expr, return_type)
1594 public override Expression DoResolve (EmitContext ec)
1596 // This should never be invoked, we are born in fully
1597 // initialized state.
1602 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1604 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1605 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1606 return base.DoResolveLValue (ec, right_side);
1609 public override void Emit (EmitContext ec)
1612 ILGenerator ig = ec.ig;
1616 if (t.IsGenericParameter || t.IsGenericType && t.IsValueType)
1617 ig.Emit (OpCodes.Unbox_Any, t);
1621 ig.Emit (OpCodes.Unbox, t);
1623 LoadFromPtr (ig, t);
1629 /// This is used to perform explicit numeric conversions.
1631 /// Explicit numeric conversions might trigger exceptions in a checked
1632 /// context, so they should generate the conv.ovf opcodes instead of
1635 public class ConvCast : EmptyCast {
1636 public enum Mode : byte {
1637 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1639 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1640 U2_I1, U2_U1, U2_I2, U2_CH,
1641 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1642 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1643 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1644 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1645 CH_I1, CH_U1, CH_I2,
1646 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1647 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1652 public ConvCast (Expression child, Type return_type, Mode m)
1653 : base (child, return_type)
1658 public override Expression DoResolve (EmitContext ec)
1660 // This should never be invoked, we are born in fully
1661 // initialized state.
1666 public override string ToString ()
1668 return String.Format ("ConvCast ({0}, {1})", mode, child);
1671 public override void Emit (EmitContext ec)
1673 ILGenerator ig = ec.ig;
1679 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1680 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1681 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1682 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1683 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1685 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1686 case Mode.U1_CH: /* nothing */ break;
1688 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1689 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1690 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1691 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1692 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1693 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1695 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1696 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1697 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1698 case Mode.U2_CH: /* nothing */ break;
1700 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1701 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1702 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1703 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1704 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1705 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1706 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1708 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1709 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1710 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1711 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1712 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1713 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1715 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1716 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1717 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1718 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1719 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1720 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1721 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1722 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1724 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1725 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1726 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1727 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1728 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1729 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1730 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1731 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1733 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1734 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1735 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1737 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1738 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1739 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1740 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1741 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1742 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1743 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1744 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1745 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1747 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1748 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1749 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1750 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1751 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1752 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1753 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1754 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1755 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1756 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1760 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1761 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1762 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1763 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1764 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1766 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1767 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
1769 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
1770 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
1771 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
1772 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
1773 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
1774 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
1776 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
1777 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
1778 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
1779 case Mode.U2_CH: /* nothing */ break;
1781 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
1782 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
1783 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
1784 case Mode.I4_U4: /* nothing */ break;
1785 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
1786 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
1787 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
1789 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
1790 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
1791 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
1792 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
1793 case Mode.U4_I4: /* nothing */ break;
1794 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
1796 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
1797 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
1798 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
1799 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
1800 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
1801 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
1802 case Mode.I8_U8: /* nothing */ break;
1803 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
1805 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
1806 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
1807 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
1808 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
1809 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
1810 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
1811 case Mode.U8_I8: /* nothing */ break;
1812 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
1814 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
1815 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
1816 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
1818 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
1819 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
1820 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
1821 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
1822 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
1823 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
1824 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
1825 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
1826 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
1828 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
1829 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
1830 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
1831 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
1832 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
1833 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
1834 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
1835 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
1836 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
1837 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1843 public class OpcodeCast : EmptyCast {
1847 public OpcodeCast (Expression child, Type return_type, OpCode op)
1848 : base (child, return_type)
1852 second_valid = false;
1855 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1856 : base (child, return_type)
1861 second_valid = true;
1864 public override Expression DoResolve (EmitContext ec)
1866 // This should never be invoked, we are born in fully
1867 // initialized state.
1872 public override void Emit (EmitContext ec)
1883 /// This kind of cast is used to encapsulate a child and cast it
1884 /// to the class requested
1886 public class ClassCast : EmptyCast {
1887 public ClassCast (Expression child, Type return_type)
1888 : base (child, return_type)
1893 public override Expression DoResolve (EmitContext ec)
1895 // This should never be invoked, we are born in fully
1896 // initialized state.
1901 public override void Emit (EmitContext ec)
1905 if (TypeManager.IsGenericParameter (child.Type))
1906 ec.ig.Emit (OpCodes.Box, child.Type);
1909 if (type.IsGenericParameter)
1910 ec.ig.Emit (OpCodes.Unbox_Any, type);
1913 ec.ig.Emit (OpCodes.Castclass, type);
1918 /// SimpleName expressions are formed of a single word and only happen at the beginning
1919 /// of a dotted-name.
1921 public class SimpleName : Expression {
1923 public readonly TypeArguments Arguments;
1926 public SimpleName (string name, Location l)
1932 public SimpleName (string name, TypeArguments args, Location l)
1939 public SimpleName (string name, TypeParameter[] type_params, Location l)
1944 Arguments = new TypeArguments (l);
1945 foreach (TypeParameter type_param in type_params)
1946 Arguments.Add (new TypeParameterExpr (type_param, l));
1949 public static string RemoveGenericArity (string name)
1952 StringBuilder sb = new StringBuilder ();
1953 while (start < name.Length) {
1954 int pos = name.IndexOf ('`', start);
1956 sb.Append (name.Substring (start));
1960 sb.Append (name.Substring (start, pos-start));
1963 while ((pos < name.Length) && Char.IsNumber (name [pos]))
1969 return sb.ToString ();
1972 public SimpleName GetMethodGroup ()
1974 return new SimpleName (RemoveGenericArity (Name), Arguments, loc);
1977 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
1979 if (ec.IsFieldInitializer)
1980 Report.Error (236, l,
1981 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
1985 120, l, "`{0}': An object reference is required for the nonstatic field, method or property",
1989 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
1991 return resolved_to != null && resolved_to.Type != null &&
1992 resolved_to.Type.Name == Name &&
1993 (ec.DeclContainer.LookupType (Name, loc, /* ignore_cs0104 = */ true) != null);
1996 public override Expression DoResolve (EmitContext ec)
1998 return SimpleNameResolve (ec, null, false);
2001 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2003 return SimpleNameResolve (ec, right_side, false);
2007 public Expression DoResolve (EmitContext ec, bool intermediate)
2009 return SimpleNameResolve (ec, null, intermediate);
2012 private bool IsNestedChild (Type t, Type parent)
2017 while (parent != null) {
2018 parent = TypeManager.DropGenericTypeArguments (parent);
2019 if (TypeManager.IsNestedChildOf (t, parent))
2022 parent = parent.BaseType;
2028 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2030 if (!TypeManager.IsGenericTypeDefinition (t))
2033 DeclSpace ds = ec.DeclContainer;
2034 while (ds != null) {
2035 if (IsNestedChild (t, ds.TypeBuilder))
2044 Type[] gen_params = TypeManager.GetTypeArguments (t);
2046 int arg_count = Arguments != null ? Arguments.Count : 0;
2048 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2049 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2050 TypeArguments new_args = new TypeArguments (loc);
2051 foreach (TypeParameter param in ds.TypeParameters)
2052 new_args.Add (new TypeParameterExpr (param, loc));
2054 if (Arguments != null)
2055 new_args.Add (Arguments);
2057 return new ConstructedType (t, new_args, loc);
2064 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2066 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2068 return fne.ResolveAsTypeStep (ec, silent);
2070 int errors = Report.Errors;
2071 fne = ec.DeclContainer.LookupType (Name, loc, /*ignore_cs0104=*/ false);
2074 if (fne.Type == null)
2077 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2079 return nested.ResolveAsTypeStep (ec, false);
2081 if (Arguments != null) {
2082 ConstructedType ct = new ConstructedType (fne, Arguments, loc);
2083 return ct.ResolveAsTypeStep (ec, false);
2089 if (silent || errors != Report.Errors)
2092 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2094 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2098 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2099 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2100 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2101 Type type = a.GetType (fullname);
2103 Report.SymbolRelatedToPreviousError (type);
2104 Expression.ErrorIsInaccesible (loc, fullname);
2109 Type t = ec.DeclContainer.NamespaceEntry.NS.LookForAnyGenericType (Name);
2111 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2115 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2119 // TODO: I am still not convinced about this. If someone else will need it
2120 // implement this as virtual property in MemberCore hierarchy
2121 string GetMemberType (MemberCore mc)
2123 if (mc is PropertyBase)
2127 if (mc is FieldBase)
2129 if (mc is MethodCore)
2131 if (mc is EnumMember)
2137 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2143 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2147 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2154 /// 7.5.2: Simple Names.
2156 /// Local Variables and Parameters are handled at
2157 /// parse time, so they never occur as SimpleNames.
2159 /// The `intermediate' flag is used by MemberAccess only
2160 /// and it is used to inform us that it is ok for us to
2161 /// avoid the static check, because MemberAccess might end
2162 /// up resolving the Name as a Type name and the access as
2163 /// a static type access.
2165 /// ie: Type Type; .... { Type.GetType (""); }
2167 /// Type is both an instance variable and a Type; Type.GetType
2168 /// is the static method not an instance method of type.
2170 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2172 Expression e = null;
2175 // Stage 1: Performed by the parser (binding to locals or parameters).
2177 Block current_block = ec.CurrentBlock;
2178 if (current_block != null){
2179 LocalInfo vi = current_block.GetLocalInfo (Name);
2181 if (Arguments != null) {
2182 Report.Error (307, loc,
2183 "The variable `{0}' cannot be used with type arguments",
2188 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2189 if (right_side != null) {
2190 return var.ResolveLValue (ec, right_side, loc);
2192 ResolveFlags rf = ResolveFlags.VariableOrValue;
2194 rf |= ResolveFlags.DisableFlowAnalysis;
2195 return var.Resolve (ec, rf);
2199 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2201 if (Arguments != null) {
2202 Report.Error (307, loc,
2203 "The variable `{0}' cannot be used with type arguments",
2208 if (right_side != null)
2209 return pref.ResolveLValue (ec, right_side, loc);
2211 return pref.Resolve (ec);
2216 // Stage 2: Lookup members
2219 DeclSpace lookup_ds = ec.DeclContainer;
2220 Type almost_matched_type = null;
2221 ArrayList almost_matched = null;
2223 if (lookup_ds.TypeBuilder == null)
2226 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2230 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2231 almost_matched_type = lookup_ds.TypeBuilder;
2232 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2235 lookup_ds =lookup_ds.Parent;
2236 } while (lookup_ds != null);
2238 if (e == null && ec.ContainerType != null)
2239 e = MemberLookup (ec.ContainerType, ec.ContainerType, Name, loc);
2242 if (almost_matched == null && almostMatchedMembers.Count > 0) {
2243 almost_matched_type = ec.ContainerType;
2244 almost_matched = (ArrayList) almostMatchedMembers.Clone ();
2246 e = ResolveAsTypeStep (ec, true);
2250 if (almost_matched != null)
2251 almostMatchedMembers = almost_matched;
2252 if (almost_matched_type == null)
2253 almost_matched_type = ec.ContainerType;
2254 MemberLookupFailed (ec.ContainerType, null, almost_matched_type, ((SimpleName) this).Name, ec.DeclContainer.Name, true, loc);
2258 if (e is TypeExpr) {
2259 if (Arguments == null)
2262 ConstructedType ct = new ConstructedType (
2263 (FullNamedExpression) e, Arguments, loc);
2264 return ct.ResolveAsTypeStep (ec, false);
2267 if (e is MemberExpr) {
2268 MemberExpr me = (MemberExpr) e;
2271 if (me.IsInstance) {
2272 if (ec.IsStatic || ec.IsFieldInitializer) {
2274 // Note that an MemberExpr can be both IsInstance and IsStatic.
2275 // An unresolved MethodGroupExpr can contain both kinds of methods
2276 // and each predicate is true if the MethodGroupExpr contains
2277 // at least one of that kind of method.
2281 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2282 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2283 return EmptyExpression.Null;
2287 // Pass the buck to MemberAccess and Invocation.
2289 left = EmptyExpression.Null;
2291 left = ec.GetThis (loc);
2294 left = new TypeExpression (ec.ContainerType, loc);
2297 e = me.ResolveMemberAccess (ec, left, loc, null);
2301 me = e as MemberExpr;
2305 if (Arguments != null) {
2306 MethodGroupExpr mg = me as MethodGroupExpr;
2310 return mg.ResolveGeneric (ec, Arguments);
2313 if (!me.IsStatic && (me.InstanceExpression != null) &&
2314 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2315 me.InstanceExpression.Type != me.DeclaringType &&
2316 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2317 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2318 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2319 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2323 return (right_side != null)
2324 ? me.DoResolveLValue (ec, right_side)
2325 : me.DoResolve (ec);
2331 public override void Emit (EmitContext ec)
2334 // If this is ever reached, then we failed to
2335 // find the name as a namespace
2338 Error (103, "The name `" + Name +
2339 "' does not exist in the class `" +
2340 ec.DeclContainer.Name + "'");
2343 public override string ToString ()
2348 public override string GetSignatureForError ()
2355 /// Represents a namespace or a type. The name of the class was inspired by
2356 /// section 10.8.1 (Fully Qualified Names).
2358 public abstract class FullNamedExpression : Expression {
2359 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2364 public abstract string FullName {
2370 /// Expression that evaluates to a type
2372 public abstract class TypeExpr : FullNamedExpression {
2373 override public FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2375 TypeExpr t = DoResolveAsTypeStep (ec);
2379 eclass = ExprClass.Type;
2383 override public Expression DoResolve (EmitContext ec)
2385 return ResolveAsTypeTerminal (ec, false);
2388 override public void Emit (EmitContext ec)
2390 throw new Exception ("Should never be called");
2393 public virtual bool CheckAccessLevel (DeclSpace ds)
2395 return ds.CheckAccessLevel (Type);
2398 public virtual bool AsAccessible (DeclSpace ds, int flags)
2400 return ds.AsAccessible (Type, flags);
2403 public virtual bool IsClass {
2404 get { return Type.IsClass; }
2407 public virtual bool IsValueType {
2408 get { return Type.IsValueType; }
2411 public virtual bool IsInterface {
2412 get { return Type.IsInterface; }
2415 public virtual bool IsSealed {
2416 get { return Type.IsSealed; }
2419 public virtual bool CanInheritFrom ()
2421 if (Type == TypeManager.enum_type ||
2422 (Type == TypeManager.value_type && RootContext.StdLib) ||
2423 Type == TypeManager.multicast_delegate_type ||
2424 Type == TypeManager.delegate_type ||
2425 Type == TypeManager.array_type)
2431 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2433 public abstract string Name {
2437 public override bool Equals (object obj)
2439 TypeExpr tobj = obj as TypeExpr;
2443 return Type == tobj.Type;
2446 public override int GetHashCode ()
2448 return Type.GetHashCode ();
2451 public override string ToString ()
2458 /// Fully resolved Expression that already evaluated to a type
2460 public class TypeExpression : TypeExpr {
2461 public TypeExpression (Type t, Location l)
2464 eclass = ExprClass.Type;
2468 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2473 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2478 public override string Name {
2479 get { return Type.ToString (); }
2482 public override string FullName {
2483 get { return Type.FullName; }
2488 /// Used to create types from a fully qualified name. These are just used
2489 /// by the parser to setup the core types. A TypeLookupExpression is always
2490 /// classified as a type.
2492 public sealed class TypeLookupExpression : TypeExpr {
2493 readonly string name;
2495 public TypeLookupExpression (string name)
2498 eclass = ExprClass.Type;
2501 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2503 // It's null for corlib compilation only
2505 return DoResolveAsTypeStep (ec);
2510 static readonly char [] dot_array = { '.' };
2511 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2513 // If name is of the form `N.I', first lookup `N', then search a member `I' in it.
2515 string lookup_name = name;
2516 int pos = name.IndexOf ('.');
2518 rest = name.Substring (pos + 1);
2519 lookup_name = name.Substring (0, pos);
2522 FullNamedExpression resolved = RootNamespace.Global.Lookup (ec.DeclContainer, lookup_name, Location.Null);
2524 if (resolved != null && rest != null) {
2525 // Now handle the rest of the the name.
2526 string [] elements = rest.Split (dot_array);
2528 int count = elements.Length;
2530 while (i < count && resolved != null && resolved is Namespace) {
2531 Namespace ns = resolved as Namespace;
2532 element = elements [i++];
2533 lookup_name += "." + element;
2534 resolved = ns.Lookup (ec.DeclContainer, element, Location.Null);
2537 if (resolved != null && resolved is TypeExpr) {
2538 Type t = ((TypeExpr) resolved).Type;
2540 if (!ec.DeclContainer.CheckAccessLevel (t)) {
2542 lookup_name = t.FullName;
2549 t = TypeManager.GetNestedType (t, elements [i++]);
2554 if (resolved == null) {
2555 NamespaceEntry.Error_NamespaceNotFound (loc, lookup_name);
2559 if (!(resolved is TypeExpr)) {
2560 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
2564 type = resolved.Type;
2568 public override string Name {
2569 get { return name; }
2572 public override string FullName {
2573 get { return name; }
2578 /// Represents an "unbound generic type", ie. typeof (Foo<>).
2581 public class UnboundTypeExpression : TypeExpr
2585 public UnboundTypeExpression (MemberName name, Location l)
2591 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2594 if (name.Left != null) {
2595 Expression lexpr = name.Left.GetTypeExpression ();
2596 expr = new MemberAccess (lexpr, name.Basename);
2598 expr = new SimpleName (name.Basename, loc);
2601 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
2606 return new TypeExpression (type, loc);
2609 public override string Name {
2610 get { return name.FullName; }
2613 public override string FullName {
2614 get { return name.FullName; }
2618 public class TypeAliasExpression : TypeExpr {
2619 FullNamedExpression alias;
2624 public TypeAliasExpression (FullNamedExpression alias, TypeArguments args, Location l)
2630 eclass = ExprClass.Type;
2632 name = alias.FullName + "<" + args.ToString () + ">";
2634 name = alias.FullName;
2637 public override string Name {
2638 get { return alias.FullName; }
2641 public override string FullName {
2642 get { return name; }
2645 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2647 texpr = alias.ResolveAsTypeTerminal (ec, false);
2651 Type type = texpr.Type;
2652 int num_args = TypeManager.GetNumberOfTypeArguments (type);
2655 if (num_args == 0) {
2656 Report.Error (308, loc,
2657 "The non-generic type `{0}' cannot " +
2658 "be used with type arguments.",
2659 TypeManager.CSharpName (type));
2663 ConstructedType ctype = new ConstructedType (type, args, loc);
2664 return ctype.ResolveAsTypeTerminal (ec, false);
2665 } else if (num_args > 0) {
2666 Report.Error (305, loc,
2667 "Using the generic type `{0}' " +
2668 "requires {1} type arguments",
2669 TypeManager.CSharpName (type), num_args.ToString ());
2676 public override bool CheckAccessLevel (DeclSpace ds)
2678 return texpr.CheckAccessLevel (ds);
2681 public override bool AsAccessible (DeclSpace ds, int flags)
2683 return texpr.AsAccessible (ds, flags);
2686 public override bool IsClass {
2687 get { return texpr.IsClass; }
2690 public override bool IsValueType {
2691 get { return texpr.IsValueType; }
2694 public override bool IsInterface {
2695 get { return texpr.IsInterface; }
2698 public override bool IsSealed {
2699 get { return texpr.IsSealed; }
2704 /// This class denotes an expression which evaluates to a member
2705 /// of a struct or a class.
2707 public abstract class MemberExpr : Expression
2710 /// The name of this member.
2712 public abstract string Name {
2717 /// Whether this is an instance member.
2719 public abstract bool IsInstance {
2724 /// Whether this is a static member.
2726 public abstract bool IsStatic {
2731 /// The type which declares this member.
2733 public abstract Type DeclaringType {
2738 /// The instance expression associated with this member, if it's a
2739 /// non-static member.
2741 public Expression InstanceExpression;
2743 public static void error176 (Location loc, string name)
2745 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
2746 "with an instance reference, qualify it with a type name instead", name);
2749 // TODO: possible optimalization
2750 // Cache resolved constant result in FieldBuilder <-> expression map
2751 public virtual Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2752 SimpleName original)
2756 // original == null || original.Resolve (...) ==> left
2759 if (left is TypeExpr) {
2761 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2769 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2772 error176 (loc, GetSignatureForError ());
2776 InstanceExpression = left;
2781 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2786 if (InstanceExpression == EmptyExpression.Null) {
2787 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
2791 if (InstanceExpression.Type.IsValueType) {
2792 if (InstanceExpression is IMemoryLocation) {
2793 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2795 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2796 InstanceExpression.Emit (ec);
2798 t.AddressOf (ec, AddressOp.Store);
2801 InstanceExpression.Emit (ec);
2803 if (prepare_for_load)
2804 ec.ig.Emit (OpCodes.Dup);
2809 /// MethodGroup Expression.
2811 /// This is a fully resolved expression that evaluates to a type
2813 public class MethodGroupExpr : MemberExpr {
2814 public MethodBase [] Methods;
2815 bool has_type_arguments = false;
2816 bool identical_type_name = false;
2819 public MethodGroupExpr (MemberInfo [] mi, Location l)
2821 Methods = new MethodBase [mi.Length];
2822 mi.CopyTo (Methods, 0);
2823 eclass = ExprClass.MethodGroup;
2824 type = TypeManager.object_type;
2828 public MethodGroupExpr (ArrayList list, Location l)
2830 Methods = new MethodBase [list.Count];
2833 list.CopyTo (Methods, 0);
2835 foreach (MemberInfo m in list){
2836 if (!(m is MethodBase)){
2837 Console.WriteLine ("Name " + m.Name);
2838 Console.WriteLine ("Found a: " + m.GetType ().FullName);
2845 eclass = ExprClass.MethodGroup;
2846 type = TypeManager.object_type;
2849 public override Type DeclaringType {
2852 // We assume that the top-level type is in the end
2854 return Methods [Methods.Length - 1].DeclaringType;
2855 //return Methods [0].DeclaringType;
2859 public bool HasTypeArguments {
2861 return has_type_arguments;
2865 has_type_arguments = value;
2869 public bool IdenticalTypeName {
2871 return identical_type_name;
2875 identical_type_name = value;
2879 public bool IsBase {
2888 public override string GetSignatureForError ()
2890 return TypeManager.CSharpSignature (Methods [0]);
2893 public override string Name {
2895 return Methods [0].Name;
2899 public override bool IsInstance {
2901 foreach (MethodBase mb in Methods)
2909 public override bool IsStatic {
2911 foreach (MethodBase mb in Methods)
2919 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
2920 SimpleName original)
2922 if (!(left is TypeExpr) &&
2923 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
2924 IdenticalTypeName = true;
2926 return base.ResolveMemberAccess (ec, left, loc, original);
2929 override public Expression DoResolve (EmitContext ec)
2932 InstanceExpression = null;
2934 if (InstanceExpression != null) {
2935 InstanceExpression = InstanceExpression.DoResolve (ec);
2936 if (InstanceExpression == null)
2943 public void ReportUsageError ()
2945 Report.Error (654, loc, "Method `" + DeclaringType + "." +
2946 Name + "()' is referenced without parentheses");
2949 override public void Emit (EmitContext ec)
2951 ReportUsageError ();
2954 bool RemoveMethods (bool keep_static)
2956 ArrayList smethods = new ArrayList ();
2958 foreach (MethodBase mb in Methods){
2959 if (mb.IsStatic == keep_static)
2963 if (smethods.Count == 0)
2966 Methods = new MethodBase [smethods.Count];
2967 smethods.CopyTo (Methods, 0);
2973 /// Removes any instance methods from the MethodGroup, returns
2974 /// false if the resulting set is empty.
2976 public bool RemoveInstanceMethods ()
2978 return RemoveMethods (true);
2982 /// Removes any static methods from the MethodGroup, returns
2983 /// false if the resulting set is empty.
2985 public bool RemoveStaticMethods ()
2987 return RemoveMethods (false);
2990 public Expression ResolveGeneric (EmitContext ec, TypeArguments args)
2993 if (args.Resolve (ec) == false)
2996 Type[] atypes = args.Arguments;
2998 int first_count = 0;
2999 MethodInfo first = null;
3001 ArrayList list = new ArrayList ();
3002 foreach (MethodBase mb in Methods) {
3003 MethodInfo mi = mb as MethodInfo;
3004 if ((mi == null) || !mi.IsGenericMethod)
3007 Type[] gen_params = mi.GetGenericArguments ();
3009 if (first == null) {
3011 first_count = gen_params.Length;
3014 if (gen_params.Length != atypes.Length)
3017 list.Add (mi.MakeGenericMethod (atypes));
3020 if (list.Count > 0) {
3021 MethodGroupExpr new_mg = new MethodGroupExpr (list, Location);
3022 new_mg.InstanceExpression = InstanceExpression;
3023 new_mg.HasTypeArguments = true;
3024 new_mg.IsBase = IsBase;
3030 305, loc, "Using the generic method `{0}' " +
3031 "requires {1} type arguments", Name,
3032 first_count.ToString ());
3035 308, loc, "The non-generic method `{0}' " +
3036 "cannot be used with type arguments", Name);
3040 throw new NotImplementedException ();
3046 /// Fully resolved expression that evaluates to a Field
3048 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariable {
3049 public readonly FieldInfo FieldInfo;
3050 VariableInfo variable_info;
3052 LocalTemporary temp;
3054 bool in_initializer;
3056 public FieldExpr (FieldInfo fi, Location l, bool in_initializer):
3059 this.in_initializer = in_initializer;
3062 public FieldExpr (FieldInfo fi, Location l)
3065 eclass = ExprClass.Variable;
3066 type = TypeManager.TypeToCoreType (fi.FieldType);
3070 public override string Name {
3072 return FieldInfo.Name;
3076 public override bool IsInstance {
3078 return !FieldInfo.IsStatic;
3082 public override bool IsStatic {
3084 return FieldInfo.IsStatic;
3088 public override Type DeclaringType {
3090 return FieldInfo.DeclaringType;
3094 public override string GetSignatureForError ()
3096 return TypeManager.GetFullNameSignature (FieldInfo);
3099 public VariableInfo VariableInfo {
3101 return variable_info;
3105 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3106 SimpleName original)
3108 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
3110 Type t = fi.FieldType;
3112 if (fi.IsLiteral || (fi.IsInitOnly && t == TypeManager.decimal_type)) {
3113 IConstant ic = TypeManager.GetConstant (fi);
3116 ic = new ExternalConstant (fi);
3118 ic = ExternalConstant.CreateDecimal (fi);
3120 return base.ResolveMemberAccess (ec, left, loc, original);
3123 TypeManager.RegisterConstant (fi, ic);
3126 bool left_is_type = left is TypeExpr;
3127 if (!left_is_type && (original == null || !original.IdenticalNameAndTypeName (ec, left, loc))) {
3128 Report.SymbolRelatedToPreviousError (FieldInfo);
3129 error176 (loc, TypeManager.GetFullNameSignature (FieldInfo));
3133 if (ic.ResolveValue ()) {
3134 if (!ec.IsInObsoleteScope)
3135 ic.CheckObsoleteness (loc);
3141 if (t.IsPointer && !ec.InUnsafe) {
3146 return base.ResolveMemberAccess (ec, left, loc, original);
3149 override public Expression DoResolve (EmitContext ec)
3151 return DoResolve (ec, false, false);
3154 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
3156 if (!FieldInfo.IsStatic){
3157 if (InstanceExpression == null){
3159 // This can happen when referencing an instance field using
3160 // a fully qualified type expression: TypeName.InstanceField = xxx
3162 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3166 // Resolve the field's instance expression while flow analysis is turned
3167 // off: when accessing a field "a.b", we must check whether the field
3168 // "a.b" is initialized, not whether the whole struct "a" is initialized.
3170 if (lvalue_instance) {
3171 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
3172 Expression right_side =
3173 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
3174 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
3177 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
3178 InstanceExpression = InstanceExpression.Resolve (ec, rf);
3181 if (InstanceExpression == null)
3184 InstanceExpression.CheckMarshalByRefAccess ();
3187 if (!in_initializer && !ec.IsFieldInitializer) {
3188 ObsoleteAttribute oa;
3189 FieldBase f = TypeManager.GetField (FieldInfo);
3191 if (!ec.IsInObsoleteScope)
3192 f.CheckObsoleteness (loc);
3194 // To be sure that type is external because we do not register generated fields
3195 } else if (!(FieldInfo.DeclaringType is TypeBuilder)) {
3196 oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
3198 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
3202 AnonymousContainer am = ec.CurrentAnonymousMethod;
3204 if (!FieldInfo.IsStatic){
3205 if (!am.IsIterator && (ec.TypeContainer is Struct)){
3206 Report.Error (1673, loc,
3207 "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",
3214 // If the instance expression is a local variable or parameter.
3215 IVariable var = InstanceExpression as IVariable;
3216 if ((var == null) || (var.VariableInfo == null))
3219 VariableInfo vi = var.VariableInfo;
3220 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
3223 variable_info = vi.GetSubStruct (FieldInfo.Name);
3227 static readonly int [] codes = {
3228 191, // instance, write access
3229 192, // instance, out access
3230 198, // static, write access
3231 199, // static, out access
3232 1648, // member of value instance, write access
3233 1649, // member of value instance, out access
3234 1650, // member of value static, write access
3235 1651 // member of value static, out access
3238 static readonly string [] msgs = {
3239 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
3240 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3241 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3242 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
3243 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3244 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
3245 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3246 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
3249 // The return value is always null. Returning a value simplifies calling code.
3250 Expression Report_AssignToReadonly (Expression right_side)
3253 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3257 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
3259 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
3264 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3266 IVariable var = InstanceExpression as IVariable;
3267 if ((var != null) && (var.VariableInfo != null))
3268 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
3270 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
3271 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
3273 Expression e = DoResolve (ec, lvalue_instance, out_access);
3278 FieldBase fb = TypeManager.GetField (FieldInfo);
3282 if (FieldInfo.IsInitOnly) {
3283 // InitOnly fields can only be assigned in constructors or initializers
3284 if (!ec.IsFieldInitializer && !ec.IsConstructor)
3285 return Report_AssignToReadonly (right_side);
3287 if (ec.IsConstructor) {
3288 Type ctype = ec.TypeContainer.CurrentType;
3290 ctype = ec.ContainerType;
3292 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
3293 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
3294 return Report_AssignToReadonly (right_side);
3295 // static InitOnly fields cannot be assigned-to in an instance constructor
3296 if (IsStatic && !ec.IsStatic)
3297 return Report_AssignToReadonly (right_side);
3298 // instance constructors can't modify InitOnly fields of other instances of the same type
3299 if (!IsStatic && !(InstanceExpression is This))
3300 return Report_AssignToReadonly (right_side);
3304 if (right_side == EmptyExpression.OutAccess &&
3305 !IsStatic && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3306 Report.SymbolRelatedToPreviousError (DeclaringType);
3307 Report.Warning (197, 1, loc,
3308 "Passing `{0}' as ref or out or taking its address may cause a runtime exception because it is a field of a marshal-by-reference class",
3309 GetSignatureForError ());
3315 public override void CheckMarshalByRefAccess ()
3317 if (!IsStatic && Type.IsValueType && !(InstanceExpression is This) && DeclaringType.IsSubclassOf (TypeManager.mbr_type)) {
3318 Report.SymbolRelatedToPreviousError (DeclaringType);
3319 Report.Warning (1690, 1, loc, "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3320 GetSignatureForError ());
3324 public bool VerifyFixed ()
3326 IVariable variable = InstanceExpression as IVariable;
3327 // A variable of the form V.I is fixed when V is a fixed variable of a struct type.
3328 // We defer the InstanceExpression check after the variable check to avoid a
3329 // separate null check on InstanceExpression.
3330 return variable != null && InstanceExpression.Type.IsValueType && variable.VerifyFixed ();
3333 public override int GetHashCode ()
3335 return FieldInfo.GetHashCode ();
3338 public override bool Equals (object obj)
3340 FieldExpr fe = obj as FieldExpr;
3344 if (FieldInfo != fe.FieldInfo)
3347 if (InstanceExpression == null || fe.InstanceExpression == null)
3350 return InstanceExpression.Equals (fe.InstanceExpression);
3353 public void Emit (EmitContext ec, bool leave_copy)
3355 ILGenerator ig = ec.ig;
3356 bool is_volatile = false;
3358 FieldBase f = TypeManager.GetField (FieldInfo);
3360 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3363 f.SetMemberIsUsed ();
3366 if (FieldInfo.IsStatic){
3368 ig.Emit (OpCodes.Volatile);
3370 ig.Emit (OpCodes.Ldsfld, FieldInfo);
3373 EmitInstance (ec, false);
3376 ig.Emit (OpCodes.Volatile);
3378 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
3381 ig.Emit (OpCodes.Ldflda, FieldInfo);
3382 ig.Emit (OpCodes.Ldflda, ff.Element);
3385 ig.Emit (OpCodes.Ldfld, FieldInfo);
3390 ec.ig.Emit (OpCodes.Dup);
3391 if (!FieldInfo.IsStatic) {
3392 temp = new LocalTemporary (this.Type);
3398 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3400 FieldAttributes fa = FieldInfo.Attributes;
3401 bool is_static = (fa & FieldAttributes.Static) != 0;
3402 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
3403 ILGenerator ig = ec.ig;
3404 prepared = prepare_for_load;
3406 if (is_readonly && !ec.IsConstructor){
3407 Report_AssignToReadonly (source);
3411 EmitInstance (ec, prepare_for_load);
3415 ec.ig.Emit (OpCodes.Dup);
3416 if (!FieldInfo.IsStatic) {
3417 temp = new LocalTemporary (this.Type);
3422 FieldBase f = TypeManager.GetField (FieldInfo);
3424 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
3425 ig.Emit (OpCodes.Volatile);
3431 ig.Emit (OpCodes.Stsfld, FieldInfo);
3433 ig.Emit (OpCodes.Stfld, FieldInfo);
3441 public override void Emit (EmitContext ec)
3446 public void AddressOf (EmitContext ec, AddressOp mode)
3448 ILGenerator ig = ec.ig;
3450 FieldBase f = TypeManager.GetField (FieldInfo);
3452 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
3453 Report.Warning (420, 1, loc, "`{0}': A volatile fields cannot be passed using a ref or out parameter",
3454 f.GetSignatureForError ());
3458 if ((mode & AddressOp.Store) != 0)
3460 if ((mode & AddressOp.Load) != 0)
3461 f.SetMemberIsUsed ();
3465 // Handle initonly fields specially: make a copy and then
3466 // get the address of the copy.
3469 if (FieldInfo.IsInitOnly){
3471 if (ec.IsConstructor){
3472 if (FieldInfo.IsStatic){
3484 local = ig.DeclareLocal (type);
3485 ig.Emit (OpCodes.Stloc, local);
3486 ig.Emit (OpCodes.Ldloca, local);
3491 if (FieldInfo.IsStatic){
3492 ig.Emit (OpCodes.Ldsflda, FieldInfo);
3495 EmitInstance (ec, false);
3496 ig.Emit (OpCodes.Ldflda, FieldInfo);
3502 // A FieldExpr whose address can not be taken
3504 public class FieldExprNoAddress : FieldExpr, IMemoryLocation {
3505 public FieldExprNoAddress (FieldInfo fi, Location loc) : base (fi, loc)
3509 public new void AddressOf (EmitContext ec, AddressOp mode)
3511 Report.Error (-215, "Report this: Taking the address of a remapped parameter not supported");
3516 /// Expression that evaluates to a Property. The Assign class
3517 /// might set the `Value' expression if we are in an assignment.
3519 /// This is not an LValue because we need to re-write the expression, we
3520 /// can not take data from the stack and store it.
3522 public class PropertyExpr : MemberExpr, IAssignMethod {
3523 public readonly PropertyInfo PropertyInfo;
3526 // This is set externally by the `BaseAccess' class
3529 MethodInfo getter, setter;
3534 LocalTemporary temp;
3537 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3539 public PropertyExpr (Type containerType, PropertyInfo pi, Location l)
3542 eclass = ExprClass.PropertyAccess;
3546 type = TypeManager.TypeToCoreType (pi.PropertyType);
3548 ResolveAccessors (containerType);
3551 public override string Name {
3553 return PropertyInfo.Name;
3557 public override bool IsInstance {
3563 public override bool IsStatic {
3569 public override Type DeclaringType {
3571 return PropertyInfo.DeclaringType;
3575 public override string GetSignatureForError ()
3577 return TypeManager.GetFullNameSignature (PropertyInfo);
3580 void FindAccessors (Type invocation_type)
3582 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
3583 BindingFlags.Static | BindingFlags.Instance |
3584 BindingFlags.DeclaredOnly;
3586 Type current = PropertyInfo.DeclaringType;
3587 for (; current != null; current = current.BaseType) {
3588 MemberInfo[] group = TypeManager.MemberLookup (
3589 invocation_type, invocation_type, current,
3590 MemberTypes.Property, flags, PropertyInfo.Name, null);
3595 if (group.Length != 1)
3596 // Oooops, can this ever happen ?
3599 PropertyInfo pi = (PropertyInfo) group [0];
3602 getter = pi.GetGetMethod (true);
3605 setter = pi.GetSetMethod (true);
3607 MethodInfo accessor = getter != null ? getter : setter;
3609 if (!accessor.IsVirtual)
3615 // We also perform the permission checking here, as the PropertyInfo does not
3616 // hold the information for the accessibility of its setter/getter
3618 // TODO: can use TypeManager.GetProperty to boost performance
3619 void ResolveAccessors (Type containerType)
3621 FindAccessors (containerType);
3623 if (getter != null) {
3624 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
3625 IMethodData md = TypeManager.GetMethod (the_getter);
3627 md.SetMemberIsUsed ();
3629 AccessorTable [getter] = PropertyInfo;
3630 is_static = getter.IsStatic;
3633 if (setter != null) {
3634 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
3635 IMethodData md = TypeManager.GetMethod (the_setter);
3637 md.SetMemberIsUsed ();
3639 AccessorTable [setter] = PropertyInfo;
3640 is_static = setter.IsStatic;
3644 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
3647 InstanceExpression = null;
3651 if (InstanceExpression == null) {
3652 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3656 if (lvalue_instance)
3657 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
3659 InstanceExpression = InstanceExpression.DoResolve (ec);
3660 if (InstanceExpression == null)
3663 InstanceExpression.CheckMarshalByRefAccess ();
3665 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
3666 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
3667 TypeManager.IsFamilyAccessible (ec.ContainerType, PropertyInfo.DeclaringType) &&
3668 !TypeManager.IsFamilyAccessible (InstanceExpression.Type, ec.ContainerType)) {
3669 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
3676 void Error_PropertyNotFound (MethodInfo mi, bool getter)
3678 // TODO: correctly we should compare arguments but it will lead to bigger changes
3679 if (mi is MethodBuilder) {
3680 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
3684 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
3686 ParameterData iparams = TypeManager.GetParameterData (mi);
3687 sig.Append (getter ? "get_" : "set_");
3689 sig.Append (iparams.GetSignatureForError ());
3691 Report.SymbolRelatedToPreviousError (mi);
3692 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
3693 Name, sig.ToString ());
3696 override public Expression DoResolve (EmitContext ec)
3701 if (getter != null){
3702 if (TypeManager.GetParameterData (getter).Count != 0){
3703 Error_PropertyNotFound (getter, true);
3708 if (getter == null){
3710 // The following condition happens if the PropertyExpr was
3711 // created, but is invalid (ie, the property is inaccessible),
3712 // and we did not want to embed the knowledge about this in
3713 // the caller routine. This only avoids double error reporting.
3718 if (InstanceExpression != EmptyExpression.Null) {
3719 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
3720 TypeManager.GetFullNameSignature (PropertyInfo));
3725 bool must_do_cs1540_check = false;
3726 if (getter != null &&
3727 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
3728 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
3729 if (pm != null && pm.HasCustomAccessModifier) {
3730 Report.SymbolRelatedToPreviousError (pm);
3731 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
3732 TypeManager.CSharpSignature (getter));
3735 Report.SymbolRelatedToPreviousError (getter);
3736 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
3741 if (!InstanceResolve (ec, false, must_do_cs1540_check))
3745 // Only base will allow this invocation to happen.
3747 if (IsBase && getter.IsAbstract) {
3748 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3752 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
3762 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3764 if (right_side == EmptyExpression.OutAccess) {
3765 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
3766 GetSignatureForError ());
3770 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
3771 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
3772 GetSignatureForError ());
3776 if (setter == null){
3778 // The following condition happens if the PropertyExpr was
3779 // created, but is invalid (ie, the property is inaccessible),
3780 // and we did not want to embed the knowledge about this in
3781 // the caller routine. This only avoids double error reporting.
3785 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
3786 GetSignatureForError ());
3790 if (TypeManager.GetParameterData (setter).Count != 1){
3791 Error_PropertyNotFound (setter, false);
3795 bool must_do_cs1540_check;
3796 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
3797 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
3798 if (pm != null && pm.HasCustomAccessModifier) {
3799 Report.SymbolRelatedToPreviousError (pm);
3800 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
3801 TypeManager.CSharpSignature (setter));
3804 Report.SymbolRelatedToPreviousError (setter);
3805 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
3810 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
3814 // Only base will allow this invocation to happen.
3816 if (IsBase && setter.IsAbstract){
3817 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
3824 public override void Emit (EmitContext ec)
3829 public void Emit (EmitContext ec, bool leave_copy)
3832 // Special case: length of single dimension array property is turned into ldlen
3834 if ((getter == TypeManager.system_int_array_get_length) ||
3835 (getter == TypeManager.int_array_get_length)){
3836 Type iet = InstanceExpression.Type;
3839 // System.Array.Length can be called, but the Type does not
3840 // support invoking GetArrayRank, so test for that case first
3842 if (iet != TypeManager.array_type && (iet.GetArrayRank () == 1)) {
3844 EmitInstance (ec, false);
3845 ec.ig.Emit (OpCodes.Ldlen);
3846 ec.ig.Emit (OpCodes.Conv_I4);
3851 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, getter, null, loc, prepared, false);
3854 ec.ig.Emit (OpCodes.Dup);
3856 temp = new LocalTemporary (this.Type);
3863 // Implements the IAssignMethod interface for assignments
3865 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3867 Expression my_source = source;
3869 prepared = prepare_for_load;
3874 ec.ig.Emit (OpCodes.Dup);
3876 temp = new LocalTemporary (this.Type);
3880 } else if (leave_copy) {
3883 temp = new LocalTemporary (this.Type);
3889 ArrayList args = new ArrayList (1);
3890 args.Add (new Argument (my_source, Argument.AType.Expression));
3892 Invocation.EmitCall (ec, IsBase, IsStatic, InstanceExpression, setter, args, loc, false, prepared);
3902 /// Fully resolved expression that evaluates to an Event
3904 public class EventExpr : MemberExpr {
3905 public readonly EventInfo EventInfo;
3908 MethodInfo add_accessor, remove_accessor;
3910 internal static PtrHashtable AccessorTable = new PtrHashtable ();
3912 public EventExpr (EventInfo ei, Location loc)
3916 eclass = ExprClass.EventAccess;
3918 add_accessor = TypeManager.GetAddMethod (ei);
3919 remove_accessor = TypeManager.GetRemoveMethod (ei);
3920 if (add_accessor != null)
3921 AccessorTable [add_accessor] = ei;
3922 if (remove_accessor != null)
3923 AccessorTable [remove_accessor] = ei;
3925 if (add_accessor.IsStatic || remove_accessor.IsStatic)
3928 if (EventInfo is MyEventBuilder){
3929 MyEventBuilder eb = (MyEventBuilder) EventInfo;
3930 type = eb.EventType;
3933 type = EventInfo.EventHandlerType;
3936 public override string Name {
3938 return EventInfo.Name;
3942 public override bool IsInstance {
3948 public override bool IsStatic {
3954 public override Type DeclaringType {
3956 return EventInfo.DeclaringType;
3960 public override Expression ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3961 SimpleName original)
3964 // If the event is local to this class, we transform ourselves into a FieldExpr
3967 if (EventInfo.DeclaringType == ec.ContainerType ||
3968 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
3969 MemberInfo mi = TypeManager.GetPrivateFieldOfEvent (EventInfo);
3972 MemberExpr ml = (MemberExpr) ExprClassFromMemberInfo (ec.ContainerType, mi, loc);
3975 Report.Error (-200, loc, "Internal error!!");
3979 InstanceExpression = null;
3981 return ml.ResolveMemberAccess (ec, left, loc, original);
3985 return base.ResolveMemberAccess (ec, left, loc, original);
3989 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
3992 InstanceExpression = null;
3996 if (InstanceExpression == null) {
3997 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4001 InstanceExpression = InstanceExpression.DoResolve (ec);
4002 if (InstanceExpression == null)
4006 // This is using the same mechanism as the CS1540 check in PropertyExpr.
4007 // However, in the Event case, we reported a CS0122 instead.
4009 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
4010 InstanceExpression.Type != ec.ContainerType &&
4011 ec.ContainerType.IsSubclassOf (InstanceExpression.Type)) {
4012 Report.SymbolRelatedToPreviousError (EventInfo);
4013 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4020 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4022 return DoResolve (ec);
4025 public override Expression DoResolve (EmitContext ec)
4027 bool must_do_cs1540_check;
4028 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
4029 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
4030 Report.SymbolRelatedToPreviousError (EventInfo);
4031 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
4035 if (!InstanceResolve (ec, must_do_cs1540_check))
4041 public override void Emit (EmitContext ec)
4043 if (InstanceExpression is This)
4044 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of += or -=", GetSignatureForError ());
4046 Report.Error (70, loc, "The event `{0}' can only appear on the left hand side of += or -= "+
4047 "(except on the defining type)", Name);
4050 public override string GetSignatureForError ()
4052 return TypeManager.CSharpSignature (EventInfo);
4055 public void EmitAddOrRemove (EmitContext ec, Expression source)
4057 BinaryDelegate source_del = (BinaryDelegate) source;
4058 Expression handler = source_del.Right;
4060 Argument arg = new Argument (handler, Argument.AType.Expression);
4061 ArrayList args = new ArrayList ();
4065 if (source_del.IsAddition)
4066 Invocation.EmitCall (
4067 ec, false, IsStatic, InstanceExpression, add_accessor, args, loc);
4069 Invocation.EmitCall (
4070 ec, false, IsStatic, InstanceExpression, remove_accessor, args, loc);
4074 public class TemporaryVariable : Expression, IMemoryLocation
4079 public TemporaryVariable (Type type, Location loc)
4083 eclass = ExprClass.Value;
4086 public override Expression DoResolve (EmitContext ec)
4091 TypeExpr te = new TypeExpression (type, loc);
4092 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
4093 if (!li.Resolve (ec))
4096 if (ec.MustCaptureVariable (li)) {
4097 ScopeInfo scope = li.Block.CreateScopeInfo ();
4098 var = scope.AddLocal (li);
4105 public Variable Variable {
4106 get { return var != null ? var : li.Variable; }
4109 public override void Emit (EmitContext ec)
4111 Variable.EmitInstance (ec);
4115 public void EmitLoadAddress (EmitContext ec)
4117 Variable.EmitInstance (ec);
4118 Variable.EmitAddressOf (ec);
4121 public void Store (EmitContext ec, Expression right_side)
4123 Variable.EmitInstance (ec);
4124 right_side.Emit (ec);
4125 Variable.EmitAssign (ec);
4128 public void EmitThis (EmitContext ec)
4130 Variable.EmitInstance (ec);
4133 public void EmitStore (EmitContext ec)
4135 Variable.EmitAssign (ec);
4138 public void AddressOf (EmitContext ec, AddressOp mode)
4140 EmitLoadAddress (ec);