remove NotWorking
[mcs.git] / mcs / ecore.cs
blobf1f48c6662c08dc551f12657ba85aaa3bf3bc9da
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 #if NET_4_0
22 using SLE = System.Linq.Expressions;
23 #endif
25 /// <remarks>
26 /// The ExprClass class contains the is used to pass the
27 /// classification of an expression (value, variable, namespace,
28 /// type, method group, property access, event access, indexer access,
29 /// nothing).
30 /// </remarks>
31 public enum ExprClass : byte {
32 Invalid,
34 Value,
35 Variable,
36 Namespace,
37 Type,
38 TypeParameter,
39 MethodGroup,
40 PropertyAccess,
41 EventAccess,
42 IndexerAccess,
43 Nothing,
46 /// <remarks>
47 /// This is used to tell Resolve in which types of expressions we're
48 /// interested.
49 /// </remarks>
50 [Flags]
51 public enum ResolveFlags {
52 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
53 VariableOrValue = 1,
55 // Returns a type expression.
56 Type = 1 << 1,
58 // Returns a method group.
59 MethodGroup = 1 << 2,
61 TypeParameter = 1 << 3,
63 // Mask of all the expression class flags.
64 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
66 // Disable control flow analysis while resolving the expression.
67 // This is used when resolving the instance expression of a field expression.
68 DisableFlowAnalysis = 1 << 10,
70 // Set if this is resolving the first part of a MemberAccess.
71 Intermediate = 1 << 11,
73 // Disable control flow analysis _of struct_ while resolving the expression.
74 // This is used when resolving the instance expression of a field expression.
75 DisableStructFlowAnalysis = 1 << 12,
80 // This is just as a hint to AddressOf of what will be done with the
81 // address.
82 [Flags]
83 public enum AddressOp {
84 Store = 1,
85 Load = 2,
86 LoadStore = 3
89 /// <summary>
90 /// This interface is implemented by variables
91 /// </summary>
92 public interface IMemoryLocation {
93 /// <summary>
94 /// The AddressOf method should generate code that loads
95 /// the address of the object and leaves it on the stack.
96 ///
97 /// The `mode' argument is used to notify the expression
98 /// of whether this will be used to read from the address or
99 /// write to the address.
101 /// This is just a hint that can be used to provide good error
102 /// reporting, and should have no other side effects.
103 /// </summary>
104 void AddressOf (EmitContext ec, AddressOp mode);
108 // An expressions resolved as a direct variable reference
110 public interface IVariableReference : IFixedExpression
112 bool IsHoisted { get; }
113 string Name { get; }
114 VariableInfo VariableInfo { get; }
116 void SetHasAddressTaken ();
120 // Implemented by an expression which could be or is always
121 // fixed
123 public interface IFixedExpression
125 bool IsFixed { get; }
128 /// <remarks>
129 /// Base class for expressions
130 /// </remarks>
131 public abstract class Expression {
132 public ExprClass eclass;
133 protected Type type;
134 protected Location loc;
136 public Type Type {
137 get { return type; }
138 set { type = value; }
141 public virtual Location Location {
142 get { return loc; }
145 // Not nice but we have broken hierarchy.
146 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
150 public virtual bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
152 Attribute.Error_AttributeArgumentNotValid (ec, loc);
153 value = null;
154 return false;
157 public virtual string GetSignatureForError ()
159 return TypeManager.CSharpName (type);
162 public static bool IsAccessorAccessible (Type invocation_type, MethodInfo mi, out bool must_do_cs1540_check)
164 MethodAttributes ma = mi.Attributes & MethodAttributes.MemberAccessMask;
166 must_do_cs1540_check = false; // by default we do not check for this
168 if (ma == MethodAttributes.Public)
169 return true;
172 // If only accessible to the current class or children
174 if (ma == MethodAttributes.Private)
175 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
176 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
178 if (TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly)) {
179 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem)
180 return true;
181 } else {
182 if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem)
183 return false;
186 // Family and FamANDAssem require that we derive.
187 // FamORAssem requires that we derive if in different assemblies.
188 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
189 return false;
191 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
192 must_do_cs1540_check = true;
194 return true;
197 public virtual bool IsNull {
198 get {
199 return false;
203 /// <summary>
204 /// Performs semantic analysis on the Expression
205 /// </summary>
207 /// <remarks>
208 /// The Resolve method is invoked to perform the semantic analysis
209 /// on the node.
211 /// The return value is an expression (it can be the
212 /// same expression in some cases) or a new
213 /// expression that better represents this node.
214 ///
215 /// For example, optimizations of Unary (LiteralInt)
216 /// would return a new LiteralInt with a negated
217 /// value.
218 ///
219 /// If there is an error during semantic analysis,
220 /// then an error should be reported (using Report)
221 /// and a null value should be returned.
222 ///
223 /// There are two side effects expected from calling
224 /// Resolve(): the the field variable "eclass" should
225 /// be set to any value of the enumeration
226 /// `ExprClass' and the type variable should be set
227 /// to a valid type (this is the type of the
228 /// expression).
229 /// </remarks>
230 public abstract Expression DoResolve (ResolveContext ec);
232 public virtual Expression DoResolveLValue (ResolveContext ec, Expression right_side)
234 return null;
238 // This is used if the expression should be resolved as a type or namespace name.
239 // the default implementation fails.
241 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
243 if (!silent) {
244 ResolveContext ec = new ResolveContext (rc);
245 Expression e = Resolve (ec);
246 if (e != null)
247 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
250 return null;
254 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
255 // same name exists or as a keyword when no type was found
257 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
259 return ResolveAsTypeTerminal (rc, silent);
263 // This is used to resolve the expression as a type, a null
264 // value will be returned if the expression is not a type
265 // reference
267 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
269 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
270 if (te == null)
271 return null;
273 if (!silent) { // && !(te is TypeParameterExpr)) {
274 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
275 if (obsolete_attr != null && !ec.IsObsolete) {
276 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
280 GenericTypeExpr ct = te as GenericTypeExpr;
281 if (ct != null) {
283 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
284 // There are 2 solutions.
285 // 1, Skip this check completely when we are in override/explicit impl scope
286 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
288 MemberCore gm = ec as GenericMethod;
289 if (gm == null)
290 gm = ec as Method;
291 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
292 te.loc = loc;
293 return te;
296 // TODO: silent flag is ignored
297 ct.CheckConstraints (ec);
300 return te;
303 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
305 int errors = ec.Compiler.Report.Errors;
307 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
309 if (fne == null)
310 return null;
312 TypeExpr te = fne as TypeExpr;
313 if (te == null) {
314 if (!silent && errors == ec.Compiler.Report.Errors)
315 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
316 return null;
319 if (!te.CheckAccessLevel (ec)) {
320 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
321 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
322 return null;
325 te.loc = loc;
326 return te;
329 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
331 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
334 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
336 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
337 + " The qualifier must be of type `{2}' or derived from it",
338 TypeManager.GetFullNameSignature (m),
339 TypeManager.CSharpName (qualifier),
340 TypeManager.CSharpName (container));
344 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
346 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
347 "expressions can be used as a statement");
350 public void Error_InvalidExpressionStatement (BlockContext ec)
352 Error_InvalidExpressionStatement (ec.Report, loc);
355 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
357 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
360 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
362 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
365 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
367 // The error was already reported as CS1660
368 if (type == InternalType.AnonymousMethod)
369 return;
371 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
372 string sig1 = type.DeclaringMethod == null ?
373 TypeManager.CSharpName (type.DeclaringType) :
374 TypeManager.CSharpSignature (type.DeclaringMethod);
375 string sig2 = target.DeclaringMethod == null ?
376 TypeManager.CSharpName (target.DeclaringType) :
377 TypeManager.CSharpSignature (target.DeclaringMethod);
378 ec.Report.ExtraInformation (loc,
379 String.Format (
380 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
381 Type.Name, sig1, sig2));
382 } else if (Type.FullName == target.FullName){
383 ec.Report.ExtraInformation (loc,
384 String.Format (
385 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
386 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
389 if (expl) {
390 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
391 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
392 return;
395 ec.Report.DisableReporting ();
396 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
397 ec.Report.EnableReporting ();
399 if (expl_exists) {
400 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
401 "An explicit conversion exists (are you missing a cast?)",
402 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
403 return;
406 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
407 TypeManager.CSharpName (type),
408 TypeManager.CSharpName (target));
411 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
413 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
416 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
418 // Better message for possible generic expressions
419 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
420 if (this is TypeExpr)
421 report.SymbolRelatedToPreviousError (type);
423 string name = eclass == ExprClass.Type ? ExprClassName : "method";
424 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
425 name, GetSignatureForError ());
426 } else {
427 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
428 ExprClassName, GetSignatureForError ());
432 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
434 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
437 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
439 ec.Report.SymbolRelatedToPreviousError (type);
440 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
441 TypeManager.CSharpName (type), name);
444 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
446 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
449 ResolveFlags ExprClassToResolveFlags
451 get {
452 switch (eclass) {
453 case ExprClass.Type:
454 case ExprClass.Namespace:
455 return ResolveFlags.Type;
457 case ExprClass.MethodGroup:
458 return ResolveFlags.MethodGroup;
460 case ExprClass.TypeParameter:
461 return ResolveFlags.TypeParameter;
463 case ExprClass.Value:
464 case ExprClass.Variable:
465 case ExprClass.PropertyAccess:
466 case ExprClass.EventAccess:
467 case ExprClass.IndexerAccess:
468 return ResolveFlags.VariableOrValue;
470 default:
471 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
476 /// <summary>
477 /// Resolves an expression and performs semantic analysis on it.
478 /// </summary>
480 /// <remarks>
481 /// Currently Resolve wraps DoResolve to perform sanity
482 /// checking and assertion checking on what we expect from Resolve.
483 /// </remarks>
484 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
486 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
487 return ResolveAsTypeStep (ec, false);
489 bool do_flow_analysis = ec.DoFlowAnalysis;
490 bool omit_struct_analysis = ec.OmitStructFlowAnalysis;
491 if ((flags & ResolveFlags.DisableFlowAnalysis) != 0)
492 do_flow_analysis = false;
493 if ((flags & ResolveFlags.DisableStructFlowAnalysis) != 0)
494 omit_struct_analysis = true;
496 Expression e;
497 using (ec.WithFlowAnalysis (do_flow_analysis, omit_struct_analysis)) {
498 if (this is SimpleName) {
499 bool intermediate = (flags & ResolveFlags.Intermediate) == ResolveFlags.Intermediate;
500 e = ((SimpleName) this).DoResolve (ec, intermediate);
501 } else {
502 e = DoResolve (ec);
506 if (e == null)
507 return null;
509 if ((flags & e.ExprClassToResolveFlags) == 0) {
510 e.Error_UnexpectedKind (ec, flags, loc);
511 return null;
514 if (e.type == null && !(e is Namespace)) {
515 throw new Exception (
516 "Expression " + e.GetType () +
517 " did not set its type after Resolve\n" +
518 "called from: " + this.GetType ());
521 return e;
524 /// <summary>
525 /// Resolves an expression and performs semantic analysis on it.
526 /// </summary>
527 public Expression Resolve (ResolveContext ec)
529 Expression e = Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
531 if (e != null && e.eclass == ExprClass.MethodGroup && RootContext.Version == LanguageVersion.ISO_1) {
532 ((MethodGroupExpr) e).ReportUsageError (ec);
533 return null;
535 return e;
538 public Constant ResolveAsConstant (ResolveContext ec, MemberCore mc)
540 Expression e = Resolve (ec);
541 if (e == null)
542 return null;
544 Constant c = e as Constant;
545 if (c != null)
546 return c;
548 if (type != null && TypeManager.IsReferenceType (type))
549 Const.Error_ConstantCanBeInitializedWithNullOnly (type, loc, mc.GetSignatureForError (), ec.Report);
550 else
551 Const.Error_ExpressionMustBeConstant (loc, mc.GetSignatureForError (), ec.Report);
553 return null;
556 /// <summary>
557 /// Resolves an expression for LValue assignment
558 /// </summary>
560 /// <remarks>
561 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
562 /// checking and assertion checking on what we expect from Resolve
563 /// </remarks>
564 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
566 int errors = ec.Report.Errors;
567 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
569 Expression e = DoResolveLValue (ec, right_side);
571 if (e != null && out_access && !(e is IMemoryLocation)) {
572 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
573 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
575 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
576 // e.GetType () + " " + e.GetSignatureForError ());
577 e = null;
580 if (e == null) {
581 if (errors == ec.Report.Errors) {
582 if (out_access)
583 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
584 else
585 Error_ValueAssignment (ec, loc);
587 return null;
590 if (e.eclass == ExprClass.Invalid)
591 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
593 if ((e.type == null) && !(e is GenericTypeExpr))
594 throw new Exception ("Expression " + e + " did not set its type after Resolve");
596 return e;
599 /// <summary>
600 /// Emits the code for the expression
601 /// </summary>
603 /// <remarks>
604 /// The Emit method is invoked to generate the code
605 /// for the expression.
606 /// </remarks>
607 public abstract void Emit (EmitContext ec);
609 // Emit code to branch to @target if this expression is equivalent to @on_true.
610 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
611 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
612 // including the use of conditional branches. Note also that a branch MUST be emitted
613 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
615 Emit (ec);
616 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
619 // Emit this expression for its side effects, not for its value.
620 // The default implementation is to emit the value, and then throw it away.
621 // Subclasses can provide more efficient implementations, but those MUST be equivalent
622 public virtual void EmitSideEffect (EmitContext ec)
624 Emit (ec);
625 ec.ig.Emit (OpCodes.Pop);
628 /// <summary>
629 /// Protected constructor. Only derivate types should
630 /// be able to be created
631 /// </summary>
633 protected Expression ()
635 eclass = ExprClass.Invalid;
636 type = null;
639 /// <summary>
640 /// Returns a fully formed expression after a MemberLookup
641 /// </summary>
642 ///
643 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
645 if (mi is EventInfo)
646 return new EventExpr ((EventInfo) mi, loc);
647 else if (mi is FieldInfo) {
648 FieldInfo fi = (FieldInfo) mi;
649 if (fi.IsLiteral || (fi.IsInitOnly && fi.FieldType == TypeManager.decimal_type))
650 return new ConstantExpr (fi, loc);
651 return new FieldExpr (fi, loc);
652 } else if (mi is PropertyInfo)
653 return new PropertyExpr (container_type, (PropertyInfo) mi, loc);
654 else if (mi is Type) {
655 return new TypeExpression ((System.Type) mi, loc);
658 return null;
661 // TODO: [Obsolete ("Can be removed")]
662 protected static ArrayList almost_matched_members = new ArrayList (4);
665 // FIXME: Probably implement a cache for (t,name,current_access_set)?
667 // This code could use some optimizations, but we need to do some
668 // measurements. For example, we could use a delegate to `flag' when
669 // something can not any longer be a method-group (because it is something
670 // else).
672 // Return values:
673 // If the return value is an Array, then it is an array of
674 // MethodBases
676 // If the return value is an MemberInfo, it is anything, but a Method
678 // null on error.
680 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
681 // the arguments here and have MemberLookup return only the methods that
682 // match the argument count/type, unlike we are doing now (we delay this
683 // decision).
685 // This is so we can catch correctly attempts to invoke instance methods
686 // from a static body (scan for error 120 in ResolveSimpleName).
689 // FIXME: Potential optimization, have a static ArrayList
692 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
693 MemberTypes mt, BindingFlags bf, Location loc)
695 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
699 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
700 // `qualifier_type' or null to lookup members in the current class.
703 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
704 Type qualifier_type, Type queried_type,
705 string name, MemberTypes mt,
706 BindingFlags bf, Location loc)
708 almost_matched_members.Clear ();
710 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
711 queried_type, mt, bf, name, almost_matched_members);
713 if (mi == null)
714 return null;
716 if (mi.Length > 1) {
717 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
718 ArrayList methods = new ArrayList (2);
719 ArrayList non_methods = null;
721 foreach (MemberInfo m in mi) {
722 if (m is MethodBase) {
723 methods.Add (m);
724 continue;
727 if (non_methods == null)
728 non_methods = new ArrayList (2);
730 bool is_candidate = true;
731 for (int i = 0; i < non_methods.Count; ++i) {
732 MemberInfo n_m = (MemberInfo) non_methods [i];
733 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
734 non_methods.Remove (n_m);
735 --i;
736 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
737 is_candidate = false;
738 break;
742 if (is_candidate) {
743 non_methods.Add (m);
747 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
748 ctx.Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [1]);
749 ctx.Report.SymbolRelatedToPreviousError ((MemberInfo)non_methods [0]);
750 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
751 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [1]),
752 TypeManager.GetFullNameSignature ((MemberInfo)non_methods [0]));
753 return null;
756 if (methods.Count == 0)
757 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
759 if (non_methods != null && non_methods.Count > 0) {
760 MethodBase method = (MethodBase) methods [0];
761 MemberInfo non_method = (MemberInfo) non_methods [0];
762 if (method.DeclaringType == non_method.DeclaringType) {
763 // Cannot happen with C# code, but is valid in IL
764 ctx.Report.SymbolRelatedToPreviousError (method);
765 ctx.Report.SymbolRelatedToPreviousError (non_method);
766 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
767 TypeManager.GetFullNameSignature (non_method),
768 TypeManager.CSharpSignature (method));
769 return null;
772 if (is_interface) {
773 ctx.Report.SymbolRelatedToPreviousError (method);
774 ctx.Report.SymbolRelatedToPreviousError (non_method);
775 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
776 TypeManager.CSharpSignature (method), TypeManager.GetFullNameSignature (non_method));
780 return new MethodGroupExpr (methods, queried_type, loc);
783 if (mi [0] is MethodBase)
784 return new MethodGroupExpr (mi, queried_type, loc);
786 return ExprClassFromMemberInfo (container_type, mi [0], loc);
789 public const MemberTypes AllMemberTypes =
790 MemberTypes.Constructor |
791 MemberTypes.Event |
792 MemberTypes.Field |
793 MemberTypes.Method |
794 MemberTypes.NestedType |
795 MemberTypes.Property;
797 public const BindingFlags AllBindingFlags =
798 BindingFlags.Public |
799 BindingFlags.Static |
800 BindingFlags.Instance;
802 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
803 string name, Location loc)
805 return MemberLookup (ctx, container_type, null, queried_type, name,
806 AllMemberTypes, AllBindingFlags, loc);
809 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
810 Type queried_type, string name, Location loc)
812 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
813 name, AllMemberTypes, AllBindingFlags, loc);
816 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
817 string name, Location loc)
819 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
820 MemberTypes.Method, AllBindingFlags, loc);
823 /// <summary>
824 /// This is a wrapper for MemberLookup that is not used to "probe", but
825 /// to find a final definition. If the final definition is not found, we
826 /// look for private members and display a useful debugging message if we
827 /// find it.
828 /// </summary>
829 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
830 Type queried_type, string name,
831 MemberTypes mt, BindingFlags bf,
832 Location loc)
834 Expression e;
836 int errors = ec.Report.Errors;
837 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
839 if (e != null || errors != ec.Report.Errors)
840 return e;
842 // No errors were reported by MemberLookup, but there was an error.
843 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
844 name, null, mt, bf);
847 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
848 Type queried_type, string name, string class_name,
849 MemberTypes mt, BindingFlags bf)
851 MemberInfo[] lookup = null;
852 if (queried_type == null) {
853 class_name = "global::";
854 } else {
855 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
856 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
857 name, null);
859 if (lookup != null) {
860 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
863 // FIXME: This is still very wrong, it should be done inside
864 // OverloadResolve to do correct arguments matching.
865 // Requires MemberLookup accessiblity check removal
867 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
868 MemberInfo mi = lookup[0];
869 ec.Report.SymbolRelatedToPreviousError (mi);
870 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
871 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
872 // Although a derived class can access protected members of
873 // its base class it cannot do so through an instance of the
874 // base class (CS1540). If the qualifier_type is a base of the
875 // ec.CurrentType and the lookup succeeds with the latter one,
876 // then we are in this situation.
877 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
878 } else {
879 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
883 return e;
886 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
887 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
888 name, null);
891 if (lookup == null) {
892 if (class_name != null) {
893 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
894 name);
895 } else {
896 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
898 return null;
901 if (TypeManager.MemberLookup (queried_type, null, queried_type,
902 AllMemberTypes, AllBindingFlags |
903 BindingFlags.NonPublic, name, null) == null) {
904 if ((lookup.Length == 1) && (lookup [0] is Type)) {
905 Type t = (Type) lookup [0];
907 ec.Report.Error (305, loc,
908 "Using the generic type `{0}' " +
909 "requires {1} type arguments",
910 TypeManager.CSharpName (t),
911 TypeManager.GetNumberOfTypeArguments (t).ToString ());
912 return null;
916 return Error_MemberLookupFailed (ec, queried_type, lookup);
919 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
921 for (int i = 0; i < members.Length; ++i) {
922 if (!(members [i] is MethodBase))
923 return null;
926 // By default propagate the closest candidates upwards
927 return new MethodGroupExpr (members, type, loc, true);
930 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
932 throw new NotImplementedException ();
935 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
937 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
940 /// <summary>
941 /// Returns an expression that can be used to invoke operator true
942 /// on the expression if it exists.
943 /// </summary>
944 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
946 return GetOperatorTrueOrFalse (ec, e, true, loc);
949 /// <summary>
950 /// Returns an expression that can be used to invoke operator false
951 /// on the expression if it exists.
952 /// </summary>
953 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
955 return GetOperatorTrueOrFalse (ec, e, false, loc);
958 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
960 MethodGroupExpr operator_group;
961 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
962 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
963 if (operator_group == null)
964 return null;
966 Arguments arguments = new Arguments (1);
967 arguments.Add (new Argument (e));
968 operator_group = operator_group.OverloadResolve (
969 ec, ref arguments, false, loc);
971 if (operator_group == null)
972 return null;
974 return new UserOperatorCall (operator_group, arguments, null, loc);
977 public virtual string ExprClassName
979 get {
980 switch (eclass){
981 case ExprClass.Invalid:
982 return "Invalid";
983 case ExprClass.Value:
984 return "value";
985 case ExprClass.Variable:
986 return "variable";
987 case ExprClass.Namespace:
988 return "namespace";
989 case ExprClass.Type:
990 return "type";
991 case ExprClass.MethodGroup:
992 return "method group";
993 case ExprClass.PropertyAccess:
994 return "property access";
995 case ExprClass.EventAccess:
996 return "event access";
997 case ExprClass.IndexerAccess:
998 return "indexer access";
999 case ExprClass.Nothing:
1000 return "null";
1001 case ExprClass.TypeParameter:
1002 return "type parameter";
1004 throw new Exception ("Should not happen");
1008 /// <summary>
1009 /// Reports that we were expecting `expr' to be of class `expected'
1010 /// </summary>
1011 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
1013 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
1016 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
1018 string name;
1019 if (mc != null)
1020 name = mc.GetSignatureForError ();
1021 else
1022 name = GetSignatureForError ();
1024 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
1025 name, was, expected);
1028 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1030 string [] valid = new string [4];
1031 int count = 0;
1033 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1034 valid [count++] = "variable";
1035 valid [count++] = "value";
1038 if ((flags & ResolveFlags.Type) != 0)
1039 valid [count++] = "type";
1041 if ((flags & ResolveFlags.MethodGroup) != 0)
1042 valid [count++] = "method group";
1044 if (count == 0)
1045 valid [count++] = "unknown";
1047 StringBuilder sb = new StringBuilder (valid [0]);
1048 for (int i = 1; i < count - 1; i++) {
1049 sb.Append ("', `");
1050 sb.Append (valid [i]);
1052 if (count > 1) {
1053 sb.Append ("' or `");
1054 sb.Append (valid [count - 1]);
1057 ec.Report.Error (119, loc,
1058 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1061 public static void UnsafeError (ResolveContext ec, Location loc)
1063 UnsafeError (ec.Report, loc);
1066 public static void UnsafeError (Report Report, Location loc)
1068 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1072 // Load the object from the pointer.
1074 public static void LoadFromPtr (ILGenerator ig, Type t)
1076 if (t == TypeManager.int32_type)
1077 ig.Emit (OpCodes.Ldind_I4);
1078 else if (t == TypeManager.uint32_type)
1079 ig.Emit (OpCodes.Ldind_U4);
1080 else if (t == TypeManager.short_type)
1081 ig.Emit (OpCodes.Ldind_I2);
1082 else if (t == TypeManager.ushort_type)
1083 ig.Emit (OpCodes.Ldind_U2);
1084 else if (t == TypeManager.char_type)
1085 ig.Emit (OpCodes.Ldind_U2);
1086 else if (t == TypeManager.byte_type)
1087 ig.Emit (OpCodes.Ldind_U1);
1088 else if (t == TypeManager.sbyte_type)
1089 ig.Emit (OpCodes.Ldind_I1);
1090 else if (t == TypeManager.uint64_type)
1091 ig.Emit (OpCodes.Ldind_I8);
1092 else if (t == TypeManager.int64_type)
1093 ig.Emit (OpCodes.Ldind_I8);
1094 else if (t == TypeManager.float_type)
1095 ig.Emit (OpCodes.Ldind_R4);
1096 else if (t == TypeManager.double_type)
1097 ig.Emit (OpCodes.Ldind_R8);
1098 else if (t == TypeManager.bool_type)
1099 ig.Emit (OpCodes.Ldind_I1);
1100 else if (t == TypeManager.intptr_type)
1101 ig.Emit (OpCodes.Ldind_I);
1102 else if (TypeManager.IsEnumType (t)) {
1103 if (t == TypeManager.enum_type)
1104 ig.Emit (OpCodes.Ldind_Ref);
1105 else
1106 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1107 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1108 ig.Emit (OpCodes.Ldobj, t);
1109 else if (t.IsPointer)
1110 ig.Emit (OpCodes.Ldind_I);
1111 else
1112 ig.Emit (OpCodes.Ldind_Ref);
1116 // The stack contains the pointer and the value of type `type'
1118 public static void StoreFromPtr (ILGenerator ig, Type type)
1120 if (TypeManager.IsEnumType (type))
1121 type = TypeManager.GetEnumUnderlyingType (type);
1122 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1123 ig.Emit (OpCodes.Stind_I4);
1124 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1125 ig.Emit (OpCodes.Stind_I8);
1126 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1127 type == TypeManager.ushort_type)
1128 ig.Emit (OpCodes.Stind_I2);
1129 else if (type == TypeManager.float_type)
1130 ig.Emit (OpCodes.Stind_R4);
1131 else if (type == TypeManager.double_type)
1132 ig.Emit (OpCodes.Stind_R8);
1133 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1134 type == TypeManager.bool_type)
1135 ig.Emit (OpCodes.Stind_I1);
1136 else if (type == TypeManager.intptr_type)
1137 ig.Emit (OpCodes.Stind_I);
1138 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1139 ig.Emit (OpCodes.Stobj, type);
1140 else
1141 ig.Emit (OpCodes.Stind_Ref);
1145 // Returns the size of type `t' if known, otherwise, 0
1147 public static int GetTypeSize (Type t)
1149 t = TypeManager.TypeToCoreType (t);
1150 if (t == TypeManager.int32_type ||
1151 t == TypeManager.uint32_type ||
1152 t == TypeManager.float_type)
1153 return 4;
1154 else if (t == TypeManager.int64_type ||
1155 t == TypeManager.uint64_type ||
1156 t == TypeManager.double_type)
1157 return 8;
1158 else if (t == TypeManager.byte_type ||
1159 t == TypeManager.sbyte_type ||
1160 t == TypeManager.bool_type)
1161 return 1;
1162 else if (t == TypeManager.short_type ||
1163 t == TypeManager.char_type ||
1164 t == TypeManager.ushort_type)
1165 return 2;
1166 else if (t == TypeManager.decimal_type)
1167 return 16;
1168 else
1169 return 0;
1172 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1174 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1177 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1179 ec.Report.SymbolRelatedToPreviousError (type);
1180 if (ec.CurrentInitializerVariable != null) {
1181 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1182 TypeManager.CSharpName (type), GetSignatureForError ());
1183 } else {
1184 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1185 GetSignatureForError ());
1190 // Converts `source' to an int, uint, long or ulong.
1192 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1194 if (TypeManager.IsDynamicType (source.type)) {
1195 Arguments args = new Arguments (1);
1196 args.Add (new Argument (source));
1197 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1200 Expression converted;
1202 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1203 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1204 if (converted == null)
1205 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1206 if (converted == null)
1207 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1208 if (converted == null)
1209 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1211 if (converted == null) {
1212 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1213 return null;
1218 // Only positive constants are allowed at compile time
1220 Constant c = converted as Constant;
1221 if (c != null && c.IsNegative)
1222 Error_NegativeArrayIndex (ec, source.loc);
1224 // No conversion needed to array index
1225 if (converted.Type == TypeManager.int32_type)
1226 return converted;
1228 return new ArrayIndexCast (converted).Resolve (ec);
1232 // Derived classes implement this method by cloning the fields that
1233 // could become altered during the Resolve stage
1235 // Only expressions that are created for the parser need to implement
1236 // this.
1238 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1240 throw new NotImplementedException (
1241 String.Format (
1242 "CloneTo not implemented for expression {0}", this.GetType ()));
1246 // Clones an expression created by the parser.
1248 // We only support expressions created by the parser so far, not
1249 // expressions that have been resolved (many more classes would need
1250 // to implement CloneTo).
1252 // This infrastructure is here merely for Lambda expressions which
1253 // compile the same code using different type values for the same
1254 // arguments to find the correct overload
1256 public Expression Clone (CloneContext clonectx)
1258 Expression cloned = (Expression) MemberwiseClone ();
1259 CloneTo (clonectx, cloned);
1261 return cloned;
1265 // Implementation of expression to expression tree conversion
1267 public abstract Expression CreateExpressionTree (ResolveContext ec);
1269 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1271 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1274 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1276 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1279 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1281 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1284 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1286 TypeExpr texpr = TypeManager.expression_type_expr;
1287 if (texpr == null) {
1288 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", Kind.Class, true);
1289 if (t == null)
1290 return null;
1292 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1295 return texpr;
1298 #if NET_4_0
1300 // Implemented by all expressions which support conversion from
1301 // compiler expression to invokable runtime expression. Used by
1302 // dynamic C# binder.
1304 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1306 throw new NotImplementedException ("MakeExpression for " + GetType ());
1308 #endif
1310 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1312 // TODO: It should probably be type = storey.MutateType (type);
1316 /// <summary>
1317 /// This is just a base class for expressions that can
1318 /// appear on statements (invocations, object creation,
1319 /// assignments, post/pre increment and decrement). The idea
1320 /// being that they would support an extra Emition interface that
1321 /// does not leave a result on the stack.
1322 /// </summary>
1323 public abstract class ExpressionStatement : Expression {
1325 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1327 Expression e = Resolve (ec);
1328 if (e == null)
1329 return null;
1331 ExpressionStatement es = e as ExpressionStatement;
1332 if (es == null)
1333 Error_InvalidExpressionStatement (ec);
1335 return es;
1338 /// <summary>
1339 /// Requests the expression to be emitted in a `statement'
1340 /// context. This means that no new value is left on the
1341 /// stack after invoking this method (constrasted with
1342 /// Emit that will always leave a value on the stack).
1343 /// </summary>
1344 public abstract void EmitStatement (EmitContext ec);
1346 public override void EmitSideEffect (EmitContext ec)
1348 EmitStatement (ec);
1352 /// <summary>
1353 /// This kind of cast is used to encapsulate the child
1354 /// whose type is child.Type into an expression that is
1355 /// reported to return "return_type". This is used to encapsulate
1356 /// expressions which have compatible types, but need to be dealt
1357 /// at higher levels with.
1359 /// For example, a "byte" expression could be encapsulated in one
1360 /// of these as an "unsigned int". The type for the expression
1361 /// would be "unsigned int".
1363 /// </summary>
1364 public abstract class TypeCast : Expression
1366 protected readonly Expression child;
1368 protected TypeCast (Expression child, Type return_type)
1370 eclass = child.eclass;
1371 loc = child.Location;
1372 type = return_type;
1373 this.child = child;
1376 public override Expression CreateExpressionTree (ResolveContext ec)
1378 Arguments args = new Arguments (2);
1379 args.Add (new Argument (child.CreateExpressionTree (ec)));
1380 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1382 if (type.IsPointer || child.Type.IsPointer)
1383 Error_PointerInsideExpressionTree (ec);
1385 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1388 public override Expression DoResolve (ResolveContext ec)
1390 // This should never be invoked, we are born in fully
1391 // initialized state.
1393 return this;
1396 public override void Emit (EmitContext ec)
1398 child.Emit (ec);
1401 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1403 return child.GetAttributableValue (ec, value_type, out value);
1406 #if NET_4_0
1407 public override SLE.Expression MakeExpression (BuilderContext ctx)
1409 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1410 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1411 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1413 #endif
1415 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1417 type = storey.MutateType (type);
1418 child.MutateHoistedGenericType (storey);
1421 protected override void CloneTo (CloneContext clonectx, Expression t)
1423 // Nothing to clone
1426 public override bool IsNull {
1427 get { return child.IsNull; }
1431 public class EmptyCast : TypeCast {
1432 EmptyCast (Expression child, Type target_type)
1433 : base (child, target_type)
1437 public static Expression Create (Expression child, Type type)
1439 Constant c = child as Constant;
1440 if (c != null)
1441 return new EmptyConstantCast (c, type);
1443 EmptyCast e = child as EmptyCast;
1444 if (e != null)
1445 return new EmptyCast (e.child, type);
1447 return new EmptyCast (child, type);
1450 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1452 child.EmitBranchable (ec, label, on_true);
1455 public override void EmitSideEffect (EmitContext ec)
1457 child.EmitSideEffect (ec);
1462 // Used for predefined class library user casts (no obsolete check, etc.)
1464 public class OperatorCast : TypeCast {
1465 MethodInfo conversion_operator;
1467 public OperatorCast (Expression child, Type target_type)
1468 : this (child, target_type, false)
1472 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1473 : base (child, target_type)
1475 conversion_operator = GetConversionOperator (find_explicit);
1476 if (conversion_operator == null)
1477 throw new InternalErrorException ("Outer conversion routine is out of sync");
1480 // Returns the implicit operator that converts from
1481 // 'child.Type' to our target type (type)
1482 MethodInfo GetConversionOperator (bool find_explicit)
1484 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1486 MemberInfo [] mi;
1488 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1489 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1491 if (mi == null){
1492 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1493 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1496 foreach (MethodInfo oper in mi) {
1497 AParametersCollection pd = TypeManager.GetParameterData (oper);
1499 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1500 return oper;
1503 return null;
1506 public override void Emit (EmitContext ec)
1508 child.Emit (ec);
1509 ec.ig.Emit (OpCodes.Call, conversion_operator);
1513 /// <summary>
1514 /// This is a numeric cast to a Decimal
1515 /// </summary>
1516 public class CastToDecimal : OperatorCast {
1517 public CastToDecimal (Expression child)
1518 : this (child, false)
1522 public CastToDecimal (Expression child, bool find_explicit)
1523 : base (child, TypeManager.decimal_type, find_explicit)
1528 /// <summary>
1529 /// This is an explicit numeric cast from a Decimal
1530 /// </summary>
1531 public class CastFromDecimal : TypeCast
1533 static IDictionary operators;
1535 public CastFromDecimal (Expression child, Type return_type)
1536 : base (child, return_type)
1538 if (child.Type != TypeManager.decimal_type)
1539 throw new InternalErrorException (
1540 "The expected type is Decimal, instead it is " + child.Type.FullName);
1543 // Returns the explicit operator that converts from an
1544 // express of type System.Decimal to 'type'.
1545 public Expression Resolve ()
1547 if (operators == null) {
1548 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1549 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1550 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1552 operators = new System.Collections.Specialized.HybridDictionary ();
1553 foreach (MethodInfo oper in all_oper) {
1554 AParametersCollection pd = TypeManager.GetParameterData (oper);
1555 if (pd.Types [0] == TypeManager.decimal_type)
1556 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1560 return operators.Contains (type) ? this : null;
1563 public override void Emit (EmitContext ec)
1565 ILGenerator ig = ec.ig;
1566 child.Emit (ec);
1568 ig.Emit (OpCodes.Call, (MethodInfo)operators [type]);
1574 // Constant specialization of EmptyCast.
1575 // We need to special case this since an empty cast of
1576 // a constant is still a constant.
1578 public class EmptyConstantCast : Constant
1580 public readonly Constant child;
1582 public EmptyConstantCast(Constant child, Type type)
1583 : base (child.Location)
1585 eclass = child.eclass;
1586 this.child = child;
1587 this.type = type;
1590 public override string AsString ()
1592 return child.AsString ();
1595 public override object GetValue ()
1597 return child.GetValue ();
1600 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1602 // FIXME: check that 'type' can be converted to 'target_type' first
1603 return child.ConvertExplicitly (in_checked_context, target_type);
1606 public override Expression CreateExpressionTree (ResolveContext ec)
1608 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1609 child.CreateExpressionTree (ec),
1610 new TypeOf (new TypeExpression (type, loc), loc));
1612 if (type.IsPointer)
1613 Error_PointerInsideExpressionTree (ec);
1615 return CreateExpressionFactoryCall (ec, "Convert", args);
1618 public override Constant Increment ()
1620 return child.Increment ();
1623 public override bool IsDefaultValue {
1624 get { return child.IsDefaultValue; }
1627 public override bool IsNegative {
1628 get { return child.IsNegative; }
1631 public override bool IsNull {
1632 get { return child.IsNull; }
1635 public override bool IsZeroInteger {
1636 get { return child.IsZeroInteger; }
1639 public override void Emit (EmitContext ec)
1641 child.Emit (ec);
1644 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1646 child.EmitBranchable (ec, label, on_true);
1648 // Only to make verifier happy
1649 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1650 ec.ig.Emit (OpCodes.Unbox_Any, type);
1653 public override void EmitSideEffect (EmitContext ec)
1655 child.EmitSideEffect (ec);
1658 public override Constant ConvertImplicitly (Type target_type)
1660 // FIXME: Do we need to check user conversions?
1661 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1662 return null;
1663 return child.ConvertImplicitly (target_type);
1666 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1668 child.MutateHoistedGenericType (storey);
1673 /// <summary>
1674 /// This class is used to wrap literals which belong inside Enums
1675 /// </summary>
1676 public class EnumConstant : Constant {
1677 public Constant Child;
1679 public EnumConstant (Constant child, Type enum_type):
1680 base (child.Location)
1682 eclass = child.eclass;
1683 this.Child = child;
1684 type = enum_type;
1687 protected EnumConstant ()
1688 : base (Location.Null)
1692 public override Expression DoResolve (ResolveContext ec)
1694 // This should never be invoked, we are born in fully
1695 // initialized state.
1697 return this;
1700 public override void Emit (EmitContext ec)
1702 Child.Emit (ec);
1705 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1707 Child.EmitBranchable (ec, label, on_true);
1710 public override void EmitSideEffect (EmitContext ec)
1712 Child.EmitSideEffect (ec);
1715 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1717 value = GetTypedValue ();
1718 return true;
1721 public override string GetSignatureForError()
1723 return TypeManager.CSharpName (Type);
1726 public override object GetValue ()
1728 return Child.GetValue ();
1731 public override object GetTypedValue ()
1733 // FIXME: runtime is not ready to work with just emited enums
1734 if (!RootContext.StdLib) {
1735 return Child.GetValue ();
1738 #if MS_COMPATIBLE
1739 // Small workaround for big problem
1740 // System.Enum.ToObject cannot be called on dynamic types
1741 // EnumBuilder has to be used, but we cannot use EnumBuilder
1742 // because it does not properly support generics
1744 // This works only sometimes
1746 if (TypeManager.IsBeingCompiled (type))
1747 return Child.GetValue ();
1748 #endif
1750 return System.Enum.ToObject (type, Child.GetValue ());
1753 public override string AsString ()
1755 return Child.AsString ();
1758 public override Constant Increment()
1760 return new EnumConstant (Child.Increment (), type);
1763 public override bool IsDefaultValue {
1764 get {
1765 return Child.IsDefaultValue;
1769 public override bool IsZeroInteger {
1770 get { return Child.IsZeroInteger; }
1773 public override bool IsNegative {
1774 get {
1775 return Child.IsNegative;
1779 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1781 if (Child.Type == target_type)
1782 return Child;
1784 return Child.ConvertExplicitly (in_checked_context, target_type);
1787 public override Constant ConvertImplicitly (Type type)
1789 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1790 type = TypeManager.DropGenericTypeArguments (type);
1792 if (this_type == type) {
1793 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1794 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1795 return this;
1797 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1798 if (type.UnderlyingSystemType != child_type)
1799 Child = Child.ConvertImplicitly (type.UnderlyingSystemType);
1800 return this;
1803 if (!Convert.ImplicitStandardConversionExists (this, type)){
1804 return null;
1807 return Child.ConvertImplicitly(type);
1812 /// <summary>
1813 /// This kind of cast is used to encapsulate Value Types in objects.
1815 /// The effect of it is to box the value type emitted by the previous
1816 /// operation.
1817 /// </summary>
1818 public class BoxedCast : TypeCast {
1820 public BoxedCast (Expression expr, Type target_type)
1821 : base (expr, target_type)
1823 eclass = ExprClass.Value;
1826 public override Expression DoResolve (ResolveContext ec)
1828 // This should never be invoked, we are born in fully
1829 // initialized state.
1831 return this;
1834 public override void Emit (EmitContext ec)
1836 base.Emit (ec);
1838 ec.ig.Emit (OpCodes.Box, child.Type);
1841 public override void EmitSideEffect (EmitContext ec)
1843 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1844 // so, we need to emit the box+pop instructions in most cases
1845 if (TypeManager.IsStruct (child.Type) &&
1846 (type == TypeManager.object_type || type == TypeManager.value_type))
1847 child.EmitSideEffect (ec);
1848 else
1849 base.EmitSideEffect (ec);
1853 public class UnboxCast : TypeCast {
1854 public UnboxCast (Expression expr, Type return_type)
1855 : base (expr, return_type)
1859 public override Expression DoResolve (ResolveContext ec)
1861 // This should never be invoked, we are born in fully
1862 // initialized state.
1864 return this;
1867 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1869 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1870 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1871 return base.DoResolveLValue (ec, right_side);
1874 public override void Emit (EmitContext ec)
1876 base.Emit (ec);
1878 ILGenerator ig = ec.ig;
1879 ig.Emit (OpCodes.Unbox_Any, type);
1882 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1884 type = storey.MutateType (type);
1885 base.MutateHoistedGenericType (storey);
1889 /// <summary>
1890 /// This is used to perform explicit numeric conversions.
1892 /// Explicit numeric conversions might trigger exceptions in a checked
1893 /// context, so they should generate the conv.ovf opcodes instead of
1894 /// conv opcodes.
1895 /// </summary>
1896 public class ConvCast : TypeCast {
1897 public enum Mode : byte {
1898 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1899 U1_I1, U1_CH,
1900 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1901 U2_I1, U2_U1, U2_I2, U2_CH,
1902 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1903 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1904 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1905 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1906 CH_I1, CH_U1, CH_I2,
1907 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1908 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1909 I_I8,
1912 Mode mode;
1914 public ConvCast (Expression child, Type return_type, Mode m)
1915 : base (child, return_type)
1917 mode = m;
1920 public override Expression DoResolve (ResolveContext ec)
1922 // This should never be invoked, we are born in fully
1923 // initialized state.
1925 return this;
1928 public override string ToString ()
1930 return String.Format ("ConvCast ({0}, {1})", mode, child);
1933 public override void Emit (EmitContext ec)
1935 ILGenerator ig = ec.ig;
1937 base.Emit (ec);
1939 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1940 switch (mode){
1941 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1942 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1943 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1944 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1945 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1947 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1948 case Mode.U1_CH: /* nothing */ break;
1950 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1951 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1952 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1954 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1955 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1957 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1958 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1959 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1960 case Mode.U2_CH: /* nothing */ break;
1962 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1963 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1964 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1965 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1966 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1967 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1968 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1971 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1972 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1973 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1974 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1975 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1977 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1978 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1979 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1980 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1981 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1982 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1983 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1987 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1988 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1989 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1990 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1991 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1992 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1993 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1994 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1995 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1997 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1998 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1999 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
2001 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2002 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2003 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2004 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2005 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2006 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2007 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2008 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2009 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2011 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
2012 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
2013 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
2014 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2015 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
2016 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
2017 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
2018 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
2019 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
2020 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2022 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
2024 } else {
2025 switch (mode){
2026 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
2027 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
2028 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
2029 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
2030 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
2032 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
2033 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2036 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2037 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2038 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2039 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2040 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2042 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2043 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2044 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2045 case Mode.U2_CH: /* nothing */ break;
2047 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2048 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2049 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2050 case Mode.I4_U4: /* nothing */ break;
2051 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2052 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2053 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2056 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2057 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2058 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2059 case Mode.U4_I4: /* nothing */ break;
2060 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2062 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2063 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2064 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2065 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2066 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2067 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2068 case Mode.I8_U8: /* nothing */ break;
2069 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2072 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2073 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2074 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2075 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2076 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2077 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2078 case Mode.U8_I8: /* nothing */ break;
2079 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2080 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2082 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2083 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2084 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2086 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2087 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2088 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2089 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2090 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2091 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2092 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2093 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2094 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2096 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2097 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2098 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2099 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2100 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2101 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2102 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2103 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2104 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2105 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2107 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2113 public class OpcodeCast : TypeCast {
2114 readonly OpCode op;
2116 public OpcodeCast (Expression child, Type return_type, OpCode op)
2117 : base (child, return_type)
2119 this.op = op;
2122 public override Expression DoResolve (ResolveContext ec)
2124 // This should never be invoked, we are born in fully
2125 // initialized state.
2127 return this;
2130 public override void Emit (EmitContext ec)
2132 base.Emit (ec);
2133 ec.ig.Emit (op);
2136 public Type UnderlyingType {
2137 get { return child.Type; }
2141 /// <summary>
2142 /// This kind of cast is used to encapsulate a child and cast it
2143 /// to the class requested
2144 /// </summary>
2145 public sealed class ClassCast : TypeCast {
2146 readonly bool forced;
2148 public ClassCast (Expression child, Type return_type)
2149 : base (child, return_type)
2153 public ClassCast (Expression child, Type return_type, bool forced)
2154 : base (child, return_type)
2156 this.forced = forced;
2159 public override void Emit (EmitContext ec)
2161 base.Emit (ec);
2163 bool gen = TypeManager.IsGenericParameter (child.Type);
2164 if (gen)
2165 ec.ig.Emit (OpCodes.Box, child.Type);
2167 if (type.IsGenericParameter) {
2168 ec.ig.Emit (OpCodes.Unbox_Any, type);
2169 return;
2172 if (gen && !forced)
2173 return;
2175 ec.ig.Emit (OpCodes.Castclass, type);
2180 // Created during resolving pahse when an expression is wrapped or constantified
2181 // and original expression can be used later (e.g. for expression trees)
2183 public class ReducedExpression : Expression
2185 sealed class ReducedConstantExpression : EmptyConstantCast
2187 readonly Expression orig_expr;
2189 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2190 : base (expr, expr.Type)
2192 this.orig_expr = orig_expr;
2195 public override Constant ConvertImplicitly (Type target_type)
2197 Constant c = base.ConvertImplicitly (target_type);
2198 if (c != null)
2199 c = new ReducedConstantExpression (c, orig_expr);
2200 return c;
2203 public override Expression CreateExpressionTree (ResolveContext ec)
2205 return orig_expr.CreateExpressionTree (ec);
2208 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2211 // Even if resolved result is a constant original expression was not
2212 // and attribute accepts constants only
2214 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2215 value = null;
2216 return false;
2219 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2221 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2222 if (c != null)
2223 c = new ReducedConstantExpression (c, orig_expr);
2224 return c;
2228 sealed class ReducedExpressionStatement : ExpressionStatement
2230 readonly Expression orig_expr;
2231 readonly ExpressionStatement stm;
2233 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2235 this.orig_expr = orig;
2236 this.stm = stm;
2237 this.loc = orig.Location;
2240 public override Expression CreateExpressionTree (ResolveContext ec)
2242 return orig_expr.CreateExpressionTree (ec);
2245 public override Expression DoResolve (ResolveContext ec)
2247 eclass = stm.eclass;
2248 type = stm.Type;
2249 return this;
2252 public override void Emit (EmitContext ec)
2254 stm.Emit (ec);
2257 public override void EmitStatement (EmitContext ec)
2259 stm.EmitStatement (ec);
2262 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2264 stm.MutateHoistedGenericType (storey);
2268 readonly Expression expr, orig_expr;
2270 private ReducedExpression (Expression expr, Expression orig_expr)
2272 this.expr = expr;
2273 this.orig_expr = orig_expr;
2274 this.loc = orig_expr.Location;
2277 public static Constant Create (Constant expr, Expression original_expr)
2279 return new ReducedConstantExpression (expr, original_expr);
2282 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2284 return new ReducedExpressionStatement (s, orig);
2287 public static Expression Create (Expression expr, Expression original_expr)
2289 Constant c = expr as Constant;
2290 if (c != null)
2291 return Create (c, original_expr);
2293 ExpressionStatement s = expr as ExpressionStatement;
2294 if (s != null)
2295 return Create (s, original_expr);
2297 return new ReducedExpression (expr, original_expr);
2300 public override Expression CreateExpressionTree (ResolveContext ec)
2302 return orig_expr.CreateExpressionTree (ec);
2305 public override Expression DoResolve (ResolveContext ec)
2307 eclass = expr.eclass;
2308 type = expr.Type;
2309 return this;
2312 public override void Emit (EmitContext ec)
2314 expr.Emit (ec);
2317 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2319 expr.EmitBranchable (ec, target, on_true);
2322 #if NET_4_0
2323 public override SLE.Expression MakeExpression (BuilderContext ctx)
2325 return orig_expr.MakeExpression (ctx);
2327 #endif
2329 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2331 expr.MutateHoistedGenericType (storey);
2336 // Standard composite pattern
2338 public abstract class CompositeExpression : Expression
2340 Expression expr;
2342 protected CompositeExpression (Expression expr)
2344 this.expr = expr;
2345 this.loc = expr.Location;
2348 public override Expression CreateExpressionTree (ResolveContext ec)
2350 return expr.CreateExpressionTree (ec);
2353 public Expression Child {
2354 get { return expr; }
2357 public override Expression DoResolve (ResolveContext ec)
2359 expr = expr.Resolve (ec);
2360 if (expr != null) {
2361 type = expr.Type;
2362 eclass = expr.eclass;
2365 return this;
2368 public override void Emit (EmitContext ec)
2370 expr.Emit (ec);
2373 public override bool IsNull {
2374 get { return expr.IsNull; }
2379 // Base of expressions used only to narrow resolve flow
2381 public abstract class ShimExpression : Expression
2383 protected Expression expr;
2385 protected ShimExpression (Expression expr)
2387 this.expr = expr;
2390 protected override void CloneTo (CloneContext clonectx, Expression t)
2392 if (expr == null)
2393 return;
2395 ShimExpression target = (ShimExpression) t;
2396 target.expr = expr.Clone (clonectx);
2399 public override Expression CreateExpressionTree (ResolveContext ec)
2401 throw new NotSupportedException ("ET");
2404 public override void Emit (EmitContext ec)
2406 throw new InternalErrorException ("Missing Resolve call");
2409 public Expression Expr {
2410 get { return expr; }
2413 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2415 throw new InternalErrorException ("Missing Resolve call");
2420 // Unresolved type name expressions
2422 public abstract class ATypeNameExpression : FullNamedExpression
2424 string name;
2425 protected TypeArguments targs;
2427 protected ATypeNameExpression (string name, Location l)
2429 this.name = name;
2430 loc = l;
2433 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2435 this.name = name;
2436 this.targs = targs;
2437 loc = l;
2440 public bool HasTypeArguments {
2441 get {
2442 return targs != null;
2446 public override bool Equals (object obj)
2448 ATypeNameExpression atne = obj as ATypeNameExpression;
2449 return atne != null && atne.Name == Name &&
2450 (targs == null || targs.Equals (atne.targs));
2453 public override int GetHashCode ()
2455 return Name.GetHashCode ();
2458 public override string GetSignatureForError ()
2460 if (targs != null) {
2461 return TypeManager.RemoveGenericArity (Name) + "<" +
2462 targs.GetSignatureForError () + ">";
2465 return Name;
2468 public string Name {
2469 get {
2470 return name;
2472 set {
2473 name = value;
2477 public TypeArguments TypeArguments {
2478 get {
2479 return targs;
2484 /// <summary>
2485 /// SimpleName expressions are formed of a single word and only happen at the beginning
2486 /// of a dotted-name.
2487 /// </summary>
2488 public class SimpleName : ATypeNameExpression {
2489 bool in_transit;
2491 public SimpleName (string name, Location l)
2492 : base (name, l)
2496 public SimpleName (string name, TypeArguments args, Location l)
2497 : base (name, args, l)
2501 public SimpleName (string name, TypeParameter[] type_params, Location l)
2502 : base (name, l)
2504 targs = new TypeArguments ();
2505 foreach (TypeParameter type_param in type_params)
2506 targs.Add (new TypeParameterExpr (type_param, l));
2509 public static string RemoveGenericArity (string name)
2511 int start = 0;
2512 StringBuilder sb = null;
2513 do {
2514 int pos = name.IndexOf ('`', start);
2515 if (pos < 0) {
2516 if (start == 0)
2517 return name;
2519 sb.Append (name.Substring (start));
2520 break;
2523 if (sb == null)
2524 sb = new StringBuilder ();
2525 sb.Append (name.Substring (start, pos-start));
2527 pos++;
2528 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2529 pos++;
2531 start = pos;
2532 } while (start < name.Length);
2534 return sb.ToString ();
2537 public SimpleName GetMethodGroup ()
2539 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2542 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2544 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2545 ec.Report.Error (236, l,
2546 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2547 name);
2548 else
2549 ec.Report.Error (120, l,
2550 "An object reference is required to access non-static member `{0}'",
2551 name);
2554 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2556 return resolved_to != null && resolved_to.Type != null &&
2557 resolved_to.Type.Name == Name &&
2558 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2561 public override Expression DoResolve (ResolveContext ec)
2563 return SimpleNameResolve (ec, null, false);
2566 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2568 return SimpleNameResolve (ec, right_side, false);
2572 public Expression DoResolve (ResolveContext ec, bool intermediate)
2574 return SimpleNameResolve (ec, null, intermediate);
2577 static bool IsNestedChild (Type t, Type parent)
2579 while (parent != null) {
2580 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2581 return true;
2583 parent = parent.BaseType;
2586 return false;
2589 FullNamedExpression ResolveNested (Type t)
2591 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2592 return null;
2594 Type ds = t;
2595 while (ds != null && !IsNestedChild (t, ds))
2596 ds = ds.DeclaringType;
2598 if (ds == null)
2599 return null;
2601 Type[] gen_params = TypeManager.GetTypeArguments (t);
2603 int arg_count = targs != null ? targs.Count : 0;
2605 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2606 Type[] gargs = TypeManager.GetTypeArguments (ds);
2607 if (arg_count + gargs.Length == gen_params.Length) {
2608 TypeArguments new_args = new TypeArguments ();
2609 foreach (Type param in gargs)
2610 new_args.Add (new TypeExpression (param, loc));
2612 if (targs != null)
2613 new_args.Add (targs);
2615 return new GenericTypeExpr (t, new_args, loc);
2619 return null;
2622 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2624 int errors = ec.Compiler.Report.Errors;
2625 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2627 if (fne != null) {
2628 if (fne.Type == null)
2629 return fne;
2631 FullNamedExpression nested = ResolveNested (fne.Type);
2632 if (nested != null)
2633 return nested.ResolveAsTypeStep (ec, false);
2635 if (targs != null) {
2636 if (TypeManager.IsGenericType (fne.Type)) {
2637 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2638 return ct.ResolveAsTypeStep (ec, false);
2641 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2644 return fne;
2647 if (!HasTypeArguments && Name == "dynamic" &&
2648 RootContext.Version > LanguageVersion.V_3 &&
2649 RootContext.MetadataCompatibilityVersion > MetadataVersion.v2) {
2651 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2652 ec.Compiler.Report.Error (1980, Location,
2653 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2654 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2657 return new DynamicTypeExpr (loc);
2660 if (silent || errors != ec.Compiler.Report.Errors)
2661 return null;
2663 Error_TypeOrNamespaceNotFound (ec);
2664 return null;
2667 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2669 if (ec.CurrentType != null) {
2670 if (ec.CurrentTypeDefinition != null) {
2671 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2672 if (mc != null) {
2673 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2674 return;
2678 string ns = ec.CurrentType.Namespace;
2679 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2680 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2681 Type type = a.GetType (fullname);
2682 if (type != null) {
2683 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2684 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2685 return;
2689 if (ec.CurrentTypeDefinition != null) {
2690 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2691 if (t != null) {
2692 Namespace.Error_InvalidNumberOfTypeArguments (t, loc);
2693 return;
2698 if (targs != null) {
2699 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2700 if (retval != null) {
2701 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2702 return;
2706 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2709 // TODO: I am still not convinced about this. If someone else will need it
2710 // implement this as virtual property in MemberCore hierarchy
2711 public static string GetMemberType (MemberCore mc)
2713 if (mc is Property)
2714 return "property";
2715 if (mc is Indexer)
2716 return "indexer";
2717 if (mc is FieldBase)
2718 return "field";
2719 if (mc is MethodCore)
2720 return "method";
2721 if (mc is EnumMember)
2722 return "enum";
2723 if (mc is Event)
2724 return "event";
2726 return "type";
2729 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2731 if (in_transit)
2732 return null;
2734 in_transit = true;
2735 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2736 in_transit = false;
2738 if (e == null)
2739 return null;
2741 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2742 return e;
2744 return null;
2747 /// <remarks>
2748 /// 7.5.2: Simple Names.
2750 /// Local Variables and Parameters are handled at
2751 /// parse time, so they never occur as SimpleNames.
2753 /// The `intermediate' flag is used by MemberAccess only
2754 /// and it is used to inform us that it is ok for us to
2755 /// avoid the static check, because MemberAccess might end
2756 /// up resolving the Name as a Type name and the access as
2757 /// a static type access.
2759 /// ie: Type Type; .... { Type.GetType (""); }
2761 /// Type is both an instance variable and a Type; Type.GetType
2762 /// is the static method not an instance method of type.
2763 /// </remarks>
2764 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2766 Expression e = null;
2769 // Stage 1: Performed by the parser (binding to locals or parameters).
2771 Block current_block = ec.CurrentBlock;
2772 if (current_block != null){
2773 LocalInfo vi = current_block.GetLocalInfo (Name);
2774 if (vi != null){
2775 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2777 if (right_side != null) {
2778 e = e.ResolveLValue (ec, right_side);
2779 } else {
2780 ResolveFlags rf = ResolveFlags.VariableOrValue;
2781 if (intermediate)
2782 rf |= ResolveFlags.DisableFlowAnalysis;
2784 e = e.Resolve (ec, rf);
2787 if (targs != null && e != null)
2788 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2790 return e;
2793 e = current_block.Toplevel.GetParameterReference (Name, loc);
2794 if (e != null) {
2795 if (right_side != null)
2796 e = e.ResolveLValue (ec, right_side);
2797 else
2798 e = e.Resolve (ec);
2800 if (targs != null && e != null)
2801 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2803 return e;
2808 // Stage 2: Lookup members
2811 Type almost_matched_type = null;
2812 ArrayList almost_matched = null;
2813 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2814 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2815 if (e != null) {
2816 PropertyExpr pe = e as PropertyExpr;
2817 if (pe != null) {
2818 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2820 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2821 // it doesn't know which accessor to check permissions against
2822 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2823 break;
2824 } else if (e is EventExpr) {
2825 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2826 break;
2827 } else if (targs != null && e is TypeExpression) {
2828 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2829 break;
2830 } else {
2831 break;
2833 e = null;
2836 if (almost_matched == null && almost_matched_members.Count > 0) {
2837 almost_matched_type = lookup_ds;
2838 almost_matched = (ArrayList) almost_matched_members.Clone ();
2842 if (e == null) {
2843 if (almost_matched == null && almost_matched_members.Count > 0) {
2844 almost_matched_type = ec.CurrentType;
2845 almost_matched = (ArrayList) almost_matched_members.Clone ();
2847 e = ResolveAsTypeStep (ec, true);
2850 if (e == null) {
2851 if (current_block != null) {
2852 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2853 if (ikv != null) {
2854 LocalInfo li = ikv as LocalInfo;
2855 // Supress CS0219 warning
2856 if (li != null)
2857 li.Used = true;
2859 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2860 return null;
2864 if (RootContext.EvalMode){
2865 FieldInfo fi = Evaluator.LookupField (Name);
2866 if (fi != null)
2867 return new FieldExpr (fi, loc).Resolve (ec);
2870 if (almost_matched != null)
2871 almost_matched_members = almost_matched;
2872 if (almost_matched_type == null)
2873 almost_matched_type = ec.CurrentType;
2875 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2876 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2877 type_name, AllMemberTypes, AllBindingFlags);
2880 if (e is MemberExpr) {
2881 MemberExpr me = (MemberExpr) e;
2883 Expression left;
2884 if (me.IsInstance) {
2885 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2887 // Note that an MemberExpr can be both IsInstance and IsStatic.
2888 // An unresolved MethodGroupExpr can contain both kinds of methods
2889 // and each predicate is true if the MethodGroupExpr contains
2890 // at least one of that kind of method.
2893 if (!me.IsStatic &&
2894 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2895 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2896 return null;
2900 // Pass the buck to MemberAccess and Invocation.
2902 left = EmptyExpression.Null;
2903 } else {
2904 left = ec.GetThis (loc);
2906 } else {
2907 left = new TypeExpression (ec.CurrentType, loc);
2910 me = me.ResolveMemberAccess (ec, left, loc, null);
2911 if (me == null)
2912 return null;
2914 if (targs != null) {
2915 if (!targs.Resolve (ec))
2916 return null;
2918 me.SetTypeArguments (ec, targs);
2921 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2922 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2923 me.InstanceExpression.Type != me.DeclaringType &&
2924 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2925 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2926 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2927 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2928 return null;
2931 return (right_side != null)
2932 ? me.DoResolveLValue (ec, right_side)
2933 : me.DoResolve (ec);
2936 return e;
2940 /// <summary>
2941 /// Represents a namespace or a type. The name of the class was inspired by
2942 /// section 10.8.1 (Fully Qualified Names).
2943 /// </summary>
2944 public abstract class FullNamedExpression : Expression
2946 protected override void CloneTo (CloneContext clonectx, Expression target)
2948 // Do nothing, most unresolved type expressions cannot be
2949 // resolved to different type
2952 public override Expression CreateExpressionTree (ResolveContext ec)
2954 throw new NotSupportedException ("ET");
2957 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2959 throw new NotSupportedException ();
2962 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2964 return this;
2967 public override void Emit (EmitContext ec)
2969 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2970 GetSignatureForError ());
2974 /// <summary>
2975 /// Expression that evaluates to a type
2976 /// </summary>
2977 public abstract class TypeExpr : FullNamedExpression {
2978 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2980 TypeExpr t = DoResolveAsTypeStep (ec);
2981 if (t == null)
2982 return null;
2984 eclass = ExprClass.Type;
2985 return t;
2988 override public Expression DoResolve (ResolveContext ec)
2990 return ResolveAsTypeTerminal (ec, false);
2993 public virtual bool CheckAccessLevel (IMemberContext mc)
2995 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2998 public virtual bool IsClass {
2999 get { return Type.IsClass; }
3002 public virtual bool IsValueType {
3003 get { return TypeManager.IsStruct (Type); }
3006 public virtual bool IsInterface {
3007 get { return Type.IsInterface; }
3010 public virtual bool IsSealed {
3011 get { return Type.IsSealed; }
3014 public virtual bool CanInheritFrom ()
3016 if (Type == TypeManager.enum_type ||
3017 (Type == TypeManager.value_type && RootContext.StdLib) ||
3018 Type == TypeManager.multicast_delegate_type ||
3019 Type == TypeManager.delegate_type ||
3020 Type == TypeManager.array_type)
3021 return false;
3023 return true;
3026 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
3028 public override bool Equals (object obj)
3030 TypeExpr tobj = obj as TypeExpr;
3031 if (tobj == null)
3032 return false;
3034 return Type == tobj.Type;
3037 public override int GetHashCode ()
3039 return Type.GetHashCode ();
3042 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3044 type = storey.MutateType (type);
3048 /// <summary>
3049 /// Fully resolved Expression that already evaluated to a type
3050 /// </summary>
3051 public class TypeExpression : TypeExpr {
3052 public TypeExpression (Type t, Location l)
3054 Type = t;
3055 eclass = ExprClass.Type;
3056 loc = l;
3059 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3061 return this;
3064 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3066 return this;
3071 // Used to create types from a fully qualified name. These are just used
3072 // by the parser to setup the core types.
3074 public sealed class TypeLookupExpression : TypeExpr {
3075 readonly string ns_name;
3076 readonly string name;
3078 public TypeLookupExpression (string ns, string name)
3080 this.name = name;
3081 this.ns_name = ns;
3082 eclass = ExprClass.Type;
3085 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3088 // It's null only during mscorlib bootstrap when DefineType
3089 // nees to resolve base type of same type
3091 // For instance struct Char : IComparable<char>
3093 // TODO: it could be removed when Resolve starts to use
3094 // DeclSpace instead of Type
3096 if (type == null) {
3097 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3098 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3099 if (fne != null)
3100 type = fne.Type;
3103 return this;
3106 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3108 return this;
3111 public override string GetSignatureForError ()
3113 if (type == null)
3114 return TypeManager.CSharpName (ns_name + "." + name, null);
3116 return base.GetSignatureForError ();
3120 /// <summary>
3121 /// This class denotes an expression which evaluates to a member
3122 /// of a struct or a class.
3123 /// </summary>
3124 public abstract class MemberExpr : Expression
3126 protected bool is_base;
3128 /// <summary>
3129 /// The name of this member.
3130 /// </summary>
3131 public abstract string Name {
3132 get;
3136 // When base.member is used
3138 public bool IsBase {
3139 get { return is_base; }
3140 set { is_base = value; }
3143 /// <summary>
3144 /// Whether this is an instance member.
3145 /// </summary>
3146 public abstract bool IsInstance {
3147 get;
3150 /// <summary>
3151 /// Whether this is a static member.
3152 /// </summary>
3153 public abstract bool IsStatic {
3154 get;
3157 /// <summary>
3158 /// The type which declares this member.
3159 /// </summary>
3160 public abstract Type DeclaringType {
3161 get;
3164 /// <summary>
3165 /// The instance expression associated with this member, if it's a
3166 /// non-static member.
3167 /// </summary>
3168 public Expression InstanceExpression;
3170 public static void error176 (ResolveContext ec, Location loc, string name)
3172 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3173 "with an instance reference, qualify it with a type name instead", name);
3176 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3178 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3181 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3183 if (InstanceExpression != null)
3184 InstanceExpression.MutateHoistedGenericType (storey);
3187 // TODO: possible optimalization
3188 // Cache resolved constant result in FieldBuilder <-> expression map
3189 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3190 SimpleName original)
3193 // Precondition:
3194 // original == null || original.Resolve (...) ==> left
3197 if (left is TypeExpr) {
3198 left = left.ResolveAsBaseTerminal (ec, false);
3199 if (left == null)
3200 return null;
3202 // TODO: Same problem as in class.cs, TypeTerminal does not
3203 // always do all necessary checks
3204 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3205 if (oa != null && !ec.IsObsolete) {
3206 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3209 GenericTypeExpr ct = left as GenericTypeExpr;
3210 if (ct != null && !ct.CheckConstraints (ec))
3211 return null;
3214 if (!IsStatic) {
3215 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3216 return null;
3219 return this;
3222 if (!IsInstance) {
3223 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3224 return this;
3226 return ResolveExtensionMemberAccess (ec, left);
3229 InstanceExpression = left;
3230 return this;
3233 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3235 error176 (ec, loc, GetSignatureForError ());
3236 return this;
3239 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3241 if (IsStatic)
3242 return;
3244 if (InstanceExpression == EmptyExpression.Null) {
3245 // FIXME: This should not be here at all
3246 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3247 return;
3250 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3251 if (InstanceExpression is IMemoryLocation) {
3252 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3253 } else {
3254 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3255 InstanceExpression.Emit (ec);
3256 t.Store (ec);
3257 t.AddressOf (ec, AddressOp.Store);
3259 } else
3260 InstanceExpression.Emit (ec);
3262 if (prepare_for_load)
3263 ec.ig.Emit (OpCodes.Dup);
3266 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3268 // TODO: need to get correct member type
3269 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3270 GetSignatureForError ());
3274 ///
3275 /// Represents group of extension methods
3276 ///
3277 public class ExtensionMethodGroupExpr : MethodGroupExpr
3279 readonly NamespaceEntry namespace_entry;
3280 public Expression ExtensionExpression;
3281 Argument extension_argument;
3283 public ExtensionMethodGroupExpr (ArrayList list, NamespaceEntry n, Type extensionType, Location l)
3284 : base (list, extensionType, l)
3286 this.namespace_entry = n;
3289 public override bool IsStatic {
3290 get { return true; }
3293 public bool IsTopLevel {
3294 get { return namespace_entry == null; }
3297 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3299 extension_argument.Expr.MutateHoistedGenericType (storey);
3300 base.MutateHoistedGenericType (storey);
3303 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3305 if (arguments == null)
3306 arguments = new Arguments (1);
3308 arguments.Insert (0, new Argument (ExtensionExpression));
3309 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3311 // Store resolved argument and restore original arguments
3312 if (mg != null)
3313 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3314 else
3315 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3317 return mg;
3320 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3322 // Use normal resolve rules
3323 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3324 if (mg != null)
3325 return mg;
3327 if (ns == null)
3328 return null;
3330 // Search continues
3331 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3332 if (e == null)
3333 return base.OverloadResolve (ec, ref arguments, false, loc);
3335 e.ExtensionExpression = ExtensionExpression;
3336 e.SetTypeArguments (ec, type_arguments);
3337 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3341 /// <summary>
3342 /// MethodGroupExpr represents a group of method candidates which
3343 /// can be resolved to the best method overload
3344 /// </summary>
3345 public class MethodGroupExpr : MemberExpr
3347 public interface IErrorHandler
3349 bool AmbiguousCall (ResolveContext ec, MethodBase ambiguous);
3350 bool NoExactMatch (ResolveContext ec, MethodBase method);
3353 public IErrorHandler CustomErrorHandler;
3354 public MethodBase [] Methods;
3355 MethodBase best_candidate;
3356 // TODO: make private
3357 public TypeArguments type_arguments;
3358 bool identical_type_name;
3359 bool has_inaccessible_candidates_only;
3360 Type delegate_type;
3361 Type queried_type;
3363 public MethodGroupExpr (MemberInfo [] mi, Type type, Location l)
3364 : this (type, l)
3366 Methods = new MethodBase [mi.Length];
3367 mi.CopyTo (Methods, 0);
3370 public MethodGroupExpr (MemberInfo[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3371 : this (mi, type, l)
3373 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3376 public MethodGroupExpr (ArrayList list, Type type, Location l)
3377 : this (type, l)
3379 try {
3380 Methods = (MethodBase[])list.ToArray (typeof (MethodBase));
3381 } catch {
3382 foreach (MemberInfo m in list){
3383 if (!(m is MethodBase)){
3384 Console.WriteLine ("Name " + m.Name);
3385 Console.WriteLine ("Found a: " + m.GetType ().FullName);
3388 throw;
3394 protected MethodGroupExpr (Type type, Location loc)
3396 this.loc = loc;
3397 eclass = ExprClass.MethodGroup;
3398 this.type = InternalType.MethodGroup;
3399 queried_type = type;
3402 public override Type DeclaringType {
3403 get {
3404 return queried_type;
3408 public Type DelegateType {
3409 set {
3410 delegate_type = value;
3414 public bool IdenticalTypeName {
3415 get {
3416 return identical_type_name;
3420 public override string GetSignatureForError ()
3422 if (best_candidate != null)
3423 return TypeManager.CSharpSignature (best_candidate);
3425 return TypeManager.CSharpSignature (Methods [0]);
3428 public override string Name {
3429 get {
3430 return Methods [0].Name;
3434 public override bool IsInstance {
3435 get {
3436 if (best_candidate != null)
3437 return !best_candidate.IsStatic;
3439 foreach (MethodBase mb in Methods)
3440 if (!mb.IsStatic)
3441 return true;
3443 return false;
3447 public override bool IsStatic {
3448 get {
3449 if (best_candidate != null)
3450 return best_candidate.IsStatic;
3452 foreach (MethodBase mb in Methods)
3453 if (mb.IsStatic)
3454 return true;
3456 return false;
3460 public static explicit operator ConstructorInfo (MethodGroupExpr mg)
3462 return (ConstructorInfo)mg.best_candidate;
3465 public static explicit operator MethodInfo (MethodGroupExpr mg)
3467 return (MethodInfo)mg.best_candidate;
3471 // 7.4.3.3 Better conversion from expression
3472 // Returns : 1 if a->p is better,
3473 // 2 if a->q is better,
3474 // 0 if neither is better
3476 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3478 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3479 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3481 // Uwrap delegate from Expression<T>
3483 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3484 p = TypeManager.GetTypeArguments (p) [0];
3486 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3487 q = TypeManager.GetTypeArguments (q) [0];
3490 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3491 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3492 if (p == TypeManager.void_type && q != TypeManager.void_type)
3493 return 2;
3494 if (q == TypeManager.void_type && p != TypeManager.void_type)
3495 return 1;
3496 } else {
3497 if (argument_type == p)
3498 return 1;
3500 if (argument_type == q)
3501 return 2;
3504 return BetterTypeConversion (ec, p, q);
3508 // 7.4.3.4 Better conversion from type
3510 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3512 if (p == null || q == null)
3513 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3515 if (p == TypeManager.int32_type) {
3516 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3517 return 1;
3518 } else if (p == TypeManager.int64_type) {
3519 if (q == TypeManager.uint64_type)
3520 return 1;
3521 } else if (p == TypeManager.sbyte_type) {
3522 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3523 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3524 return 1;
3525 } else if (p == TypeManager.short_type) {
3526 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3527 q == TypeManager.uint64_type)
3528 return 1;
3529 } else if (p == InternalType.Dynamic) {
3530 if (q == TypeManager.object_type)
3531 return 2;
3534 if (q == TypeManager.int32_type) {
3535 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3536 return 2;
3537 } if (q == TypeManager.int64_type) {
3538 if (p == TypeManager.uint64_type)
3539 return 2;
3540 } else if (q == TypeManager.sbyte_type) {
3541 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3542 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3543 return 2;
3544 } if (q == TypeManager.short_type) {
3545 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3546 p == TypeManager.uint64_type)
3547 return 2;
3548 } else if (q == InternalType.Dynamic) {
3549 if (p == TypeManager.object_type)
3550 return 1;
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 (ResolveContext ec, Arguments 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 = args [j];
3591 // Provided default argument value is never better
3592 if (a.IsDefaultArgument && candidate_params == best_params)
3593 return false;
3595 Type ct = candidate_pd.Types [c_idx];
3596 Type bt = best_pd.Types [b_idx];
3598 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3600 ct = TypeManager.GetElementType (ct);
3601 --c_idx;
3604 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3606 bt = TypeManager.GetElementType (bt);
3607 --b_idx;
3610 if (ct == bt)
3611 continue;
3613 same = false;
3614 int result = BetterExpressionConversion (ec, a, ct, bt);
3616 // for each argument, the conversion to 'ct' should be no worse than
3617 // the conversion to 'bt'.
3618 if (result == 2)
3619 return false;
3621 // for at least one argument, the conversion to 'ct' should be better than
3622 // the conversion to 'bt'.
3623 if (result != 0)
3624 better_at_least_one = true;
3627 if (better_at_least_one)
3628 return true;
3631 // This handles the case
3633 // Add (float f1, float f2, float f3);
3634 // Add (params decimal [] foo);
3636 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3637 // first candidate would've chosen as better.
3639 if (!same)
3640 return false;
3643 // The two methods have equal parameter types. Now apply tie-breaking rules
3645 if (TypeManager.IsGenericMethod (best)) {
3646 if (!TypeManager.IsGenericMethod (candidate))
3647 return true;
3648 } else if (TypeManager.IsGenericMethod (candidate)) {
3649 return false;
3653 // This handles the following cases:
3655 // Trim () is better than Trim (params char[] chars)
3656 // Concat (string s1, string s2, string s3) is better than
3657 // Concat (string s1, params string [] srest)
3658 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3660 if (!candidate_params && best_params)
3661 return true;
3662 if (candidate_params && !best_params)
3663 return false;
3665 int candidate_param_count = candidate_pd.Count;
3666 int best_param_count = best_pd.Count;
3668 if (candidate_param_count != best_param_count)
3669 // can only happen if (candidate_params && best_params)
3670 return candidate_param_count > best_param_count && best_pd.HasParams;
3673 // now, both methods have the same number of parameters, and the parameters have the same types
3674 // Pick the "more specific" signature
3677 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3678 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3680 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3681 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3683 bool specific_at_least_once = false;
3684 for (int j = 0; j < candidate_param_count; ++j)
3686 Type ct = orig_candidate_pd.Types [j];
3687 Type bt = orig_best_pd.Types [j];
3688 if (ct.Equals (bt))
3689 continue;
3690 Type specific = MoreSpecific (ct, bt);
3691 if (specific == bt)
3692 return false;
3693 if (specific == ct)
3694 specific_at_least_once = true;
3697 if (specific_at_least_once)
3698 return true;
3700 // FIXME: handle lifted operators
3701 // ...
3703 return false;
3706 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3708 if (!IsStatic)
3709 return base.ResolveExtensionMemberAccess (ec, left);
3712 // When left side is an expression and at least one candidate method is
3713 // static, it can be extension method
3715 InstanceExpression = left;
3716 return this;
3719 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3720 SimpleName original)
3722 if (!(left is TypeExpr) &&
3723 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3724 identical_type_name = true;
3726 return base.ResolveMemberAccess (ec, left, loc, original);
3729 public override Expression CreateExpressionTree (ResolveContext ec)
3731 if (best_candidate == null) {
3732 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3733 return null;
3736 IMethodData md = TypeManager.GetMethod (best_candidate);
3737 if (md != null && md.IsExcluded ())
3738 ec.Report.Error (765, loc,
3739 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3741 return new TypeOfMethod (best_candidate, loc);
3744 override public Expression DoResolve (ResolveContext ec)
3746 if (InstanceExpression != null) {
3747 InstanceExpression = InstanceExpression.DoResolve (ec);
3748 if (InstanceExpression == null)
3749 return null;
3752 return this;
3755 public void ReportUsageError (ResolveContext ec)
3757 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3758 Name + "()' is referenced without parentheses");
3761 override public void Emit (EmitContext ec)
3763 throw new NotSupportedException ();
3764 // ReportUsageError ();
3767 public void EmitCall (EmitContext ec, Arguments arguments)
3769 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3772 void Error_AmbiguousCall (ResolveContext ec, MethodBase ambiguous)
3774 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3775 return;
3777 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3778 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3779 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate));
3782 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodBase method,
3783 Argument a, AParametersCollection expected_par, Type paramType)
3785 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3787 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3788 ec.Report.SymbolRelatedToPreviousError (method);
3789 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3790 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3791 TypeManager.CSharpSignature (method));
3792 return;
3794 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3795 TypeManager.CSharpSignature (method));
3796 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3797 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3798 TypeManager.CSharpName (method.DeclaringType));
3799 } else {
3800 ec.Report.SymbolRelatedToPreviousError (method);
3801 if (emg != null) {
3802 ec.Report.Error (1928, loc,
3803 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3804 emg.ExtensionExpression.GetSignatureForError (),
3805 emg.Name, TypeManager.CSharpSignature (method));
3806 } else {
3807 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3808 TypeManager.CSharpSignature (method));
3812 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3814 string index = (idx + 1).ToString ();
3815 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3816 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3817 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3818 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3819 index, Parameter.GetModifierSignature (a.Modifier));
3820 else
3821 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3822 index, Parameter.GetModifierSignature (mod));
3823 } else {
3824 string p1 = a.GetSignatureForError ();
3825 string p2 = TypeManager.CSharpName (paramType);
3827 if (p1 == p2) {
3828 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3829 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3830 ec.Report.SymbolRelatedToPreviousError (paramType);
3833 if (idx == 0 && emg != null) {
3834 ec.Report.Error (1929, loc,
3835 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3836 } else {
3837 ec.Report.Error (1503, loc,
3838 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3843 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3845 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3846 Name, TypeManager.CSharpName (target));
3849 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3851 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3852 Name, arg_count.ToString ());
3855 protected virtual int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
3857 return parameters.Count;
3860 public static bool IsAncestralType (Type first_type, Type second_type)
3862 return first_type != second_type &&
3863 (TypeManager.IsSubclassOf (second_type, first_type) ||
3864 TypeManager.ImplementsInterface (second_type, first_type));
3868 /// Determines if the candidate method is applicable (section 14.4.2.1)
3869 /// to the given set of arguments
3870 /// A return value rates candidate method compatibility,
3871 /// 0 = the best, int.MaxValue = the worst
3873 public int IsApplicable (ResolveContext ec,
3874 ref Arguments arguments, int arg_count, ref MethodBase method, ref bool params_expanded_form)
3876 MethodBase candidate = method;
3878 AParametersCollection pd = TypeManager.GetParameterData (candidate);
3879 int param_count = GetApplicableParametersCount (candidate, pd);
3880 int optional_count = 0;
3882 if (arg_count != param_count) {
3883 for (int i = 0; i < pd.Count; ++i) {
3884 if (pd.FixedParameters [i].HasDefaultValue) {
3885 optional_count = pd.Count - i;
3886 break;
3890 int args_gap = Math.Abs (arg_count - param_count);
3891 if (optional_count != 0) {
3892 if (args_gap > optional_count)
3893 return int.MaxValue - 10000 + args_gap - optional_count;
3895 // Readjust expected number when params used
3896 if (pd.HasParams) {
3897 optional_count--;
3898 if (arg_count < param_count)
3899 param_count--;
3900 } else if (arg_count > param_count) {
3901 return int.MaxValue - 10000 + args_gap;
3903 } else if (arg_count != param_count) {
3904 if (!pd.HasParams)
3905 return int.MaxValue - 10000 + args_gap;
3906 if (arg_count < param_count - 1)
3907 return int.MaxValue - 10000 + args_gap;
3910 // Initialize expanded form of a method with 1 params parameter
3911 params_expanded_form = param_count == 1 && pd.HasParams;
3913 // Resize to fit optional arguments
3914 if (optional_count != 0) {
3915 Arguments resized;
3916 if (arguments == null) {
3917 resized = new Arguments (optional_count);
3918 } else {
3919 resized = new Arguments (param_count);
3920 resized.AddRange (arguments);
3923 for (int i = arg_count; i < param_count; ++i)
3924 resized.Add (null);
3925 arguments = resized;
3929 if (arg_count > 0) {
3931 // Shuffle named arguments to the right positions if there are any
3933 if (arguments [arg_count - 1] is NamedArgument) {
3934 arg_count = arguments.Count;
3936 for (int i = 0; i < arg_count; ++i) {
3937 bool arg_moved = false;
3938 while (true) {
3939 NamedArgument na = arguments[i] as NamedArgument;
3940 if (na == null)
3941 break;
3943 int index = pd.GetParameterIndexByName (na.Name.Value);
3945 // Named parameter not found or already reordered
3946 if (index <= i)
3947 break;
3949 // When using parameters which should not be available to the user
3950 if (index >= param_count)
3951 break;
3953 if (!arg_moved) {
3954 arguments.MarkReorderedArgument (na);
3955 arg_moved = true;
3958 Argument temp = arguments[index];
3959 arguments[index] = arguments[i];
3960 arguments[i] = temp;
3962 if (temp == null)
3963 break;
3966 } else {
3967 arg_count = arguments.Count;
3969 } else if (arguments != null) {
3970 arg_count = arguments.Count;
3974 // 1. Handle generic method using type arguments when specified or type inference
3976 if (TypeManager.IsGenericMethod (candidate)) {
3977 if (type_arguments != null) {
3978 Type [] g_args = candidate.GetGenericArguments ();
3979 if (g_args.Length != type_arguments.Count)
3980 return int.MaxValue - 20000 + Math.Abs (type_arguments.Count - g_args.Length);
3982 // TODO: Don't create new method, create Parameters only
3983 method = ((MethodInfo) candidate).MakeGenericMethod (type_arguments.Arguments);
3984 candidate = method;
3985 pd = TypeManager.GetParameterData (candidate);
3986 } else {
3987 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3988 if (score != 0)
3989 return score - 20000;
3991 if (TypeManager.IsGenericMethodDefinition (candidate))
3992 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3993 TypeManager.CSharpSignature (candidate));
3995 pd = TypeManager.GetParameterData (candidate);
3997 } else {
3998 if (type_arguments != null)
3999 return int.MaxValue - 15000;
4003 // 2. Each argument has to be implicitly convertible to method parameter
4005 method = candidate;
4006 Parameter.Modifier p_mod = 0;
4007 Type pt = null;
4008 for (int i = 0; i < arg_count; i++) {
4009 Argument a = arguments [i];
4010 if (a == null) {
4011 if (!pd.FixedParameters [i].HasDefaultValue)
4012 throw new InternalErrorException ();
4014 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
4015 if (e == null)
4016 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
4018 arguments [i] = new Argument (e, Argument.AType.Default);
4019 continue;
4022 if (p_mod != Parameter.Modifier.PARAMS) {
4023 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4024 pt = pd.Types [i];
4025 } else {
4026 params_expanded_form = true;
4029 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4030 int score = 1;
4031 if (!params_expanded_form)
4032 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4034 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4035 // It can be applicable in expanded form
4036 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4037 if (score == 0)
4038 params_expanded_form = true;
4041 if (score != 0) {
4042 if (params_expanded_form)
4043 ++score;
4044 return (arg_count - i) * 2 + score;
4048 if (arg_count != param_count)
4049 params_expanded_form = true;
4051 return 0;
4054 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4057 // Types have to be identical when ref or out modifer is used
4059 if (arg_mod != 0 || param_mod != 0) {
4060 if (TypeManager.HasElementType (parameter))
4061 parameter = TypeManager.GetElementType (parameter);
4063 Type a_type = argument.Type;
4064 if (TypeManager.HasElementType (a_type))
4065 a_type = TypeManager.GetElementType (a_type);
4067 if (a_type != parameter) {
4068 if (TypeManager.IsDynamicType (a_type))
4069 return 0;
4071 return 2;
4073 } else {
4074 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4075 if (TypeManager.IsDynamicType (argument.Type))
4076 return 0;
4078 return 2;
4082 if (arg_mod != param_mod)
4083 return 1;
4085 return 0;
4088 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4090 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4091 return false;
4093 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4094 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4096 if (cand_pd.Count != base_pd.Count)
4097 return false;
4099 for (int j = 0; j < cand_pd.Count; ++j)
4101 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4102 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4103 Type ct = cand_pd.Types [j];
4104 Type bt = base_pd.Types [j];
4106 if (cm != bm || ct != bt)
4107 return false;
4110 return true;
4113 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4115 if (mg1 == null) {
4116 if (mg2 == null)
4117 return null;
4118 return mg2;
4121 if (mg2 == null)
4122 return mg1;
4124 ArrayList all = new ArrayList (mg1.Methods);
4125 foreach (MethodBase m in mg2.Methods){
4126 if (!TypeManager.ArrayContainsMethod (mg1.Methods, m, false))
4127 all.Add (m);
4130 return new MethodGroupExpr (all, null, loc);
4133 static Type MoreSpecific (Type p, Type q)
4135 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4136 return q;
4137 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4138 return p;
4140 if (TypeManager.HasElementType (p))
4142 Type pe = TypeManager.GetElementType (p);
4143 Type qe = TypeManager.GetElementType (q);
4144 Type specific = MoreSpecific (pe, qe);
4145 if (specific == pe)
4146 return p;
4147 if (specific == qe)
4148 return q;
4150 else if (TypeManager.IsGenericType (p))
4152 Type[] pargs = TypeManager.GetTypeArguments (p);
4153 Type[] qargs = TypeManager.GetTypeArguments (q);
4155 bool p_specific_at_least_once = false;
4156 bool q_specific_at_least_once = false;
4158 for (int i = 0; i < pargs.Length; i++)
4160 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4161 if (specific == pargs [i])
4162 p_specific_at_least_once = true;
4163 if (specific == qargs [i])
4164 q_specific_at_least_once = true;
4167 if (p_specific_at_least_once && !q_specific_at_least_once)
4168 return p;
4169 if (!p_specific_at_least_once && q_specific_at_least_once)
4170 return q;
4173 return null;
4176 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4178 base.MutateHoistedGenericType (storey);
4180 MethodInfo mi = best_candidate as MethodInfo;
4181 if (mi != null) {
4182 best_candidate = storey.MutateGenericMethod (mi);
4183 return;
4186 best_candidate = storey.MutateConstructor ((ConstructorInfo) this);
4189 /// <summary>
4190 /// Find the Applicable Function Members (7.4.2.1)
4192 /// me: Method Group expression with the members to select.
4193 /// it might contain constructors or methods (or anything
4194 /// that maps to a method).
4196 /// Arguments: ArrayList containing resolved Argument objects.
4198 /// loc: The location if we want an error to be reported, or a Null
4199 /// location for "probing" purposes.
4201 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4202 /// that is the best match of me on Arguments.
4204 /// </summary>
4205 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4206 bool may_fail, Location loc)
4208 bool method_params = false;
4209 Type applicable_type = null;
4210 ArrayList candidates = new ArrayList (2);
4211 ArrayList candidate_overrides = null;
4214 // Used to keep a map between the candidate
4215 // and whether it is being considered in its
4216 // normal or expanded form
4218 // false is normal form, true is expanded form
4220 Hashtable candidate_to_form = null;
4221 Hashtable candidates_expanded = null;
4222 Arguments candidate_args = Arguments;
4224 int arg_count = Arguments != null ? Arguments.Count : 0;
4226 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4227 if (!may_fail)
4228 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4229 return null;
4232 int nmethods = Methods.Length;
4234 if (!IsBase) {
4236 // Methods marked 'override' don't take part in 'applicable_type'
4237 // computation, nor in the actual overload resolution.
4238 // However, they still need to be emitted instead of a base virtual method.
4239 // So, we salt them away into the 'candidate_overrides' array.
4241 // In case of reflected methods, we replace each overriding method with
4242 // its corresponding base virtual method. This is to improve compatibility
4243 // with non-C# libraries which change the visibility of overrides (#75636)
4245 int j = 0;
4246 for (int i = 0; i < Methods.Length; ++i) {
4247 MethodBase m = Methods [i];
4248 if (TypeManager.IsOverride (m)) {
4249 if (candidate_overrides == null)
4250 candidate_overrides = new ArrayList ();
4251 candidate_overrides.Add (m);
4252 m = TypeManager.TryGetBaseDefinition (m);
4254 if (m != null)
4255 Methods [j++] = m;
4257 nmethods = j;
4261 // Enable message recording, it's used mainly by lambda expressions
4263 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4264 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4267 // First we construct the set of applicable methods
4269 bool is_sorted = true;
4270 int best_candidate_rate = int.MaxValue;
4271 for (int i = 0; i < nmethods; i++) {
4272 Type decl_type = Methods [i].DeclaringType;
4275 // If we have already found an applicable method
4276 // we eliminate all base types (Section 14.5.5.1)
4278 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4279 continue;
4282 // Check if candidate is applicable (section 14.4.2.1)
4284 bool params_expanded_form = false;
4285 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4287 if (candidate_rate < best_candidate_rate) {
4288 best_candidate_rate = candidate_rate;
4289 best_candidate = Methods [i];
4292 if (params_expanded_form) {
4293 if (candidate_to_form == null)
4294 candidate_to_form = new PtrHashtable ();
4295 MethodBase candidate = Methods [i];
4296 candidate_to_form [candidate] = candidate;
4299 if (candidate_args != Arguments) {
4300 if (candidates_expanded == null)
4301 candidates_expanded = new Hashtable (2);
4303 candidates_expanded.Add (Methods [i], candidate_args);
4304 candidate_args = Arguments;
4307 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4308 if (msg_recorder != null)
4309 msg_recorder.EndSession ();
4310 continue;
4313 msg_recorder = null;
4314 candidates.Add (Methods [i]);
4316 if (applicable_type == null)
4317 applicable_type = decl_type;
4318 else if (applicable_type != decl_type) {
4319 is_sorted = false;
4320 if (IsAncestralType (applicable_type, decl_type))
4321 applicable_type = decl_type;
4325 ec.Report.SetPrinter (prev_recorder);
4326 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4327 if (!may_fail)
4328 msg_recorder.Merge (prev_recorder);
4330 return null;
4333 int candidate_top = candidates.Count;
4335 if (applicable_type == null) {
4337 // When we found a top level method which does not match and it's
4338 // not an extension method. We start extension methods lookup from here
4340 if (InstanceExpression != null) {
4341 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4342 if (ex_method_lookup != null) {
4343 ex_method_lookup.ExtensionExpression = InstanceExpression;
4344 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4345 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4349 if (may_fail)
4350 return null;
4353 // Okay so we have failed to find exact match so we
4354 // return error info about the closest match
4356 if (best_candidate != null) {
4357 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4358 return null;
4360 if (NoExactMatch (ec, ref Arguments, candidate_to_form))
4361 return null;
4365 // We failed to find any method with correct argument count
4367 if (Name == ConstructorInfo.ConstructorName) {
4368 ec.Report.SymbolRelatedToPreviousError (queried_type);
4369 ec.Report.Error (1729, loc,
4370 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4371 TypeManager.CSharpName (queried_type), arg_count);
4372 } else {
4373 Error_ArgumentCountWrong (ec, arg_count);
4376 return null;
4379 if (arg_count != 0 && Arguments.HasDynamic) {
4380 best_candidate = null;
4381 return this;
4384 if (!is_sorted) {
4386 // At this point, applicable_type is _one_ of the most derived types
4387 // in the set of types containing the methods in this MethodGroup.
4388 // Filter the candidates so that they only contain methods from the
4389 // most derived types.
4392 int finalized = 0; // Number of finalized candidates
4394 do {
4395 // Invariant: applicable_type is a most derived type
4397 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4398 // eliminating all it's base types. At the same time, we'll also move
4399 // every unrelated type to the end of the array, and pick the next
4400 // 'applicable_type'.
4402 Type next_applicable_type = null;
4403 int j = finalized; // where to put the next finalized candidate
4404 int k = finalized; // where to put the next undiscarded candidate
4405 for (int i = finalized; i < candidate_top; ++i) {
4406 MethodBase candidate = (MethodBase) candidates [i];
4407 Type decl_type = candidate.DeclaringType;
4409 if (decl_type == applicable_type) {
4410 candidates [k++] = candidates [j];
4411 candidates [j++] = candidates [i];
4412 continue;
4415 if (IsAncestralType (decl_type, applicable_type))
4416 continue;
4418 if (next_applicable_type != null &&
4419 IsAncestralType (decl_type, next_applicable_type))
4420 continue;
4422 candidates [k++] = candidates [i];
4424 if (next_applicable_type == null ||
4425 IsAncestralType (next_applicable_type, decl_type))
4426 next_applicable_type = decl_type;
4429 applicable_type = next_applicable_type;
4430 finalized = j;
4431 candidate_top = k;
4432 } while (applicable_type != null);
4436 // Now we actually find the best method
4439 best_candidate = (MethodBase) candidates [0];
4440 method_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4443 // TODO: Broken inverse order of candidates logic does not work with optional
4444 // parameters used for method overrides and I am not going to fix it for SRE
4446 if (candidates_expanded != null && candidates_expanded.Contains (best_candidate)) {
4447 candidate_args = (Arguments) candidates_expanded [best_candidate];
4448 arg_count = candidate_args.Count;
4451 for (int ix = 1; ix < candidate_top; ix++) {
4452 MethodBase candidate = (MethodBase) candidates [ix];
4454 if (candidate == best_candidate)
4455 continue;
4457 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4459 if (BetterFunction (ec, candidate_args, arg_count,
4460 candidate, cand_params,
4461 best_candidate, method_params)) {
4462 best_candidate = candidate;
4463 method_params = cand_params;
4467 // Now check that there are no ambiguities i.e the selected method
4468 // should be better than all the others
4470 MethodBase ambiguous = null;
4471 for (int ix = 1; ix < candidate_top; ix++) {
4472 MethodBase candidate = (MethodBase) candidates [ix];
4474 if (candidate == best_candidate)
4475 continue;
4477 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4478 if (!BetterFunction (ec, candidate_args, arg_count,
4479 best_candidate, method_params,
4480 candidate, cand_params))
4482 if (!may_fail)
4483 ec.Report.SymbolRelatedToPreviousError (candidate);
4484 ambiguous = candidate;
4488 if (ambiguous != null) {
4489 Error_AmbiguousCall (ec, ambiguous);
4490 return this;
4494 // If the method is a virtual function, pick an override closer to the LHS type.
4496 if (!IsBase && best_candidate.IsVirtual) {
4497 if (TypeManager.IsOverride (best_candidate))
4498 throw new InternalErrorException (
4499 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4501 if (candidate_overrides != null) {
4502 Type[] gen_args = null;
4503 bool gen_override = false;
4504 if (TypeManager.IsGenericMethod (best_candidate))
4505 gen_args = TypeManager.GetGenericArguments (best_candidate);
4507 foreach (MethodBase candidate in candidate_overrides) {
4508 if (TypeManager.IsGenericMethod (candidate)) {
4509 if (gen_args == null)
4510 continue;
4512 if (gen_args.Length != TypeManager.GetGenericArguments (candidate).Length)
4513 continue;
4514 } else {
4515 if (gen_args != null)
4516 continue;
4519 if (IsOverride (candidate, best_candidate)) {
4520 gen_override = true;
4521 best_candidate = candidate;
4525 if (gen_override && gen_args != null) {
4526 best_candidate = ((MethodInfo) best_candidate).MakeGenericMethod (gen_args);
4532 // And now check if the arguments are all
4533 // compatible, perform conversions if
4534 // necessary etc. and return if everything is
4535 // all right
4537 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4538 method_params, may_fail, loc))
4539 return null;
4541 if (best_candidate == null)
4542 return null;
4544 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4545 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4546 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate, loc))
4547 return null;
4550 // Check ObsoleteAttribute on the best method
4552 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4553 if (oa != null && !ec.IsObsolete)
4554 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4556 IMethodData data = TypeManager.GetMethod (the_method);
4557 if (data != null)
4558 data.SetMemberIsUsed ();
4560 Arguments = candidate_args;
4561 return this;
4564 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, Hashtable candidate_to_form)
4566 AParametersCollection pd = TypeManager.GetParameterData (best_candidate);
4567 int arg_count = Arguments == null ? 0 : Arguments.Count;
4569 if (arg_count == pd.Count || pd.HasParams) {
4570 if (TypeManager.IsGenericMethodDefinition (best_candidate)) {
4571 if (type_arguments == null) {
4572 ec.Report.Error (411, loc,
4573 "The type arguments for method `{0}' cannot be inferred from " +
4574 "the usage. Try specifying the type arguments explicitly",
4575 TypeManager.CSharpSignature (best_candidate));
4576 return true;
4579 Type[] g_args = TypeManager.GetGenericArguments (best_candidate);
4580 if (type_arguments.Count != g_args.Length) {
4581 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4582 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4583 TypeManager.CSharpSignature (best_candidate),
4584 g_args.Length.ToString ());
4585 return true;
4587 } else {
4588 if (type_arguments != null && !TypeManager.IsGenericMethod (best_candidate)) {
4589 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4590 return true;
4594 if (has_inaccessible_candidates_only) {
4595 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4596 // Although a derived class can access protected members of
4597 // its base class it cannot do so through an instance of the
4598 // base class (CS1540). If the qualifier_type is a base of the
4599 // ec.CurrentType and the lookup succeeds with the latter one,
4600 // then we are in this situation.
4601 Error_CannotAccessProtected (ec, loc, best_candidate, queried_type, ec.CurrentType);
4602 } else {
4603 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4604 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4608 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (best_candidate);
4609 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, false, loc))
4610 return true;
4612 if (has_inaccessible_candidates_only)
4613 return true;
4616 return false;
4619 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4621 type_arguments = ta;
4624 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4625 int arg_count, MethodBase method,
4626 bool chose_params_expanded,
4627 bool may_fail, Location loc)
4629 AParametersCollection pd = TypeManager.GetParameterData (method);
4630 int param_count = GetApplicableParametersCount (method, pd);
4632 int errors = ec.Report.Errors;
4633 Parameter.Modifier p_mod = 0;
4634 Type pt = null;
4635 int a_idx = 0, a_pos = 0;
4636 Argument a = null;
4637 ArrayList params_initializers = null;
4638 bool has_unsafe_arg = method is MethodInfo ? ((MethodInfo) method).ReturnType.IsPointer : false;
4640 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4641 a = arguments [a_idx];
4642 if (p_mod != Parameter.Modifier.PARAMS) {
4643 p_mod = pd.FixedParameters [a_idx].ModFlags;
4644 pt = pd.Types [a_idx];
4645 has_unsafe_arg |= pt.IsPointer;
4647 if (p_mod == Parameter.Modifier.PARAMS) {
4648 if (chose_params_expanded) {
4649 params_initializers = new ArrayList (arg_count - a_idx);
4650 pt = TypeManager.GetElementType (pt);
4656 // Types have to be identical when ref or out modifer is used
4658 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4659 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4660 break;
4662 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4663 break;
4665 continue;
4666 } else {
4667 NamedArgument na = a as NamedArgument;
4668 if (na != null) {
4669 int name_index = pd.GetParameterIndexByName (na.Name.Value);
4670 if (name_index < 0 || name_index >= param_count) {
4671 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4672 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4673 ec.Report.Error (1746, na.Name.Location,
4674 "The delegate `{0}' does not contain a parameter named `{1}'",
4675 TypeManager.CSharpName (DeclaringType), na.Name.Value);
4676 } else {
4677 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4678 ec.Report.Error (1739, na.Name.Location,
4679 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4680 TypeManager.CSharpSignature (method), na.Name.Value);
4682 } else if (arguments[name_index] != a) {
4683 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4684 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4685 else
4686 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4688 ec.Report.Error (1744, na.Name.Location,
4689 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4690 na.Name.Value);
4695 if (TypeManager.IsDynamicType (a.Expr.Type))
4696 continue;
4698 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4699 break;
4701 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4702 if (conv == null)
4703 break;
4706 // Convert params arguments to an array initializer
4708 if (params_initializers != null) {
4709 // we choose to use 'a.Expr' rather than 'conv' so that
4710 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4711 params_initializers.Add (a.Expr);
4712 arguments.RemoveAt (a_idx--);
4713 --arg_count;
4714 continue;
4717 // Update the argument with the implicit conversion
4718 a.Expr = conv;
4721 if (a_idx != arg_count) {
4722 if (!may_fail && ec.Report.Errors == errors) {
4723 if (CustomErrorHandler != null)
4724 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4725 else
4726 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4728 return false;
4732 // Fill not provided arguments required by params modifier
4734 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4735 if (arguments == null)
4736 arguments = new Arguments (1);
4738 pt = pd.Types [param_count - 1];
4739 pt = TypeManager.GetElementType (pt);
4740 has_unsafe_arg |= pt.IsPointer;
4741 params_initializers = new ArrayList (0);
4745 // Append an array argument with all params arguments
4747 if (params_initializers != null) {
4748 arguments.Add (new Argument (
4749 new ArrayCreation (new TypeExpression (pt, loc), "[]",
4750 params_initializers, loc).Resolve (ec)));
4751 arg_count++;
4754 if (arg_count < param_count) {
4755 if (!may_fail)
4756 Error_ArgumentCountWrong (ec, arg_count);
4757 return false;
4760 if (has_unsafe_arg && !ec.IsUnsafe) {
4761 if (!may_fail)
4762 UnsafeError (ec, loc);
4763 return false;
4766 return true;
4770 public class ConstantExpr : MemberExpr
4772 FieldInfo constant;
4774 public ConstantExpr (FieldInfo constant, Location loc)
4776 this.constant = constant;
4777 this.loc = loc;
4780 public override string Name {
4781 get { throw new NotImplementedException (); }
4784 public override bool IsInstance {
4785 get { return !IsStatic; }
4788 public override bool IsStatic {
4789 get { return constant.IsStatic; }
4792 public override Type DeclaringType {
4793 get { return constant.DeclaringType; }
4796 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc, SimpleName original)
4798 constant = TypeManager.GetGenericFieldDefinition (constant);
4800 IConstant ic = TypeManager.GetConstant (constant);
4801 if (ic == null) {
4802 if (constant.IsLiteral) {
4803 ic = new ExternalConstant (constant);
4804 } else {
4805 ic = ExternalConstant.CreateDecimal (constant);
4806 // HACK: decimal field was not resolved as constant
4807 if (ic == null)
4808 return new FieldExpr (constant, loc).ResolveMemberAccess (ec, left, loc, original);
4810 TypeManager.RegisterConstant (constant, ic);
4813 return base.ResolveMemberAccess (ec, left, loc, original);
4816 public override Expression CreateExpressionTree (ResolveContext ec)
4818 throw new NotSupportedException ("ET");
4821 public override Expression DoResolve (ResolveContext ec)
4823 IConstant ic = TypeManager.GetConstant (constant);
4824 if (ic.ResolveValue ()) {
4825 if (!ec.IsObsolete)
4826 ic.CheckObsoleteness (loc);
4829 return ic.CreateConstantReference (loc);
4832 public override void Emit (EmitContext ec)
4834 throw new NotSupportedException ();
4837 public override string GetSignatureForError ()
4839 return TypeManager.GetFullNameSignature (constant);
4843 /// <summary>
4844 /// Fully resolved expression that evaluates to a Field
4845 /// </summary>
4846 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4847 public FieldInfo FieldInfo;
4848 readonly Type constructed_generic_type;
4849 VariableInfo variable_info;
4851 LocalTemporary temp;
4852 bool prepared;
4854 protected FieldExpr (Location l)
4856 loc = l;
4859 public FieldExpr (FieldInfo fi, Location l)
4861 FieldInfo = fi;
4862 type = TypeManager.TypeToCoreType (fi.FieldType);
4863 loc = l;
4866 public FieldExpr (FieldInfo fi, Type genericType, Location l)
4867 : this (fi, l)
4869 if (TypeManager.IsGenericTypeDefinition (genericType))
4870 return;
4871 this.constructed_generic_type = genericType;
4874 public override string Name {
4875 get {
4876 return FieldInfo.Name;
4880 public override bool IsInstance {
4881 get {
4882 return !FieldInfo.IsStatic;
4886 public override bool IsStatic {
4887 get {
4888 return FieldInfo.IsStatic;
4892 public override Type DeclaringType {
4893 get {
4894 return FieldInfo.DeclaringType;
4898 public override string GetSignatureForError ()
4900 return TypeManager.GetFullNameSignature (FieldInfo);
4903 public VariableInfo VariableInfo {
4904 get {
4905 return variable_info;
4909 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4910 SimpleName original)
4912 FieldInfo fi = TypeManager.GetGenericFieldDefinition (FieldInfo);
4913 Type t = fi.FieldType;
4915 if (t.IsPointer && !ec.IsUnsafe) {
4916 UnsafeError (ec, loc);
4919 return base.ResolveMemberAccess (ec, left, loc, original);
4922 public void SetHasAddressTaken ()
4924 IVariableReference vr = InstanceExpression as IVariableReference;
4925 if (vr != null)
4926 vr.SetHasAddressTaken ();
4929 public override Expression CreateExpressionTree (ResolveContext ec)
4931 Expression instance;
4932 if (InstanceExpression == null) {
4933 instance = new NullLiteral (loc);
4934 } else {
4935 instance = InstanceExpression.CreateExpressionTree (ec);
4938 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4939 instance,
4940 CreateTypeOfExpression ());
4942 return CreateExpressionFactoryCall (ec, "Field", args);
4945 public Expression CreateTypeOfExpression ()
4947 return new TypeOfField (GetConstructedFieldInfo (), loc);
4950 override public Expression DoResolve (ResolveContext ec)
4952 return DoResolve (ec, false, false);
4955 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4957 if (!FieldInfo.IsStatic){
4958 if (InstanceExpression == null){
4960 // This can happen when referencing an instance field using
4961 // a fully qualified type expression: TypeName.InstanceField = xxx
4963 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4964 return null;
4967 // Resolve the field's instance expression while flow analysis is turned
4968 // off: when accessing a field "a.b", we must check whether the field
4969 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4971 if (lvalue_instance) {
4972 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4973 Expression right_side =
4974 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4976 if (InstanceExpression != EmptyExpression.Null)
4977 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4979 } else {
4980 ResolveFlags rf = ResolveFlags.VariableOrValue | ResolveFlags.DisableFlowAnalysis;
4982 if (InstanceExpression != EmptyExpression.Null)
4983 InstanceExpression = InstanceExpression.Resolve (ec, rf);
4986 if (InstanceExpression == null)
4987 return null;
4989 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4990 InstanceExpression.CheckMarshalByRefAccess (ec);
4994 // TODO: the code above uses some non-standard multi-resolve rules
4995 if (eclass != ExprClass.Invalid)
4996 return this;
4998 if (!ec.IsObsolete) {
4999 FieldBase f = TypeManager.GetField (FieldInfo);
5000 if (f != null) {
5001 f.CheckObsoleteness (loc);
5002 } else {
5003 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (FieldInfo);
5004 if (oa != null)
5005 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (FieldInfo), loc, ec.Report);
5009 IFixedBuffer fb = AttributeTester.GetFixedBuffer (FieldInfo);
5010 IVariableReference var = InstanceExpression as IVariableReference;
5012 if (fb != null) {
5013 IFixedExpression fe = InstanceExpression as IFixedExpression;
5014 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5015 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5018 if (InstanceExpression.eclass != ExprClass.Variable) {
5019 ec.Report.SymbolRelatedToPreviousError (FieldInfo);
5020 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5021 TypeManager.GetFullNameSignature (FieldInfo));
5022 } else if (var != null && var.IsHoisted) {
5023 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5026 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5029 eclass = ExprClass.Variable;
5031 // If the instance expression is a local variable or parameter.
5032 if (var == null || var.VariableInfo == null)
5033 return this;
5035 VariableInfo vi = var.VariableInfo;
5036 if (!vi.IsFieldAssigned (ec, FieldInfo.Name, loc))
5037 return null;
5039 variable_info = vi.GetSubStruct (FieldInfo.Name);
5040 eclass = ExprClass.Variable;
5041 return this;
5044 static readonly int [] codes = {
5045 191, // instance, write access
5046 192, // instance, out access
5047 198, // static, write access
5048 199, // static, out access
5049 1648, // member of value instance, write access
5050 1649, // member of value instance, out access
5051 1650, // member of value static, write access
5052 1651 // member of value static, out access
5055 static readonly string [] msgs = {
5056 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5057 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5058 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5059 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5060 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5061 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5062 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5063 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5066 // The return value is always null. Returning a value simplifies calling code.
5067 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5069 int i = 0;
5070 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5071 i += 1;
5072 if (IsStatic)
5073 i += 2;
5074 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5075 i += 4;
5076 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5078 return null;
5081 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5083 IVariableReference var = InstanceExpression as IVariableReference;
5084 if (var != null && var.VariableInfo != null)
5085 var.VariableInfo.SetFieldAssigned (ec, FieldInfo.Name);
5087 bool lvalue_instance = !FieldInfo.IsStatic && TypeManager.IsValueType (FieldInfo.DeclaringType);
5088 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5090 Expression e = DoResolve (ec, lvalue_instance, out_access);
5092 if (e == null)
5093 return null;
5095 FieldBase fb = TypeManager.GetField (FieldInfo);
5096 if (fb != null) {
5097 fb.SetAssigned ();
5099 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5100 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5101 ec.Report.Warning (420, 1, loc,
5102 "`{0}': A volatile field references will not be treated as volatile",
5103 fb.GetSignatureForError ());
5107 if (FieldInfo.IsInitOnly) {
5108 // InitOnly fields can only be assigned in constructors or initializers
5109 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5110 return Report_AssignToReadonly (ec, right_side);
5112 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5113 Type ctype = ec.CurrentType;
5115 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5116 if (!TypeManager.IsEqual (ctype, FieldInfo.DeclaringType))
5117 return Report_AssignToReadonly (ec, right_side);
5118 // static InitOnly fields cannot be assigned-to in an instance constructor
5119 if (IsStatic && !ec.IsStatic)
5120 return Report_AssignToReadonly (ec, right_side);
5121 // instance constructors can't modify InitOnly fields of other instances of the same type
5122 if (!IsStatic && !(InstanceExpression is This))
5123 return Report_AssignToReadonly (ec, right_side);
5127 if (right_side == EmptyExpression.OutAccess.Instance &&
5128 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5129 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5130 ec.Report.Warning (197, 1, loc,
5131 "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",
5132 GetSignatureForError ());
5135 eclass = ExprClass.Variable;
5136 return this;
5139 bool is_marshal_by_ref ()
5141 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5144 public override void CheckMarshalByRefAccess (ResolveContext ec)
5146 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5147 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5148 ec.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",
5149 GetSignatureForError ());
5153 public override int GetHashCode ()
5155 return FieldInfo.GetHashCode ();
5158 public bool IsFixed {
5159 get {
5161 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5163 IVariableReference variable = InstanceExpression as IVariableReference;
5164 if (variable != null)
5165 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5167 IFixedExpression fe = InstanceExpression as IFixedExpression;
5168 return fe != null && fe.IsFixed;
5172 public bool IsHoisted {
5173 get {
5174 IVariableReference hv = InstanceExpression as IVariableReference;
5175 return hv != null && hv.IsHoisted;
5179 public override bool Equals (object obj)
5181 FieldExpr fe = obj as FieldExpr;
5182 if (fe == null)
5183 return false;
5185 if (FieldInfo != fe.FieldInfo)
5186 return false;
5188 if (InstanceExpression == null || fe.InstanceExpression == null)
5189 return true;
5191 return InstanceExpression.Equals (fe.InstanceExpression);
5194 public void Emit (EmitContext ec, bool leave_copy)
5196 ILGenerator ig = ec.ig;
5197 bool is_volatile = false;
5199 FieldBase f = TypeManager.GetField (FieldInfo);
5200 if (f != null){
5201 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5202 is_volatile = true;
5204 f.SetMemberIsUsed ();
5207 if (FieldInfo.IsStatic){
5208 if (is_volatile)
5209 ig.Emit (OpCodes.Volatile);
5211 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5212 } else {
5213 if (!prepared)
5214 EmitInstance (ec, false);
5216 // Optimization for build-in types
5217 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType)) {
5218 LoadFromPtr (ig, type);
5219 } else {
5220 IFixedBuffer ff = AttributeTester.GetFixedBuffer (FieldInfo);
5221 if (ff != null) {
5222 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5223 ig.Emit (OpCodes.Ldflda, ff.Element);
5224 } else {
5225 if (is_volatile)
5226 ig.Emit (OpCodes.Volatile);
5228 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5233 if (leave_copy) {
5234 ec.ig.Emit (OpCodes.Dup);
5235 if (!FieldInfo.IsStatic) {
5236 temp = new LocalTemporary (this.Type);
5237 temp.Store (ec);
5242 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5244 FieldAttributes fa = FieldInfo.Attributes;
5245 bool is_static = (fa & FieldAttributes.Static) != 0;
5246 ILGenerator ig = ec.ig;
5248 prepared = prepare_for_load;
5249 EmitInstance (ec, prepared);
5251 source.Emit (ec);
5252 if (leave_copy) {
5253 ec.ig.Emit (OpCodes.Dup);
5254 if (!FieldInfo.IsStatic) {
5255 temp = new LocalTemporary (this.Type);
5256 temp.Store (ec);
5260 FieldBase f = TypeManager.GetField (FieldInfo);
5261 if (f != null){
5262 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5263 ig.Emit (OpCodes.Volatile);
5265 f.SetAssigned ();
5268 if (is_static)
5269 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5270 else
5271 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5273 if (temp != null) {
5274 temp.Emit (ec);
5275 temp.Release (ec);
5276 temp = null;
5280 public override void Emit (EmitContext ec)
5282 Emit (ec, false);
5285 public override void EmitSideEffect (EmitContext ec)
5287 FieldBase f = TypeManager.GetField (FieldInfo);
5288 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5290 if (is_volatile || is_marshal_by_ref ())
5291 base.EmitSideEffect (ec);
5294 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5296 r.Error (844, loc,
5297 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5298 name, GetSignatureForError ());
5301 public void AddressOf (EmitContext ec, AddressOp mode)
5303 ILGenerator ig = ec.ig;
5305 FieldBase f = TypeManager.GetField (FieldInfo);
5306 if (f != null){
5307 if ((mode & AddressOp.Store) != 0)
5308 f.SetAssigned ();
5309 if ((mode & AddressOp.Load) != 0)
5310 f.SetMemberIsUsed ();
5314 // Handle initonly fields specially: make a copy and then
5315 // get the address of the copy.
5317 bool need_copy;
5318 if (FieldInfo.IsInitOnly){
5319 need_copy = true;
5320 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5321 if (FieldInfo.IsStatic){
5322 if (ec.IsStatic)
5323 need_copy = false;
5324 } else
5325 need_copy = false;
5327 } else
5328 need_copy = false;
5330 if (need_copy){
5331 LocalBuilder local;
5332 Emit (ec);
5333 local = ig.DeclareLocal (type);
5334 ig.Emit (OpCodes.Stloc, local);
5335 ig.Emit (OpCodes.Ldloca, local);
5336 return;
5340 if (FieldInfo.IsStatic){
5341 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5342 } else {
5343 if (!prepared)
5344 EmitInstance (ec, false);
5345 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5349 FieldInfo GetConstructedFieldInfo ()
5351 if (constructed_generic_type == null)
5352 return FieldInfo;
5354 return TypeBuilder.GetField (constructed_generic_type, FieldInfo);
5357 #if NET_4_0
5358 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5360 return MakeExpression (ctx);
5363 public override SLE.Expression MakeExpression (BuilderContext ctx)
5365 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), FieldInfo);
5367 #endif
5369 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5371 FieldInfo = storey.MutateField (FieldInfo);
5372 base.MutateHoistedGenericType (storey);
5377 /// <summary>
5378 /// Expression that evaluates to a Property. The Assign class
5379 /// might set the `Value' expression if we are in an assignment.
5381 /// This is not an LValue because we need to re-write the expression, we
5382 /// can not take data from the stack and store it.
5383 /// </summary>
5384 public class PropertyExpr : MemberExpr, IDynamicAssign
5386 public readonly PropertyInfo PropertyInfo;
5387 MethodInfo getter, setter;
5388 bool is_static;
5390 bool resolved;
5391 TypeArguments targs;
5393 LocalTemporary temp;
5394 bool prepared;
5396 public PropertyExpr (Type container_type, PropertyInfo pi, Location l)
5398 PropertyInfo = pi;
5399 eclass = ExprClass.PropertyAccess;
5400 is_static = false;
5401 loc = l;
5403 type = TypeManager.TypeToCoreType (pi.PropertyType);
5405 ResolveAccessors (container_type);
5408 public override string Name {
5409 get {
5410 return PropertyInfo.Name;
5414 public override bool IsInstance {
5415 get {
5416 return !is_static;
5420 public override bool IsStatic {
5421 get {
5422 return is_static;
5426 public override Expression CreateExpressionTree (ResolveContext ec)
5428 Arguments args;
5429 if (IsSingleDimensionalArrayLength ()) {
5430 args = new Arguments (1);
5431 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5432 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5435 if (is_base) {
5436 Error_BaseAccessInExpressionTree (ec, loc);
5437 return null;
5440 args = new Arguments (2);
5441 if (InstanceExpression == null)
5442 args.Add (new Argument (new NullLiteral (loc)));
5443 else
5444 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5445 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5446 return CreateExpressionFactoryCall (ec, "Property", args);
5449 public Expression CreateSetterTypeOfExpression ()
5451 return new TypeOfMethod (setter, loc);
5454 public override Type DeclaringType {
5455 get {
5456 return PropertyInfo.DeclaringType;
5460 public override string GetSignatureForError ()
5462 return TypeManager.GetFullNameSignature (PropertyInfo);
5465 void FindAccessors (Type invocation_type)
5467 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5468 BindingFlags.Static | BindingFlags.Instance |
5469 BindingFlags.DeclaredOnly;
5471 Type current = PropertyInfo.DeclaringType;
5472 for (; current != null; current = current.BaseType) {
5473 MemberInfo[] group = TypeManager.MemberLookup (
5474 invocation_type, invocation_type, current,
5475 MemberTypes.Property, flags, PropertyInfo.Name, null);
5477 if (group == null)
5478 continue;
5480 if (group.Length != 1)
5481 // Oooops, can this ever happen ?
5482 return;
5484 PropertyInfo pi = (PropertyInfo) group [0];
5486 if (getter == null)
5487 getter = pi.GetGetMethod (true);
5489 if (setter == null)
5490 setter = pi.GetSetMethod (true);
5492 MethodInfo accessor = getter != null ? getter : setter;
5494 if (!accessor.IsVirtual)
5495 return;
5500 // We also perform the permission checking here, as the PropertyInfo does not
5501 // hold the information for the accessibility of its setter/getter
5503 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5504 void ResolveAccessors (Type container_type)
5506 FindAccessors (container_type);
5508 if (getter != null) {
5509 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5510 IMethodData md = TypeManager.GetMethod (the_getter);
5511 if (md != null)
5512 md.SetMemberIsUsed ();
5514 is_static = getter.IsStatic;
5517 if (setter != null) {
5518 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5519 IMethodData md = TypeManager.GetMethod (the_setter);
5520 if (md != null)
5521 md.SetMemberIsUsed ();
5523 is_static = setter.IsStatic;
5527 #if NET_4_0
5528 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5530 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), setter);
5533 public override SLE.Expression MakeExpression (BuilderContext ctx)
5535 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), getter);
5537 #endif
5539 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5541 if (InstanceExpression != null)
5542 InstanceExpression.MutateHoistedGenericType (storey);
5544 type = storey.MutateType (type);
5545 if (getter != null)
5546 getter = storey.MutateGenericMethod (getter);
5547 if (setter != null)
5548 setter = storey.MutateGenericMethod (setter);
5551 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5553 if (is_static) {
5554 InstanceExpression = null;
5555 return true;
5558 if (InstanceExpression == null) {
5559 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5560 return false;
5563 InstanceExpression = InstanceExpression.DoResolve (ec);
5564 if (lvalue_instance && InstanceExpression != null)
5565 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5567 if (InstanceExpression == null)
5568 return false;
5570 InstanceExpression.CheckMarshalByRefAccess (ec);
5572 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5573 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5574 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5575 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5576 ec.Report.SymbolRelatedToPreviousError (PropertyInfo);
5577 Error_CannotAccessProtected (ec, loc, PropertyInfo, InstanceExpression.Type, ec.CurrentType);
5578 return false;
5581 return true;
5584 void Error_PropertyNotFound (ResolveContext ec, MethodInfo mi, bool getter)
5586 // TODO: correctly we should compare arguments but it will lead to bigger changes
5587 if (mi is MethodBuilder) {
5588 Error_TypeDoesNotContainDefinition (ec, loc, PropertyInfo.DeclaringType, Name);
5589 return;
5592 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5593 sig.Append ('.');
5594 AParametersCollection iparams = TypeManager.GetParameterData (mi);
5595 sig.Append (getter ? "get_" : "set_");
5596 sig.Append (Name);
5597 sig.Append (iparams.GetSignatureForError ());
5599 ec.Report.SymbolRelatedToPreviousError (mi);
5600 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5601 Name, sig.ToString ());
5604 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5606 bool dummy;
5607 MethodInfo accessor = lvalue ? setter : getter;
5608 if (accessor == null && lvalue)
5609 accessor = getter;
5610 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5613 bool IsSingleDimensionalArrayLength ()
5615 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5616 return false;
5618 string t_name = InstanceExpression.Type.Name;
5619 int t_name_len = t_name.Length;
5620 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5623 public override Expression DoResolve (ResolveContext ec)
5625 if (resolved)
5626 return this;
5628 bool must_do_cs1540_check = false;
5629 ec.Report.DisableReporting ();
5630 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5631 ec.Report.EnableReporting ();
5633 if (!res) {
5634 if (InstanceExpression != null) {
5635 Type expr_type = InstanceExpression.Type;
5636 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5637 if (ex_method_lookup != null) {
5638 ex_method_lookup.ExtensionExpression = InstanceExpression;
5639 ex_method_lookup.SetTypeArguments (ec, targs);
5640 return ex_method_lookup.DoResolve (ec);
5644 ResolveGetter (ec, ref must_do_cs1540_check);
5645 return null;
5648 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5649 return null;
5652 // Only base will allow this invocation to happen.
5654 if (IsBase && getter.IsAbstract) {
5655 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5658 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe){
5659 UnsafeError (ec, loc);
5662 if (!ec.IsObsolete) {
5663 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5664 if (pb != null) {
5665 pb.CheckObsoleteness (loc);
5666 } else {
5667 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5668 if (oa != null)
5669 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5673 resolved = true;
5675 return this;
5678 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5680 if (right_side == EmptyExpression.OutAccess.Instance) {
5681 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5682 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5683 PropertyInfo.Name);
5684 } else {
5685 right_side.DoResolveLValue (ec, this);
5687 return null;
5690 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5691 Error_CannotModifyIntermediateExpressionValue (ec);
5694 if (setter == null){
5696 // The following condition happens if the PropertyExpr was
5697 // created, but is invalid (ie, the property is inaccessible),
5698 // and we did not want to embed the knowledge about this in
5699 // the caller routine. This only avoids double error reporting.
5701 if (getter == null)
5702 return null;
5704 if (ec.CurrentBlock.Toplevel.GetParameterReference (PropertyInfo.Name, loc) is MemberAccess) {
5705 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5706 PropertyInfo.Name);
5707 } else {
5708 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5709 GetSignatureForError ());
5711 return null;
5714 if (targs != null) {
5715 base.SetTypeArguments (ec, targs);
5716 return null;
5719 if (TypeManager.GetParameterData (setter).Count != 1){
5720 Error_PropertyNotFound (ec, setter, false);
5721 return null;
5724 bool must_do_cs1540_check;
5725 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5726 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter) as PropertyBase.PropertyMethod;
5727 if (pm != null && pm.HasCustomAccessModifier) {
5728 ec.Report.SymbolRelatedToPreviousError (pm);
5729 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5730 TypeManager.CSharpSignature (setter));
5732 else {
5733 ec.Report.SymbolRelatedToPreviousError (setter);
5734 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5736 return null;
5739 if (!InstanceResolve (ec, TypeManager.IsStruct (PropertyInfo.DeclaringType), must_do_cs1540_check))
5740 return null;
5743 // Only base will allow this invocation to happen.
5745 if (IsBase && setter.IsAbstract){
5746 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (PropertyInfo));
5749 if (PropertyInfo.PropertyType.IsPointer && !ec.IsUnsafe) {
5750 UnsafeError (ec, loc);
5753 if (!ec.IsObsolete) {
5754 PropertyBase pb = TypeManager.GetProperty (PropertyInfo);
5755 if (pb != null) {
5756 pb.CheckObsoleteness (loc);
5757 } else {
5758 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (PropertyInfo);
5759 if (oa != null)
5760 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5764 return this;
5767 public override void Emit (EmitContext ec)
5769 Emit (ec, false);
5772 public void Emit (EmitContext ec, bool leave_copy)
5775 // Special case: length of single dimension array property is turned into ldlen
5777 if (IsSingleDimensionalArrayLength ()) {
5778 if (!prepared)
5779 EmitInstance (ec, false);
5780 ec.ig.Emit (OpCodes.Ldlen);
5781 ec.ig.Emit (OpCodes.Conv_I4);
5782 return;
5785 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5787 if (leave_copy) {
5788 ec.ig.Emit (OpCodes.Dup);
5789 if (!is_static) {
5790 temp = new LocalTemporary (this.Type);
5791 temp.Store (ec);
5797 // Implements the IAssignMethod interface for assignments
5799 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5801 Expression my_source = source;
5803 if (prepare_for_load) {
5804 prepared = true;
5805 source.Emit (ec);
5807 if (leave_copy) {
5808 ec.ig.Emit (OpCodes.Dup);
5809 if (!is_static) {
5810 temp = new LocalTemporary (this.Type);
5811 temp.Store (ec);
5814 } else if (leave_copy) {
5815 source.Emit (ec);
5816 temp = new LocalTemporary (this.Type);
5817 temp.Store (ec);
5818 my_source = temp;
5821 Arguments args = new Arguments (1);
5822 args.Add (new Argument (my_source));
5824 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5826 if (temp != null) {
5827 temp.Emit (ec);
5828 temp.Release (ec);
5832 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5834 if (targs != null) {
5835 base.SetTypeArguments (ec, targs);
5836 return false;
5839 if (getter != null) {
5840 if (TypeManager.GetParameterData (getter).Count != 0) {
5841 Error_PropertyNotFound (ec, getter, true);
5842 return false;
5846 if (getter == null) {
5848 // The following condition happens if the PropertyExpr was
5849 // created, but is invalid (ie, the property is inaccessible),
5850 // and we did not want to embed the knowledge about this in
5851 // the caller routine. This only avoids double error reporting.
5853 if (setter == null)
5854 return false;
5856 if (InstanceExpression != EmptyExpression.Null) {
5857 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5858 TypeManager.GetFullNameSignature (PropertyInfo));
5859 return false;
5863 if (getter != null &&
5864 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5865 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter) as PropertyBase.PropertyMethod;
5866 if (pm != null && pm.HasCustomAccessModifier) {
5867 ec.Report.SymbolRelatedToPreviousError (pm);
5868 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5869 TypeManager.CSharpSignature (getter));
5870 } else {
5871 ec.Report.SymbolRelatedToPreviousError (getter);
5872 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter), ec.Report);
5875 return false;
5878 return true;
5881 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5883 targs = ta;
5887 /// <summary>
5888 /// Fully resolved expression that evaluates to an Event
5889 /// </summary>
5890 public class EventExpr : MemberExpr {
5891 public readonly EventInfo EventInfo;
5893 bool is_static;
5894 MethodInfo add_accessor, remove_accessor;
5896 public EventExpr (EventInfo ei, Location loc)
5898 EventInfo = ei;
5899 this.loc = loc;
5900 eclass = ExprClass.EventAccess;
5902 add_accessor = TypeManager.GetAddMethod (ei);
5903 remove_accessor = TypeManager.GetRemoveMethod (ei);
5904 if (add_accessor.IsStatic || remove_accessor.IsStatic)
5905 is_static = true;
5907 if (EventInfo is MyEventBuilder){
5908 MyEventBuilder eb = (MyEventBuilder) EventInfo;
5909 type = eb.EventType;
5910 eb.SetUsed ();
5911 } else
5912 type = EventInfo.EventHandlerType;
5915 public override string Name {
5916 get {
5917 return EventInfo.Name;
5921 public override bool IsInstance {
5922 get {
5923 return !is_static;
5927 public override bool IsStatic {
5928 get {
5929 return is_static;
5933 public override Type DeclaringType {
5934 get {
5935 return EventInfo.DeclaringType;
5939 public void Error_AssignmentEventOnly (ResolveContext ec)
5941 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5942 GetSignatureForError ());
5945 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5946 SimpleName original)
5949 // If the event is local to this class, we transform ourselves into a FieldExpr
5952 if (EventInfo.DeclaringType == ec.CurrentType ||
5953 TypeManager.IsNestedChildOf(ec.CurrentType, EventInfo.DeclaringType)) {
5955 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5956 EventField mi = TypeManager.GetEventField (EventInfo);
5958 if (mi != null) {
5959 if (!ec.IsObsolete)
5960 mi.CheckObsoleteness (loc);
5962 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5963 Error_AssignmentEventOnly (ec);
5965 FieldExpr ml = new FieldExpr (mi.BackingField.FieldBuilder, loc);
5967 InstanceExpression = null;
5969 return ml.ResolveMemberAccess (ec, left, loc, original);
5973 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5974 Error_AssignmentEventOnly (ec);
5976 return base.ResolveMemberAccess (ec, left, loc, original);
5979 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5981 if (is_static) {
5982 InstanceExpression = null;
5983 return true;
5986 if (InstanceExpression == null) {
5987 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5988 return false;
5991 InstanceExpression = InstanceExpression.DoResolve (ec);
5992 if (InstanceExpression == null)
5993 return false;
5995 if (IsBase && add_accessor.IsAbstract) {
5996 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(add_accessor));
5997 return false;
6001 // This is using the same mechanism as the CS1540 check in PropertyExpr.
6002 // However, in the Event case, we reported a CS0122 instead.
6004 // TODO: Exact copy from PropertyExpr
6006 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
6007 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
6008 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
6009 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
6010 ec.Report.SymbolRelatedToPreviousError (EventInfo);
6011 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
6012 return false;
6015 return true;
6018 public bool IsAccessibleFrom (Type invocation_type)
6020 bool dummy;
6021 return IsAccessorAccessible (invocation_type, add_accessor, out dummy) &&
6022 IsAccessorAccessible (invocation_type, remove_accessor, out dummy);
6025 public override Expression CreateExpressionTree (ResolveContext ec)
6027 throw new NotSupportedException ("ET");
6030 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6032 // contexts where an LValue is valid have already devolved to FieldExprs
6033 Error_CannotAssign (ec);
6034 return null;
6037 public override Expression DoResolve (ResolveContext ec)
6039 bool must_do_cs1540_check;
6040 if (!(IsAccessorAccessible (ec.CurrentType, add_accessor, out must_do_cs1540_check) &&
6041 IsAccessorAccessible (ec.CurrentType, remove_accessor, out must_do_cs1540_check))) {
6042 ec.Report.SymbolRelatedToPreviousError (EventInfo);
6043 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (EventInfo), ec.Report);
6044 return null;
6047 if (!InstanceResolve (ec, must_do_cs1540_check))
6048 return null;
6050 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6051 Error_CannotAssign (ec);
6052 return null;
6055 if (!ec.IsObsolete) {
6056 EventField ev = TypeManager.GetEventField (EventInfo);
6057 if (ev != null) {
6058 ev.CheckObsoleteness (loc);
6059 } else {
6060 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (EventInfo);
6061 if (oa != null)
6062 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
6066 return this;
6069 public override void Emit (EmitContext ec)
6071 throw new NotSupportedException ();
6072 //Error_CannotAssign ();
6075 public void Error_CannotAssign (ResolveContext ec)
6077 ec.Report.Error (70, loc,
6078 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6079 GetSignatureForError (), TypeManager.CSharpName (EventInfo.DeclaringType));
6082 public override string GetSignatureForError ()
6084 return TypeManager.CSharpSignature (EventInfo);
6087 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6089 Arguments args = new Arguments (1);
6090 args.Add (new Argument (source));
6091 Invocation.EmitCall (ec, IsBase, InstanceExpression, is_add ? add_accessor : remove_accessor, args, loc);
6095 public class TemporaryVariable : VariableReference
6097 LocalInfo li;
6099 public TemporaryVariable (Type type, Location loc)
6101 this.type = type;
6102 this.loc = loc;
6103 eclass = ExprClass.Variable;
6106 public override Expression CreateExpressionTree (ResolveContext ec)
6108 throw new NotSupportedException ("ET");
6111 public override Expression DoResolve (ResolveContext ec)
6113 if (li != null)
6114 return this;
6116 TypeExpr te = new TypeExpression (type, loc);
6117 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6118 if (!li.Resolve (ec))
6119 return null;
6122 // Don't capture temporary variables except when using
6123 // iterator redirection
6125 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6126 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6127 storey.CaptureLocalVariable (ec, li);
6130 return this;
6133 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6135 return DoResolve (ec);
6138 public override void Emit (EmitContext ec)
6140 Emit (ec, false);
6143 public void EmitAssign (EmitContext ec, Expression source)
6145 EmitAssign (ec, source, false, false);
6148 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6150 return li.HoistedVariant;
6153 public override bool IsFixed {
6154 get { return true; }
6157 public override bool IsRef {
6158 get { return false; }
6161 public override string Name {
6162 get { throw new NotImplementedException (); }
6165 public override void SetHasAddressTaken ()
6167 throw new NotImplementedException ();
6170 protected override ILocalVariable Variable {
6171 get { return li; }
6174 public override VariableInfo VariableInfo {
6175 get { throw new NotImplementedException (); }
6179 ///
6180 /// Handles `var' contextual keyword; var becomes a keyword only
6181 /// if no type called var exists in a variable scope
6182 ///
6183 class VarExpr : SimpleName
6185 // Used for error reporting only
6186 ArrayList initializer;
6188 public VarExpr (Location loc)
6189 : base ("var", loc)
6193 public ArrayList VariableInitializer {
6194 set {
6195 this.initializer = value;
6199 public bool InferType (ResolveContext ec, Expression right_side)
6201 if (type != null)
6202 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6204 type = right_side.Type;
6205 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6206 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6207 right_side.GetSignatureForError ());
6208 return false;
6211 eclass = ExprClass.Variable;
6212 return true;
6215 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6217 if (RootContext.Version < LanguageVersion.V_3)
6218 base.Error_TypeOrNamespaceNotFound (ec);
6219 else
6220 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6223 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6225 TypeExpr te = base.ResolveAsContextualType (rc, true);
6226 if (te != null)
6227 return te;
6229 if (RootContext.Version < LanguageVersion.V_3)
6230 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6232 if (initializer == null)
6233 return null;
6235 if (initializer.Count > 1) {
6236 Location loc_init = ((CSharpParser.VariableDeclaration) initializer[1]).Location;
6237 rc.Compiler.Report.Error (819, loc_init, "An implicitly typed local variable declaration cannot include multiple declarators");
6238 initializer = null;
6239 return null;
6242 Expression variable_initializer = ((CSharpParser.VariableDeclaration) initializer[0]).expression_or_array_initializer;
6243 if (variable_initializer == null) {
6244 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
6245 return null;
6248 return null;