2008-10-06 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / mcs / ecore.cs
blob030b5313db12eb420ac764e9b2b32d84066bd55e
1 //
2 // ecore.cs: Core of the Expression representation for the intermediate tree.
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
7 //
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
13 namespace Mono.CSharp {
14 using System;
15 using System.Collections;
16 using System.Diagnostics;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text;
21 /// <remarks>
22 /// The ExprClass class contains the is used to pass the
23 /// classification of an expression (value, variable, namespace,
24 /// type, method group, property access, event access, indexer access,
25 /// nothing).
26 /// </remarks>
27 public enum ExprClass : byte {
28 Invalid,
30 Value,
31 Variable,
32 Namespace,
33 Type,
34 TypeParameter,
35 MethodGroup,
36 PropertyAccess,
37 EventAccess,
38 IndexerAccess,
39 Nothing,
42 /// <remarks>
43 /// This is used to tell Resolve in which types of expressions we're
44 /// interested.
45 /// </remarks>
46 [Flags]
47 public enum ResolveFlags {
48 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
49 VariableOrValue = 1,
51 // Returns a type expression.
52 Type = 1 << 1,
54 // Returns a method group.
55 MethodGroup = 1 << 2,
57 TypeParameter = 1 << 3,
59 // Mask of all the expression class flags.
60 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
62 // Disable control flow analysis while resolving the expression.
63 // This is used when resolving the instance expression of a field expression.
64 DisableFlowAnalysis = 1 << 10,
66 // Set if this is resolving the first part of a MemberAccess.
67 Intermediate = 1 << 11,
69 // Disable control flow analysis _of struct_ while resolving the expression.
70 // This is used when resolving the instance expression of a field expression.
71 DisableStructFlowAnalysis = 1 << 12,
76 // This is just as a hint to AddressOf of what will be done with the
77 // address.
78 [Flags]
79 public enum AddressOp {
80 Store = 1,
81 Load = 2,
82 LoadStore = 3
85 /// <summary>
86 /// This interface is implemented by variables
87 /// </summary>
88 public interface IMemoryLocation {
89 /// <summary>
90 /// The AddressOf method should generate code that loads
91 /// the address of the object and leaves it on the stack.
92 ///
93 /// The `mode' argument is used to notify the expression
94 /// of whether this will be used to read from the address or
95 /// write to the address.
96 ///
97 /// This is just a hint that can be used to provide good error
98 /// reporting, and should have no other side effects.
99 /// </summary>
100 void AddressOf (EmitContext ec, AddressOp mode);
104 // An expressions resolved as a direct variable reference
106 public interface IVariableReference : IFixedExpression
108 bool IsHoisted { get; }
109 string Name { get; }
110 VariableInfo VariableInfo { get; }
112 void SetHasAddressTaken ();
116 // Implemented by an expression which could be or is always
117 // fixed
119 public interface IFixedExpression
121 bool IsFixed { get; }
124 /// <remarks>
125 /// Base class for expressions
126 /// </remarks>
127 public abstract class Expression {
128 public ExprClass eclass;
129 protected Type type;
130 protected Location loc;
132 public Type Type {
133 get { return type; }
134 set { type = value; }
137 public virtual Location Location {
138 get { return loc; }
141 /// <summary>
142 /// Utility wrapper routine for Error, just to beautify the code
143 /// </summary>
144 public void Error (int error, string s)
146 Report.Error (error, loc, s);
149 // Not nice but we have broken hierarchy.
150 public virtual void CheckMarshalByRefAccess (EmitContext ec)
154 public virtual bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
156 Attribute.Error_AttributeArgumentNotValid (loc);
157 value = null;
158 return false;
161 public virtual string GetSignatureForError ()
163 return TypeManager.CSharpName (type);
166 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
168 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
170 must_do_cs1540_check = false; // by default we do not check for this
172 if (ma == MethodAttributes.Public)
173 return true;
176 // If only accessible to the current class or children
178 if (ma == MethodAttributes.Private)
179 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
180 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
182 if (TypeManager.IsThisOrFriendAssembly (mi.DeclaringType.Assembly)) {
183 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
184 return true;
185 } else {
186 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
187 return false;
190 // Family and FamANDAssem require that we derive.
191 // FamORAssem requires that we derive if in different assemblies.
192 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
193 return false;
195 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
196 must_do_cs1540_check = true;
198 return true;
201 public virtual bool IsNull {
202 get {
203 return false;
207 /// <summary>
208 /// Performs semantic analysis on the Expression
209 /// </summary>
211 /// <remarks>
212 /// The Resolve method is invoked to perform the semantic analysis
213 /// on the node.
215 /// The return value is an expression (it can be the
216 /// same expression in some cases) or a new
217 /// expression that better represents this node.
218 ///
219 /// For example, optimizations of Unary (LiteralInt)
220 /// would return a new LiteralInt with a negated
221 /// value.
222 ///
223 /// If there is an error during semantic analysis,
224 /// then an error should be reported (using Report)
225 /// and a null value should be returned.
226 ///
227 /// There are two side effects expected from calling
228 /// Resolve(): the the field variable "eclass" should
229 /// be set to any value of the enumeration
230 /// `ExprClass' and the type variable should be set
231 /// to a valid type (this is the type of the
232 /// expression).
233 /// </remarks>
234 public abstract Expression DoResolve (EmitContext ec);
236 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
238 return null;
242 // This is used if the expression should be resolved as a type or namespace name.
243 // the default implementation fails.
245 public virtual FullNamedExpression ResolveAsTypeStep (IResolveContext rc, bool silent)
247 if (!silent) {
248 Expression e = this;
249 EmitContext ec = rc as EmitContext;
250 if (ec != null)
251 e = e.Resolve (ec);
252 if (e != null)
253 e.Error_UnexpectedKind (ResolveFlags.Type, loc);
255 return null;
259 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
260 // same name exists or as a keyword when no type was found
262 public virtual TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
264 return ResolveAsTypeTerminal (rc, silent);
268 // This is used to resolve the expression as a type, a null
269 // value will be returned if the expression is not a type
270 // reference
272 public virtual TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
274 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
275 if (te == null)
276 return null;
278 if (!silent) { // && !(te is TypeParameterExpr)) {
279 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
280 if (obsolete_attr != null && !ec.IsInObsoleteScope) {
281 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location);
285 ConstructedType ct = te as ConstructedType;
286 if (ct != null) {
287 // Skip constrains check for overrides and explicit implementations
288 // TODO: they should use different overload
289 GenericMethod gm = ec.GenericDeclContainer as GenericMethod;
290 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
291 te.loc = loc;
292 return te;
295 // TODO: silent flag is ignored
296 ct.CheckConstraints (ec);
299 return te;
302 public TypeExpr ResolveAsBaseTerminal (IResolveContext ec, bool silent)
304 int errors = Report.Errors;
306 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
308 if (fne == null)
309 return null;
311 TypeExpr te = fne as TypeExpr;
312 if (te == null) {
313 if (!silent && errors == Report.Errors)
314 fne.Error_UnexpectedKind (null, "type", loc);
315 return null;
318 if (!te.CheckAccessLevel (ec.GenericDeclContainer)) {
319 Report.SymbolRelatedToPreviousError (te.Type);
320 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type));
321 return null;
324 te.loc = loc;
325 return te;
328 public static void ErrorIsInaccesible (Location loc, string name)
330 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
333 protected static void Error_CannotAccessProtected (Location loc, MemberInfo m, Type qualifier, Type container)
335 Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
336 + " The qualifier must be of type `{2}' or derived from it",
337 TypeManager.GetFullNameSignature (m),
338 TypeManager.CSharpName (qualifier),
339 TypeManager.CSharpName (container));
343 public static void Error_InvalidExpressionStatement (Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement ()
351 Error_InvalidExpressionStatement (loc);
354 protected void Error_CannotAssign (string to, string roContext)
356 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
357 to, roContext);
360 public static void Error_VoidInvalidInTheContext (Location loc)
362 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
365 public virtual void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
367 // The error was already reported as CS1660
368 if (type == TypeManager.anonymous_method_type)
369 return;
371 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
372 #if GMCS_SOURCE
373 string sig1 = type.DeclaringMethod == null ?
374 TypeManager.CSharpName (type.DeclaringType) :
375 TypeManager.CSharpSignature (type.DeclaringMethod);
376 string sig2 = target.DeclaringMethod == null ?
377 TypeManager.CSharpName (target.DeclaringType) :
378 TypeManager.CSharpSignature (target.DeclaringMethod);
379 Report.ExtraInformation (loc,
380 String.Format (
381 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
382 Type.Name, sig1, sig2));
383 #endif
384 } else if (Type.FullName == target.FullName){
385 Report.ExtraInformation (loc,
386 String.Format (
387 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
388 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
391 if (expl) {
392 Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
393 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
394 return;
397 Report.DisableReporting ();
398 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
399 Report.EnableReporting ();
401 if (expl_exists) {
402 Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
403 "An explicit conversion exists (are you missing a cast?)",
404 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
405 return;
408 Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
409 TypeManager.CSharpName (type),
410 TypeManager.CSharpName (target));
413 public virtual void Error_VariableIsUsedBeforeItIsDeclared (string name)
415 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
418 protected virtual void Error_TypeDoesNotContainDefinition (Type type, string name)
420 Error_TypeDoesNotContainDefinition (loc, type, name);
423 public static void Error_TypeDoesNotContainDefinition (Location loc, Type type, string name)
425 Report.SymbolRelatedToPreviousError (type);
426 Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
427 TypeManager.CSharpName (type), name);
430 protected static void Error_ValueAssignment (Location loc)
432 Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
435 ResolveFlags ExprClassToResolveFlags
437 get {
438 switch (eclass) {
439 case ExprClass.Type:
440 case ExprClass.Namespace:
441 return ResolveFlags.Type;
443 case ExprClass.MethodGroup:
444 return ResolveFlags.MethodGroup;
446 case ExprClass.TypeParameter:
447 return ResolveFlags.TypeParameter;
449 case ExprClass.Value:
450 case ExprClass.Variable:
451 case ExprClass.PropertyAccess:
452 case ExprClass.EventAccess:
453 case ExprClass.IndexerAccess:
454 return ResolveFlags.VariableOrValue;
456 default:
457 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
462 /// <summary>
463 /// Resolves an expression and performs semantic analysis on it.
464 /// </summary>
466 /// <remarks>
467 /// Currently Resolve wraps DoResolve to perform sanity
468 /// checking and assertion checking on what we expect from Resolve.
469 /// </remarks>
470 public Expression Resolve (EmitContext ec, ResolveFlags flags)
472 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
473 return ResolveAsTypeStep (ec, false);
475 bool do_flow_analysis = ec.DoFlowAnalysis;
476 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
477 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
478 do_flow_analysis = false;
479 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
480 omit_struct_analysis = true;
482 Expression e;
483 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
484 if (this is SimpleName) {
485 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
486 e = ((SimpleName) this).DoResolve (ec, intermediate);
487 } else {
488 e = DoResolve (ec);
492 if (e == null)
493 return null;
495 if ((flags & e.ExprClassToResolveFlags) == 0) {
496 e.Error_UnexpectedKind (flags, loc);
497 return null;
500 if (e.type == null && !(e is Namespace)) {
501 throw new Exception (
502 "Expression " + e.GetType () +
503 " did not set its type after Resolve\n" +
504 "called from: " + this.GetType ());
507 return e;
510 /// <summary>
511 /// Resolves an expression and performs semantic analysis on it.
512 /// </summary>
513 public Expression Resolve (EmitContext ec)
515 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
517 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
518 ((MethodGroupExpr) e).ReportUsageError ();
519 return null;
521 return e;
524 public Constant ResolveAsConstant (EmitContext ec, MemberCore mc)
526 Expression e = Resolve (ec);
527 if (e == null)
528 return null;
530 Constant c = e as Constant;
531 if (c != null)
532 return c;
534 if (type != null && TypeManager.IsReferenceType (type))
535 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError ());
536 else
537 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError ());
539 return null;
542 /// <summary>
543 /// Resolves an expression for LValue assignment
544 /// </summary>
546 /// <remarks>
547 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
548 /// checking and assertion checking on what we expect from Resolve
549 /// </remarks>
550 public Expression ResolveLValue (EmitContext ec, Expression right_side, Location loc)
552 int errors = Report.Errors;
553 bool out_access = right_side == EmptyExpression.OutAccess;
555 Expression e = DoResolveLValue (ec, right_side);
557 if (e != null && out_access && !(e is IMemoryLocation)) {
558 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
559 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
561 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
562 // e.GetType () + " " + e.GetSignatureForError ());
563 e = null;
566 if (e == null) {
567 if (errors == Report.Errors) {
568 if (out_access)
569 Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
570 else
571 Error_ValueAssignment (loc);
573 return null;
576 if (e.eclass == ExprClass.Invalid)
577 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
579 if ((e.type == null) && !(e is ConstructedType))
580 throw new Exception ("Expression " + e + " did not set its type after Resolve");
582 return e;
585 /// <summary>
586 /// Emits the code for the expression
587 /// </summary>
589 /// <remarks>
590 /// The Emit method is invoked to generate the code
591 /// for the expression.
592 /// </remarks>
593 public abstract void Emit (EmitContext ec);
595 // Emit code to branch to @target if this expression is equivalent to @on_true.
596 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
597 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
598 // including the use of conditional branches. Note also that a branch MUST be emitted
599 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
601 Emit (ec);
602 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
605 // Emit this expression for its side effects, not for its value.
606 // The default implementation is to emit the value, and then throw it away.
607 // Subclasses can provide more efficient implementations, but those MUST be equivalent
608 public virtual void EmitSideEffect (EmitContext ec)
610 Emit (ec);
611 ec.ig.Emit (OpCodes.Pop);
614 /// <summary>
615 /// Protected constructor. Only derivate types should
616 /// be able to be created
617 /// </summary>
619 protected Expression ()
621 eclass = ExprClass.Invalid;
622 type = null;
625 /// <summary>
626 /// Returns a fully formed expression after a MemberLookup
627 /// </summary>
628 ///
629 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
631 if (mi is EventInfo)
632 return new EventExpr ((EventInfo) mi, loc);
633 else if (mi is FieldInfo) {
634 FieldInfo fi = (FieldInfo) mi;
635 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
636 return new ConstantExpr (fi, loc);
637 return new FieldExpr (fi, loc);
638 } else if (mi is PropertyInfo)
639 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
640 else if (mi is Type) {
641 return new TypeExpression ((System.Type) mi, loc);
644 return null;
647 protected static ArrayList almost_matched_members = new ArrayList (4);
650 // FIXME: Probably implement a cache for (t,name,current_access_set)?
652 // This code could use some optimizations, but we need to do some
653 // measurements. For example, we could use a delegate to `flag' when
654 // something can not any longer be a method-group (because it is something
655 // else).
657 // Return values:
658 // If the return value is an Array, then it is an array of
659 // MethodBases
661 // If the return value is an MemberInfo, it is anything, but a Method
663 // null on error.
665 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
666 // the arguments here and have MemberLookup return only the methods that
667 // match the argument count/type, unlike we are doing now (we delay this
668 // decision).
670 // This is so we can catch correctly attempts to invoke instance methods
671 // from a static body (scan for error 120 in ResolveSimpleName).
674 // FIXME: Potential optimization, have a static ArrayList
677 public static Expression MemberLookup (Type container_type, Type queried_type, string name,
678 MemberTypes mt, BindingFlags bf, Location loc)
680 return MemberLookup (container_type, null, queried_type, name, mt, bf, loc);
684 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
685 // `qualifier_type' or null to lookup members in the current class.
688 public static Expression MemberLookup (Type container_type,
689 Type qualifier_type, Type queried_type,
690 string name, MemberTypes mt,
691 BindingFlags bf, Location loc)
693 almost_matched_members.Clear ();
695 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
696 queried_type, mt, bf, name, almost_matched_members);
698 if (mi == null)
699 return null;
701 if (mi.Length > 1) {
702 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
703 ArrayList methods = new ArrayList (2);
704 ArrayList non_methods = null;
706 foreach (MemberInfo m in mi) {
707 if (m is MethodBase) {
708 methods.Add (m);
709 continue;
712 if (non_methods == null) {
713 non_methods = new ArrayList (2);
714 non_methods.Add (m);
715 continue;
718 foreach (MemberInfo n_m in non_methods) {
719 if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType))
720 continue;
722 Report.SymbolRelatedToPreviousError (m);
723 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
724 TypeManager.GetFullNameSignature (m), TypeManager.GetFullNameSignature (n_m));
725 return null;
729 if (methods.Count == 0)
730 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
732 if (non_methods != null) {
733 MethodBase method = (MethodBase) methods [0];
734 MemberInfo non_method = (MemberInfo) non_methods [0];
735 if (method.DeclaringType == non_method.DeclaringType) {
736 // Cannot happen with C# code, but is valid in IL
737 Report.SymbolRelatedToPreviousError (method);
738 Report.SymbolRelatedToPreviousError (non_method);
739 Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
740 TypeManager.GetFullNameSignature (non_method),
741 TypeManager.CSharpSignature (method));
742 return null;
745 if (is_interface) {
746 Report.SymbolRelatedToPreviousError (method);
747 Report.SymbolRelatedToPreviousError (non_method);
748 Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
749 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
753 return new MethodGroupExpr (methods, queried_type, loc);
756 if (mi [0] is MethodBase)
757 return new MethodGroupExpr (mi, queried_type, loc);
759 return ExprClassFromMemberInfo (container_type, mi [0], loc);
762 public const MemberTypes AllMemberTypes =
763 MemberTypes.Constructor |
764 MemberTypes.Event |
765 MemberTypes.Field |
766 MemberTypes.Method |
767 MemberTypes.NestedType |
768 MemberTypes.Property;
770 public const BindingFlags AllBindingFlags =
771 BindingFlags.Public |
772 BindingFlags.Static |
773 BindingFlags.Instance;
775 public static Expression MemberLookup (Type container_type, Type queried_type,
776 string name, Location loc)
778 return MemberLookup (container_type, null, queried_type, name,
779 AllMemberTypes, AllBindingFlags, loc);
782 public static Expression MemberLookup (Type container_type, Type qualifier_type,
783 Type queried_type, string name, Location loc)
785 return MemberLookup (container_type, qualifier_type, queried_type,
786 name, AllMemberTypes, AllBindingFlags, loc);
789 public static MethodGroupExpr MethodLookup (Type container_type, Type queried_type,
790 string name, Location loc)
792 return (MethodGroupExpr)MemberLookup (container_type, null, queried_type, name,
793 MemberTypes.Method, AllBindingFlags, loc);
796 /// <summary>
797 /// This is a wrapper for MemberLookup that is not used to "probe", but
798 /// to find a final definition. If the final definition is not found, we
799 /// look for private members and display a useful debugging message if we
800 /// find it.
801 /// </summary>
802 protected Expression MemberLookupFinal (EmitContext ec, Type qualifier_type,
803 Type queried_type, string name,
804 MemberTypes mt, BindingFlags bf,
805 Location loc)
807 Expression e;
809 int errors = Report.Errors;
810 e = MemberLookup (ec.ContainerType, qualifier_type, queried_type, name, mt, bf, loc);
812 if (e != null || errors != Report.Errors)
813 return e;
815 // No errors were reported by MemberLookup, but there was an error.
816 return Error_MemberLookupFailed (ec.ContainerType, qualifier_type, queried_type,
817 name, null, mt, bf);
820 protected virtual Expression Error_MemberLookupFailed (Type container_type, Type qualifier_type,
821 Type queried_type, string name, string class_name,
822 MemberTypes mt, BindingFlags bf)
824 if (almost_matched_members.Count != 0) {
825 for (int i = 0; i < almost_matched_members.Count; ++i) {
826 MemberInfo m = (MemberInfo) almost_matched_members [i];
827 for (int j = 0; j < i; ++j) {
828 if (m == almost_matched_members [j]) {
829 m = null;
830 break;
833 if (m == null)
834 continue;
836 Type declaring_type = m.DeclaringType;
838 Report.SymbolRelatedToPreviousError (m);
839 if (qualifier_type == null) {
840 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
841 TypeManager.CSharpName (m.DeclaringType),
842 TypeManager.CSharpName (container_type));
844 } else if (qualifier_type != container_type &&
845 TypeManager.IsNestedFamilyAccessible (container_type, declaring_type)) {
846 // Although a derived class can access protected members of
847 // its base class it cannot do so through an instance of the
848 // base class (CS1540). If the qualifier_type is a base of the
849 // ec.ContainerType and the lookup succeeds with the latter one,
850 // then we are in this situation.
851 Error_CannotAccessProtected (loc, m, qualifier_type, container_type);
852 } else {
853 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (m));
856 almost_matched_members.Clear ();
857 return null;
860 MemberInfo[] lookup = null;
861 if (queried_type == null) {
862 class_name = "global::";
863 } else {
864 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
865 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
866 name, null);
868 if (lookup != null) {
869 Report.SymbolRelatedToPreviousError (lookup [0]);
870 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (lookup [0]));
871 return Error_MemberLookupFailed (lookup);
874 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
875 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
876 name, null);
879 if (lookup == null) {
880 if (class_name != null) {
881 Report.Error (103, loc, "The name `{0}' does not exist in the current context",
882 name);
883 } else {
884 Error_TypeDoesNotContainDefinition (queried_type, name);
886 return null;
889 if (TypeManager.MemberLookup (queried_type, null, queried_type,
890 AllMemberTypes, AllBindingFlags |
891 BindingFlags.NonPublic, name, null) == null) {
892 if ((lookup.Length == 1) && (lookup [0] is Type)) {
893 Type t = (Type) lookup [0];
895 Report.Error (305, loc,
896 "Using the generic type `{0}' " +
897 "requires {1} type arguments",
898 TypeManager.CSharpName (t),
899 TypeManager.GetNumberOfTypeArguments (t).ToString ());
900 return null;
904 return Error_MemberLookupFailed (lookup);
907 protected virtual Expression Error_MemberLookupFailed (MemberInfo[] members)
909 for (int i = 0; i < members.Length; ++i) {
910 if (!(members [i] is MethodBase))
911 return null;
914 // By default propagate the closest candidates upwards
915 return new MethodGroupExpr (members, type, loc);
918 protected virtual void Error_NegativeArrayIndex (Location loc)
920 throw new NotImplementedException ();
923 protected void Error_PointerInsideExpressionTree ()
925 Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
928 /// <summary>
929 /// Returns an expression that can be used to invoke operator true
930 /// on the expression if it exists.
931 /// </summary>
932 static public Expression GetOperatorTrue (EmitContext ec, Expression e, Location loc)
934 return GetOperatorTrueOrFalse (ec, e, true, loc);
937 /// <summary>
938 /// Returns an expression that can be used to invoke operator false
939 /// on the expression if it exists.
940 /// </summary>
941 static public Expression GetOperatorFalse (EmitContext ec, Expression e, Location loc)
943 return GetOperatorTrueOrFalse (ec, e, false, loc);
946 static Expression GetOperatorTrueOrFalse (EmitContext ec, Expression e, bool is_true, Location loc)
948 MethodGroupExpr operator_group;
949 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
950 operator_group = MethodLookup (ec.ContainerType, e.Type, mname, loc) as MethodGroupExpr;
951 if (operator_group == null)
952 return null;
954 ArrayList arguments = new ArrayList (1);
955 arguments.Add (new Argument (e, Argument.AType.Expression));
956 operator_group = operator_group.OverloadResolve (
957 ec, ref arguments, false, loc);
959 if (operator_group == null)
960 return null;
962 return new UserOperatorCall (operator_group, arguments, null, loc);
965 /// <summary>
966 /// Resolves the expression `e' into a boolean expression: either through
967 /// an implicit conversion, or through an `operator true' invocation
968 /// </summary>
969 public static Expression ResolveBoolean (EmitContext ec, Expression e, Location loc)
971 e = e.Resolve (ec);
972 if (e == null)
973 return null;
975 if (e.Type == TypeManager.bool_type)
976 return e;
978 Expression converted = Convert.ImplicitConversion (ec, e, TypeManager.bool_type, Location.Null);
980 if (converted != null)
981 return converted;
984 // If no implicit conversion to bool exists, try using `operator true'
986 converted = Expression.GetOperatorTrue (ec, e, loc);
987 if (converted == null){
988 e.Error_ValueCannotBeConverted (ec, loc, TypeManager.bool_type, false);
989 return null;
991 return converted;
994 public virtual string ExprClassName
996 get {
997 switch (eclass){
998 case ExprClass.Invalid:
999 return "Invalid";
1000 case ExprClass.Value:
1001 return "value";
1002 case ExprClass.Variable:
1003 return "variable";
1004 case ExprClass.Namespace:
1005 return "namespace";
1006 case ExprClass.Type:
1007 return "type";
1008 case ExprClass.MethodGroup:
1009 return "method group";
1010 case ExprClass.PropertyAccess:
1011 return "property access";
1012 case ExprClass.EventAccess:
1013 return "event access";
1014 case ExprClass.IndexerAccess:
1015 return "indexer access";
1016 case ExprClass.Nothing:
1017 return "null";
1018 case ExprClass.TypeParameter:
1019 return "type parameter";
1021 throw new Exception ("Should not happen");
1025 /// <summary>
1026 /// Reports that we were expecting `expr' to be of class `expected'
1027 /// </summary>
1028 public void Error_UnexpectedKind (DeclSpace ds, string expected, Location loc)
1030 Error_UnexpectedKind (ds, expected, ExprClassName, loc);
1033 public void Error_UnexpectedKind (DeclSpace ds, string expected, string was, Location loc)
1035 string name = GetSignatureForError ();
1036 if (ds != null)
1037 name = ds.GetSignatureForError () + '.' + name;
1039 Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1040 name, was, expected);
1043 public void Error_UnexpectedKind (ResolveFlags flags, Location loc)
1045 string [] valid = new string [4];
1046 int count = 0;
1048 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1049 valid [count++] = "variable";
1050 valid [count++] = "value";
1053 if ((flags & ResolveFlags.Type) != 0)
1054 valid [count++] = "type";
1056 if ((flags & ResolveFlags.MethodGroup) != 0)
1057 valid [count++] = "method group";
1059 if (count == 0)
1060 valid [count++] = "unknown";
1062 StringBuilder sb = new StringBuilder (valid [0]);
1063 for (int i = 1; i < count - 1; i++) {
1064 sb.Append ("', `");
1065 sb.Append (valid [i]);
1067 if (count > 1) {
1068 sb.Append ("' or `");
1069 sb.Append (valid [count - 1]);
1072 Report.Error (119, loc,
1073 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1076 public static void UnsafeError (Location loc)
1078 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1082 // Load the object from the pointer.
1084 public static void LoadFromPtr (ILGenerator ig, Type t)
1086 if (t == TypeManager.int32_type)
1087 ig.Emit (OpCodes.Ldind_I4);
1088 else if (t == TypeManager.uint32_type)
1089 ig.Emit (OpCodes.Ldind_U4);
1090 else if (t == TypeManager.short_type)
1091 ig.Emit (OpCodes.Ldind_I2);
1092 else if (t == TypeManager.ushort_type)
1093 ig.Emit (OpCodes.Ldind_U2);
1094 else if (t == TypeManager.char_type)
1095 ig.Emit (OpCodes.Ldind_U2);
1096 else if (t == TypeManager.byte_type)
1097 ig.Emit (OpCodes.Ldind_U1);
1098 else if (t == TypeManager.sbyte_type)
1099 ig.Emit (OpCodes.Ldind_I1);
1100 else if (t == TypeManager.uint64_type)
1101 ig.Emit (OpCodes.Ldind_I8);
1102 else if (t == TypeManager.int64_type)
1103 ig.Emit (OpCodes.Ldind_I8);
1104 else if (t == TypeManager.float_type)
1105 ig.Emit (OpCodes.Ldind_R4);
1106 else if (t == TypeManager.double_type)
1107 ig.Emit (OpCodes.Ldind_R8);
1108 else if (t == TypeManager.bool_type)
1109 ig.Emit (OpCodes.Ldind_I1);
1110 else if (t == TypeManager.intptr_type)
1111 ig.Emit (OpCodes.Ldind_I);
1112 else if (TypeManager.IsEnumType (t)) {
1113 if (t == TypeManager.enum_type)
1114 ig.Emit (OpCodes.Ldind_Ref);
1115 else
1116 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1117 } else if (t.IsValueType || TypeManager.IsGenericParameter (t))
1118 ig.Emit (OpCodes.Ldobj, t);
1119 else if (t.IsPointer)
1120 ig.Emit (OpCodes.Ldind_I);
1121 else
1122 ig.Emit (OpCodes.Ldind_Ref);
1126 // The stack contains the pointer and the value of type `type'
1128 public static void StoreFromPtr (ILGenerator ig, Type type)
1130 if (TypeManager.IsEnumType (type))
1131 type = TypeManager.GetEnumUnderlyingType (type);
1132 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1133 ig.Emit (OpCodes.Stind_I4);
1134 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1135 ig.Emit (OpCodes.Stind_I8);
1136 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1137 type == TypeManager.ushort_type)
1138 ig.Emit (OpCodes.Stind_I2);
1139 else if (type == TypeManager.float_type)
1140 ig.Emit (OpCodes.Stind_R4);
1141 else if (type == TypeManager.double_type)
1142 ig.Emit (OpCodes.Stind_R8);
1143 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1144 type == TypeManager.bool_type)
1145 ig.Emit (OpCodes.Stind_I1);
1146 else if (type == TypeManager.intptr_type)
1147 ig.Emit (OpCodes.Stind_I);
1148 else if (type.IsValueType || TypeManager.IsGenericParameter (type))
1149 ig.Emit (OpCodes.Stobj, type);
1150 else
1151 ig.Emit (OpCodes.Stind_Ref);
1155 // Returns the size of type `t' if known, otherwise, 0
1157 public static int GetTypeSize (Type t)
1159 t = TypeManager.TypeToCoreType (t);
1160 if (t == TypeManager.int32_type ||
1161 t == TypeManager.uint32_type ||
1162 t == TypeManager.float_type)
1163 return 4;
1164 else if (t == TypeManager.int64_type ||
1165 t == TypeManager.uint64_type ||
1166 t == TypeManager.double_type)
1167 return 8;
1168 else if (t == TypeManager.byte_type ||
1169 t == TypeManager.sbyte_type ||
1170 t == TypeManager.bool_type)
1171 return 1;
1172 else if (t == TypeManager.short_type ||
1173 t == TypeManager.char_type ||
1174 t == TypeManager.ushort_type)
1175 return 2;
1176 else if (t == TypeManager.decimal_type)
1177 return 16;
1178 else
1179 return 0;
1182 protected void Error_CannotCallAbstractBase (string name)
1184 Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1187 protected void Error_CannotModifyIntermediateExpressionValue (EmitContext ec)
1189 Report.SymbolRelatedToPreviousError (type);
1190 if (ec.CurrentInitializerVariable != null) {
1191 Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1192 TypeManager.CSharpName (type), GetSignatureForError ());
1193 } else {
1194 Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1195 GetSignatureForError ());
1200 // Converts `source' to an int, uint, long or ulong.
1202 public Expression ConvertExpressionToArrayIndex (EmitContext ec, Expression source)
1204 Expression converted;
1206 using (ec.With (EmitContext.Flags.CheckState, true)) {
1207 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1208 if (converted == null)
1209 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1210 if (converted == null)
1211 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1212 if (converted == null)
1213 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1215 if (converted == null) {
1216 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1217 return null;
1222 // Only positive constants are allowed at compile time
1224 Constant c = converted as Constant;
1225 if (c != null) {
1226 if (c.IsNegative) {
1227 Error_NegativeArrayIndex (source.loc);
1229 return c;
1232 return new ArrayIndexCast (converted).Resolve (ec);
1236 // Derived classes implement this method by cloning the fields that
1237 // could become altered during the Resolve stage
1239 // Only expressions that are created for the parser need to implement
1240 // this.
1242 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1244 throw new NotImplementedException (
1245 String.Format (
1246 "CloneTo not implemented for expression {0}", this.GetType ()));
1250 // Clones an expression created by the parser.
1252 // We only support expressions created by the parser so far, not
1253 // expressions that have been resolved (many more classes would need
1254 // to implement CloneTo).
1256 // This infrastructure is here merely for Lambda expressions which
1257 // compile the same code using different type values for the same
1258 // arguments to find the correct overload
1260 public Expression Clone (CloneContext clonectx)
1262 Expression cloned = (Expression) MemberwiseClone ();
1263 CloneTo (clonectx, cloned);
1265 return cloned;
1269 // Implementation of expression to expression tree conversion
1271 public abstract Expression CreateExpressionTree (EmitContext ec);
1273 protected Expression CreateExpressionFactoryCall (string name, ArrayList args)
1275 return CreateExpressionFactoryCall (name, null, args, loc);
1278 protected Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args)
1280 return CreateExpressionFactoryCall (name, typeArguments, args, loc);
1283 public static Expression CreateExpressionFactoryCall (string name, TypeArguments typeArguments, ArrayList args, Location loc)
1285 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (loc), name, typeArguments, loc), args);
1288 protected static TypeExpr CreateExpressionTypeExpression (Location loc)
1290 TypeExpr texpr = TypeManager.expression_type_expr;
1291 if (texpr == null) {
1292 Type t = TypeManager.CoreLookupType ("System.Linq.Expressions", "Expression", Kind.Class, true);
1293 if (t == null)
1294 return null;
1296 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1299 return texpr;
1302 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1304 // TODO: It should probably be type = storey.MutateType (type);
1308 /// <summary>
1309 /// This is just a base class for expressions that can
1310 /// appear on statements (invocations, object creation,
1311 /// assignments, post/pre increment and decrement). The idea
1312 /// being that they would support an extra Emition interface that
1313 /// does not leave a result on the stack.
1314 /// </summary>
1315 public abstract class ExpressionStatement : Expression {
1317 public virtual ExpressionStatement ResolveStatement (EmitContext ec)
1319 Expression e = Resolve (ec);
1320 if (e == null)
1321 return null;
1323 ExpressionStatement es = e as ExpressionStatement;
1324 if (es == null)
1325 Error_InvalidExpressionStatement ();
1327 return es;
1330 /// <summary>
1331 /// Requests the expression to be emitted in a `statement'
1332 /// context. This means that no new value is left on the
1333 /// stack after invoking this method (constrasted with
1334 /// Emit that will always leave a value on the stack).
1335 /// </summary>
1336 public abstract void EmitStatement (EmitContext ec);
1338 public override void EmitSideEffect (EmitContext ec)
1340 EmitStatement (ec);
1344 /// <summary>
1345 /// This kind of cast is used to encapsulate the child
1346 /// whose type is child.Type into an expression that is
1347 /// reported to return "return_type". This is used to encapsulate
1348 /// expressions which have compatible types, but need to be dealt
1349 /// at higher levels with.
1351 /// For example, a "byte" expression could be encapsulated in one
1352 /// of these as an "unsigned int". The type for the expression
1353 /// would be "unsigned int".
1355 /// </summary>
1356 public abstract class TypeCast : Expression
1358 protected readonly Expression child;
1360 protected TypeCast (Expression child, Type return_type)
1362 eclass = child.eclass;
1363 loc = child.Location;
1364 type = return_type;
1365 this.child = child;
1368 public override Expression CreateExpressionTree (EmitContext ec)
1370 ArrayList args = new ArrayList (2);
1371 args.Add (new Argument (child.CreateExpressionTree (ec)));
1372 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1374 if (type.IsPointer || child.Type.IsPointer)
1375 Error_PointerInsideExpressionTree ();
1377 return CreateExpressionFactoryCall (ec.CheckState ? "ConvertChecked" : "Convert", args);
1380 public override Expression DoResolve (EmitContext ec)
1382 // This should never be invoked, we are born in fully
1383 // initialized state.
1385 return this;
1388 public override void Emit (EmitContext ec)
1390 child.Emit (ec);
1393 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1395 return child.GetAttributableValue (ec, value_type, out value);
1398 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1400 type = storey.MutateType (type);
1401 child.MutateHoistedGenericType (storey);
1404 protected override void CloneTo (CloneContext clonectx, Expression t)
1406 // Nothing to clone
1409 public override bool IsNull {
1410 get { return child.IsNull; }
1414 public class EmptyCast : TypeCast {
1415 EmptyCast (Expression child, Type target_type)
1416 : base (child, target_type)
1420 public static Expression Create (Expression child, Type type)
1422 Constant c = child as Constant;
1423 if (c != null)
1424 return new EmptyConstantCast (c, type);
1426 EmptyCast e = child as EmptyCast;
1427 if (e != null)
1428 return new EmptyCast (e.child, type);
1430 return new EmptyCast (child, type);
1433 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1435 child.EmitBranchable (ec, label, on_true);
1438 public override void EmitSideEffect (EmitContext ec)
1440 child.EmitSideEffect (ec);
1445 // Used for predefined class library user casts (no obsolete check, etc.)
1447 public class OperatorCast : TypeCast {
1448 MethodInfo conversion_operator;
1450 public OperatorCast (Expression child, Type target_type)
1451 : this (child, target_type, false)
1455 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1456 : base (child, target_type)
1458 conversion_operator = GetConversionOperator (find_explicit);
1459 if (conversion_operator == null)
1460 throw new InternalErrorException ("Outer conversion routine is out of sync");
1463 // Returns the implicit operator that converts from
1464 // 'child.Type' to our target type (type)
1465 MethodInfo GetConversionOperator (bool find_explicit)
1467 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1469 MemberInfo [] mi;
1471 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1472 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1474 if (mi == null){
1475 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1476 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1479 foreach (MethodInfo oper in mi) {
1480 AParametersCollection pd = TypeManager.GetParameterData (oper);
1482 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1483 return oper;
1486 return null;
1489 public override void Emit (EmitContext ec)
1491 child.Emit (ec);
1492 ec.ig.Emit (OpCodes.Call, conversion_operator);
1496 /// <summary>
1497 /// This is a numeric cast to a Decimal
1498 /// </summary>
1499 public class CastToDecimal : OperatorCast {
1500 public CastToDecimal (Expression child)
1501 : this (child, false)
1505 public CastToDecimal (Expression child, bool find_explicit)
1506 : base (child, TypeManager.decimal_type, find_explicit)
1511 /// <summary>
1512 /// This is an explicit numeric cast from a Decimal
1513 /// </summary>
1514 public class CastFromDecimal : TypeCast
1516 static IDictionary operators;
1518 public CastFromDecimal (Expression child, Type return_type)
1519 : base (child, return_type)
1521 if (child.Type != TypeManager.decimal_type)
1522 throw new InternalErrorException (
1523 "The expected type is Decimal, instead it is " + child.Type.FullName);
1526 // Returns the explicit operator that converts from an
1527 // express of type System.Decimal to 'type'.
1528 public Expression Resolve ()
1530 if (operators == null) {
1531 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1532 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1533 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1535 operators = new System.Collections.Specialized.HybridDictionary ();
1536 foreach (MethodInfo oper in all_oper) {
1537 AParametersCollection pd = TypeManager.GetParameterData (oper);
1538 if (pd.Types [0] == TypeManager.decimal_type)
1539 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1543 return operators.Contains (type) ? this : null;
1546 public override void Emit (EmitContext ec)
1548 ILGenerator ig = ec.ig;
1549 child.Emit (ec);
1551 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1557 // Constant specialization of EmptyCast.
1558 // We need to special case this since an empty cast of
1559 // a constant is still a constant.
1561 public class EmptyConstantCast : Constant
1563 public readonly Constant child;
1565 public EmptyConstantCast(Constant child, Type type)
1566 : base (child.Location)
1568 eclass = child.eclass;
1569 this.child = child;
1570 this.type = type;
1573 public override string AsString ()
1575 return child.AsString ();
1578 public override object GetValue ()
1580 return child.GetValue ();
1583 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1585 // FIXME: check that 'type' can be converted to 'target_type' first
1586 return child.ConvertExplicitly (in_checked_context, target_type);
1589 public override Expression CreateExpressionTree (EmitContext ec)
1591 ArrayList args = new ArrayList (2);
1592 args.Add (new Argument (child.CreateExpressionTree (ec)));
1593 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1594 if (type.IsPointer)
1595 Error_PointerInsideExpressionTree ();
1597 return CreateExpressionFactoryCall ("Convert", args);
1600 public override Constant Increment ()
1602 return child.Increment ();
1605 public override bool IsDefaultValue {
1606 get { return child.IsDefaultValue; }
1609 public override bool IsNegative {
1610 get { return child.IsNegative; }
1613 public override bool IsNull {
1614 get { return child.IsNull; }
1617 public override bool IsZeroInteger {
1618 get { return child.IsZeroInteger; }
1621 public override void Emit (EmitContext ec)
1623 child.Emit (ec);
1626 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1628 child.EmitBranchable (ec, label, on_true);
1631 public override void EmitSideEffect (EmitContext ec)
1633 child.EmitSideEffect (ec);
1636 public override Constant ConvertImplicitly (Type target_type)
1638 // FIXME: Do we need to check user conversions?
1639 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1640 return null;
1641 return child.ConvertImplicitly (target_type);
1644 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1646 child.MutateHoistedGenericType (storey);
1651 /// <summary>
1652 /// This class is used to wrap literals which belong inside Enums
1653 /// </summary>
1654 public class EnumConstant : Constant {
1655 public Constant Child;
1657 public EnumConstant (Constant child, Type enum_type):
1658 base (child.Location)
1660 eclass = child.eclass;
1661 this.Child = child;
1662 type = enum_type;
1665 public override Expression DoResolve (EmitContext ec)
1667 // This should never be invoked, we are born in fully
1668 // initialized state.
1670 return this;
1673 public override void Emit (EmitContext ec)
1675 Child.Emit (ec);
1678 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1680 Child.EmitBranchable (ec, label, on_true);
1683 public override void EmitSideEffect (EmitContext ec)
1685 Child.EmitSideEffect (ec);
1688 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
1690 value = GetTypedValue ();
1691 return true;
1694 public override string GetSignatureForError()
1696 return TypeManager.CSharpName (Type);
1699 public override object GetValue ()
1701 return Child.GetValue ();
1704 public override object GetTypedValue ()
1706 // FIXME: runtime is not ready to work with just emited enums
1707 if (!RootContext.StdLib) {
1708 return Child.GetValue ();
1711 #if MS_COMPATIBLE
1712 // Small workaround for big problem
1713 // System.Enum.ToObject cannot be called on dynamic types
1714 // EnumBuilder has to be used, but we cannot use EnumBuilder
1715 // because it does not properly support generics
1717 // This works only sometimes
1719 if (type.Module == CodeGen.Module.Builder)
1720 return Child.GetValue ();
1721 #endif
1723 return System.Enum.ToObject (type, Child.GetValue ());
1726 public override string AsString ()
1728 return Child.AsString ();
1731 public override Constant Increment()
1733 return new EnumConstant (Child.Increment (), type);
1736 public override bool IsDefaultValue {
1737 get {
1738 return Child.IsDefaultValue;
1742 public override bool IsZeroInteger {
1743 get { return Child.IsZeroInteger; }
1746 public override bool IsNegative {
1747 get {
1748 return Child.IsNegative;
1752 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1754 if (Child.Type == target_type)
1755 return Child;
1757 return Child.ConvertExplicitly (in_checked_context, target_type);
1760 public override Constant ConvertImplicitly (Type type)
1762 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1763 type = TypeManager.DropGenericTypeArguments (type);
1765 if (this_type == type) {
1766 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1767 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1768 return this;
1770 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1771 if (type.UnderlyingSystemType != child_type)
1772 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1773 return this;
1776 if (!Convert.ImplicitStandardConversionExists (this, type)){
1777 return null;
1780 return Child.ConvertImplicitly(type);
1785 /// <summary>
1786 /// This kind of cast is used to encapsulate Value Types in objects.
1788 /// The effect of it is to box the value type emitted by the previous
1789 /// operation.
1790 /// </summary>
1791 public class BoxedCast : TypeCast {
1793 public BoxedCast (Expression expr, Type target_type)
1794 : base (expr, target_type)
1796 eclass = ExprClass.Value;
1799 public override Expression DoResolve (EmitContext ec)
1801 // This should never be invoked, we are born in fully
1802 // initialized state.
1804 return this;
1807 public override void Emit (EmitContext ec)
1809 base.Emit (ec);
1811 ec.ig.Emit (OpCodes.Box, child.Type);
1814 public override void EmitSideEffect (EmitContext ec)
1816 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1817 // so, we need to emit the box+pop instructions in most cases
1818 if (child.Type.IsValueType &&
1819 (type == TypeManager.object_type || type == TypeManager.value_type))
1820 child.EmitSideEffect (ec);
1821 else
1822 base.EmitSideEffect (ec);
1826 public class UnboxCast : TypeCast {
1827 public UnboxCast (Expression expr, Type return_type)
1828 : base (expr, return_type)
1832 public override Expression DoResolve (EmitContext ec)
1834 // This should never be invoked, we are born in fully
1835 // initialized state.
1837 return this;
1840 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
1842 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1843 Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1844 return base.DoResolveLValue (ec, right_side);
1847 public override void Emit (EmitContext ec)
1849 ILGenerator ig = ec.ig;
1851 base.Emit (ec);
1852 #if GMCS_SOURCE
1853 if (type.IsGenericParameter || type.IsGenericType && type.IsValueType)
1854 ig.Emit (OpCodes.Unbox_Any, type);
1855 else
1856 #endif
1858 ig.Emit (OpCodes.Unbox, type);
1860 LoadFromPtr (ig, type);
1864 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1866 type = storey.MutateType (type);
1867 base.MutateHoistedGenericType (storey);
1871 /// <summary>
1872 /// This is used to perform explicit numeric conversions.
1874 /// Explicit numeric conversions might trigger exceptions in a checked
1875 /// context, so they should generate the conv.ovf opcodes instead of
1876 /// conv opcodes.
1877 /// </summary>
1878 public class ConvCast : TypeCast {
1879 public enum Mode : byte {
1880 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1881 U1_I1, U1_CH,
1882 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1883 U2_I1, U2_U1, U2_I2, U2_CH,
1884 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1885 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1886 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH,
1887 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH,
1888 CH_I1, CH_U1, CH_I2,
1889 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1890 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4
1893 Mode mode;
1895 public ConvCast (Expression child, Type return_type, Mode m)
1896 : base (child, return_type)
1898 mode = m;
1901 public override Expression DoResolve (EmitContext ec)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1906 return this;
1909 public override string ToString ()
1911 return String.Format ("ConvCast ({0}, {1})", mode, child);
1914 public override void Emit (EmitContext ec)
1916 ILGenerator ig = ec.ig;
1918 base.Emit (ec);
1920 if (ec.CheckState){
1921 switch (mode){
1922 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1923 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1924 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1925 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1926 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1928 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1929 case Mode.U1_CH: /* nothing */ break;
1931 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1932 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1933 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1934 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1935 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1936 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1938 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1939 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1940 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1941 case Mode.U2_CH: /* nothing */ break;
1943 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1944 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1945 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1946 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1947 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1948 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1949 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1951 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1952 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1953 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1954 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1955 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1956 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1958 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1959 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1960 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1961 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1963 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1964 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1965 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1968 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1969 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1970 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1971 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1972 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1973 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1974 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1976 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1977 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1978 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1980 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1981 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1982 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1983 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1984 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1985 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1986 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1987 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1988 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1990 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1991 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1992 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1993 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1994 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1995 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1996 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1997 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1998 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1999 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2001 } else {
2002 switch (mode){
2003 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2004 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2005 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2006 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2007 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2009 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2010 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2012 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2015 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2016 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2017 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2019 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2020 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2021 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2022 case Mode.U2_CH: /* nothing */ break;
2024 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2025 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2026 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2027 case Mode.I4_U4: /* nothing */ break;
2028 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2029 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2034 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2035 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2036 case Mode.U4_I4: /* nothing */ break;
2037 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2039 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2040 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2041 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2042 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2043 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2044 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2045 case Mode.I8_U8: /* nothing */ break;
2046 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2048 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2049 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2050 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2053 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2054 case Mode.U8_I8: /* nothing */ break;
2055 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2057 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2058 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2059 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2061 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2071 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2072 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2073 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2074 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2075 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2076 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2077 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2078 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2079 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2086 public class OpcodeCast : TypeCast {
2087 readonly OpCode op;
2089 public OpcodeCast (Expression child, Type return_type, OpCode op)
2090 : base (child, return_type)
2092 this.op = op;
2095 public override Expression DoResolve (EmitContext ec)
2097 // This should never be invoked, we are born in fully
2098 // initialized state.
2100 return this;
2103 public override void Emit (EmitContext ec)
2105 base.Emit (ec);
2106 ec.ig.Emit (op);
2109 public Type UnderlyingType {
2110 get { return child.Type; }
2114 /// <summary>
2115 /// This kind of cast is used to encapsulate a child and cast it
2116 /// to the class requested
2117 /// </summary>
2118 public sealed class ClassCast : TypeCast {
2119 Type child_generic_parameter;
2121 public ClassCast (Expression child, Type return_type)
2122 : base (child, return_type)
2125 if (TypeManager.IsGenericParameter (child.Type))
2126 child_generic_parameter = child.Type;
2129 public override Expression DoResolve (EmitContext ec)
2131 // This should never be invoked, we are born in fully
2132 // initialized state.
2134 return this;
2137 public override void Emit (EmitContext ec)
2139 base.Emit (ec);
2141 if (child_generic_parameter != null)
2142 ec.ig.Emit (OpCodes.Box, child_generic_parameter);
2144 #if GMCS_SOURCE
2145 if (type.IsGenericParameter)
2146 ec.ig.Emit (OpCodes.Unbox_Any, type);
2147 else
2148 #endif
2149 ec.ig.Emit (OpCodes.Castclass, type);
2152 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2154 type = storey.MutateType (type);
2155 if (child_generic_parameter != null)
2156 child_generic_parameter = storey.MutateGenericArgument (child_generic_parameter);
2158 base.MutateHoistedGenericType (storey);
2163 // Created during resolving pahse when an expression is wrapped or constantified
2164 // and original expression can be used later (e.g. for expression trees)
2166 public class ReducedExpression : Expression
2168 sealed class ReducedConstantExpression : EmptyConstantCast
2170 readonly Expression orig_expr;
2172 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2173 : base (expr, expr.Type)
2175 this.orig_expr = orig_expr;
2178 public override Constant ConvertImplicitly (Type target_type)
2180 Constant c = base.ConvertImplicitly (target_type);
2181 if (c != null)
2182 c = new ReducedConstantExpression (c, orig_expr);
2183 return c;
2186 public override Expression CreateExpressionTree (EmitContext ec)
2188 return orig_expr.CreateExpressionTree (ec);
2191 public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
2194 // Even if resolved result is a constant original expression was not
2195 // and attribute accepts constants only
2197 Attribute.Error_AttributeArgumentNotValid (orig_expr.Location);
2198 value = null;
2199 return false;
2202 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2204 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2205 if (c != null)
2206 c = new ReducedConstantExpression (c, orig_expr);
2207 return c;
2211 sealed class ReducedExpressionStatement : ExpressionStatement
2213 readonly Expression orig_expr;
2214 readonly ExpressionStatement stm;
2216 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2218 this.orig_expr = orig;
2219 this.stm = stm;
2220 this.loc = orig.Location;
2223 public override Expression CreateExpressionTree (EmitContext ec)
2225 return orig_expr.CreateExpressionTree (ec);
2228 public override Expression DoResolve (EmitContext ec)
2230 eclass = stm.eclass;
2231 type = stm.Type;
2232 return this;
2235 public override void Emit (EmitContext ec)
2237 stm.Emit (ec);
2240 public override void EmitStatement (EmitContext ec)
2242 stm.EmitStatement (ec);
2245 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2247 stm.MutateHoistedGenericType (storey);
2251 readonly Expression expr, orig_expr;
2253 private ReducedExpression (Expression expr, Expression orig_expr)
2255 this.expr = expr;
2256 this.orig_expr = orig_expr;
2257 this.loc = orig_expr.Location;
2260 public static Constant Create (Constant expr, Expression original_expr)
2262 return new ReducedConstantExpression (expr, original_expr);
2265 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2267 return new ReducedExpressionStatement (s, orig);
2270 public static Expression Create (Expression expr, Expression original_expr)
2272 Constant c = expr as Constant;
2273 if (c != null)
2274 return Create (c, original_expr);
2276 ExpressionStatement s = expr as ExpressionStatement;
2277 if (s != null)
2278 return Create (s, original_expr);
2280 return new ReducedExpression (expr, original_expr);
2283 public override Expression CreateExpressionTree (EmitContext ec)
2285 return orig_expr.CreateExpressionTree (ec);
2288 public override Expression DoResolve (EmitContext ec)
2290 eclass = expr.eclass;
2291 type = expr.Type;
2292 return this;
2295 public override void Emit (EmitContext ec)
2297 expr.Emit (ec);
2300 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2302 expr.EmitBranchable (ec, target, on_true);
2305 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2307 expr.MutateHoistedGenericType (storey);
2312 // Unresolved type name expressions
2314 public abstract class ATypeNameExpression : FullNamedExpression
2316 public readonly string Name;
2317 protected TypeArguments targs;
2319 protected ATypeNameExpression (string name, Location l)
2321 Name = name;
2322 loc = l;
2325 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2327 Name = name;
2328 this.targs = targs;
2329 loc = l;
2332 public bool HasTypeArguments {
2333 get {
2334 return targs != null;
2338 public override string GetSignatureForError ()
2340 if (targs != null) {
2341 return TypeManager.RemoveGenericArity (Name) + "<" +
2342 targs.GetSignatureForError () + ">";
2345 return Name;
2349 /// <summary>
2350 /// SimpleName expressions are formed of a single word and only happen at the beginning
2351 /// of a dotted-name.
2352 /// </summary>
2353 public class SimpleName : ATypeNameExpression {
2354 bool in_transit;
2356 public SimpleName (string name, Location l)
2357 : base (name, l)
2361 public SimpleName (string name, TypeArguments args, Location l)
2362 : base (name, args, l)
2366 public SimpleName (string name, TypeParameter[] type_params, Location l)
2367 : base (name, l)
2369 targs = new TypeArguments (l);
2370 foreach (TypeParameter type_param in type_params)
2371 targs.Add (new TypeParameterExpr (type_param, l));
2374 public static string RemoveGenericArity (string name)
2376 int start = 0;
2377 StringBuilder sb = null;
2378 do {
2379 int pos = name.IndexOf ('`', start);
2380 if (pos < 0) {
2381 if (start == 0)
2382 return name;
2384 sb.Append (name.Substring (start));
2385 break;
2388 if (sb == null)
2389 sb = new StringBuilder ();
2390 sb.Append (name.Substring (start, pos-start));
2392 pos++;
2393 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2394 pos++;
2396 start = pos;
2397 } while (start < name.Length);
2399 return sb.ToString ();
2402 public SimpleName GetMethodGroup ()
2404 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2407 public static void Error_ObjectRefRequired (EmitContext ec, Location l, string name)
2409 if (ec.IsInFieldInitializer)
2410 Report.Error (236, l,
2411 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2412 name);
2413 else
2414 Report.Error (120, l,
2415 "An object reference is required to access non-static member `{0}'",
2416 name);
2419 public bool IdenticalNameAndTypeName (EmitContext ec, Expression resolved_to, Location loc)
2421 return resolved_to != null && resolved_to.Type != null &&
2422 resolved_to.Type.Name == Name &&
2423 (ec.DeclContainer.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2426 public override Expression DoResolve (EmitContext ec)
2428 return SimpleNameResolve (ec, null, false);
2431 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
2433 return SimpleNameResolve (ec, right_side, false);
2437 public Expression DoResolve (EmitContext ec, bool intermediate)
2439 return SimpleNameResolve (ec, null, intermediate);
2442 static bool IsNestedChild (Type t, Type parent)
2444 while (parent != null) {
2445 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2446 return true;
2448 parent = parent.BaseType;
2451 return false;
2454 FullNamedExpression ResolveNested (IResolveContext ec, Type t)
2456 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2457 return null;
2459 DeclSpace ds = ec.DeclContainer;
2460 while (ds != null && !IsNestedChild (t, ds.TypeBuilder))
2461 ds = ds.Parent;
2463 if (ds == null)
2464 return null;
2466 Type[] gen_params = TypeManager.GetTypeArguments (t);
2468 int arg_count = targs != null ? targs.Count : 0;
2470 for (; (ds != null) && ds.IsGeneric; ds = ds.Parent) {
2471 if (arg_count + ds.CountTypeParameters == gen_params.Length) {
2472 TypeArguments new_args = new TypeArguments (loc);
2473 foreach (TypeParameter param in ds.TypeParameters)
2474 new_args.Add (new TypeParameterExpr (param, loc));
2476 if (targs != null)
2477 new_args.Add (targs);
2479 return new ConstructedType (t, new_args, loc);
2483 return null;
2486 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2488 FullNamedExpression fne = ec.GenericDeclContainer.LookupGeneric (Name, loc);
2489 if (fne != null)
2490 return fne.ResolveAsTypeStep (ec, silent);
2492 int errors = Report.Errors;
2493 fne = ec.DeclContainer.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2495 if (fne != null) {
2496 if (fne.Type == null)
2497 return fne;
2499 FullNamedExpression nested = ResolveNested (ec, fne.Type);
2500 if (nested != null)
2501 return nested.ResolveAsTypeStep (ec, false);
2503 if (targs != null) {
2504 ConstructedType ct = new ConstructedType (fne, targs, loc);
2505 return ct.ResolveAsTypeStep (ec, false);
2508 return fne;
2511 if (silent || errors != Report.Errors)
2512 return null;
2514 Error_TypeOrNamespaceNotFound (ec);
2515 return null;
2518 protected virtual void Error_TypeOrNamespaceNotFound (IResolveContext ec)
2520 MemberCore mc = ec.DeclContainer.GetDefinition (Name);
2521 if (mc != null) {
2522 Error_UnexpectedKind (ec.DeclContainer, "type", GetMemberType (mc), loc);
2523 return;
2526 string ns = ec.DeclContainer.NamespaceEntry.NS.Name;
2527 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2528 foreach (Assembly a in RootNamespace.Global.Assemblies) {
2529 Type type = a.GetType (fullname);
2530 if (type != null) {
2531 Report.SymbolRelatedToPreviousError (type);
2532 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type));
2533 return;
2537 Type t = ec.DeclContainer.LookupAnyGeneric (Name);
2538 if (t != null) {
2539 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2540 return;
2543 if (targs != null) {
2544 FullNamedExpression retval = ec.DeclContainer.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2545 if (retval != null) {
2546 Namespace.Error_TypeArgumentsCannotBeUsed (retval.Type, loc);
2547 return;
2551 NamespaceEntry.Error_NamespaceNotFound (loc, Name);
2554 // TODO: I am still not convinced about this. If someone else will need it
2555 // implement this as virtual property in MemberCore hierarchy
2556 public static string GetMemberType (MemberCore mc)
2558 if (mc is Property)
2559 return "property";
2560 if (mc is Indexer)
2561 return "indexer";
2562 if (mc is FieldBase)
2563 return "field";
2564 if (mc is MethodCore)
2565 return "method";
2566 if (mc is EnumMember)
2567 return "enum";
2568 if (mc is Event)
2569 return "event";
2571 return "type";
2574 Expression SimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2576 if (in_transit)
2577 return null;
2579 in_transit = true;
2580 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2581 in_transit = false;
2583 if (e == null)
2584 return null;
2586 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2587 return e;
2589 return null;
2592 /// <remarks>
2593 /// 7.5.2: Simple Names.
2595 /// Local Variables and Parameters are handled at
2596 /// parse time, so they never occur as SimpleNames.
2598 /// The `intermediate' flag is used by MemberAccess only
2599 /// and it is used to inform us that it is ok for us to
2600 /// avoid the static check, because MemberAccess might end
2601 /// up resolving the Name as a Type name and the access as
2602 /// a static type access.
2604 /// ie: Type Type; .... { Type.GetType (""); }
2606 /// Type is both an instance variable and a Type; Type.GetType
2607 /// is the static method not an instance method of type.
2608 /// </remarks>
2609 Expression DoSimpleNameResolve (EmitContext ec, Expression right_side, bool intermediate)
2611 Expression e = null;
2614 // Stage 1: Performed by the parser (binding to locals or parameters).
2616 Block current_block = ec.CurrentBlock;
2617 if (current_block != null){
2618 LocalInfo vi = current_block.GetLocalInfo (Name);
2619 if (vi != null){
2620 if (targs != null) {
2621 Report.Error (307, loc,
2622 "The variable `{0}' cannot be used with type arguments",
2623 Name);
2624 return null;
2627 LocalVariableReference var = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2628 if (right_side != null) {
2629 return var.ResolveLValue (ec, right_side, loc);
2630 } else {
2631 ResolveFlags rf = ResolveFlags.VariableOrValue;
2632 if (intermediate)
2633 rf |= ResolveFlags.DisableFlowAnalysis;
2634 return var.Resolve (ec, rf);
2638 ParameterReference pref = current_block.Toplevel.GetParameterReference (Name, loc);
2639 if (pref != null) {
2640 if (targs != null) {
2641 Report.Error (307, loc,
2642 "The variable `{0}' cannot be used with type arguments",
2643 Name);
2644 return null;
2647 if (right_side != null)
2648 return pref.ResolveLValue (ec, right_side, loc);
2649 else
2650 return pref.Resolve (ec);
2653 Expression expr = current_block.Toplevel.GetTransparentIdentifier (Name);
2654 if (expr != null) {
2655 if (right_side != null)
2656 return expr.ResolveLValue (ec, right_side, loc);
2657 return expr.Resolve (ec);
2662 // Stage 2: Lookup members
2665 Type almost_matched_type = null;
2666 ArrayList almost_matched = null;
2667 for (DeclSpace lookup_ds = ec.DeclContainer; lookup_ds != null; lookup_ds = lookup_ds.Parent) {
2668 // either RootDeclSpace or GenericMethod
2669 if (lookup_ds.TypeBuilder == null)
2670 continue;
2672 e = MemberLookup (ec.ContainerType, lookup_ds.TypeBuilder, Name, loc);
2673 if (e != null) {
2674 PropertyExpr pe = e as PropertyExpr;
2675 if (pe != null) {
2676 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2678 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2679 // it doesn't know which accessor to check permissions against
2680 if (param.IsEmpty && pe.IsAccessibleFrom (ec.ContainerType, right_side != null))
2681 break;
2682 } else if (e is EventExpr) {
2683 if (((EventExpr) e).IsAccessibleFrom (ec.ContainerType))
2684 break;
2685 } else {
2686 break;
2688 e = null;
2691 if (almost_matched == null && almost_matched_members.Count > 0) {
2692 almost_matched_type = lookup_ds.TypeBuilder;
2693 almost_matched = (ArrayList) almost_matched_members.Clone ();
2697 if (e == null) {
2698 if (almost_matched == null && almost_matched_members.Count > 0) {
2699 almost_matched_type = ec.ContainerType;
2700 almost_matched = (ArrayList) almost_matched_members.Clone ();
2702 e = ResolveAsTypeStep (ec, true);
2705 if (e == null) {
2706 if (current_block != null) {
2707 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2708 if (ikv != null) {
2709 LocalInfo li = ikv as LocalInfo;
2710 // Supress CS0219 warning
2711 if (li != null)
2712 li.Used = true;
2714 Error_VariableIsUsedBeforeItIsDeclared (Name);
2715 return null;
2719 if (RootContext.EvalMode){
2720 FieldInfo fi = Evaluator.LookupField (Name);
2721 if (fi != null)
2722 return new FieldExpr (fi, loc).Resolve (ec);
2725 if (almost_matched != null)
2726 almost_matched_members = almost_matched;
2727 if (almost_matched_type == null)
2728 almost_matched_type = ec.ContainerType;
2729 Error_MemberLookupFailed (ec.ContainerType, null, almost_matched_type, Name,
2730 ec.DeclContainer.Name, AllMemberTypes, AllBindingFlags);
2731 return null;
2734 if (e is TypeExpr) {
2735 if (targs == null)
2736 return e;
2738 ConstructedType ct = new ConstructedType (
2739 e.Type, targs, loc);
2740 return ct.ResolveAsTypeStep (ec, false);
2743 if (e is MemberExpr) {
2744 MemberExpr me = (MemberExpr) e;
2746 Expression left;
2747 if (me.IsInstance) {
2748 if (ec.IsStatic || ec.IsInFieldInitializer) {
2750 // Note that an MemberExpr can be both IsInstance and IsStatic.
2751 // An unresolved MethodGroupExpr can contain both kinds of methods
2752 // and each predicate is true if the MethodGroupExpr contains
2753 // at least one of that kind of method.
2756 if (!me.IsStatic &&
2757 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2758 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2759 return null;
2763 // Pass the buck to MemberAccess and Invocation.
2765 left = EmptyExpression.Null;
2766 } else {
2767 left = ec.GetThis (loc);
2769 } else {
2770 left = new TypeExpression (ec.ContainerType, loc);
2773 me = me.ResolveMemberAccess (ec, left, loc, null);
2774 if (me == null)
2775 return null;
2777 if (targs != null) {
2778 targs.Resolve (ec);
2779 me.SetTypeArguments (targs);
2782 if (!me.IsStatic && (me.InstanceExpression != null) &&
2783 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2784 me.InstanceExpression.Type != me.DeclaringType &&
2785 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2786 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2787 Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2788 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2789 return null;
2792 return (right_side != null)
2793 ? me.DoResolveLValue (ec, right_side)
2794 : me.DoResolve (ec);
2797 return e;
2800 protected override void CloneTo (CloneContext clonectx, Expression target)
2802 // CloneTo: Nothing, we do not keep any state on this expression
2806 /// <summary>
2807 /// Represents a namespace or a type. The name of the class was inspired by
2808 /// section 10.8.1 (Fully Qualified Names).
2809 /// </summary>
2810 public abstract class FullNamedExpression : Expression {
2812 public override Expression CreateExpressionTree (EmitContext ec)
2814 throw new NotSupportedException ("ET");
2817 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2819 throw new NotSupportedException ();
2822 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2824 return this;
2827 public override void Emit (EmitContext ec)
2829 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2830 GetSignatureForError ());
2834 /// <summary>
2835 /// Expression that evaluates to a type
2836 /// </summary>
2837 public abstract class TypeExpr : FullNamedExpression {
2838 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
2840 TypeExpr t = DoResolveAsTypeStep (ec);
2841 if (t == null)
2842 return null;
2844 eclass = ExprClass.Type;
2845 return t;
2848 override public Expression DoResolve (EmitContext ec)
2850 return ResolveAsTypeTerminal (ec, false);
2853 public virtual bool CheckAccessLevel (DeclSpace ds)
2855 return ds.CheckAccessLevel (Type);
2858 public virtual bool AsAccessible (DeclSpace ds)
2860 return ds.IsAccessibleAs (Type);
2863 public virtual bool IsClass {
2864 get { return Type.IsClass; }
2867 public virtual bool IsValueType {
2868 get { return Type.IsValueType; }
2871 public virtual bool IsInterface {
2872 get { return Type.IsInterface; }
2875 public virtual bool IsSealed {
2876 get { return Type.IsSealed; }
2879 public virtual bool CanInheritFrom ()
2881 if (Type == TypeManager.enum_type ||
2882 (Type == TypeManager.value_type && RootContext.StdLib) ||
2883 Type == TypeManager.multicast_delegate_type ||
2884 Type == TypeManager.delegate_type ||
2885 Type == TypeManager.array_type)
2886 return false;
2888 return true;
2891 protected abstract TypeExpr DoResolveAsTypeStep (IResolveContext ec);
2893 public override bool Equals (object obj)
2895 TypeExpr tobj = obj as TypeExpr;
2896 if (tobj == null)
2897 return false;
2899 return Type == tobj.Type;
2902 public override int GetHashCode ()
2904 return Type.GetHashCode ();
2907 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2909 type = storey.MutateType (type);
2913 /// <summary>
2914 /// Fully resolved Expression that already evaluated to a type
2915 /// </summary>
2916 public class TypeExpression : TypeExpr {
2917 public TypeExpression (Type t, Location l)
2919 Type = t;
2920 eclass = ExprClass.Type;
2921 loc = l;
2924 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
2926 return this;
2929 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2931 return this;
2935 /// <summary>
2936 /// Used to create types from a fully qualified name. These are just used
2937 /// by the parser to setup the core types. A TypeLookupExpression is always
2938 /// classified as a type.
2939 /// </summary>
2940 public sealed class TypeLookupExpression : TypeExpr {
2941 readonly string name;
2943 public TypeLookupExpression (string name)
2945 this.name = name;
2946 eclass = ExprClass.Type;
2949 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
2951 // It's null for corlib compilation only
2952 if (type == null)
2953 return DoResolveAsTypeStep (ec);
2955 return this;
2958 private class UnexpectedType
2962 // This performes recursive type lookup, providing support for generic types.
2963 // For example, given the type:
2965 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]]
2967 // The types will be checked in the following order:
2968 // _
2969 // System |
2970 // System.Collections |
2971 // System.Collections.Generic |
2972 // _ |
2973 // System | recursive call 1 |
2974 // System.Int32 _| | main method call
2975 // _ |
2976 // System | recursive call 2 |
2977 // System.String _| |
2978 // |
2979 // System.Collections.Generic.KeyValuePair`2[[System.Int32],[System.String]] _|
2981 private Type TypeLookup (IResolveContext ec, string name)
2983 int index = 0;
2984 int dot = 0;
2985 bool done = false;
2986 FullNamedExpression resolved = null;
2987 Type type = null;
2988 Type recursive_type = null;
2989 while (index < name.Length) {
2990 if (name[index] == '[') {
2991 int open = index;
2992 int braces = 1;
2993 do {
2994 index++;
2995 if (name[index] == '[')
2996 braces++;
2997 else if (name[index] == ']')
2998 braces--;
2999 } while (braces > 0);
3000 recursive_type = TypeLookup (ec, name.Substring (open + 1, index - open - 1));
3001 if (recursive_type == null || (recursive_type == typeof(UnexpectedType)))
3002 return recursive_type;
3004 else {
3005 if (name[index] == ',')
3006 done = true;
3007 else if ((name[index] == '.' && !done) || (index == name.Length && name[0] != '[')) {
3008 string substring = name.Substring(dot, index - dot);
3010 if (resolved == null)
3011 resolved = RootNamespace.Global.Lookup (ec.DeclContainer, substring, Location.Null);
3012 else if (resolved is Namespace)
3013 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3014 else if (type != null)
3015 type = TypeManager.GetNestedType (type, substring);
3016 else
3017 return null;
3019 if (resolved == null)
3020 return null;
3021 else if (type == null && resolved is TypeExpr)
3022 type = resolved.Type;
3024 dot = index + 1;
3027 index++;
3029 if (name[0] != '[') {
3030 string substring = name.Substring(dot, index - dot);
3032 if (type != null)
3033 return TypeManager.GetNestedType (type, substring);
3035 if (resolved != null) {
3036 resolved = (resolved as Namespace).Lookup (ec.DeclContainer, substring, Location.Null);
3037 if (resolved is TypeExpr)
3038 return resolved.Type;
3040 if (resolved == null)
3041 return null;
3043 resolved.Error_UnexpectedKind (ec.DeclContainer, "type", loc);
3044 return typeof (UnexpectedType);
3046 else
3047 return null;
3049 else
3050 return recursive_type;
3053 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3055 Type t = TypeLookup (ec, name);
3056 if (t == null) {
3057 NamespaceEntry.Error_NamespaceNotFound (loc, name);
3058 return null;
3060 if (t == typeof(UnexpectedType))
3061 return null;
3062 type = t;
3063 return this;
3066 protected override void CloneTo (CloneContext clonectx, Expression target)
3068 // CloneTo: Nothing, we do not keep any state on this expression
3071 public override string GetSignatureForError ()
3073 if (type == null)
3074 return TypeManager.CSharpName (name, null);
3076 return base.GetSignatureForError ();
3080 /// <summary>
3081 /// Represents an "unbound generic type", ie. typeof (Foo<>).
3082 /// See 14.5.11.
3083 /// </summary>
3084 public class UnboundTypeExpression : TypeExpr
3086 MemberName name;
3088 public UnboundTypeExpression (MemberName name, Location l)
3090 this.name = name;
3091 loc = l;
3094 protected override void CloneTo (CloneContext clonectx, Expression target)
3096 // Nothing to clone
3099 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
3101 Expression expr;
3102 if (name.Left != null) {
3103 Expression lexpr = name.Left.GetTypeExpression ();
3104 expr = new MemberAccess (lexpr, name.Basename);
3105 } else {
3106 expr = new SimpleName (name.Basename, loc);
3109 FullNamedExpression fne = expr.ResolveAsTypeStep (ec, false);
3110 if (fne == null)
3111 return null;
3113 type = fne.Type;
3114 return new TypeExpression (type, loc);
3118 /// <summary>
3119 /// This class denotes an expression which evaluates to a member
3120 /// of a struct or a class.
3121 /// </summary>
3122 public abstract class MemberExpr : Expression
3124 protected bool is_base;
3126 /// <summary>
3127 /// The name of this member.
3128 /// </summary>
3129 public abstract string Name {
3130 get;
3134 // When base.member is used
3136 public bool IsBase {
3137 get { return is_base; }
3138 set { is_base = value; }
3141 /// <summary>
3142 /// Whether this is an instance member.
3143 /// </summary>
3144 public abstract bool IsInstance {
3145 get;
3148 /// <summary>
3149 /// Whether this is a static member.
3150 /// </summary>
3151 public abstract bool IsStatic {
3152 get;
3155 /// <summary>
3156 /// The type which declares this member.
3157 /// </summary>
3158 public abstract Type DeclaringType {
3159 get;
3162 /// <summary>
3163 /// The instance expression associated with this member, if it's a
3164 /// non-static member.
3165 /// </summary>
3166 public Expression InstanceExpression;
3168 public static void error176 (Location loc, string name)
3170 Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3171 "with an instance reference, qualify it with a type name instead", name);
3174 public static void Error_BaseAccessInExpressionTree (Location loc)
3176 Report.Error (831, loc, "An expression tree may not contain a base access");
3179 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3181 if (InstanceExpression != null)
3182 InstanceExpression.MutateHoistedGenericType (storey);
3185 // TODO: possible optimalization
3186 // Cache resolved constant result in FieldBuilder <-> expression map
3187 public virtual MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3188 SimpleName original)
3191 // Precondition:
3192 // original == null || original.Resolve (...) ==> left
3195 if (left is TypeExpr) {
3196 left = left.ResolveAsBaseTerminal (ec, false);
3197 if (left == null)
3198 return null;
3200 // TODO: Same problem as in class.cs, TypeTerminal does not
3201 // always do all necessary checks
3202 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3203 if (oa != null && !ec.IsInObsoleteScope) {
3204 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc);
3207 ConstructedType ct = left as ConstructedType;
3208 if (ct != null && !ct.CheckConstraints (ec))
3209 return null;
3212 if (!IsStatic) {
3213 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3214 return null;
3217 return this;
3220 if (!IsInstance) {
3221 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3222 return this;
3224 return ResolveExtensionMemberAccess (left);
3227 InstanceExpression = left;
3228 return this;
3231 protected virtual MemberExpr ResolveExtensionMemberAccess (Expression left)
3233 error176 (loc, GetSignatureForError ());
3234 return this;
3237 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3239 if (IsStatic)
3240 return;
3242 if (InstanceExpression == EmptyExpression.Null) {
3243 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3244 return;
3247 if (InstanceExpression.Type.IsValueType) {
3248 if (InstanceExpression is IMemoryLocation) {
3249 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3250 } else {
3251 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3252 InstanceExpression.Emit (ec);
3253 t.Store (ec);
3254 t.AddressOf (ec, AddressOp.Store);
3256 } else
3257 InstanceExpression.Emit (ec);
3259 if (prepare_for_load)
3260 ec.ig.Emit (OpCodes.Dup);
3263 public virtual void SetTypeArguments (TypeArguments ta)
3265 // TODO: need to get correct member type
3266 Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3267 GetSignatureForError ());
3271 ///
3272 /// Represents group of extension methods
3273 ///
3274 public class ExtensionMethodGroupExpr : MethodGroupExpr
3276 readonly NamespaceEntry namespace_entry;
3277 public Expression ExtensionExpression;
3278 Argument extension_argument;
3280 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3281 : base (list, extensionType, l)
3283 this.namespace_entry = n;
3286 public override bool IsStatic {
3287 get { return true; }
3290 public bool IsTopLevel {
3291 get { return namespace_entry == null; }
3294 public override void EmitArguments (EmitContext ec, ArrayList arguments)
3296 if (arguments == null)
3297 arguments = new ArrayList (1);
3298 arguments.Insert (0, extension_argument);
3299 base.EmitArguments (ec, arguments);
3302 public override void EmitCall (EmitContext ec, ArrayList arguments)
3304 if (arguments == null)
3305 arguments = new ArrayList (1);
3306 arguments.Insert (0, extension_argument);
3307 base.EmitCall (ec, arguments);
3310 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3312 extension_argument.Expr.MutateHoistedGenericType (storey);
3313 base.MutateHoistedGenericType (storey);
3316 public override MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList arguments, bool may_fail, Location loc)
3318 if (arguments == null)
3319 arguments = new ArrayList (1);
3321 arguments.Insert (0, new Argument (ExtensionExpression));
3322 MethodGroupExpr mg = ResolveOverloadExtensions (ec, arguments, namespace_entry, loc);
3324 // Store resolved argument and restore original arguments
3325 if (mg != null)
3326 ((ExtensionMethodGroupExpr)mg).extension_argument = (Argument)arguments [0];
3327 arguments.RemoveAt (0);
3329 return mg;
3332 MethodGroupExpr ResolveOverloadExtensions (EmitContext ec, ArrayList arguments, NamespaceEntry ns, Location loc)
3334 // Use normal resolve rules
3335 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3336 if (mg != null)
3337 return mg;
3339 if (ns == null)
3340 return null;
3342 // Search continues
3343 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, null, Name, loc);
3344 if (e == null)
3345 return base.OverloadResolve (ec, ref arguments, false, loc);
3347 e.ExtensionExpression = ExtensionExpression;
3348 e.SetTypeArguments (type_arguments);
3349 return e.ResolveOverloadExtensions (ec, arguments, e.namespace_entry, loc);
3353 /// <summary>
3354 /// MethodGroupExpr represents a group of method candidates which
3355 /// can be resolved to the best method overload
3356 /// </summary>
3357 public class MethodGroupExpr : MemberExpr
3359 public interface IErrorHandler
3361 bool NoExactMatch (EmitContext ec, MethodBase method);
3364 public IErrorHandler CustomErrorHandler;
3365 public MethodBase [] Methods;
3366 MethodBase best_candidate;
3367 // TODO: make private
3368 public TypeArguments type_arguments;
3369 bool identical_type_name;
3370 Type delegate_type;
3372 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3373 : this (type, l)
3375 Methods = new MethodBase [mi.Length];
3376 mi.CopyTo (Methods, 0);
3379 public MethodGroupExpr (ArrayList list, Type type, Location l)
3380 : this (type, l)
3382 try {
3383 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3384 } catch {
3385 foreach (MemberInfo m in list){
3386 if (!(m is MethodBase)){
3387 Console.WriteLine ("Name " + m.Name);
3388 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3391 throw;
3397 protected MethodGroupExpr (Type type, Location loc)
3399 this.loc = loc;
3400 eclass = ExprClass.MethodGroup;
3401 this.type = type;
3404 public override Type DeclaringType {
3405 get {
3407 // We assume that the top-level type is in the end
3409 return Methods [Methods.Length - 1].DeclaringType;
3410 //return Methods [0].DeclaringType;
3414 public Type DelegateType {
3415 set {
3416 delegate_type = value;
3420 public bool IdenticalTypeName {
3421 get {
3422 return identical_type_name;
3426 public override string GetSignatureForError ()
3428 if (best_candidate != null)
3429 return TypeManager.CSharpSignature (best_candidate);
3431 return TypeManager.CSharpSignature (Methods [0]);
3434 public override string Name {
3435 get {
3436 return Methods [0].Name;
3440 public override bool IsInstance {
3441 get {
3442 if (best_candidate != null)
3443 return !best_candidate.IsStatic;
3445 foreach (MethodBase mb in Methods)
3446 if (!mb.IsStatic)
3447 return true;
3449 return false;
3453 public override bool IsStatic {
3454 get {
3455 if (best_candidate != null)
3456 return best_candidate.IsStatic;
3458 foreach (MethodBase mb in Methods)
3459 if (mb.IsStatic)
3460 return true;
3462 return false;
3466 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3468 return (ConstructorInfo)mg.best_candidate;
3471 public static explicit operator MethodInfo (MethodGroupExpr mg)
3473 return (MethodInfo)mg.best_candidate;
3477 // 7.4.3.3 Better conversion from expression
3478 // Returns : 1 if a->p is better,
3479 // 2 if a->q is better,
3480 // 0 if neither is better
3482 static int BetterExpressionConversion (EmitContext ec, Argument a, Type p, Type q)
3484 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3485 if (argument_type == TypeManager.anonymous_method_type && RootContext.Version > LanguageVersion.ISO_2) {
3487 // Uwrap delegate from Expression<T>
3489 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3490 p = TypeManager.GetTypeArguments (p) [0];
3492 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3493 q = TypeManager.GetTypeArguments (q) [0];
3496 p = Delegate.GetInvokeMethod (null, p).ReturnType;
3497 q = Delegate.GetInvokeMethod (null, q).ReturnType;
3498 if (p == TypeManager.void_type && q != TypeManager.void_type)
3499 return 2;
3500 if (q == TypeManager.void_type && p != TypeManager.void_type)
3501 return 1;
3502 } else {
3503 if (argument_type == p)
3504 return 1;
3506 if (argument_type == q)
3507 return 2;
3510 return BetterTypeConversion (ec, p, q);
3514 // 7.4.3.4 Better conversion from type
3516 public static int BetterTypeConversion (EmitContext ec, Type p, Type q)
3518 if (p == null || q == null)
3519 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3521 if (p == TypeManager.int32_type) {
3522 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3523 return 1;
3524 } else if (p == TypeManager.int64_type) {
3525 if (q == TypeManager.uint64_type)
3526 return 1;
3527 } else if (p == TypeManager.sbyte_type) {
3528 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3529 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3530 return 1;
3531 } else if (p == TypeManager.short_type) {
3532 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3533 q == TypeManager.uint64_type)
3534 return 1;
3537 if (q == TypeManager.int32_type) {
3538 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3539 return 2;
3540 } if (q == TypeManager.int64_type) {
3541 if (p == TypeManager.uint64_type)
3542 return 2;
3543 } else if (q == TypeManager.sbyte_type) {
3544 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3545 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3546 return 2;
3547 } if (q == TypeManager.short_type) {
3548 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3549 p == TypeManager.uint64_type)
3550 return 2;
3553 // TODO: this is expensive
3554 Expression p_tmp = new EmptyExpression (p);
3555 Expression q_tmp = new EmptyExpression (q);
3557 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3558 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3560 if (p_to_q && !q_to_p)
3561 return 1;
3563 if (q_to_p && !p_to_q)
3564 return 2;
3566 return 0;
3569 /// <summary>
3570 /// Determines "Better function" between candidate
3571 /// and the current best match
3572 /// </summary>
3573 /// <remarks>
3574 /// Returns a boolean indicating :
3575 /// false if candidate ain't better
3576 /// true if candidate is better than the current best match
3577 /// </remarks>
3578 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
3579 MethodBase candidate, bool candidate_params,
3580 MethodBase best, bool best_params)
3582 AParametersCollection candidate_pd = TypeManager.GetParameterData (candidate);
3583 AParametersCollection best_pd = TypeManager.GetParameterData (best);
3585 bool better_at_least_one = false;
3586 bool same = true;
3587 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3589 Argument a = (Argument) args [j];
3591 Type ct = candidate_pd.Types [c_idx];
3592 Type bt = best_pd.Types [b_idx];
3594 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3596 ct = TypeManager.GetElementType (ct);
3597 --c_idx;
3600 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3602 bt = TypeManager.GetElementType (bt);
3603 --b_idx;
3606 if (ct.Equals (bt))
3607 continue;
3609 same = false;
3610 int result = BetterExpressionConversion (ec, a, ct, bt);
3612 // for each argument, the conversion to 'ct' should be no worse than
3613 // the conversion to 'bt'.
3614 if (result == 2)
3615 return false;
3617 // for at least one argument, the conversion to 'ct' should be better than
3618 // the conversion to 'bt'.
3619 if (result != 0)
3620 better_at_least_one = true;
3623 if (better_at_least_one)
3624 return true;
3627 // This handles the case
3629 // Add (float f1, float f2, float f3);
3630 // Add (params decimal [] foo);
3632 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3633 // first candidate would've chosen as better.
3635 if (!same)
3636 return false;
3639 // The two methods have equal parameter types. Now apply tie-breaking rules
3641 if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
3642 return true;
3643 if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
3644 return false;
3647 // This handles the following cases:
3649 // Trim () is better than Trim (params char[] chars)
3650 // Concat (string s1, string s2, string s3) is better than
3651 // Concat (string s1, params string [] srest)
3652 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3654 if (!candidate_params && best_params)
3655 return true;
3656 if (candidate_params && !best_params)
3657 return false;
3659 int candidate_param_count = candidate_pd.Count;
3660 int best_param_count = best_pd.Count;
3662 if (candidate_param_count != best_param_count)
3663 // can only happen if (candidate_params && best_params)
3664 return candidate_param_count > best_param_count;
3667 // now, both methods have the same number of parameters, and the parameters have the same types
3668 // Pick the "more specific" signature
3671 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3672 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3674 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3675 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3677 bool specific_at_least_once = false;
3678 for (int j = 0; j < candidate_param_count; ++j)
3680 Type ct = orig_candidate_pd.Types [j];
3681 Type bt = orig_best_pd.Types [j];
3682 if (ct.Equals (bt))
3683 continue;
3684 Type specific = MoreSpecific (ct, bt);
3685 if (specific == bt)
3686 return false;
3687 if (specific == ct)
3688 specific_at_least_once = true;
3691 if (specific_at_least_once)
3692 return true;
3694 // FIXME: handle lifted operators
3695 // ...
3697 return false;
3700 protected override MemberExpr ResolveExtensionMemberAccess (Expression left)
3702 if (!IsStatic)
3703 return base.ResolveExtensionMemberAccess (left);
3706 // When left side is an expression and at least one candidate method is
3707 // static, it can be extension method
3709 InstanceExpression = left;
3710 return this;
3713 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
3714 SimpleName original)
3716 if (!(left is TypeExpr) &&
3717 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3718 identical_type_name = true;
3720 return base.ResolveMemberAccess (ec, left, loc, original);
3723 public override Expression CreateExpressionTree (EmitContext ec)
3725 if (best_candidate == null) {
3726 Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3727 return null;
3730 if (best_candidate.IsConstructor)
3731 return new TypeOfConstructorInfo (best_candidate, loc);
3733 IMethodData md = TypeManager.GetMethod (best_candidate);
3734 if (md != null && md.IsExcluded ())
3735 Report.Error (765, loc,
3736 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3738 return new TypeOfMethodInfo (best_candidate, loc);
3741 override public Expression DoResolve (EmitContext ec)
3743 if (InstanceExpression != null) {
3744 InstanceExpression = InstanceExpression.DoResolve (ec);
3745 if (InstanceExpression == null)
3746 return null;
3749 return this;
3752 public void ReportUsageError ()
3754 Report.Error (654, loc, "Method `" + DeclaringType + "." +
3755 Name + "()' is referenced without parentheses");
3758 override public void Emit (EmitContext ec)
3760 ReportUsageError ();
3763 public virtual void EmitArguments (EmitContext ec, ArrayList arguments)
3765 Invocation.EmitArguments (ec, arguments, false, null);
3768 public virtual void EmitCall (EmitContext ec, ArrayList arguments)
3770 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3773 protected virtual void Error_InvalidArguments (EmitContext ec, Location loc, int idx, MethodBase method,
3774 Argument a, AParametersCollection expected_par, Type paramType)
3776 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3778 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3779 Report.SymbolRelatedToPreviousError (method);
3780 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3781 Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3782 TypeManager.CSharpSignature (method));
3783 return;
3785 Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3786 TypeManager.CSharpSignature (method));
3787 } else if (delegate_type == null) {
3788 Report.SymbolRelatedToPreviousError (method);
3789 if (emg != null) {
3790 Report.Error (1928, loc,
3791 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3792 emg.ExtensionExpression.GetSignatureForError (),
3793 emg.Name, TypeManager.CSharpSignature (method));
3794 } else {
3795 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3796 TypeManager.CSharpSignature (method));
3798 } else
3799 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3800 TypeManager.CSharpName (delegate_type));
3802 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3804 string index = (idx + 1).ToString ();
3805 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3806 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3807 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3808 Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3809 index, Parameter.GetModifierSignature (a.Modifier));
3810 else
3811 Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3812 index, Parameter.GetModifierSignature (mod));
3813 } else {
3814 string p1 = a.GetSignatureForError ();
3815 string p2 = TypeManager.CSharpName (paramType);
3817 if (p1 == p2) {
3818 Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3819 Report.SymbolRelatedToPreviousError (a.Expr.Type);
3820 Report.SymbolRelatedToPreviousError (paramType);
3823 if (idx == 0 && emg != null) {
3824 Report.Error (1929, loc,
3825 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3826 } else {
3827 Report.Error (1503, loc,
3828 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3833 public override void Error_ValueCannotBeConverted (EmitContext ec, Location loc, Type target, bool expl)
3835 Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3836 Name, TypeManager.CSharpName (target));
3839 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3841 return parameters.Count;
3844 public static bool IsAncestralType (Type first_type, Type second_type)
3846 return first_type != second_type &&
3847 (TypeManager.IsSubclassOf (second_type, first_type) ||
3848 TypeManager.ImplementsInterface (second_type, first_type));
3852 /// Determines if the candidate method is applicable (section 14.4.2.1)
3853 /// to the given set of arguments
3854 /// A return value rates candidate method compatibility,
3855 /// 0 = the best, int.MaxValue = the worst
3857 public int IsApplicable (EmitContext ec,
3858 ArrayList arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3860 MethodBase candidate = method;
3862 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3863 int param_count = GetApplicableParametersCount (candidate, pd);
3865 if (arg_count != param_count) {
3866 if (!pd.HasParams)
3867 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3868 if (arg_count < param_count - 1)
3869 return int.MaxValue - 10000 + Math.Abs (arg_count - param_count);
3872 #if GMCS_SOURCE
3874 // 1. Handle generic method using type arguments when specified or type inference
3876 if (TypeManager.IsGenericMethod (candidate)) {
3877 if (type_arguments != null) {
3878 Type [] g_args = candidate.GetGenericArguments ();
3879 if (g_args.Length != type_arguments.Count)
3880 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3882 // TODO: Don't create new method, create Parameters only
3883 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3884 candidate = method;
3885 pd = TypeManager.GetParameterData (candidate);
3886 } else {
3887 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3888 if (score != 0)
3889 return score - 20000;
3891 if (TypeManager.IsGenericMethodDefinition (candidate))
3892 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3893 TypeManager.CSharpSignature (candidate));
3895 pd = TypeManager.GetParameterData (candidate);
3897 } else {
3898 if (type_arguments != null)
3899 return int.MaxValue - 15000;
3901 #endif
3904 // 2. Each argument has to be implicitly convertible to method parameter
3906 method = candidate;
3907 Parameter.Modifier p_mod = 0;
3908 Type pt = null;
3909 for (int i = 0; i < arg_count; i++) {
3910 Argument a = (Argument) arguments [i];
3911 Parameter.Modifier a_mod = a.Modifier &
3912 ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3914 if (p_mod != Parameter.Modifier.PARAMS) {
3915 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3917 if (p_mod == Parameter.Modifier.ARGLIST) {
3918 if (a.Type == TypeManager.runtime_argument_handle_type)
3919 continue;
3921 p_mod = 0;
3924 pt = pd.Types [i];
3925 } else {
3926 params_expanded_form = true;
3929 int score = 1;
3930 if (!params_expanded_form)
3931 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3933 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0) {
3934 // It can be applicable in expanded form
3935 score = IsArgumentCompatible (ec, a_mod, a, 0, pt.GetElementType ());
3936 if (score == 0)
3937 params_expanded_form = true;
3940 if (score != 0) {
3941 if (params_expanded_form)
3942 ++score;
3943 return (arg_count - i) * 2 + score;
3947 if (arg_count != param_count)
3948 params_expanded_form = true;
3950 return 0;
3953 int IsArgumentCompatible (EmitContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
3956 // Types have to be identical when ref or out modifer is used
3958 if (arg_mod != 0 || param_mod != 0) {
3959 if (TypeManager.HasElementType (parameter))
3960 parameter = parameter.GetElementType ();
3962 Type a_type = argument.Type;
3963 if (TypeManager.HasElementType (a_type))
3964 a_type = a_type.GetElementType ();
3966 if (a_type != parameter)
3967 return 2;
3968 } else {
3969 if (delegate_type != null ?
3970 !Delegate.IsTypeCovariant (argument.Expr, parameter) :
3971 !Convert.ImplicitConversionExists (ec, argument.Expr, parameter))
3972 return 2;
3975 if (arg_mod != param_mod)
3976 return 1;
3978 return 0;
3981 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
3983 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
3984 return false;
3986 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
3987 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
3989 if (cand_pd.Count != base_pd.Count)
3990 return false;
3992 for (int j = 0; j < cand_pd.Count; ++j)
3994 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
3995 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
3996 Type ct = cand_pd.Types [j];
3997 Type bt = base_pd.Types [j];
3999 if (cm != bm || ct != bt)
4000 return false;
4003 return true;
4006 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4008 if (mg1 == null) {
4009 if (mg2 == null)
4010 return null;
4011 return mg2;
4014 if (mg2 == null)
4015 return mg1;
4017 ArrayList all = new ArrayList (mg1.Methods);
4018 foreach (MethodBase m in mg2.Methods){
4019 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
4020 all.Add (m);
4023 return new MethodGroupExpr (all, null, loc);
4026 static Type MoreSpecific (Type p, Type q)
4028 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4029 return q;
4030 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4031 return p;
4033 if (TypeManager.HasElementType (p))
4035 Type pe = TypeManager.GetElementType (p);
4036 Type qe = TypeManager.GetElementType (q);
4037 Type specific = MoreSpecific (pe, qe);
4038 if (specific == pe)
4039 return p;
4040 if (specific == qe)
4041 return q;
4043 else if (TypeManager.IsGenericType (p))
4045 Type[] pargs = TypeManager.GetTypeArguments (p);
4046 Type[] qargs = TypeManager.GetTypeArguments (q);
4048 bool p_specific_at_least_once = false;
4049 bool q_specific_at_least_once = false;
4051 for (int i = 0; i < pargs.Length; i++)
4053 Type specific = MoreSpecific (pargs [i], qargs [i]);
4054 if (specific == pargs [i])
4055 p_specific_at_least_once = true;
4056 if (specific == qargs [i])
4057 q_specific_at_least_once = true;
4060 if (p_specific_at_least_once && !q_specific_at_least_once)
4061 return p;
4062 if (!p_specific_at_least_once && q_specific_at_least_once)
4063 return q;
4066 return null;
4069 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4071 base.MutateHoistedGenericType (storey);
4073 MethodInfo mi = best_candidate as MethodInfo;
4074 if (mi != null) {
4075 best_candidate = storey.MutateGenericMethod (mi);
4076 return;
4079 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4082 /// <summary>
4083 /// Find the Applicable Function Members (7.4.2.1)
4085 /// me: Method Group expression with the members to select.
4086 /// it might contain constructors or methods (or anything
4087 /// that maps to a method).
4089 /// Arguments: ArrayList containing resolved Argument objects.
4091 /// loc: The location if we want an error to be reported, or a Null
4092 /// location for "probing" purposes.
4094 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4095 /// that is the best match of me on Arguments.
4097 /// </summary>
4098 public virtual MethodGroupExpr OverloadResolve (EmitContext ec, ref ArrayList Arguments,
4099 bool may_fail, Location loc)
4101 bool method_params = false;
4102 Type applicable_type = null;
4103 int arg_count = 0;
4104 ArrayList candidates = new ArrayList (2);
4105 ArrayList candidate_overrides = null;
4108 // Used to keep a map between the candidate
4109 // and whether it is being considered in its
4110 // normal or expanded form
4112 // false is normal form, true is expanded form
4114 Hashtable candidate_to_form = null;
4116 if (Arguments != null)
4117 arg_count = Arguments.Count;
4119 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4120 if (!may_fail)
4121 Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4122 return null;
4125 int nmethods = Methods.Length;
4127 if (!IsBase) {
4129 // Methods marked 'override' don't take part in 'applicable_type'
4130 // computation, nor in the actual overload resolution.
4131 // However, they still need to be emitted instead of a base virtual method.
4132 // So, we salt them away into the 'candidate_overrides' array.
4134 // In case of reflected methods, we replace each overriding method with
4135 // its corresponding base virtual method. This is to improve compatibility
4136 // with non-C# libraries which change the visibility of overrides (#75636)
4138 int j = 0;
4139 for (int i = 0; i < Methods.Length; ++i) {
4140 MethodBase m = Methods [i];
4141 if (TypeManager.IsOverride (m)) {
4142 if (candidate_overrides == null)
4143 candidate_overrides = new ArrayList ();
4144 candidate_overrides.Add (m);
4145 m = TypeManager.TryGetBaseDefinition (m);
4147 if (m != null)
4148 Methods [j++] = m;
4150 nmethods = j;
4154 // Enable message recording, it's used mainly by lambda expressions
4156 Report.IMessageRecorder msg_recorder = new Report.MessageRecorder ();
4157 Report.IMessageRecorder prev_recorder = Report.SetMessageRecorder (msg_recorder);
4160 // First we construct the set of applicable methods
4162 bool is_sorted = true;
4163 int best_candidate_rate = int.MaxValue;
4164 for (int i = 0; i < nmethods; i++) {
4165 Type decl_type = Methods [i].DeclaringType;
4168 // If we have already found an applicable method
4169 // we eliminate all base types (Section 14.5.5.1)
4171 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4172 continue;
4175 // Check if candidate is applicable (section 14.4.2.1)
4177 bool params_expanded_form = false;
4178 int candidate_rate = IsApplicable (ec, Arguments, arg_count, ref Methods [i], ref params_expanded_form);
4180 if (candidate_rate < best_candidate_rate) {
4181 best_candidate_rate = candidate_rate;
4182 best_candidate = Methods [i];
4185 if (params_expanded_form) {
4186 if (candidate_to_form == null)
4187 candidate_to_form = new PtrHashtable ();
4188 MethodBase candidate = Methods [i];
4189 candidate_to_form [candidate] = candidate;
4192 if (candidate_rate != 0) {
4193 if (msg_recorder != null)
4194 msg_recorder.EndSession ();
4195 continue;
4198 msg_recorder = null;
4199 candidates.Add (Methods [i]);
4201 if (applicable_type == null)
4202 applicable_type = decl_type;
4203 else if (applicable_type != decl_type) {
4204 is_sorted = false;
4205 if (IsAncestralType (applicable_type, decl_type))
4206 applicable_type = decl_type;
4210 Report.SetMessageRecorder (prev_recorder);
4211 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4212 if (!may_fail)
4213 msg_recorder.PrintMessages ();
4215 return null;
4218 int candidate_top = candidates.Count;
4220 if (applicable_type == null) {
4222 // When we found a top level method which does not match and it's
4223 // not an extension method. We start extension methods lookup from here
4225 if (InstanceExpression != null) {
4226 ExtensionMethodGroupExpr ex_method_lookup = ec.TypeContainer.LookupExtensionMethod (type, Name, loc);
4227 if (ex_method_lookup != null) {
4228 ex_method_lookup.ExtensionExpression = InstanceExpression;
4229 ex_method_lookup.SetTypeArguments (type_arguments);
4230 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4234 if (may_fail)
4235 return null;
4238 // Okay so we have failed to find exact match so we
4239 // return error info about the closest match
4241 if (best_candidate != null) {
4242 if (CustomErrorHandler != null) {
4243 if (CustomErrorHandler.NoExactMatch (ec, best_candidate))
4244 return null;
4247 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4248 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4249 if (arg_count == pd.Count || pd.HasParams) {
4250 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4251 if (type_arguments == null) {
4252 Report.Error (411, loc,
4253 "The type arguments for method `{0}' cannot be inferred from " +
4254 "the usage. Try specifying the type arguments explicitly",
4255 TypeManager.CSharpSignature (best_candidate));
4256 return null;
4259 Type [] g_args = TypeManager.GetGenericArguments (best_candidate);
4260 if (type_arguments.Count != g_args.Length) {
4261 Report.SymbolRelatedToPreviousError (best_candidate);
4262 Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4263 TypeManager.CSharpSignature (best_candidate),
4264 g_args.Length.ToString ());
4265 return null;
4267 } else {
4268 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4269 Namespace.Error_TypeArgumentsCannotBeUsed (best_candidate, loc);
4270 return null;
4274 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, may_fail, loc))
4275 return null;
4279 if (almost_matched_members.Count != 0) {
4280 Error_MemberLookupFailed (ec.ContainerType, type, type, ".ctor",
4281 null, MemberTypes.Constructor, AllBindingFlags);
4282 return null;
4286 // We failed to find any method with correct argument count
4288 if (Name == ConstructorInfo.ConstructorName) {
4289 Report.SymbolRelatedToPreviousError (type);
4290 Report.Error (1729, loc,
4291 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4292 TypeManager.CSharpName (type), arg_count);
4293 } else {
4294 Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4295 Name, arg_count.ToString ());
4298 return null;
4301 if (!is_sorted) {
4303 // At this point, applicable_type is _one_ of the most derived types
4304 // in the set of types containing the methods in this MethodGroup.
4305 // Filter the candidates so that they only contain methods from the
4306 // most derived types.
4309 int finalized = 0; // Number of finalized candidates
4311 do {
4312 // Invariant: applicable_type is a most derived type
4314 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4315 // eliminating all it's base types. At the same time, we'll also move
4316 // every unrelated type to the end of the array, and pick the next
4317 // 'applicable_type'.
4319 Type next_applicable_type = null;
4320 int j = finalized; // where to put the next finalized candidate
4321 int k = finalized; // where to put the next undiscarded candidate
4322 for (int i = finalized; i < candidate_top; ++i) {
4323 MethodBase candidate = (MethodBase) candidates [i];
4324 Type decl_type = candidate.DeclaringType;
4326 if (decl_type == applicable_type) {
4327 candidates [k++] = candidates [j];
4328 candidates [j++] = candidates [i];
4329 continue;
4332 if (IsAncestralType (decl_type, applicable_type))
4333 continue;
4335 if (next_applicable_type != null &&
4336 IsAncestralType (decl_type, next_applicable_type))
4337 continue;
4339 candidates [k++] = candidates [i];
4341 if (next_applicable_type == null ||
4342 IsAncestralType (next_applicable_type, decl_type))
4343 next_applicable_type = decl_type;
4346 applicable_type = next_applicable_type;
4347 finalized = j;
4348 candidate_top = k;
4349 } while (applicable_type != null);
4353 // Now we actually find the best method
4356 best_candidate = (MethodBase) candidates [0];
4357 if (delegate_type == null)
4358 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4360 for (int ix = 1; ix < candidate_top; ix++) {
4361 MethodBase candidate = (MethodBase) candidates [ix];
4363 if (candidate == best_candidate)
4364 continue;
4366 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4368 if (BetterFunction (ec, Arguments, arg_count,
4369 candidate, cand_params,
4370 best_candidate, method_params)) {
4371 best_candidate = candidate;
4372 method_params = cand_params;
4376 // Now check that there are no ambiguities i.e the selected method
4377 // should be better than all the others
4379 MethodBase ambiguous = null;
4380 for (int ix = 1; ix < candidate_top; ix++) {
4381 MethodBase candidate = (MethodBase) candidates [ix];
4383 if (candidate == best_candidate)
4384 continue;
4386 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4387 if (!BetterFunction (ec, Arguments, arg_count,
4388 best_candidate, method_params,
4389 candidate, cand_params))
4391 if (!may_fail)
4392 Report.SymbolRelatedToPreviousError (candidate);
4393 ambiguous = candidate;
4397 if (ambiguous != null) {
4398 Report.SymbolRelatedToPreviousError (best_candidate);
4399 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4400 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
4401 return this;
4405 // If the method is a virtual function, pick an override closer to the LHS type.
4407 if (!IsBase && best_candidate.IsVirtual) {
4408 if (TypeManager.IsOverride (best_candidate))
4409 throw new InternalErrorException (
4410 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4412 if (candidate_overrides != null) {
4413 Type[] gen_args = null;
4414 bool gen_override = false;
4415 if (TypeManager.IsGenericMethod (best_candidate))
4416 gen_args = TypeManager.GetGenericArguments (best_candidate);
4418 foreach (MethodBase candidate in candidate_overrides) {
4419 if (TypeManager.IsGenericMethod (candidate)) {
4420 if (gen_args == null)
4421 continue;
4423 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4424 continue;
4425 } else {
4426 if (gen_args != null)
4427 continue;
4430 if (IsOverride (candidate, best_candidate)) {
4431 gen_override = true;
4432 best_candidate = candidate;
4436 if (gen_override && gen_args != null) {
4437 #if GMCS_SOURCE
4438 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4439 #endif
4445 // And now check if the arguments are all
4446 // compatible, perform conversions if
4447 // necessary etc. and return if everything is
4448 // all right
4450 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate,
4451 method_params, may_fail, loc))
4452 return null;
4454 if (best_candidate == null)
4455 return null;
4457 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4458 #if GMCS_SOURCE
4459 if (the_method.IsGenericMethodDefinition &&
4460 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4461 return null;
4462 #endif
4465 // Check ObsoleteAttribute on the best method
4467 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4468 if (oa != null && !ec.IsInObsoleteScope)
4469 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
4471 IMethodData data = TypeManager.GetMethod (the_method);
4472 if (data != null)
4473 data.SetMemberIsUsed ();
4475 return this;
4478 public override void SetTypeArguments (TypeArguments ta)
4480 type_arguments = ta;
4483 public bool VerifyArgumentsCompat (EmitContext ec, ref ArrayList arguments,
4484 int arg_count, MethodBase method,
4485 bool chose_params_expanded,
4486 bool may_fail, Location loc)
4488 AParametersCollection pd = TypeManager.GetParameterData (method);
4490 int errors = Report.Errors;
4491 Parameter.Modifier p_mod = 0;
4492 Type pt = null;
4493 int a_idx = 0, a_pos = 0;
4494 Argument a = null;
4495 ArrayList params_initializers = null;
4496 bool has_unsafe_arg = false;
4498 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4499 a = (Argument) arguments [a_idx];
4500 if (p_mod != Parameter.Modifier.PARAMS) {
4501 p_mod = pd.FixedParameters [a_idx].ModFlags;
4502 pt = pd.Types [a_idx];
4503 has_unsafe_arg |= pt.IsPointer;
4505 if (p_mod == Parameter.Modifier.ARGLIST) {
4506 if (a.Type != TypeManager.runtime_argument_handle_type)
4507 break;
4508 continue;
4511 if (p_mod == Parameter.Modifier.PARAMS) {
4512 if (chose_params_expanded) {
4513 params_initializers = new ArrayList (arg_count - a_idx);
4514 pt = TypeManager.GetElementType (pt);
4520 // Types have to be identical when ref or out modifer is used
4522 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4523 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4524 break;
4526 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4527 break;
4529 continue;
4532 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4533 if (conv == null)
4534 break;
4537 // Convert params arguments to an array initializer
4539 if (params_initializers != null) {
4540 // we choose to use 'a.Expr' rather than 'conv' so that
4541 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4542 params_initializers.Add (a.Expr);
4543 arguments.RemoveAt (a_idx--);
4544 --arg_count;
4545 continue;
4548 // Update the argument with the implicit conversion
4549 a.Expr = conv;
4553 // Fill not provided arguments required by params modifier
4555 if (params_initializers == null && pd.HasParams && arg_count < pd.Count && a_idx + 1 == pd.Count) {
4556 if (arguments == null)
4557 arguments = new ArrayList (1);
4559 pt = pd.Types [GetApplicableParametersCount (method, pd) - 1];
4560 pt = TypeManager.GetElementType (pt);
4561 has_unsafe_arg |= pt.IsPointer;
4562 params_initializers = new ArrayList (0);
4565 if (a_idx == arg_count) {
4567 // Append an array argument with all params arguments
4569 if (params_initializers != null) {
4570 arguments.Add (new Argument (
4571 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4572 params_initializers, loc).Resolve (ec)));
4575 if (has_unsafe_arg && !ec.InUnsafe) {
4576 if (!may_fail)
4577 UnsafeError (loc);
4578 return false;
4581 return true;
4584 if (!may_fail && Report.Errors == errors) {
4585 if (CustomErrorHandler != null)
4586 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4587 else
4588 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4590 return false;
4594 public class ConstantExpr : MemberExpr
4596 FieldInfo constant;
4598 public ConstantExpr (FieldInfo constant, Location loc)
4600 this.constant = constant;
4601 this.loc = loc;
4604 public override string Name {
4605 get { throw new NotImplementedException (); }
4608 public override bool IsInstance {
4609 get { return !IsStatic; }
4612 public override bool IsStatic {
4613 get { return constant.IsStatic; }
4616 public override Type DeclaringType {
4617 get { return constant.DeclaringType; }
4620 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc, SimpleName original)
4622 constant = TypeManager.GetGenericFieldDefinition (constant);
4624 IConstant ic = TypeManager.GetConstant (constant);
4625 if (ic == null) {
4626 if (constant.IsLiteral) {
4627 ic = new ExternalConstant (constant);
4628 } else {
4629 ic = ExternalConstant.CreateDecimal (constant);
4630 // HACK: decimal field was not resolved as constant
4631 if (ic == null)
4632 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4634 TypeManager.RegisterConstant (constant, ic);
4637 return base.ResolveMemberAccess (ec, left, loc, original);
4640 public override Expression CreateExpressionTree (EmitContext ec)
4642 throw new NotSupportedException ("ET");
4645 public override Expression DoResolve (EmitContext ec)
4647 IConstant ic = TypeManager.GetConstant (constant);
4648 if (ic.ResolveValue ()) {
4649 if (!ec.IsInObsoleteScope)
4650 ic.CheckObsoleteness (loc);
4653 return ic.CreateConstantReference (loc);
4656 public override void Emit (EmitContext ec)
4658 throw new NotSupportedException ();
4661 public override string GetSignatureForError ()
4663 return TypeManager.GetFullNameSignature (constant);
4667 /// <summary>
4668 /// Fully resolved expression that evaluates to a Field
4669 /// </summary>
4670 public class FieldExpr : MemberExpr, IAssignMethod, IMemoryLocation, IVariableReference {
4671 public FieldInfo FieldInfo;
4672 readonly Type constructed_generic_type;
4673 VariableInfo variable_info;
4675 LocalTemporary temp;
4676 bool prepared;
4678 public FieldExpr (FieldInfo fi, Location l)
4680 FieldInfo = fi;
4681 type = TypeManager.TypeToCoreType (fi.FieldType);
4682 loc = l;
4685 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4686 : this (fi, l)
4688 this.constructed_generic_type = genericType;
4691 public override string Name {
4692 get {
4693 return FieldInfo.Name;
4697 public override bool IsInstance {
4698 get {
4699 return !FieldInfo.IsStatic;
4703 public override bool IsStatic {
4704 get {
4705 return FieldInfo.IsStatic;
4709 public override Type DeclaringType {
4710 get {
4711 return FieldInfo.DeclaringType;
4715 public override string GetSignatureForError ()
4717 return TypeManager.GetFullNameSignature (FieldInfo);
4720 public VariableInfo VariableInfo {
4721 get {
4722 return variable_info;
4726 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
4727 SimpleName original)
4729 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4730 Type t = fi.FieldType;
4732 if (t.IsPointer && !ec.InUnsafe) {
4733 UnsafeError (loc);
4736 return base.ResolveMemberAccess (ec, left, loc, original);
4739 public void SetHasAddressTaken ()
4741 IVariableReference vr = InstanceExpression as IVariableReference;
4742 if (vr != null)
4743 vr.SetHasAddressTaken ();
4746 public override Expression CreateExpressionTree (EmitContext ec)
4748 Expression instance;
4749 if (InstanceExpression == null) {
4750 instance = new NullLiteral (loc);
4751 } else {
4752 instance = InstanceExpression.CreateExpressionTree (ec);
4755 ArrayList args = new ArrayList (2);
4756 args.Add (new Argument (instance));
4757 args.Add (new Argument (CreateTypeOfExpression ()));
4758 return CreateExpressionFactoryCall ("Field", args);
4761 public Expression CreateTypeOfExpression ()
4763 return new TypeOfField (FieldInfo, loc);
4766 override public Expression DoResolve (EmitContext ec)
4768 return DoResolve (ec, false, false);
4771 Expression DoResolve (EmitContext ec, bool lvalue_instance, bool out_access)
4773 if (!FieldInfo.IsStatic){
4774 if (InstanceExpression == null){
4776 // This can happen when referencing an instance field using
4777 // a fully qualified type expression: TypeName.InstanceField = xxx
4779 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4780 return null;
4783 // Resolve the field's instance expression while flow analysis is turned
4784 // off: when accessing a field "a.b", we must check whether the field
4785 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4787 if (lvalue_instance) {
4788 using (ec.With (EmitContext.Flags.DoFlowAnalysis, false)) {
4789 Expression right_side =
4790 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4791 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side, loc);
4793 } else {
4794 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4795 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4798 if (InstanceExpression == null)
4799 return null;
4801 using (ec.Set (EmitContext.Flags.OmitStructFlowAnalysis)) {
4802 InstanceExpression.CheckMarshalByRefAccess (ec);
4806 // TODO: the code above uses some non-standard multi-resolve rules
4807 if (eclass != ExprClass.Invalid)
4808 return this;
4810 if (!ec.IsInObsoleteScope) {
4811 FieldBase f = TypeManager.GetField (FieldInfo);
4812 if (f != null) {
4813 f.CheckObsoleteness (loc);
4814 } else {
4815 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
4816 if (oa != null)
4817 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc);
4821 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
4822 IVariableReference var = InstanceExpression as IVariableReference;
4824 if (fb != null) {
4825 IFixedExpression fe = InstanceExpression as IFixedExpression;
4826 if (!ec.InFixedInitializer && (fe == null || !fe.IsFixed)) {
4827 Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4830 if (InstanceExpression.eclass != ExprClass.Variable) {
4831 Report.SymbolRelatedToPreviousError (FieldInfo);
4832 Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4833 TypeManager.GetFullNameSignature (FieldInfo));
4834 } else if (var != null && var.IsHoisted) {
4835 AnonymousMethodExpression.Error_AddressOfCapturedVar (var, loc);
4838 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4841 eclass = ExprClass.Variable;
4843 // If the instance expression is a local variable or parameter.
4844 if (var == null || var.VariableInfo == null)
4845 return this;
4847 VariableInfo vi = var.VariableInfo;
4848 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
4849 return null;
4851 variable_info = vi.GetSubStruct (FieldInfo.Name);
4852 eclass = ExprClass.Variable;
4853 return this;
4856 static readonly int [] codes = {
4857 191, // instance, write access
4858 192, // instance, out access
4859 198, // static, write access
4860 199, // static, out access
4861 1648, // member of value instance, write access
4862 1649, // member of value instance, out access
4863 1650, // member of value static, write access
4864 1651 // member of value static, out access
4867 static readonly string [] msgs = {
4868 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4869 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4870 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4871 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4872 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4873 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4874 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4875 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4878 // The return value is always null. Returning a value simplifies calling code.
4879 Expression Report_AssignToReadonly (Expression right_side)
4881 int i = 0;
4882 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4883 i += 1;
4884 if (IsStatic)
4885 i += 2;
4886 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4887 i += 4;
4888 Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4890 return null;
4893 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4895 IVariableReference var = InstanceExpression as IVariableReference;
4896 if (var != null && var.VariableInfo != null)
4897 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
4899 bool lvalue_instance = !FieldInfo.IsStatic && FieldInfo.DeclaringType.IsValueType;
4900 bool out_access = right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess;
4902 Expression e = DoResolve (ec, lvalue_instance, out_access);
4904 if (e == null)
4905 return null;
4907 FieldBase fb = TypeManager.GetField (FieldInfo);
4908 if (fb != null)
4909 fb.SetAssigned ();
4911 if (FieldInfo.IsInitOnly) {
4912 // InitOnly fields can only be assigned in constructors or initializers
4913 if (!ec.IsInFieldInitializer && !ec.IsConstructor)
4914 return Report_AssignToReadonly (right_side);
4916 if (ec.IsConstructor) {
4917 Type ctype = ec.TypeContainer.CurrentType;
4918 if (ctype == null)
4919 ctype = ec.ContainerType;
4921 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4922 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
4923 return Report_AssignToReadonly (right_side);
4924 // static InitOnly fields cannot be assigned-to in an instance constructor
4925 if (IsStatic && !ec.IsStatic)
4926 return Report_AssignToReadonly (right_side);
4927 // instance constructors can't modify InitOnly fields of other instances of the same type
4928 if (!IsStatic && !(InstanceExpression is This))
4929 return Report_AssignToReadonly (right_side);
4933 if (right_side == EmptyExpression.OutAccess &&
4934 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
4935 Report.SymbolRelatedToPreviousError (DeclaringType);
4936 Report.Warning (197, 1, loc,
4937 "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",
4938 GetSignatureForError ());
4941 eclass = ExprClass.Variable;
4942 return this;
4945 bool is_marshal_by_ref ()
4947 return !IsStatic && Type.IsValueType && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
4950 public override void CheckMarshalByRefAccess (EmitContext ec)
4952 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
4953 Report.SymbolRelatedToPreviousError (DeclaringType);
4954 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",
4955 GetSignatureForError ());
4959 public override int GetHashCode ()
4961 return FieldInfo.GetHashCode ();
4964 public bool IsFixed {
4965 get {
4967 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4969 IVariableReference variable = InstanceExpression as IVariableReference;
4970 return variable != null && InstanceExpression.Type.IsValueType && variable.IsFixed;
4974 public bool IsHoisted {
4975 get {
4976 IVariableReference hv = InstanceExpression as IVariableReference;
4977 return hv != null && hv.IsHoisted;
4981 public override bool Equals (object obj)
4983 FieldExpr fe = obj as FieldExpr;
4984 if (fe == null)
4985 return false;
4987 if (FieldInfo != fe.FieldInfo)
4988 return false;
4990 if (InstanceExpression == null || fe.InstanceExpression == null)
4991 return true;
4993 return InstanceExpression.Equals (fe.InstanceExpression);
4996 public void Emit (EmitContext ec, bool leave_copy)
4998 ILGenerator ig = ec.ig;
4999 bool is_volatile = false;
5001 FieldBase f = TypeManager.GetField (FieldInfo);
5002 if (f != null){
5003 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5004 is_volatile = true;
5006 f.SetMemberIsUsed ();
5009 if (FieldInfo.IsStatic){
5010 if (is_volatile)
5011 ig.Emit (OpCodes.Volatile);
5013 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5014 } else {
5015 if (!prepared)
5016 EmitInstance (ec, false);
5018 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5019 if (ff != null) {
5020 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5021 ig.Emit (OpCodes.Ldflda, ff.Element);
5022 } else {
5023 if (is_volatile)
5024 ig.Emit (OpCodes.Volatile);
5026 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5030 if (leave_copy) {
5031 ec.ig.Emit (OpCodes.Dup);
5032 if (!FieldInfo.IsStatic) {
5033 temp = new LocalTemporary (this.Type);
5034 temp.Store (ec);
5039 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5041 FieldAttributes fa = FieldInfo.Attributes;
5042 bool is_static = (fa & FieldAttributes.Static) != 0;
5043 bool is_readonly = (fa & FieldAttributes.InitOnly) != 0;
5044 ILGenerator ig = ec.ig;
5046 if (is_readonly && !ec.IsConstructor){
5047 Report_AssignToReadonly (source);
5048 return;
5051 prepared = prepare_for_load;
5052 EmitInstance (ec, prepared);
5054 source.Emit (ec);
5055 if (leave_copy) {
5056 ec.ig.Emit (OpCodes.Dup);
5057 if (!FieldInfo.IsStatic) {
5058 temp = new LocalTemporary (this.Type);
5059 temp.Store (ec);
5063 FieldBase f = TypeManager.GetField (FieldInfo);
5064 if (f != null){
5065 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5066 ig.Emit (OpCodes.Volatile);
5068 f.SetAssigned ();
5071 if (is_static)
5072 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5073 else
5074 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5076 if (temp != null) {
5077 temp.Emit (ec);
5078 temp.Release (ec);
5079 temp = null;
5083 public override void Emit (EmitContext ec)
5085 Emit (ec, false);
5088 public override void EmitSideEffect (EmitContext ec)
5090 FieldBase f = TypeManager.GetField (FieldInfo);
5091 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5093 if (is_volatile || is_marshal_by_ref ())
5094 base.EmitSideEffect (ec);
5097 public override void Error_VariableIsUsedBeforeItIsDeclared (string name)
5099 Report.Error (844, loc,
5100 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5101 name, GetSignatureForError ());
5104 public void AddressOf (EmitContext ec, AddressOp mode)
5106 ILGenerator ig = ec.ig;
5108 FieldBase f = TypeManager.GetField (FieldInfo);
5109 if (f != null){
5110 if ((f.ModFlags & Modifiers.VOLATILE) != 0){
5111 Report.Warning (420, 1, loc, "`{0}': A volatile field references will not be treated as volatile",
5112 f.GetSignatureForError ());
5115 if ((mode & AddressOp.Store) != 0)
5116 f.SetAssigned ();
5117 if ((mode & AddressOp.Load) != 0)
5118 f.SetMemberIsUsed ();
5122 // Handle initonly fields specially: make a copy and then
5123 // get the address of the copy.
5125 bool need_copy;
5126 if (FieldInfo.IsInitOnly){
5127 need_copy = true;
5128 if (ec.IsConstructor){
5129 if (FieldInfo.IsStatic){
5130 if (ec.IsStatic)
5131 need_copy = false;
5132 } else
5133 need_copy = false;
5135 } else
5136 need_copy = false;
5138 if (need_copy){
5139 LocalBuilder local;
5140 Emit (ec);
5141 local = ig.DeclareLocal (type);
5142 ig.Emit (OpCodes.Stloc, local);
5143 ig.Emit (OpCodes.Ldloca, local);
5144 return;
5148 if (FieldInfo.IsStatic){
5149 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5150 } else {
5151 if (!prepared)
5152 EmitInstance (ec, false);
5153 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5157 FieldInfo GetConstructedFieldInfo ()
5159 if (constructed_generic_type == null)
5160 return FieldInfo;
5161 #if GMCS_SOURCE
5162 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5163 #else
5164 throw new NotSupportedException ();
5165 #endif
5168 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5170 FieldInfo = storey.MutateField (FieldInfo);
5171 base.MutateHoistedGenericType (storey);
5176 /// <summary>
5177 /// Expression that evaluates to a Property. The Assign class
5178 /// might set the `Value' expression if we are in an assignment.
5180 /// This is not an LValue because we need to re-write the expression, we
5181 /// can not take data from the stack and store it.
5182 /// </summary>
5183 public class PropertyExpr : MemberExpr, IAssignMethod {
5184 public readonly PropertyInfo PropertyInfo;
5185 MethodInfo getter, setter;
5186 bool is_static;
5188 bool resolved;
5190 LocalTemporary temp;
5191 bool prepared;
5193 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5195 PropertyInfo = pi;
5196 eclass = ExprClass.PropertyAccess;
5197 is_static = false;
5198 loc = l;
5200 type = TypeManager.TypeToCoreType (pi.PropertyType);
5202 ResolveAccessors (container_type);
5205 public override string Name {
5206 get {
5207 return PropertyInfo.Name;
5211 public override bool IsInstance {
5212 get {
5213 return !is_static;
5217 public override bool IsStatic {
5218 get {
5219 return is_static;
5223 public override Expression CreateExpressionTree (EmitContext ec)
5225 ArrayList args;
5226 if (IsSingleDimensionalArrayLength ()) {
5227 args = new ArrayList (1);
5228 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5229 return CreateExpressionFactoryCall ("ArrayLength", args);
5232 if (is_base) {
5233 Error_BaseAccessInExpressionTree (loc);
5234 return null;
5237 args = new ArrayList (2);
5238 if (InstanceExpression == null)
5239 args.Add (new Argument (new NullLiteral (loc)));
5240 else
5241 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5242 args.Add (new Argument (new TypeOfMethodInfo (getter, loc)));
5243 return CreateExpressionFactoryCall ("Property", args);
5246 public Expression CreateSetterTypeOfExpression ()
5248 return new TypeOfMethodInfo (setter, loc);
5251 public override Type DeclaringType {
5252 get {
5253 return PropertyInfo.DeclaringType;
5257 public override string GetSignatureForError ()
5259 return TypeManager.GetFullNameSignature (PropertyInfo);
5262 void FindAccessors (Type invocation_type)
5264 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5265 BindingFlags.Static | BindingFlags.Instance |
5266 BindingFlags.DeclaredOnly;
5268 Type current = PropertyInfo.DeclaringType;
5269 for (; current != null; current = current.BaseType) {
5270 MemberInfo[] group = TypeManager.MemberLookup (
5271 invocation_type, invocation_type, current,
5272 MemberTypes.Property, flags, PropertyInfo.Name, null);
5274 if (group == null)
5275 continue;
5277 if (group.Length != 1)
5278 // Oooops, can this ever happen ?
5279 return;
5281 PropertyInfo pi = (PropertyInfo) group [0];
5283 if (getter == null)
5284 getter = pi.GetGetMethod (true);
5286 if (setter == null)
5287 setter = pi.GetSetMethod (true);
5289 MethodInfo accessor = getter != null ? getter : setter;
5291 if (!accessor.IsVirtual)
5292 return;
5297 // We also perform the permission checking here, as the PropertyInfo does not
5298 // hold the information for the accessibility of its setter/getter
5300 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5301 void ResolveAccessors (Type container_type)
5303 FindAccessors (container_type);
5305 if (getter != null) {
5306 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5307 IMethodData md = TypeManager.GetMethod (the_getter);
5308 if (md != null)
5309 md.SetMemberIsUsed ();
5311 is_static = getter.IsStatic;
5314 if (setter != null) {
5315 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5316 IMethodData md = TypeManager.GetMethod (the_setter);
5317 if (md != null)
5318 md.SetMemberIsUsed ();
5320 is_static = setter.IsStatic;
5324 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5326 if (InstanceExpression != null)
5327 InstanceExpression.MutateHoistedGenericType (storey);
5329 type = storey.MutateType (type);
5330 if (getter != null)
5331 getter = storey.MutateGenericMethod (getter);
5332 if (setter != null)
5333 setter = storey.MutateGenericMethod (setter);
5336 bool InstanceResolve (EmitContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5338 if (is_static) {
5339 InstanceExpression = null;
5340 return true;
5343 if (InstanceExpression == null) {
5344 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5345 return false;
5348 InstanceExpression = InstanceExpression.DoResolve (ec);
5349 if (lvalue_instance && InstanceExpression != null)
5350 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess, loc);
5352 if (InstanceExpression == null)
5353 return false;
5355 InstanceExpression.CheckMarshalByRefAccess (ec);
5357 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5358 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5359 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5360 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5361 Report.SymbolRelatedToPreviousError (PropertyInfo);
5362 Error_CannotAccessProtected (loc, PropertyInfo, InstanceExpression.Type, ec.ContainerType);
5363 return false;
5366 return true;
5369 void Error_PropertyNotFound (MethodInfo mi, bool getter)
5371 // TODO: correctly we should compare arguments but it will lead to bigger changes
5372 if (mi is MethodBuilder) {
5373 Error_TypeDoesNotContainDefinition (loc, PropertyInfo.DeclaringType, Name);
5374 return;
5377 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5378 sig.Append ('.');
5379 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5380 sig.Append (getter ? "get_" : "set_");
5381 sig.Append (Name);
5382 sig.Append (iparams.GetSignatureForError ());
5384 Report.SymbolRelatedToPreviousError (mi);
5385 Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5386 Name, sig.ToString ());
5389 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5391 bool dummy;
5392 MethodInfo accessor = lvalue ? setter : getter;
5393 if (accessor == null && lvalue)
5394 accessor = getter;
5395 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5398 bool IsSingleDimensionalArrayLength ()
5400 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5401 return false;
5403 string t_name = InstanceExpression.Type.Name;
5404 int t_name_len = t_name.Length;
5405 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5408 override public Expression DoResolve (EmitContext ec)
5410 if (resolved)
5411 return this;
5413 if (getter != null){
5414 if (TypeManager.GetParameterData (getter).Count != 0){
5415 Error_PropertyNotFound (getter, true);
5416 return null;
5420 if (getter == null){
5422 // The following condition happens if the PropertyExpr was
5423 // created, but is invalid (ie, the property is inaccessible),
5424 // and we did not want to embed the knowledge about this in
5425 // the caller routine. This only avoids double error reporting.
5427 if (setter == null)
5428 return null;
5430 if (InstanceExpression != EmptyExpression.Null) {
5431 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5432 TypeManager.GetFullNameSignature (PropertyInfo));
5433 return null;
5437 bool must_do_cs1540_check = false;
5438 if (getter != null &&
5439 !IsAccessorAccessible (ec.ContainerType, getter, out must_do_cs1540_check)) {
5440 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5441 if (pm != null && pm.HasCustomAccessModifier) {
5442 Report.SymbolRelatedToPreviousError (pm);
5443 Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5444 TypeManager.CSharpSignature (getter));
5446 else {
5447 Report.SymbolRelatedToPreviousError (getter);
5448 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter));
5450 return null;
5453 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5454 return null;
5457 // Only base will allow this invocation to happen.
5459 if (IsBase && getter.IsAbstract) {
5460 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5463 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe){
5464 UnsafeError (loc);
5467 if (!ec.IsInObsoleteScope) {
5468 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5469 if (pb != null) {
5470 pb.CheckObsoleteness (loc);
5471 } else {
5472 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5473 if (oa != null)
5474 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5478 resolved = true;
5480 return this;
5483 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5485 if (right_side == EmptyExpression.OutAccess) {
5486 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5487 Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5488 PropertyInfo.Name);
5489 } else {
5490 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as `ref' or `out' parameter",
5491 GetSignatureForError ());
5493 return null;
5496 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5497 Error_CannotModifyIntermediateExpressionValue (ec);
5500 if (setter == null){
5502 // The following condition happens if the PropertyExpr was
5503 // created, but is invalid (ie, the property is inaccessible),
5504 // and we did not want to embed the knowledge about this in
5505 // the caller routine. This only avoids double error reporting.
5507 if (getter == null)
5508 return null;
5510 if (ec.CurrentBlock.Toplevel.GetTransparentIdentifier (PropertyInfo.Name) != null) {
5511 Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5512 PropertyInfo.Name);
5513 } else {
5514 Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5515 GetSignatureForError ());
5517 return null;
5520 if (TypeManager.GetParameterData (setter).Count != 1){
5521 Error_PropertyNotFound (setter, false);
5522 return null;
5525 bool must_do_cs1540_check;
5526 if (!IsAccessorAccessible (ec.ContainerType, setter, out must_do_cs1540_check)) {
5527 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5528 if (pm != null && pm.HasCustomAccessModifier) {
5529 Report.SymbolRelatedToPreviousError (pm);
5530 Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5531 TypeManager.CSharpSignature (setter));
5533 else {
5534 Report.SymbolRelatedToPreviousError (setter);
5535 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter));
5537 return null;
5540 if (!InstanceResolve (ec, PropertyInfo.DeclaringType.IsValueType, must_do_cs1540_check))
5541 return null;
5544 // Only base will allow this invocation to happen.
5546 if (IsBase && setter.IsAbstract){
5547 Error_CannotCallAbstractBase (TypeManager.GetFullNameSignature (PropertyInfo));
5550 if (PropertyInfo.PropertyType.IsPointer && !ec.InUnsafe) {
5551 UnsafeError (loc);
5554 if (!ec.IsInObsoleteScope) {
5555 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5556 if (pb != null) {
5557 pb.CheckObsoleteness (loc);
5558 } else {
5559 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5560 if (oa != null)
5561 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5565 return this;
5568 public override void Emit (EmitContext ec)
5570 Emit (ec, false);
5573 public void Emit (EmitContext ec, bool leave_copy)
5576 // Special case: length of single dimension array property is turned into ldlen
5578 if (IsSingleDimensionalArrayLength ()) {
5579 if (!prepared)
5580 EmitInstance (ec, false);
5581 ec.ig.Emit (OpCodes.Ldlen);
5582 ec.ig.Emit (OpCodes.Conv_I4);
5583 return;
5586 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5588 if (leave_copy) {
5589 ec.ig.Emit (OpCodes.Dup);
5590 if (!is_static) {
5591 temp = new LocalTemporary (this.Type);
5592 temp.Store (ec);
5598 // Implements the IAssignMethod interface for assignments
5600 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5602 Expression my_source = source;
5604 if (prepare_for_load) {
5605 prepared = true;
5606 source.Emit (ec);
5608 if (leave_copy) {
5609 ec.ig.Emit (OpCodes.Dup);
5610 if (!is_static) {
5611 temp = new LocalTemporary (this.Type);
5612 temp.Store (ec);
5615 } else if (leave_copy) {
5616 source.Emit (ec);
5617 temp = new LocalTemporary (this.Type);
5618 temp.Store (ec);
5619 my_source = temp;
5622 ArrayList args = new ArrayList (1);
5623 args.Add (new Argument (my_source, Argument.AType.Expression));
5625 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5627 if (temp != null) {
5628 temp.Emit (ec);
5629 temp.Release (ec);
5634 /// <summary>
5635 /// Fully resolved expression that evaluates to an Event
5636 /// </summary>
5637 public class EventExpr : MemberExpr {
5638 public readonly EventInfo EventInfo;
5640 bool is_static;
5641 MethodInfo add_accessor, remove_accessor;
5643 public EventExpr (EventInfo ei, Location loc)
5645 EventInfo = ei;
5646 this.loc = loc;
5647 eclass = ExprClass.EventAccess;
5649 add_accessor = TypeManager.GetAddMethod (ei);
5650 remove_accessor = TypeManager.GetRemoveMethod (ei);
5651 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5652 is_static = true;
5654 if (EventInfo is MyEventBuilder){
5655 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5656 type = eb.EventType;
5657 eb.SetUsed ();
5658 } else
5659 type = EventInfo.EventHandlerType;
5662 public override string Name {
5663 get {
5664 return EventInfo.Name;
5668 public override bool IsInstance {
5669 get {
5670 return !is_static;
5674 public override bool IsStatic {
5675 get {
5676 return is_static;
5680 public override Type DeclaringType {
5681 get {
5682 return EventInfo.DeclaringType;
5686 void Error_AssignmentEventOnly ()
5688 Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5689 GetSignatureForError ());
5692 public override MemberExpr ResolveMemberAccess (EmitContext ec, Expression left, Location loc,
5693 SimpleName original)
5696 // If the event is local to this class, we transform ourselves into a FieldExpr
5699 if (EventInfo.DeclaringType == ec.ContainerType ||
5700 TypeManager.IsNestedChildOf(ec.ContainerType, EventInfo.DeclaringType)) {
5701 EventField mi = TypeManager.GetEventField (EventInfo);
5703 if (mi != null) {
5704 if (!ec.IsInObsoleteScope)
5705 mi.CheckObsoleteness (loc);
5707 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.IsInCompoundAssignment)
5708 Error_AssignmentEventOnly ();
5710 FieldExpr ml = new FieldExpr (mi.FieldBuilder, loc);
5712 InstanceExpression = null;
5714 return ml.ResolveMemberAccess (ec, left, loc, original);
5718 if (left is This && !ec.IsInCompoundAssignment)
5719 Error_AssignmentEventOnly ();
5721 return base.ResolveMemberAccess (ec, left, loc, original);
5724 bool InstanceResolve (EmitContext ec, bool must_do_cs1540_check)
5726 if (is_static) {
5727 InstanceExpression = null;
5728 return true;
5731 if (InstanceExpression == null) {
5732 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5733 return false;
5736 InstanceExpression = InstanceExpression.DoResolve (ec);
5737 if (InstanceExpression == null)
5738 return false;
5740 if (IsBase && add_accessor.IsAbstract) {
5741 Error_CannotCallAbstractBase(TypeManager.CSharpSignature(add_accessor));
5742 return false;
5746 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5747 // However, in the Event case, we reported a CS0122 instead.
5749 // TODO: Exact copy from PropertyExpr
5751 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5752 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.ContainerType) &&
5753 !TypeManager.IsNestedChildOf (ec.ContainerType, InstanceExpression.Type) &&
5754 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.ContainerType)) {
5755 Report.SymbolRelatedToPreviousError (EventInfo);
5756 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5757 return false;
5760 return true;
5763 public bool IsAccessibleFrom (Type invocation_type)
5765 bool dummy;
5766 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
5767 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
5770 public override Expression CreateExpressionTree (EmitContext ec)
5772 throw new NotSupportedException ("ET");
5775 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5777 // contexts where an LValue is valid have already devolved to FieldExprs
5778 Error_CannotAssign ();
5779 return null;
5782 public override Expression DoResolve (EmitContext ec)
5784 bool must_do_cs1540_check;
5785 if (!(IsAccessorAccessible (ec.ContainerType, add_accessor, out must_do_cs1540_check) &&
5786 IsAccessorAccessible (ec.ContainerType, remove_accessor, out must_do_cs1540_check))) {
5787 Report.SymbolRelatedToPreviousError (EventInfo);
5788 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo));
5789 return null;
5792 if (!InstanceResolve (ec, must_do_cs1540_check))
5793 return null;
5795 if (!ec.IsInCompoundAssignment) {
5796 Error_CannotAssign ();
5797 return null;
5800 if (!ec.IsInObsoleteScope) {
5801 EventField ev = TypeManager.GetEventField (EventInfo);
5802 if (ev != null) {
5803 ev.CheckObsoleteness (loc);
5804 } else {
5805 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
5806 if (oa != null)
5807 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc);
5811 return this;
5814 public override void Emit (EmitContext ec)
5816 Error_CannotAssign ();
5819 public void Error_CannotAssign ()
5821 Report.Error (70, loc,
5822 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5823 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
5826 public override string GetSignatureForError ()
5828 return TypeManager.CSharpSignature (EventInfo);
5831 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5833 ArrayList args = new ArrayList (1);
5834 args.Add (new Argument (source, Argument.AType.Expression));
5835 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
5839 public class TemporaryVariable : VariableReference
5841 LocalInfo li;
5843 public TemporaryVariable (Type type, Location loc)
5845 this.type = type;
5846 this.loc = loc;
5847 eclass = ExprClass.Variable;
5850 public override Expression CreateExpressionTree (EmitContext ec)
5852 throw new NotSupportedException ("ET");
5855 public override Expression DoResolve (EmitContext ec)
5857 if (li != null)
5858 return this;
5860 TypeExpr te = new TypeExpression (type, loc);
5861 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5862 if (!li.Resolve (ec))
5863 return null;
5866 // Don't capture temporary variables except when using
5867 // iterator redirection
5869 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5870 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5871 storey.CaptureLocalVariable (ec, li);
5874 return this;
5877 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5879 return DoResolve (ec);
5882 public override void Emit (EmitContext ec)
5884 Emit (ec, false);
5887 public void EmitAssign (EmitContext ec, Expression source)
5889 EmitAssign (ec, source, false, false);
5892 public override HoistedVariable HoistedVariable {
5893 get { return li.HoistedVariableReference; }
5896 public override bool IsFixed {
5897 get { return true; }
5900 public override bool IsRef {
5901 get { return false; }
5904 public override string Name {
5905 get { throw new NotImplementedException (); }
5908 public override void SetHasAddressTaken ()
5910 throw new NotImplementedException ();
5913 protected override ILocalVariable Variable {
5914 get { return li; }
5917 public override VariableInfo VariableInfo {
5918 get { throw new NotImplementedException (); }
5922 ///
5923 /// Handles `var' contextual keyword; var becomes a keyword only
5924 /// if no type called var exists in a variable scope
5925 ///
5926 public class VarExpr : SimpleName
5928 // Used for error reporting only
5929 ArrayList initializer;
5931 public VarExpr (Location loc)
5932 : base ("var", loc)
5936 public ArrayList VariableInitializer {
5937 set {
5938 this.initializer = value;
5942 public bool InferType (EmitContext ec, Expression right_side)
5944 if (type != null)
5945 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5947 type = right_side.Type;
5948 if (type == TypeManager.null_type || type == TypeManager.void_type || type == TypeManager.anonymous_method_type) {
5949 Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5950 right_side.GetSignatureForError ());
5951 return false;
5954 eclass = ExprClass.Variable;
5955 return true;
5958 protected override void Error_TypeOrNamespaceNotFound (IResolveContext ec)
5960 Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5963 public override TypeExpr ResolveAsContextualType (IResolveContext rc, bool silent)
5965 TypeExpr te = base.ResolveAsContextualType (rc, true);
5966 if (te != null)
5967 return te;
5969 if (initializer == null)
5970 return null;
5972 if (initializer.Count > 1) {
5973 Location loc = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [1]).Location;
5974 Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5975 initializer = null;
5976 return null;
5979 Expression variable_initializer = ((Mono.CSharp.CSharpParser.VariableDeclaration)initializer [0]).expression_or_array_initializer;
5980 if (variable_initializer == null) {
5981 Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
5982 return null;
5985 return null;