* SolutionParser.cs: Identify and emit warning for a
[mcs.git] / mcs / ecore.cs
blob336bd0be58b5ac78caaaeb36840a2634eedac569
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 using System;
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
19 using SLE = System.Linq.Expressions;
20 using System.Linq;
22 namespace Mono.CSharp {
24 /// <remarks>
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
28 /// nothing).
29 /// </remarks>
30 public enum ExprClass : byte {
31 Unresolved = 0,
33 Value,
34 Variable,
35 Namespace,
36 Type,
37 TypeParameter,
38 MethodGroup,
39 PropertyAccess,
40 EventAccess,
41 IndexerAccess,
42 Nothing,
45 /// <remarks>
46 /// This is used to tell Resolve in which types of expressions we're
47 /// interested.
48 /// </remarks>
49 [Flags]
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
52 VariableOrValue = 1,
54 // Returns a type expression.
55 Type = 1 << 1,
57 // Returns a method group.
58 MethodGroup = 1 << 2,
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
65 // Set if this is resolving the first part of a MemberAccess.
66 Intermediate = 1 << 11,
70 // This is just as a hint to AddressOf of what will be done with the
71 // address.
72 [Flags]
73 public enum AddressOp {
74 Store = 1,
75 Load = 2,
76 LoadStore = 3
79 /// <summary>
80 /// This interface is implemented by variables
81 /// </summary>
82 public interface IMemoryLocation {
83 /// <summary>
84 /// The AddressOf method should generate code that loads
85 /// the address of the object and leaves it on the stack.
86 ///
87 /// The `mode' argument is used to notify the expression
88 /// of whether this will be used to read from the address or
89 /// write to the address.
90 ///
91 /// This is just a hint that can be used to provide good error
92 /// reporting, and should have no other side effects.
93 /// </summary>
94 void AddressOf (EmitContext ec, AddressOp mode);
98 // An expressions resolved as a direct variable reference
100 public interface IVariableReference : IFixedExpression
102 bool IsHoisted { get; }
103 string Name { get; }
104 VariableInfo VariableInfo { get; }
106 void SetHasAddressTaken ();
110 // Implemented by an expression which could be or is always
111 // fixed
113 public interface IFixedExpression
115 bool IsFixed { get; }
118 /// <remarks>
119 /// Base class for expressions
120 /// </remarks>
121 public abstract class Expression {
122 public ExprClass eclass;
123 protected Type type;
124 protected Location loc;
126 public Type Type {
127 get { return type; }
128 set { type = value; }
131 public virtual Location Location {
132 get { return loc; }
135 // Not nice but we have broken hierarchy.
136 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
140 public virtual bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
142 Attribute.Error_AttributeArgumentNotValid (ec, loc);
143 value = null;
144 return false;
147 public virtual string GetSignatureForError ()
149 return TypeManager.CSharpName (type);
152 public static bool IsAccessorAccessible (Type invocation_type, MethodSpec mi, out bool must_do_cs1540_check)
154 var ma = mi.Modifiers & Modifiers.AccessibilityMask;
156 must_do_cs1540_check = false; // by default we do not check for this
158 if (ma == Modifiers.PUBLIC)
159 return true;
162 // If only accessible to the current class or children
164 if (ma == Modifiers.PRIVATE)
165 return TypeManager.IsPrivateAccessible (invocation_type, mi.DeclaringType) ||
166 TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType);
168 if ((ma & Modifiers.INTERNAL) != 0) {
169 var b = TypeManager.IsThisOrFriendAssembly (invocation_type.Assembly, mi.DeclaringType.Assembly);
170 if (b || ma == Modifiers.INTERNAL)
171 return b;
174 // Family and FamANDAssem require that we derive.
175 // FamORAssem requires that we derive if in different assemblies.
176 if (!TypeManager.IsNestedFamilyAccessible (invocation_type, mi.DeclaringType))
177 return false;
179 if (!TypeManager.IsNestedChildOf (invocation_type, mi.DeclaringType))
180 must_do_cs1540_check = true;
182 return true;
185 public virtual bool IsNull {
186 get {
187 return false;
191 /// <summary>
192 /// Performs semantic analysis on the Expression
193 /// </summary>
195 /// <remarks>
196 /// The Resolve method is invoked to perform the semantic analysis
197 /// on the node.
199 /// The return value is an expression (it can be the
200 /// same expression in some cases) or a new
201 /// expression that better represents this node.
202 ///
203 /// For example, optimizations of Unary (LiteralInt)
204 /// would return a new LiteralInt with a negated
205 /// value.
206 ///
207 /// If there is an error during semantic analysis,
208 /// then an error should be reported (using Report)
209 /// and a null value should be returned.
210 ///
211 /// There are two side effects expected from calling
212 /// Resolve(): the the field variable "eclass" should
213 /// be set to any value of the enumeration
214 /// `ExprClass' and the type variable should be set
215 /// to a valid type (this is the type of the
216 /// expression).
217 /// </remarks>
218 protected abstract Expression DoResolve (ResolveContext rc);
220 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
222 return null;
226 // This is used if the expression should be resolved as a type or namespace name.
227 // the default implementation fails.
229 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
231 if (!silent) {
232 ResolveContext ec = new ResolveContext (rc);
233 Expression e = Resolve (ec);
234 if (e != null)
235 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
238 return null;
242 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
243 // same name exists or as a keyword when no type was found
245 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
247 return ResolveAsTypeTerminal (rc, silent);
251 // This is used to resolve the expression as a type, a null
252 // value will be returned if the expression is not a type
253 // reference
255 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
257 TypeExpr te = ResolveAsBaseTerminal (ec, silent);
258 if (te == null)
259 return null;
261 if (!silent) { // && !(te is TypeParameterExpr)) {
262 ObsoleteAttribute obsolete_attr = AttributeTester.GetObsoleteAttribute (te.Type);
263 if (obsolete_attr != null && !ec.IsObsolete) {
264 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
268 GenericTypeExpr ct = te as GenericTypeExpr;
269 if (ct != null) {
271 // TODO: Constrained type parameters check for parameters of generic method overrides is broken
272 // There are 2 solutions.
273 // 1, Skip this check completely when we are in override/explicit impl scope
274 // 2, Copy type parameters constraints from base implementation and pass (they have to be emitted anyway)
276 MemberCore gm = ec as GenericMethod;
277 if (gm == null)
278 gm = ec as Method;
279 if (gm != null && ((gm.ModFlags & Modifiers.OVERRIDE) != 0 || gm.MemberName.Left != null)) {
280 te.loc = loc;
281 return te;
284 // TODO: silent flag is ignored
285 ct.CheckConstraints (ec);
288 return te;
291 public TypeExpr ResolveAsBaseTerminal (IMemberContext ec, bool silent)
293 int errors = ec.Compiler.Report.Errors;
295 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
297 if (fne == null)
298 return null;
300 TypeExpr te = fne as TypeExpr;
301 if (te == null) {
302 if (!silent && errors == ec.Compiler.Report.Errors)
303 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
304 return null;
307 if (!te.CheckAccessLevel (ec)) {
308 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
309 ErrorIsInaccesible (loc, TypeManager.CSharpName (te.Type), ec.Compiler.Report);
310 return null;
313 te.loc = loc;
314 return te;
317 public static void ErrorIsInaccesible (Location loc, string name, Report Report)
319 Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", name);
322 protected static void Error_CannotAccessProtected (ResolveContext ec, Location loc, MemberInfo m, Type qualifier, Type container)
324 ec.Report.Error (1540, loc, "Cannot access protected member `{0}' via a qualifier of type `{1}'."
325 + " The qualifier must be of type `{2}' or derived from it",
326 TypeManager.GetFullNameSignature (m),
327 TypeManager.CSharpName (qualifier),
328 TypeManager.CSharpName (container));
332 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
334 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
337 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, Type type, Location loc, string name)
339 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
340 name, TypeManager.CSharpName (type));
343 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
345 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
346 "expressions can be used as a statement");
349 public void Error_InvalidExpressionStatement (BlockContext ec)
351 Error_InvalidExpressionStatement (ec.Report, loc);
354 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
356 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
359 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
361 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
364 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, Type target, bool expl)
366 // The error was already reported as CS1660
367 if (type == InternalType.AnonymousMethod)
368 return;
370 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
371 string sig1 = type.DeclaringMethod == null ?
372 TypeManager.CSharpName (type.DeclaringType) :
373 TypeManager.CSharpSignature (type.DeclaringMethod);
374 string sig2 = target.DeclaringMethod == null ?
375 TypeManager.CSharpName (target.DeclaringType) :
376 TypeManager.CSharpSignature (target.DeclaringMethod);
377 ec.Report.ExtraInformation (loc,
378 String.Format (
379 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
380 Type.Name, sig1, sig2));
381 } else if (Type.FullName == target.FullName){
382 ec.Report.ExtraInformation (loc,
383 String.Format (
384 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
385 Type.FullName, Type.Assembly.FullName, target.Assembly.FullName));
388 if (expl) {
389 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
390 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
391 return;
394 ec.Report.DisableReporting ();
395 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
396 ec.Report.EnableReporting ();
398 if (expl_exists) {
399 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
400 "An explicit conversion exists (are you missing a cast?)",
401 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
402 return;
405 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
406 TypeManager.CSharpName (type),
407 TypeManager.CSharpName (target));
410 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
412 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
415 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc)
417 // Better message for possible generic expressions
418 if (eclass == ExprClass.MethodGroup || eclass == ExprClass.Type) {
419 if (this is TypeExpr)
420 report.SymbolRelatedToPreviousError (type);
422 string name = eclass == ExprClass.Type ? ExprClassName : "method";
423 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
424 name, GetSignatureForError ());
425 } else {
426 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
427 ExprClassName, GetSignatureForError ());
431 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, Type type, string name)
433 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
436 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, Type type, string name)
438 ec.Report.SymbolRelatedToPreviousError (type);
439 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
440 TypeManager.CSharpName (type), name);
443 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
445 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
448 ResolveFlags ExprClassToResolveFlags {
449 get {
450 switch (eclass) {
451 case ExprClass.Type:
452 case ExprClass.Namespace:
453 return ResolveFlags.Type;
455 case ExprClass.MethodGroup:
456 return ResolveFlags.MethodGroup;
458 case ExprClass.TypeParameter:
459 return ResolveFlags.TypeParameter;
461 case ExprClass.Value:
462 case ExprClass.Variable:
463 case ExprClass.PropertyAccess:
464 case ExprClass.EventAccess:
465 case ExprClass.IndexerAccess:
466 return ResolveFlags.VariableOrValue;
468 default:
469 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
474 /// <summary>
475 /// Resolves an expression and performs semantic analysis on it.
476 /// </summary>
478 /// <remarks>
479 /// Currently Resolve wraps DoResolve to perform sanity
480 /// checking and assertion checking on what we expect from Resolve.
481 /// </remarks>
482 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
484 if (eclass != ExprClass.Unresolved)
485 return this;
487 Expression e;
488 if (this is SimpleName) {
489 e = ((SimpleName) this).DoResolve (ec, (flags & ResolveFlags.Intermediate) != 0);
490 } else {
491 e = DoResolve (ec);
494 if (e == null)
495 return null;
497 if ((flags & e.ExprClassToResolveFlags) == 0) {
498 e.Error_UnexpectedKind (ec, flags, loc);
499 return null;
502 if (e.type == null)
503 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
505 return e;
508 /// <summary>
509 /// Resolves an expression and performs semantic analysis on it.
510 /// </summary>
511 public Expression Resolve (ResolveContext rc)
513 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
516 /// <summary>
517 /// Resolves an expression for LValue assignment
518 /// </summary>
520 /// <remarks>
521 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
522 /// checking and assertion checking on what we expect from Resolve
523 /// </remarks>
524 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
526 int errors = ec.Report.Errors;
527 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
529 Expression e = DoResolveLValue (ec, right_side);
531 if (e != null && out_access && !(e is IMemoryLocation)) {
532 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
533 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
535 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
536 // e.GetType () + " " + e.GetSignatureForError ());
537 e = null;
540 if (e == null) {
541 if (errors == ec.Report.Errors) {
542 if (out_access)
543 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
544 else
545 Error_ValueAssignment (ec, loc);
547 return null;
550 if (e.eclass == ExprClass.Unresolved)
551 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
553 if ((e.type == null) && !(e is GenericTypeExpr))
554 throw new Exception ("Expression " + e + " did not set its type after Resolve");
556 return e;
559 /// <summary>
560 /// Emits the code for the expression
561 /// </summary>
563 /// <remarks>
564 /// The Emit method is invoked to generate the code
565 /// for the expression.
566 /// </remarks>
567 public abstract void Emit (EmitContext ec);
569 // Emit code to branch to @target if this expression is equivalent to @on_true.
570 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
571 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
572 // including the use of conditional branches. Note also that a branch MUST be emitted
573 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
575 Emit (ec);
576 ec.ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
579 // Emit this expression for its side effects, not for its value.
580 // The default implementation is to emit the value, and then throw it away.
581 // Subclasses can provide more efficient implementations, but those MUST be equivalent
582 public virtual void EmitSideEffect (EmitContext ec)
584 Emit (ec);
585 ec.ig.Emit (OpCodes.Pop);
588 /// <summary>
589 /// Protected constructor. Only derivate types should
590 /// be able to be created
591 /// </summary>
593 protected Expression ()
597 /// <summary>
598 /// Returns a fully formed expression after a MemberLookup
599 /// </summary>
600 ///
601 public static Expression ExprClassFromMemberInfo (Type container_type, MemberInfo mi, Location loc)
603 if (mi is EventInfo)
604 return new EventExpr (Import.CreateEvent ((EventInfo) mi), loc);
605 else if (mi is FieldInfo) {
606 FieldInfo fi = (FieldInfo) mi;
607 var spec = Import.CreateField (fi);
608 if (spec is ConstSpec)
609 return new ConstantExpr ((ConstSpec) spec, loc);
610 return new FieldExpr (spec, loc);
611 } else if (mi is PropertyInfo)
612 return new PropertyExpr (container_type, Import.CreateProperty ((PropertyInfo) mi), loc);
613 else if (mi is Type) {
614 return new TypeExpression ((System.Type) mi, loc);
617 return null;
620 // TODO: [Obsolete ("Can be removed")]
621 protected static IList<MemberInfo> almost_matched_members = new List<MemberInfo> (4);
624 // FIXME: Probably implement a cache for (t,name,current_access_set)?
626 // This code could use some optimizations, but we need to do some
627 // measurements. For example, we could use a delegate to `flag' when
628 // something can not any longer be a method-group (because it is something
629 // else).
631 // Return values:
632 // If the return value is an Array, then it is an array of
633 // MethodBases
635 // If the return value is an MemberInfo, it is anything, but a Method
637 // null on error.
639 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
640 // the arguments here and have MemberLookup return only the methods that
641 // match the argument count/type, unlike we are doing now (we delay this
642 // decision).
644 // This is so we can catch correctly attempts to invoke instance methods
645 // from a static body (scan for error 120 in ResolveSimpleName).
648 // FIXME: Potential optimization, have a static ArrayList
651 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type, string name,
652 MemberTypes mt, BindingFlags bf, Location loc)
654 return MemberLookup (ctx, container_type, null, queried_type, name, mt, bf, loc);
658 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
659 // `qualifier_type' or null to lookup members in the current class.
662 public static Expression MemberLookup (CompilerContext ctx, Type container_type,
663 Type qualifier_type, Type queried_type,
664 string name, MemberTypes mt,
665 BindingFlags bf, Location loc)
667 almost_matched_members.Clear ();
669 MemberInfo [] mi = TypeManager.MemberLookup (container_type, qualifier_type,
670 queried_type, mt, bf, name, almost_matched_members);
672 if (mi == null)
673 return null;
675 if (mi.Length > 1) {
676 bool is_interface = qualifier_type != null && qualifier_type.IsInterface;
677 var methods = new List<MethodSpec> (2);
678 List<MemberInfo> non_methods = null;
680 foreach (var m in mi) {
681 if (m is MethodBase) {
682 methods.Add (Import.CreateMethod ((MethodBase) m));
683 continue;
686 if (non_methods == null)
687 non_methods = new List<MemberInfo> (2);
689 bool is_candidate = true;
690 for (int i = 0; i < non_methods.Count; ++i) {
691 MemberInfo n_m = non_methods [i];
692 if (n_m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (m.DeclaringType, n_m.DeclaringType)) {
693 non_methods.Remove (n_m);
694 --i;
695 } else if (m.DeclaringType.IsInterface && TypeManager.ImplementsInterface (n_m.DeclaringType, m.DeclaringType)) {
696 is_candidate = false;
697 break;
701 if (is_candidate) {
702 non_methods.Add (m);
706 if (methods.Count == 0 && non_methods != null && non_methods.Count > 1) {
707 ctx.Report.SymbolRelatedToPreviousError (non_methods [1]);
708 ctx.Report.SymbolRelatedToPreviousError (non_methods [0]);
709 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
710 TypeManager.GetFullNameSignature (non_methods [1]),
711 TypeManager.GetFullNameSignature (non_methods [0]));
712 return null;
715 if (methods.Count == 0)
716 return ExprClassFromMemberInfo (container_type, (MemberInfo)non_methods [0], loc);
718 if (non_methods != null && non_methods.Count > 0) {
719 var method = methods [0];
720 MemberInfo non_method = (MemberInfo) non_methods [0];
721 if (method.DeclaringType == non_method.DeclaringType) {
722 // Cannot happen with C# code, but is valid in IL
723 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
724 ctx.Report.SymbolRelatedToPreviousError (non_method);
725 ctx.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
726 TypeManager.GetFullNameSignature (non_method),
727 TypeManager.CSharpSignature (method.MetaInfo));
728 return null;
731 if (is_interface) {
732 ctx.Report.SymbolRelatedToPreviousError (method.MetaInfo);
733 ctx.Report.SymbolRelatedToPreviousError (non_method);
734 ctx.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and non-method `{1}'. Using method `{0}'",
735 TypeManager.CSharpSignature (method.MetaInfo), TypeManager.GetFullNameSignature (non_method));
739 return new MethodGroupExpr (methods, queried_type, loc);
742 if (mi [0] is MethodBase)
743 return new MethodGroupExpr (mi.Select (l => Import.CreateMethod ((MethodBase) l)).ToArray (), queried_type, loc);
745 return ExprClassFromMemberInfo (container_type, mi [0], loc);
748 public const MemberTypes AllMemberTypes =
749 MemberTypes.Constructor |
750 MemberTypes.Event |
751 MemberTypes.Field |
752 MemberTypes.Method |
753 MemberTypes.NestedType |
754 MemberTypes.Property;
756 public const BindingFlags AllBindingFlags =
757 BindingFlags.Public |
758 BindingFlags.Static |
759 BindingFlags.Instance;
761 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type queried_type,
762 string name, Location loc)
764 return MemberLookup (ctx, container_type, null, queried_type, name,
765 AllMemberTypes, AllBindingFlags, loc);
768 public static Expression MemberLookup (CompilerContext ctx, Type container_type, Type qualifier_type,
769 Type queried_type, string name, Location loc)
771 return MemberLookup (ctx, container_type, qualifier_type, queried_type,
772 name, AllMemberTypes, AllBindingFlags, loc);
775 public static MethodGroupExpr MethodLookup (CompilerContext ctx, Type container_type, Type queried_type,
776 string name, Location loc)
778 return (MethodGroupExpr)MemberLookup (ctx, container_type, null, queried_type, name,
779 MemberTypes.Method, AllBindingFlags, loc);
782 /// <summary>
783 /// This is a wrapper for MemberLookup that is not used to "probe", but
784 /// to find a final definition. If the final definition is not found, we
785 /// look for private members and display a useful debugging message if we
786 /// find it.
787 /// </summary>
788 protected Expression MemberLookupFinal (ResolveContext ec, Type qualifier_type,
789 Type queried_type, string name,
790 MemberTypes mt, BindingFlags bf,
791 Location loc)
793 Expression e;
795 int errors = ec.Report.Errors;
796 e = MemberLookup (ec.Compiler, ec.CurrentType, qualifier_type, queried_type, name, mt, bf, loc);
798 if (e != null || errors != ec.Report.Errors)
799 return e;
801 // No errors were reported by MemberLookup, but there was an error.
802 return Error_MemberLookupFailed (ec, ec.CurrentType, qualifier_type, queried_type,
803 name, null, mt, bf);
806 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type container_type, Type qualifier_type,
807 Type queried_type, string name, string class_name,
808 MemberTypes mt, BindingFlags bf)
810 MemberInfo[] lookup = null;
811 if (queried_type == null) {
812 class_name = "global::";
813 } else {
814 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
815 mt, (bf & ~BindingFlags.Public) | BindingFlags.NonPublic,
816 name, null);
818 if (lookup != null) {
819 Expression e = Error_MemberLookupFailed (ec, queried_type, lookup);
822 // FIXME: This is still very wrong, it should be done inside
823 // OverloadResolve to do correct arguments matching.
824 // Requires MemberLookup accessiblity check removal
826 if (e == null || (mt & (MemberTypes.Method | MemberTypes.Constructor)) == 0) {
827 MemberInfo mi = lookup[0];
828 ec.Report.SymbolRelatedToPreviousError (mi);
829 if (qualifier_type != null && container_type != null && qualifier_type != container_type &&
830 TypeManager.IsNestedFamilyAccessible (container_type, mi.DeclaringType)) {
831 // Although a derived class can access protected members of
832 // its base class it cannot do so through an instance of the
833 // base class (CS1540). If the qualifier_type is a base of the
834 // ec.CurrentType and the lookup succeeds with the latter one,
835 // then we are in this situation.
836 Error_CannotAccessProtected (ec, loc, mi, qualifier_type, container_type);
837 } else {
838 ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (mi), ec.Report);
842 return e;
845 lookup = TypeManager.MemberLookup (queried_type, null, queried_type,
846 AllMemberTypes, AllBindingFlags | BindingFlags.NonPublic,
847 name, null);
850 if (lookup == null) {
851 if (class_name != null) {
852 ec.Report.Error (103, loc, "The name `{0}' does not exist in the current context",
853 name);
854 } else {
855 Error_TypeDoesNotContainDefinition (ec, queried_type, name);
857 return null;
860 if (TypeManager.MemberLookup (queried_type, null, queried_type,
861 AllMemberTypes, AllBindingFlags |
862 BindingFlags.NonPublic, name, null) == null) {
863 if ((lookup.Length == 1) && (lookup [0] is Type)) {
864 Type t = (Type) lookup [0];
866 ec.Report.Error (305, loc,
867 "Using the generic type `{0}' " +
868 "requires {1} type arguments",
869 TypeManager.CSharpName (t),
870 TypeManager.GetNumberOfTypeArguments (t).ToString ());
871 return null;
875 return Error_MemberLookupFailed (ec, queried_type, lookup);
878 protected virtual Expression Error_MemberLookupFailed (ResolveContext ec, Type type, MemberInfo[] members)
880 List<MethodSpec> methods = new List<MethodSpec> ();
881 for (int i = 0; i < members.Length; ++i) {
882 if (!(members [i] is MethodBase))
883 return null;
885 methods.Add (Import.CreateMethod (members[i] as MethodBase));
888 // By default propagate the closest candidates upwards
889 return new MethodGroupExpr (methods.ToArray (), type, loc, true);
892 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
894 throw new NotImplementedException ();
897 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
899 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
902 /// <summary>
903 /// Returns an expression that can be used to invoke operator true
904 /// on the expression if it exists.
905 /// </summary>
906 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
908 return GetOperatorTrueOrFalse (ec, e, true, loc);
911 /// <summary>
912 /// Returns an expression that can be used to invoke operator false
913 /// on the expression if it exists.
914 /// </summary>
915 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
917 return GetOperatorTrueOrFalse (ec, e, false, loc);
920 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
922 MethodGroupExpr operator_group;
923 string mname = Operator.GetMetadataName (is_true ? Operator.OpType.True : Operator.OpType.False);
924 operator_group = MethodLookup (ec.Compiler, ec.CurrentType, e.Type, mname, loc) as MethodGroupExpr;
925 if (operator_group == null)
926 return null;
928 Arguments arguments = new Arguments (1);
929 arguments.Add (new Argument (e));
930 operator_group = operator_group.OverloadResolve (
931 ec, ref arguments, false, loc);
933 if (operator_group == null)
934 return null;
936 return new UserOperatorCall (operator_group, arguments, null, loc);
939 public virtual string ExprClassName
941 get {
942 switch (eclass){
943 case ExprClass.Unresolved:
944 return "Unresolved";
945 case ExprClass.Value:
946 return "value";
947 case ExprClass.Variable:
948 return "variable";
949 case ExprClass.Namespace:
950 return "namespace";
951 case ExprClass.Type:
952 return "type";
953 case ExprClass.MethodGroup:
954 return "method group";
955 case ExprClass.PropertyAccess:
956 return "property access";
957 case ExprClass.EventAccess:
958 return "event access";
959 case ExprClass.IndexerAccess:
960 return "indexer access";
961 case ExprClass.Nothing:
962 return "null";
963 case ExprClass.TypeParameter:
964 return "type parameter";
966 throw new Exception ("Should not happen");
970 /// <summary>
971 /// Reports that we were expecting `expr' to be of class `expected'
972 /// </summary>
973 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
975 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
978 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
980 string name;
981 if (mc != null)
982 name = mc.GetSignatureForError ();
983 else
984 name = GetSignatureForError ();
986 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
987 name, was, expected);
990 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
992 string [] valid = new string [4];
993 int count = 0;
995 if ((flags & ResolveFlags.VariableOrValue) != 0) {
996 valid [count++] = "variable";
997 valid [count++] = "value";
1000 if ((flags & ResolveFlags.Type) != 0)
1001 valid [count++] = "type";
1003 if ((flags & ResolveFlags.MethodGroup) != 0)
1004 valid [count++] = "method group";
1006 if (count == 0)
1007 valid [count++] = "unknown";
1009 StringBuilder sb = new StringBuilder (valid [0]);
1010 for (int i = 1; i < count - 1; i++) {
1011 sb.Append ("', `");
1012 sb.Append (valid [i]);
1014 if (count > 1) {
1015 sb.Append ("' or `");
1016 sb.Append (valid [count - 1]);
1019 ec.Report.Error (119, loc,
1020 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1023 public static void UnsafeError (ResolveContext ec, Location loc)
1025 UnsafeError (ec.Report, loc);
1028 public static void UnsafeError (Report Report, Location loc)
1030 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1034 // Load the object from the pointer.
1036 public static void LoadFromPtr (ILGenerator ig, Type t)
1038 if (t == TypeManager.int32_type)
1039 ig.Emit (OpCodes.Ldind_I4);
1040 else if (t == TypeManager.uint32_type)
1041 ig.Emit (OpCodes.Ldind_U4);
1042 else if (t == TypeManager.short_type)
1043 ig.Emit (OpCodes.Ldind_I2);
1044 else if (t == TypeManager.ushort_type)
1045 ig.Emit (OpCodes.Ldind_U2);
1046 else if (t == TypeManager.char_type)
1047 ig.Emit (OpCodes.Ldind_U2);
1048 else if (t == TypeManager.byte_type)
1049 ig.Emit (OpCodes.Ldind_U1);
1050 else if (t == TypeManager.sbyte_type)
1051 ig.Emit (OpCodes.Ldind_I1);
1052 else if (t == TypeManager.uint64_type)
1053 ig.Emit (OpCodes.Ldind_I8);
1054 else if (t == TypeManager.int64_type)
1055 ig.Emit (OpCodes.Ldind_I8);
1056 else if (t == TypeManager.float_type)
1057 ig.Emit (OpCodes.Ldind_R4);
1058 else if (t == TypeManager.double_type)
1059 ig.Emit (OpCodes.Ldind_R8);
1060 else if (t == TypeManager.bool_type)
1061 ig.Emit (OpCodes.Ldind_I1);
1062 else if (t == TypeManager.intptr_type)
1063 ig.Emit (OpCodes.Ldind_I);
1064 else if (TypeManager.IsEnumType (t)) {
1065 if (t == TypeManager.enum_type)
1066 ig.Emit (OpCodes.Ldind_Ref);
1067 else
1068 LoadFromPtr (ig, TypeManager.GetEnumUnderlyingType (t));
1069 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
1070 ig.Emit (OpCodes.Ldobj, t);
1071 else if (t.IsPointer)
1072 ig.Emit (OpCodes.Ldind_I);
1073 else
1074 ig.Emit (OpCodes.Ldind_Ref);
1078 // The stack contains the pointer and the value of type `type'
1080 public static void StoreFromPtr (ILGenerator ig, Type type)
1082 if (TypeManager.IsEnumType (type))
1083 type = TypeManager.GetEnumUnderlyingType (type);
1084 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1085 ig.Emit (OpCodes.Stind_I4);
1086 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
1087 ig.Emit (OpCodes.Stind_I8);
1088 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
1089 type == TypeManager.ushort_type)
1090 ig.Emit (OpCodes.Stind_I2);
1091 else if (type == TypeManager.float_type)
1092 ig.Emit (OpCodes.Stind_R4);
1093 else if (type == TypeManager.double_type)
1094 ig.Emit (OpCodes.Stind_R8);
1095 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
1096 type == TypeManager.bool_type)
1097 ig.Emit (OpCodes.Stind_I1);
1098 else if (type == TypeManager.intptr_type)
1099 ig.Emit (OpCodes.Stind_I);
1100 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
1101 ig.Emit (OpCodes.Stobj, type);
1102 else
1103 ig.Emit (OpCodes.Stind_Ref);
1107 // Returns the size of type `t' if known, otherwise, 0
1109 public static int GetTypeSize (Type t)
1111 t = TypeManager.TypeToCoreType (t);
1112 if (t == TypeManager.int32_type ||
1113 t == TypeManager.uint32_type ||
1114 t == TypeManager.float_type)
1115 return 4;
1116 else if (t == TypeManager.int64_type ||
1117 t == TypeManager.uint64_type ||
1118 t == TypeManager.double_type)
1119 return 8;
1120 else if (t == TypeManager.byte_type ||
1121 t == TypeManager.sbyte_type ||
1122 t == TypeManager.bool_type)
1123 return 1;
1124 else if (t == TypeManager.short_type ||
1125 t == TypeManager.char_type ||
1126 t == TypeManager.ushort_type)
1127 return 2;
1128 else if (t == TypeManager.decimal_type)
1129 return 16;
1130 else
1131 return 0;
1134 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
1136 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
1139 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
1141 ec.Report.SymbolRelatedToPreviousError (type);
1142 if (ec.CurrentInitializerVariable != null) {
1143 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
1144 TypeManager.CSharpName (type), GetSignatureForError ());
1145 } else {
1146 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
1147 GetSignatureForError ());
1152 // Converts `source' to an int, uint, long or ulong.
1154 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1156 if (TypeManager.IsDynamicType (source.type)) {
1157 Arguments args = new Arguments (1);
1158 args.Add (new Argument (source));
1159 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1162 Expression converted;
1164 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1165 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
1166 if (converted == null)
1167 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
1168 if (converted == null)
1169 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
1170 if (converted == null)
1171 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
1173 if (converted == null) {
1174 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
1175 return null;
1180 // Only positive constants are allowed at compile time
1182 Constant c = converted as Constant;
1183 if (c != null && c.IsNegative)
1184 Error_NegativeArrayIndex (ec, source.loc);
1186 // No conversion needed to array index
1187 if (converted.Type == TypeManager.int32_type)
1188 return converted;
1190 return new ArrayIndexCast (converted).Resolve (ec);
1194 // Derived classes implement this method by cloning the fields that
1195 // could become altered during the Resolve stage
1197 // Only expressions that are created for the parser need to implement
1198 // this.
1200 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1202 throw new NotImplementedException (
1203 String.Format (
1204 "CloneTo not implemented for expression {0}", this.GetType ()));
1208 // Clones an expression created by the parser.
1210 // We only support expressions created by the parser so far, not
1211 // expressions that have been resolved (many more classes would need
1212 // to implement CloneTo).
1214 // This infrastructure is here merely for Lambda expressions which
1215 // compile the same code using different type values for the same
1216 // arguments to find the correct overload
1218 public Expression Clone (CloneContext clonectx)
1220 Expression cloned = (Expression) MemberwiseClone ();
1221 CloneTo (clonectx, cloned);
1223 return cloned;
1227 // Implementation of expression to expression tree conversion
1229 public abstract Expression CreateExpressionTree (ResolveContext ec);
1231 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1233 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1236 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1238 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1241 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1243 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1246 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1248 TypeExpr texpr = TypeManager.expression_type_expr;
1249 if (texpr == null) {
1250 Type t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
1251 if (t == null)
1252 return null;
1254 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
1257 return texpr;
1261 // Implemented by all expressions which support conversion from
1262 // compiler expression to invokable runtime expression. Used by
1263 // dynamic C# binder.
1265 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1267 throw new NotImplementedException ("MakeExpression for " + GetType ());
1270 public virtual void MutateHoistedGenericType (AnonymousMethodStorey storey)
1272 // TODO: It should probably be type = storey.MutateType (type);
1276 /// <summary>
1277 /// This is just a base class for expressions that can
1278 /// appear on statements (invocations, object creation,
1279 /// assignments, post/pre increment and decrement). The idea
1280 /// being that they would support an extra Emition interface that
1281 /// does not leave a result on the stack.
1282 /// </summary>
1283 public abstract class ExpressionStatement : Expression {
1285 public virtual ExpressionStatement ResolveStatement (BlockContext ec)
1287 Expression e = Resolve (ec);
1288 if (e == null)
1289 return null;
1291 ExpressionStatement es = e as ExpressionStatement;
1292 if (es == null)
1293 Error_InvalidExpressionStatement (ec);
1295 return es;
1298 /// <summary>
1299 /// Requests the expression to be emitted in a `statement'
1300 /// context. This means that no new value is left on the
1301 /// stack after invoking this method (constrasted with
1302 /// Emit that will always leave a value on the stack).
1303 /// </summary>
1304 public abstract void EmitStatement (EmitContext ec);
1306 public override void EmitSideEffect (EmitContext ec)
1308 EmitStatement (ec);
1312 /// <summary>
1313 /// This kind of cast is used to encapsulate the child
1314 /// whose type is child.Type into an expression that is
1315 /// reported to return "return_type". This is used to encapsulate
1316 /// expressions which have compatible types, but need to be dealt
1317 /// at higher levels with.
1319 /// For example, a "byte" expression could be encapsulated in one
1320 /// of these as an "unsigned int". The type for the expression
1321 /// would be "unsigned int".
1323 /// </summary>
1324 public abstract class TypeCast : Expression
1326 protected readonly Expression child;
1328 protected TypeCast (Expression child, Type return_type)
1330 eclass = child.eclass;
1331 loc = child.Location;
1332 type = return_type;
1333 this.child = child;
1336 public override Expression CreateExpressionTree (ResolveContext ec)
1338 Arguments args = new Arguments (2);
1339 args.Add (new Argument (child.CreateExpressionTree (ec)));
1340 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1342 if (type.IsPointer || child.Type.IsPointer)
1343 Error_PointerInsideExpressionTree (ec);
1345 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1348 protected override Expression DoResolve (ResolveContext ec)
1350 // This should never be invoked, we are born in fully
1351 // initialized state.
1353 return this;
1356 public override void Emit (EmitContext ec)
1358 child.Emit (ec);
1361 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1363 return child.GetAttributableValue (ec, value_type, out value);
1366 public override SLE.Expression MakeExpression (BuilderContext ctx)
1368 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1369 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type) :
1370 SLE.Expression.Convert (child.MakeExpression (ctx), type);
1373 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1375 type = storey.MutateType (type);
1376 child.MutateHoistedGenericType (storey);
1379 protected override void CloneTo (CloneContext clonectx, Expression t)
1381 // Nothing to clone
1384 public override bool IsNull {
1385 get { return child.IsNull; }
1389 public class EmptyCast : TypeCast {
1390 EmptyCast (Expression child, Type target_type)
1391 : base (child, target_type)
1395 public static Expression Create (Expression child, Type type)
1397 Constant c = child as Constant;
1398 if (c != null)
1399 return new EmptyConstantCast (c, type);
1401 EmptyCast e = child as EmptyCast;
1402 if (e != null)
1403 return new EmptyCast (e.child, type);
1405 return new EmptyCast (child, type);
1408 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1410 child.EmitBranchable (ec, label, on_true);
1413 public override void EmitSideEffect (EmitContext ec)
1415 child.EmitSideEffect (ec);
1420 // Used for predefined class library user casts (no obsolete check, etc.)
1422 public class OperatorCast : TypeCast {
1423 MethodInfo conversion_operator;
1425 public OperatorCast (Expression child, Type target_type)
1426 : this (child, target_type, false)
1430 public OperatorCast (Expression child, Type target_type, bool find_explicit)
1431 : base (child, target_type)
1433 conversion_operator = GetConversionOperator (find_explicit);
1434 if (conversion_operator == null)
1435 throw new InternalErrorException ("Outer conversion routine is out of sync");
1438 // Returns the implicit operator that converts from
1439 // 'child.Type' to our target type (type)
1440 MethodInfo GetConversionOperator (bool find_explicit)
1442 string operator_name = find_explicit ? "op_Explicit" : "op_Implicit";
1444 MemberInfo [] mi;
1446 mi = TypeManager.MemberLookup (child.Type, child.Type, child.Type, MemberTypes.Method,
1447 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1449 if (mi == null){
1450 mi = TypeManager.MemberLookup (type, type, type, MemberTypes.Method,
1451 BindingFlags.Static | BindingFlags.Public, operator_name, null);
1454 foreach (MethodInfo oper in mi) {
1455 AParametersCollection pd = TypeManager.GetParameterData (oper);
1457 if (pd.Types [0] == child.Type && TypeManager.TypeToCoreType (oper.ReturnType) == type)
1458 return oper;
1461 return null;
1464 public override void Emit (EmitContext ec)
1466 child.Emit (ec);
1467 ec.ig.Emit (OpCodes.Call, conversion_operator);
1471 /// <summary>
1472 /// This is a numeric cast to a Decimal
1473 /// </summary>
1474 public class CastToDecimal : OperatorCast {
1475 public CastToDecimal (Expression child)
1476 : this (child, false)
1480 public CastToDecimal (Expression child, bool find_explicit)
1481 : base (child, TypeManager.decimal_type, find_explicit)
1486 /// <summary>
1487 /// This is an explicit numeric cast from a Decimal
1488 /// </summary>
1489 public class CastFromDecimal : TypeCast
1491 static Dictionary<Type, MethodInfo> operators;
1493 public CastFromDecimal (Expression child, Type return_type)
1494 : base (child, return_type)
1496 if (child.Type != TypeManager.decimal_type)
1497 throw new InternalErrorException (
1498 "The expected type is Decimal, instead it is " + child.Type.FullName);
1501 // Returns the explicit operator that converts from an
1502 // express of type System.Decimal to 'type'.
1503 public Expression Resolve ()
1505 if (operators == null) {
1506 MemberInfo[] all_oper = TypeManager.MemberLookup (TypeManager.decimal_type,
1507 TypeManager.decimal_type, TypeManager.decimal_type, MemberTypes.Method,
1508 BindingFlags.Static | BindingFlags.Public, "op_Explicit", null);
1510 operators = new Dictionary<Type, MethodInfo> (ReferenceEquality<Type>.Default);
1511 foreach (MethodInfo oper in all_oper) {
1512 AParametersCollection pd = TypeManager.GetParameterData (oper);
1513 if (pd.Types [0] == TypeManager.decimal_type)
1514 operators.Add (TypeManager.TypeToCoreType (oper.ReturnType), oper);
1518 return operators.ContainsKey (type) ? this : null;
1521 public override void Emit (EmitContext ec)
1523 ILGenerator ig = ec.ig;
1524 child.Emit (ec);
1526 ig.Emit (OpCodes.Call, operators [type]);
1532 // Constant specialization of EmptyCast.
1533 // We need to special case this since an empty cast of
1534 // a constant is still a constant.
1536 public class EmptyConstantCast : Constant
1538 public Constant child;
1540 public EmptyConstantCast (Constant child, Type type)
1541 : base (child.Location)
1543 if (child == null)
1544 throw new ArgumentNullException ("child");
1546 this.child = child;
1547 this.eclass = child.eclass;
1548 this.type = type;
1551 public override string AsString ()
1553 return child.AsString ();
1556 public override object GetValue ()
1558 return child.GetValue ();
1561 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
1563 if (child.Type == target_type)
1564 return child;
1566 // FIXME: check that 'type' can be converted to 'target_type' first
1567 return child.ConvertExplicitly (in_checked_context, target_type);
1570 public override Expression CreateExpressionTree (ResolveContext ec)
1572 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1573 child.CreateExpressionTree (ec),
1574 new TypeOf (new TypeExpression (type, loc), loc));
1576 if (type.IsPointer)
1577 Error_PointerInsideExpressionTree (ec);
1579 return CreateExpressionFactoryCall (ec, "Convert", args);
1582 public override bool IsDefaultValue {
1583 get { return child.IsDefaultValue; }
1586 public override bool IsNegative {
1587 get { return child.IsNegative; }
1590 public override bool IsNull {
1591 get { return child.IsNull; }
1594 public override bool IsOneInteger {
1595 get { return child.IsOneInteger; }
1598 public override bool IsZeroInteger {
1599 get { return child.IsZeroInteger; }
1602 protected override Expression DoResolve (ResolveContext rc)
1604 return this;
1607 public override void Emit (EmitContext ec)
1609 child.Emit (ec);
1612 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1614 child.EmitBranchable (ec, label, on_true);
1616 // Only to make verifier happy
1617 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1618 ec.ig.Emit (OpCodes.Unbox_Any, type);
1621 public override void EmitSideEffect (EmitContext ec)
1623 child.EmitSideEffect (ec);
1626 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
1628 // FIXME: Do we need to check user conversions?
1629 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1630 return null;
1631 return child.ConvertImplicitly (rc, target_type);
1634 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1636 child.MutateHoistedGenericType (storey);
1640 /// <summary>
1641 /// This class is used to wrap literals which belong inside Enums
1642 /// </summary>
1643 public class EnumConstant : Constant
1645 public Constant Child;
1647 public EnumConstant (Constant child, Type enum_type)
1648 : base (child.Location)
1650 this.Child = child;
1651 this.type = enum_type;
1654 protected EnumConstant (Location loc)
1655 : base (loc)
1659 protected override Expression DoResolve (ResolveContext rc)
1661 Child = Child.Resolve (rc);
1662 this.eclass = ExprClass.Value;
1663 return this;
1666 public override void Emit (EmitContext ec)
1668 Child.Emit (ec);
1671 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1673 Child.EmitBranchable (ec, label, on_true);
1676 public override void EmitSideEffect (EmitContext ec)
1678 Child.EmitSideEffect (ec);
1681 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
1683 value = GetTypedValue ();
1684 return true;
1687 public override string GetSignatureForError()
1689 return TypeManager.CSharpName (Type);
1692 public override object GetValue ()
1694 return Child.GetValue ();
1697 public override object GetTypedValue ()
1699 // FIXME: runtime is not ready to work with just emited enums
1700 if (!RootContext.StdLib) {
1701 return Child.GetValue ();
1704 #if MS_COMPATIBLE
1705 // Small workaround for big problem
1706 // System.Enum.ToObject cannot be called on dynamic types
1707 // EnumBuilder has to be used, but we cannot use EnumBuilder
1708 // because it does not properly support generics
1710 // This works only sometimes
1712 if (TypeManager.IsBeingCompiled (type))
1713 return Child.GetValue ();
1714 #endif
1716 return System.Enum.ToObject (type, Child.GetValue ());
1719 public override string AsString ()
1721 return Child.AsString ();
1724 public EnumConstant Increment()
1726 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1729 public override bool IsDefaultValue {
1730 get {
1731 return Child.IsDefaultValue;
1735 public override bool IsZeroInteger {
1736 get { return Child.IsZeroInteger; }
1739 public override bool IsNegative {
1740 get {
1741 return Child.IsNegative;
1745 public override Constant ConvertExplicitly(bool in_checked_context, Type target_type)
1747 if (Child.Type == target_type)
1748 return Child;
1750 return Child.ConvertExplicitly (in_checked_context, target_type);
1753 public override Constant ConvertImplicitly (ResolveContext rc, Type type)
1755 Type this_type = TypeManager.DropGenericTypeArguments (Type);
1756 type = TypeManager.DropGenericTypeArguments (type);
1758 if (this_type == type) {
1759 // This is workaround of mono bug. It can be removed when the latest corlib spreads enough
1760 if (TypeManager.IsEnumType (type.UnderlyingSystemType))
1761 return this;
1763 Type child_type = TypeManager.DropGenericTypeArguments (Child.Type);
1764 if (type.UnderlyingSystemType != child_type)
1765 Child = Child.ConvertImplicitly (rc, type.UnderlyingSystemType);
1766 return this;
1769 if (!Convert.ImplicitStandardConversionExists (this, type)){
1770 return null;
1773 return Child.ConvertImplicitly (rc, type);
1777 /// <summary>
1778 /// This kind of cast is used to encapsulate Value Types in objects.
1780 /// The effect of it is to box the value type emitted by the previous
1781 /// operation.
1782 /// </summary>
1783 public class BoxedCast : TypeCast {
1785 public BoxedCast (Expression expr, Type target_type)
1786 : base (expr, target_type)
1788 eclass = ExprClass.Value;
1791 protected override Expression DoResolve (ResolveContext ec)
1793 // This should never be invoked, we are born in fully
1794 // initialized state.
1796 return this;
1799 public override void Emit (EmitContext ec)
1801 base.Emit (ec);
1803 ec.ig.Emit (OpCodes.Box, child.Type);
1806 public override void EmitSideEffect (EmitContext ec)
1808 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1809 // so, we need to emit the box+pop instructions in most cases
1810 if (TypeManager.IsStruct (child.Type) &&
1811 (type == TypeManager.object_type || type == TypeManager.value_type))
1812 child.EmitSideEffect (ec);
1813 else
1814 base.EmitSideEffect (ec);
1818 public class UnboxCast : TypeCast {
1819 public UnboxCast (Expression expr, Type return_type)
1820 : base (expr, return_type)
1824 protected override Expression DoResolve (ResolveContext ec)
1826 // This should never be invoked, we are born in fully
1827 // initialized state.
1829 return this;
1832 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1834 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1835 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1836 return base.DoResolveLValue (ec, right_side);
1839 public override void Emit (EmitContext ec)
1841 base.Emit (ec);
1843 ILGenerator ig = ec.ig;
1844 ig.Emit (OpCodes.Unbox_Any, type);
1847 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
1849 type = storey.MutateType (type);
1850 base.MutateHoistedGenericType (storey);
1854 /// <summary>
1855 /// This is used to perform explicit numeric conversions.
1857 /// Explicit numeric conversions might trigger exceptions in a checked
1858 /// context, so they should generate the conv.ovf opcodes instead of
1859 /// conv opcodes.
1860 /// </summary>
1861 public class ConvCast : TypeCast {
1862 public enum Mode : byte {
1863 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1864 U1_I1, U1_CH,
1865 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1866 U2_I1, U2_U1, U2_I2, U2_CH,
1867 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1868 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1869 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1870 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1871 CH_I1, CH_U1, CH_I2,
1872 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1873 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1874 I_I8,
1877 Mode mode;
1879 public ConvCast (Expression child, Type return_type, Mode m)
1880 : base (child, return_type)
1882 mode = m;
1885 protected override Expression DoResolve (ResolveContext ec)
1887 // This should never be invoked, we are born in fully
1888 // initialized state.
1890 return this;
1893 public override string ToString ()
1895 return String.Format ("ConvCast ({0}, {1})", mode, child);
1898 public override void Emit (EmitContext ec)
1900 ILGenerator ig = ec.ig;
1902 base.Emit (ec);
1904 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1905 switch (mode){
1906 case Mode.I1_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1907 case Mode.I1_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1908 case Mode.I1_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1909 case Mode.I1_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1910 case Mode.I1_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1912 case Mode.U1_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1913 case Mode.U1_CH: /* nothing */ break;
1915 case Mode.I2_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1916 case Mode.I2_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1917 case Mode.I2_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1918 case Mode.I2_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1919 case Mode.I2_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1920 case Mode.I2_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1922 case Mode.U2_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1923 case Mode.U2_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1924 case Mode.U2_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1925 case Mode.U2_CH: /* nothing */ break;
1927 case Mode.I4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1928 case Mode.I4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1929 case Mode.I4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1930 case Mode.I4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1931 case Mode.I4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1932 case Mode.I4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1933 case Mode.I4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1935 case Mode.U4_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1936 case Mode.U4_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1937 case Mode.U4_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1938 case Mode.U4_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1939 case Mode.U4_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1940 case Mode.U4_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1942 case Mode.I8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1943 case Mode.I8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1944 case Mode.I8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1945 case Mode.I8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1946 case Mode.I8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1947 case Mode.I8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1948 case Mode.I8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1949 case Mode.I8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1950 case Mode.I8_I: ig.Emit (OpCodes.Conv_Ovf_U); break;
1952 case Mode.U8_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1953 case Mode.U8_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1954 case Mode.U8_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1955 case Mode.U8_U2: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1956 case Mode.U8_I4: ig.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1957 case Mode.U8_U4: ig.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1958 case Mode.U8_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1959 case Mode.U8_CH: ig.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1960 case Mode.U8_I: ig.Emit (OpCodes.Conv_Ovf_U_Un); break;
1962 case Mode.CH_I1: ig.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1963 case Mode.CH_U1: ig.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1964 case Mode.CH_I2: ig.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1966 case Mode.R4_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1967 case Mode.R4_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1968 case Mode.R4_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1969 case Mode.R4_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1970 case Mode.R4_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1971 case Mode.R4_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1972 case Mode.R4_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1973 case Mode.R4_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1974 case Mode.R4_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1976 case Mode.R8_I1: ig.Emit (OpCodes.Conv_Ovf_I1); break;
1977 case Mode.R8_U1: ig.Emit (OpCodes.Conv_Ovf_U1); break;
1978 case Mode.R8_I2: ig.Emit (OpCodes.Conv_Ovf_I2); break;
1979 case Mode.R8_U2: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1980 case Mode.R8_I4: ig.Emit (OpCodes.Conv_Ovf_I4); break;
1981 case Mode.R8_U4: ig.Emit (OpCodes.Conv_Ovf_U4); break;
1982 case Mode.R8_I8: ig.Emit (OpCodes.Conv_Ovf_I8); break;
1983 case Mode.R8_U8: ig.Emit (OpCodes.Conv_Ovf_U8); break;
1984 case Mode.R8_CH: ig.Emit (OpCodes.Conv_Ovf_U2); break;
1985 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
1987 case Mode.I_I8: ig.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1989 } else {
1990 switch (mode){
1991 case Mode.I1_U1: ig.Emit (OpCodes.Conv_U1); break;
1992 case Mode.I1_U2: ig.Emit (OpCodes.Conv_U2); break;
1993 case Mode.I1_U4: ig.Emit (OpCodes.Conv_U4); break;
1994 case Mode.I1_U8: ig.Emit (OpCodes.Conv_I8); break;
1995 case Mode.I1_CH: ig.Emit (OpCodes.Conv_U2); break;
1997 case Mode.U1_I1: ig.Emit (OpCodes.Conv_I1); break;
1998 case Mode.U1_CH: ig.Emit (OpCodes.Conv_U2); break;
2000 case Mode.I2_I1: ig.Emit (OpCodes.Conv_I1); break;
2001 case Mode.I2_U1: ig.Emit (OpCodes.Conv_U1); break;
2002 case Mode.I2_U2: ig.Emit (OpCodes.Conv_U2); break;
2003 case Mode.I2_U4: ig.Emit (OpCodes.Conv_U4); break;
2004 case Mode.I2_U8: ig.Emit (OpCodes.Conv_I8); break;
2005 case Mode.I2_CH: ig.Emit (OpCodes.Conv_U2); break;
2007 case Mode.U2_I1: ig.Emit (OpCodes.Conv_I1); break;
2008 case Mode.U2_U1: ig.Emit (OpCodes.Conv_U1); break;
2009 case Mode.U2_I2: ig.Emit (OpCodes.Conv_I2); break;
2010 case Mode.U2_CH: /* nothing */ break;
2012 case Mode.I4_I1: ig.Emit (OpCodes.Conv_I1); break;
2013 case Mode.I4_U1: ig.Emit (OpCodes.Conv_U1); break;
2014 case Mode.I4_I2: ig.Emit (OpCodes.Conv_I2); break;
2015 case Mode.I4_U4: /* nothing */ break;
2016 case Mode.I4_U2: ig.Emit (OpCodes.Conv_U2); break;
2017 case Mode.I4_U8: ig.Emit (OpCodes.Conv_I8); break;
2018 case Mode.I4_CH: ig.Emit (OpCodes.Conv_U2); break;
2020 case Mode.U4_I1: ig.Emit (OpCodes.Conv_I1); break;
2021 case Mode.U4_U1: ig.Emit (OpCodes.Conv_U1); break;
2022 case Mode.U4_I2: ig.Emit (OpCodes.Conv_I2); break;
2023 case Mode.U4_U2: ig.Emit (OpCodes.Conv_U2); break;
2024 case Mode.U4_I4: /* nothing */ break;
2025 case Mode.U4_CH: ig.Emit (OpCodes.Conv_U2); break;
2027 case Mode.I8_I1: ig.Emit (OpCodes.Conv_I1); break;
2028 case Mode.I8_U1: ig.Emit (OpCodes.Conv_U1); break;
2029 case Mode.I8_I2: ig.Emit (OpCodes.Conv_I2); break;
2030 case Mode.I8_U2: ig.Emit (OpCodes.Conv_U2); break;
2031 case Mode.I8_I4: ig.Emit (OpCodes.Conv_I4); break;
2032 case Mode.I8_U4: ig.Emit (OpCodes.Conv_U4); break;
2033 case Mode.I8_U8: /* nothing */ break;
2034 case Mode.I8_CH: ig.Emit (OpCodes.Conv_U2); break;
2035 case Mode.I8_I: ig.Emit (OpCodes.Conv_U); break;
2037 case Mode.U8_I1: ig.Emit (OpCodes.Conv_I1); break;
2038 case Mode.U8_U1: ig.Emit (OpCodes.Conv_U1); break;
2039 case Mode.U8_I2: ig.Emit (OpCodes.Conv_I2); break;
2040 case Mode.U8_U2: ig.Emit (OpCodes.Conv_U2); break;
2041 case Mode.U8_I4: ig.Emit (OpCodes.Conv_I4); break;
2042 case Mode.U8_U4: ig.Emit (OpCodes.Conv_U4); break;
2043 case Mode.U8_I8: /* nothing */ break;
2044 case Mode.U8_CH: ig.Emit (OpCodes.Conv_U2); break;
2045 case Mode.U8_I: ig.Emit (OpCodes.Conv_U); break;
2047 case Mode.CH_I1: ig.Emit (OpCodes.Conv_I1); break;
2048 case Mode.CH_U1: ig.Emit (OpCodes.Conv_U1); break;
2049 case Mode.CH_I2: ig.Emit (OpCodes.Conv_I2); break;
2051 case Mode.R4_I1: ig.Emit (OpCodes.Conv_I1); break;
2052 case Mode.R4_U1: ig.Emit (OpCodes.Conv_U1); break;
2053 case Mode.R4_I2: ig.Emit (OpCodes.Conv_I2); break;
2054 case Mode.R4_U2: ig.Emit (OpCodes.Conv_U2); break;
2055 case Mode.R4_I4: ig.Emit (OpCodes.Conv_I4); break;
2056 case Mode.R4_U4: ig.Emit (OpCodes.Conv_U4); break;
2057 case Mode.R4_I8: ig.Emit (OpCodes.Conv_I8); break;
2058 case Mode.R4_U8: ig.Emit (OpCodes.Conv_U8); break;
2059 case Mode.R4_CH: ig.Emit (OpCodes.Conv_U2); break;
2061 case Mode.R8_I1: ig.Emit (OpCodes.Conv_I1); break;
2062 case Mode.R8_U1: ig.Emit (OpCodes.Conv_U1); break;
2063 case Mode.R8_I2: ig.Emit (OpCodes.Conv_I2); break;
2064 case Mode.R8_U2: ig.Emit (OpCodes.Conv_U2); break;
2065 case Mode.R8_I4: ig.Emit (OpCodes.Conv_I4); break;
2066 case Mode.R8_U4: ig.Emit (OpCodes.Conv_U4); break;
2067 case Mode.R8_I8: ig.Emit (OpCodes.Conv_I8); break;
2068 case Mode.R8_U8: ig.Emit (OpCodes.Conv_U8); break;
2069 case Mode.R8_CH: ig.Emit (OpCodes.Conv_U2); break;
2070 case Mode.R8_R4: ig.Emit (OpCodes.Conv_R4); break;
2072 case Mode.I_I8: ig.Emit (OpCodes.Conv_U8); break;
2078 public class OpcodeCast : TypeCast {
2079 readonly OpCode op;
2081 public OpcodeCast (Expression child, Type return_type, OpCode op)
2082 : base (child, return_type)
2084 this.op = op;
2087 protected override Expression DoResolve (ResolveContext ec)
2089 // This should never be invoked, we are born in fully
2090 // initialized state.
2092 return this;
2095 public override void Emit (EmitContext ec)
2097 base.Emit (ec);
2098 ec.ig.Emit (op);
2101 public Type UnderlyingType {
2102 get { return child.Type; }
2106 /// <summary>
2107 /// This kind of cast is used to encapsulate a child and cast it
2108 /// to the class requested
2109 /// </summary>
2110 public sealed class ClassCast : TypeCast {
2111 readonly bool forced;
2113 public ClassCast (Expression child, Type return_type)
2114 : base (child, return_type)
2118 public ClassCast (Expression child, Type return_type, bool forced)
2119 : base (child, return_type)
2121 this.forced = forced;
2124 public override void Emit (EmitContext ec)
2126 base.Emit (ec);
2128 bool gen = TypeManager.IsGenericParameter (child.Type);
2129 if (gen)
2130 ec.ig.Emit (OpCodes.Box, child.Type);
2132 if (type.IsGenericParameter) {
2133 ec.ig.Emit (OpCodes.Unbox_Any, type);
2134 return;
2137 if (gen && !forced)
2138 return;
2140 ec.ig.Emit (OpCodes.Castclass, type);
2145 // Created during resolving pahse when an expression is wrapped or constantified
2146 // and original expression can be used later (e.g. for expression trees)
2148 public class ReducedExpression : Expression
2150 sealed class ReducedConstantExpression : EmptyConstantCast
2152 readonly Expression orig_expr;
2154 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2155 : base (expr, expr.Type)
2157 this.orig_expr = orig_expr;
2160 public override Constant ConvertImplicitly (ResolveContext rc, Type target_type)
2162 Constant c = base.ConvertImplicitly (rc, target_type);
2163 if (c != null)
2164 c = new ReducedConstantExpression (c, orig_expr);
2166 return c;
2169 public override Expression CreateExpressionTree (ResolveContext ec)
2171 return orig_expr.CreateExpressionTree (ec);
2174 public override bool GetAttributableValue (ResolveContext ec, Type value_type, out object value)
2177 // Even if resolved result is a constant original expression was not
2178 // and attribute accepts constants only
2180 Attribute.Error_AttributeArgumentNotValid (ec, orig_expr.Location);
2181 value = null;
2182 return false;
2185 public override Constant ConvertExplicitly (bool in_checked_context, Type target_type)
2187 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2188 if (c != null)
2189 c = new ReducedConstantExpression (c, orig_expr);
2190 return c;
2194 sealed class ReducedExpressionStatement : ExpressionStatement
2196 readonly Expression orig_expr;
2197 readonly ExpressionStatement stm;
2199 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2201 this.orig_expr = orig;
2202 this.stm = stm;
2203 this.loc = orig.Location;
2206 public override Expression CreateExpressionTree (ResolveContext ec)
2208 return orig_expr.CreateExpressionTree (ec);
2211 protected override Expression DoResolve (ResolveContext ec)
2213 eclass = stm.eclass;
2214 type = stm.Type;
2215 return this;
2218 public override void Emit (EmitContext ec)
2220 stm.Emit (ec);
2223 public override void EmitStatement (EmitContext ec)
2225 stm.EmitStatement (ec);
2228 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2230 stm.MutateHoistedGenericType (storey);
2234 readonly Expression expr, orig_expr;
2236 private ReducedExpression (Expression expr, Expression orig_expr)
2238 this.expr = expr;
2239 this.eclass = expr.eclass;
2240 this.type = expr.Type;
2241 this.orig_expr = orig_expr;
2242 this.loc = orig_expr.Location;
2246 // Creates fully resolved expression switcher
2248 public static Constant Create (Constant expr, Expression original_expr)
2250 if (expr.eclass == ExprClass.Unresolved)
2251 throw new ArgumentException ("Unresolved expression");
2253 return new ReducedConstantExpression (expr, original_expr);
2256 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2258 return new ReducedExpressionStatement (s, orig);
2262 // Creates unresolved reduce expression. The original expression has to be
2263 // already resolved
2265 public static Expression Create (Expression expr, Expression original_expr)
2267 Constant c = expr as Constant;
2268 if (c != null)
2269 return Create (c, original_expr);
2271 ExpressionStatement s = expr as ExpressionStatement;
2272 if (s != null)
2273 return Create (s, original_expr);
2275 if (expr.eclass == ExprClass.Unresolved)
2276 throw new ArgumentException ("Unresolved expression");
2278 return new ReducedExpression (expr, original_expr);
2281 public override Expression CreateExpressionTree (ResolveContext ec)
2283 return orig_expr.CreateExpressionTree (ec);
2286 protected override Expression DoResolve (ResolveContext ec)
2288 return this;
2291 public override void Emit (EmitContext ec)
2293 expr.Emit (ec);
2296 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2298 expr.EmitBranchable (ec, target, on_true);
2301 public override SLE.Expression MakeExpression (BuilderContext ctx)
2303 return orig_expr.MakeExpression (ctx);
2306 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2308 expr.MutateHoistedGenericType (storey);
2313 // Standard composite pattern
2315 public abstract class CompositeExpression : Expression
2317 Expression expr;
2319 protected CompositeExpression (Expression expr)
2321 this.expr = expr;
2322 this.loc = expr.Location;
2325 public override Expression CreateExpressionTree (ResolveContext ec)
2327 return expr.CreateExpressionTree (ec);
2330 public Expression Child {
2331 get { return expr; }
2334 protected override Expression DoResolve (ResolveContext ec)
2336 expr = expr.Resolve (ec);
2337 if (expr != null) {
2338 type = expr.Type;
2339 eclass = expr.eclass;
2342 return this;
2345 public override void Emit (EmitContext ec)
2347 expr.Emit (ec);
2350 public override bool IsNull {
2351 get { return expr.IsNull; }
2356 // Base of expressions used only to narrow resolve flow
2358 public abstract class ShimExpression : Expression
2360 protected Expression expr;
2362 protected ShimExpression (Expression expr)
2364 this.expr = expr;
2367 protected override void CloneTo (CloneContext clonectx, Expression t)
2369 if (expr == null)
2370 return;
2372 ShimExpression target = (ShimExpression) t;
2373 target.expr = expr.Clone (clonectx);
2376 public override Expression CreateExpressionTree (ResolveContext ec)
2378 throw new NotSupportedException ("ET");
2381 public override void Emit (EmitContext ec)
2383 throw new InternalErrorException ("Missing Resolve call");
2386 public Expression Expr {
2387 get { return expr; }
2390 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2392 throw new InternalErrorException ("Missing Resolve call");
2397 // Unresolved type name expressions
2399 public abstract class ATypeNameExpression : FullNamedExpression
2401 string name;
2402 protected TypeArguments targs;
2404 protected ATypeNameExpression (string name, Location l)
2406 this.name = name;
2407 loc = l;
2410 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2412 this.name = name;
2413 this.targs = targs;
2414 loc = l;
2417 public bool HasTypeArguments {
2418 get {
2419 return targs != null;
2423 public override bool Equals (object obj)
2425 ATypeNameExpression atne = obj as ATypeNameExpression;
2426 return atne != null && atne.Name == Name &&
2427 (targs == null || targs.Equals (atne.targs));
2430 public override int GetHashCode ()
2432 return Name.GetHashCode ();
2435 public override string GetSignatureForError ()
2437 if (targs != null) {
2438 return TypeManager.RemoveGenericArity (Name) + "<" +
2439 targs.GetSignatureForError () + ">";
2442 return Name;
2445 public string Name {
2446 get {
2447 return name;
2449 set {
2450 name = value;
2454 public TypeArguments TypeArguments {
2455 get {
2456 return targs;
2461 /// <summary>
2462 /// SimpleName expressions are formed of a single word and only happen at the beginning
2463 /// of a dotted-name.
2464 /// </summary>
2465 public class SimpleName : ATypeNameExpression
2467 public SimpleName (string name, Location l)
2468 : base (name, l)
2472 public SimpleName (string name, TypeArguments args, Location l)
2473 : base (name, args, l)
2477 public SimpleName (string name, TypeParameter[] type_params, Location l)
2478 : base (name, l)
2480 targs = new TypeArguments ();
2481 foreach (TypeParameter type_param in type_params)
2482 targs.Add (new TypeParameterExpr (type_param, l));
2485 public static string RemoveGenericArity (string name)
2487 int start = 0;
2488 StringBuilder sb = null;
2489 do {
2490 int pos = name.IndexOf ('`', start);
2491 if (pos < 0) {
2492 if (start == 0)
2493 return name;
2495 sb.Append (name.Substring (start));
2496 break;
2499 if (sb == null)
2500 sb = new StringBuilder ();
2501 sb.Append (name.Substring (start, pos-start));
2503 pos++;
2504 while ((pos < name.Length) && Char.IsNumber (name [pos]))
2505 pos++;
2507 start = pos;
2508 } while (start < name.Length);
2510 return sb.ToString ();
2513 public SimpleName GetMethodGroup ()
2515 return new SimpleName (RemoveGenericArity (Name), targs, loc);
2518 public static void Error_ObjectRefRequired (ResolveContext ec, Location l, string name)
2520 if (ec.HasSet (ResolveContext.Options.FieldInitializerScope))
2521 ec.Report.Error (236, l,
2522 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2523 name);
2524 else
2525 ec.Report.Error (120, l,
2526 "An object reference is required to access non-static member `{0}'",
2527 name);
2530 public bool IdenticalNameAndTypeName (IMemberContext mc, Expression resolved_to, Location loc)
2532 return resolved_to != null && resolved_to.Type != null &&
2533 resolved_to.Type.Name == Name &&
2534 (mc.LookupNamespaceOrType (Name, loc, /* ignore_cs0104 = */ true) != null);
2537 protected override Expression DoResolve (ResolveContext ec)
2539 return SimpleNameResolve (ec, null, false);
2542 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2544 return SimpleNameResolve (ec, right_side, false);
2547 public Expression DoResolve (ResolveContext ec, bool intermediate)
2549 return SimpleNameResolve (ec, null, intermediate);
2552 static bool IsNestedChild (Type t, Type parent)
2554 while (parent != null) {
2555 if (TypeManager.IsNestedChildOf (t, TypeManager.DropGenericTypeArguments (parent)))
2556 return true;
2558 parent = parent.BaseType;
2561 return false;
2564 FullNamedExpression ResolveNested (Type t)
2566 if (!TypeManager.IsGenericTypeDefinition (t) && !TypeManager.IsGenericType (t))
2567 return null;
2569 Type ds = t;
2570 while (ds != null && !IsNestedChild (t, ds))
2571 ds = ds.DeclaringType;
2573 if (ds == null)
2574 return null;
2576 Type[] gen_params = TypeManager.GetTypeArguments (t);
2578 int arg_count = targs != null ? targs.Count : 0;
2580 for (; (ds != null) && TypeManager.IsGenericType (ds); ds = ds.DeclaringType) {
2581 Type[] gargs = TypeManager.GetTypeArguments (ds);
2582 if (arg_count + gargs.Length == gen_params.Length) {
2583 TypeArguments new_args = new TypeArguments ();
2584 foreach (Type param in gargs)
2585 new_args.Add (new TypeExpression (param, loc));
2587 if (targs != null)
2588 new_args.Add (targs);
2590 return new GenericTypeExpr (t, new_args, loc);
2594 return null;
2597 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2599 int errors = ec.Compiler.Report.Errors;
2600 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, loc, /*ignore_cs0104=*/ false);
2602 if (fne != null) {
2603 if (fne.Type == null)
2604 return fne;
2606 FullNamedExpression nested = ResolveNested (fne.Type);
2607 if (nested != null)
2608 return nested.ResolveAsTypeStep (ec, false);
2610 if (targs != null) {
2611 if (TypeManager.IsGenericType (fne.Type)) {
2612 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2613 return ct.ResolveAsTypeStep (ec, false);
2616 fne.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2619 return fne;
2622 if (!HasTypeArguments && Name == "dynamic" &&
2623 RootContext.Version > LanguageVersion.V_3 &&
2624 RootContext.MetadataCompatibilityVersion > MetadataVersion.v2) {
2626 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2627 ec.Compiler.Report.Error (1980, Location,
2628 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2629 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2632 return new DynamicTypeExpr (loc);
2635 if (silent || errors != ec.Compiler.Report.Errors)
2636 return null;
2638 Error_TypeOrNamespaceNotFound (ec);
2639 return null;
2642 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2644 if (ec.CurrentType != null) {
2645 if (ec.CurrentTypeDefinition != null) {
2646 MemberCore mc = ec.CurrentTypeDefinition.GetDefinition (Name);
2647 if (mc != null) {
2648 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2649 return;
2653 string ns = ec.CurrentType.Namespace;
2654 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2655 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2656 Type type = a.GetType (fullname);
2657 if (type != null) {
2658 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2659 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2660 return;
2664 if (ec.CurrentTypeDefinition != null) {
2665 Type t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2666 if (t != null) {
2667 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2668 return;
2673 if (targs != null) {
2674 FullNamedExpression retval = ec.LookupNamespaceOrType (SimpleName.RemoveGenericArity (Name), loc, true);
2675 if (retval != null) {
2676 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2677 return;
2681 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2684 // TODO: I am still not convinced about this. If someone else will need it
2685 // implement this as virtual property in MemberCore hierarchy
2686 public static string GetMemberType (MemberCore mc)
2688 if (mc is Property)
2689 return "property";
2690 if (mc is Indexer)
2691 return "indexer";
2692 if (mc is FieldBase)
2693 return "field";
2694 if (mc is MethodCore)
2695 return "method";
2696 if (mc is EnumMember)
2697 return "enum";
2698 if (mc is Event)
2699 return "event";
2701 return "type";
2704 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2706 Expression e = DoSimpleNameResolve (ec, right_side, intermediate);
2708 if (e == null)
2709 return null;
2711 if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2712 return e;
2714 return null;
2717 /// <remarks>
2718 /// 7.5.2: Simple Names.
2720 /// Local Variables and Parameters are handled at
2721 /// parse time, so they never occur as SimpleNames.
2723 /// The `intermediate' flag is used by MemberAccess only
2724 /// and it is used to inform us that it is ok for us to
2725 /// avoid the static check, because MemberAccess might end
2726 /// up resolving the Name as a Type name and the access as
2727 /// a static type access.
2729 /// ie: Type Type; .... { Type.GetType (""); }
2731 /// Type is both an instance variable and a Type; Type.GetType
2732 /// is the static method not an instance method of type.
2733 /// </remarks>
2734 Expression DoSimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2736 Expression e = null;
2739 // Stage 1: Performed by the parser (binding to locals or parameters).
2741 Block current_block = ec.CurrentBlock;
2742 if (current_block != null){
2743 LocalInfo vi = current_block.GetLocalInfo (Name);
2744 if (vi != null){
2745 e = new LocalVariableReference (ec.CurrentBlock, Name, loc);
2747 if (right_side != null) {
2748 e = e.ResolveLValue (ec, right_side);
2749 } else {
2750 if (intermediate) {
2751 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
2752 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2754 } else {
2755 e = e.Resolve (ec, ResolveFlags.VariableOrValue);
2759 if (targs != null && e != null)
2760 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2762 return e;
2765 e = current_block.Toplevel.GetParameterReference (Name, loc);
2766 if (e != null) {
2767 if (right_side != null)
2768 e = e.ResolveLValue (ec, right_side);
2769 else
2770 e = e.Resolve (ec);
2772 if (targs != null && e != null)
2773 e.Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
2775 return e;
2780 // Stage 2: Lookup members
2783 Type almost_matched_type = null;
2784 IList<MemberInfo> almost_matched = null;
2785 for (Type lookup_ds = ec.CurrentType; lookup_ds != null; lookup_ds = lookup_ds.DeclaringType) {
2786 e = MemberLookup (ec.Compiler, ec.CurrentType, lookup_ds, Name, loc);
2787 if (e != null) {
2788 PropertyExpr pe = e as PropertyExpr;
2789 if (pe != null) {
2790 AParametersCollection param = TypeManager.GetParameterData (pe.PropertyInfo);
2792 // since TypeManager.MemberLookup doesn't know if we're doing a lvalue access or not,
2793 // it doesn't know which accessor to check permissions against
2794 if (param.IsEmpty && pe.IsAccessibleFrom (ec.CurrentType, right_side != null))
2795 break;
2796 } else if (e is EventExpr) {
2797 if (((EventExpr) e).IsAccessibleFrom (ec.CurrentType))
2798 break;
2799 } else if (targs != null && e is TypeExpression) {
2800 e = new GenericTypeExpr (e.Type, targs, loc).ResolveAsTypeStep (ec, false);
2801 break;
2802 } else {
2803 break;
2805 e = null;
2808 if (almost_matched == null && almost_matched_members.Count > 0) {
2809 almost_matched_type = lookup_ds;
2810 almost_matched = new List<MemberInfo>(almost_matched_members);
2814 if (e == null) {
2815 if (almost_matched == null && almost_matched_members.Count > 0) {
2816 almost_matched_type = ec.CurrentType;
2817 almost_matched = new List<MemberInfo> (almost_matched_members);
2819 e = ResolveAsTypeStep (ec, true);
2822 if (e == null) {
2823 if (current_block != null) {
2824 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2825 if (ikv != null) {
2826 LocalInfo li = ikv as LocalInfo;
2827 // Supress CS0219 warning
2828 if (li != null)
2829 li.Used = true;
2831 Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
2832 return null;
2836 if (RootContext.EvalMode){
2837 FieldInfo fi = Evaluator.LookupField (Name);
2838 if (fi != null)
2839 return new FieldExpr (Import.CreateField (fi), loc).Resolve (ec);
2842 if (almost_matched != null)
2843 almost_matched_members = almost_matched;
2844 if (almost_matched_type == null)
2845 almost_matched_type = ec.CurrentType;
2847 string type_name = ec.MemberContext.CurrentType == null ? null : ec.MemberContext.CurrentType.Name;
2848 return Error_MemberLookupFailed (ec, ec.CurrentType, null, almost_matched_type, Name,
2849 type_name, AllMemberTypes, AllBindingFlags);
2852 if (e is MemberExpr) {
2853 MemberExpr me = (MemberExpr) e;
2855 Expression left;
2856 if (me.IsInstance) {
2857 if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope)) {
2859 // Note that an MemberExpr can be both IsInstance and IsStatic.
2860 // An unresolved MethodGroupExpr can contain both kinds of methods
2861 // and each predicate is true if the MethodGroupExpr contains
2862 // at least one of that kind of method.
2865 if (!me.IsStatic &&
2866 (!intermediate || !IdenticalNameAndTypeName (ec, me, loc))) {
2867 Error_ObjectRefRequired (ec, loc, me.GetSignatureForError ());
2868 return null;
2872 // Pass the buck to MemberAccess and Invocation.
2874 left = EmptyExpression.Null;
2875 } else {
2876 left = ec.GetThis (loc);
2878 } else {
2879 left = new TypeExpression (ec.CurrentType, loc);
2882 me = me.ResolveMemberAccess (ec, left, loc, null);
2883 if (me == null)
2884 return null;
2886 if (targs != null) {
2887 if (!targs.Resolve (ec))
2888 return null;
2890 me.SetTypeArguments (ec, targs);
2893 if (!me.IsStatic && (me.InstanceExpression != null && me.InstanceExpression != EmptyExpression.Null) &&
2894 TypeManager.IsNestedFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2895 me.InstanceExpression.Type != me.DeclaringType &&
2896 !TypeManager.IsFamilyAccessible (me.InstanceExpression.Type, me.DeclaringType) &&
2897 (!intermediate || !IdenticalNameAndTypeName (ec, e, loc))) {
2898 ec.Report.Error (38, loc, "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2899 TypeManager.CSharpName (me.DeclaringType), TypeManager.CSharpName (me.InstanceExpression.Type));
2900 return null;
2903 return (right_side != null)
2904 ? me.DoResolveLValue (ec, right_side)
2905 : me.Resolve (ec);
2908 return e;
2912 /// <summary>
2913 /// Represents a namespace or a type. The name of the class was inspired by
2914 /// section 10.8.1 (Fully Qualified Names).
2915 /// </summary>
2916 public abstract class FullNamedExpression : Expression
2918 protected override void CloneTo (CloneContext clonectx, Expression target)
2920 // Do nothing, most unresolved type expressions cannot be
2921 // resolved to different type
2924 public override Expression CreateExpressionTree (ResolveContext ec)
2926 throw new NotSupportedException ("ET");
2929 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
2931 throw new NotSupportedException ();
2934 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2936 return this;
2939 public override void Emit (EmitContext ec)
2941 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2942 GetSignatureForError ());
2946 /// <summary>
2947 /// Expression that evaluates to a type
2948 /// </summary>
2949 public abstract class TypeExpr : FullNamedExpression {
2950 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2952 TypeExpr t = DoResolveAsTypeStep (ec);
2953 if (t == null)
2954 return null;
2956 eclass = ExprClass.Type;
2957 return t;
2960 protected override Expression DoResolve (ResolveContext ec)
2962 return ResolveAsTypeTerminal (ec, false);
2965 public virtual bool CheckAccessLevel (IMemberContext mc)
2967 return mc.CurrentTypeDefinition.CheckAccessLevel (Type);
2970 public virtual bool IsClass {
2971 get { return Type.IsClass; }
2974 public virtual bool IsValueType {
2975 get { return TypeManager.IsStruct (Type); }
2978 public virtual bool IsInterface {
2979 get { return Type.IsInterface; }
2982 public virtual bool IsSealed {
2983 get { return Type.IsSealed; }
2986 public virtual bool CanInheritFrom ()
2988 if (Type == TypeManager.enum_type ||
2989 (Type == TypeManager.value_type && RootContext.StdLib) ||
2990 Type == TypeManager.multicast_delegate_type ||
2991 Type == TypeManager.delegate_type ||
2992 Type == TypeManager.array_type)
2993 return false;
2995 return true;
2998 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
3000 public override bool Equals (object obj)
3002 TypeExpr tobj = obj as TypeExpr;
3003 if (tobj == null)
3004 return false;
3006 return Type == tobj.Type;
3009 public override int GetHashCode ()
3011 return Type.GetHashCode ();
3014 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3016 type = storey.MutateType (type);
3020 /// <summary>
3021 /// Fully resolved Expression that already evaluated to a type
3022 /// </summary>
3023 public class TypeExpression : TypeExpr {
3024 public TypeExpression (Type t, Location l)
3026 Type = t;
3027 eclass = ExprClass.Type;
3028 loc = l;
3031 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3033 return this;
3036 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3038 return this;
3043 // Used to create types from a fully qualified name. These are just used
3044 // by the parser to setup the core types.
3046 public sealed class TypeLookupExpression : TypeExpr {
3047 readonly string ns_name;
3048 readonly string name;
3050 public TypeLookupExpression (string ns, string name)
3052 this.name = name;
3053 this.ns_name = ns;
3054 eclass = ExprClass.Type;
3057 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
3060 // It's null only during mscorlib bootstrap when DefineType
3061 // nees to resolve base type of same type
3063 // For instance struct Char : IComparable<char>
3065 // TODO: it could be removed when Resolve starts to use
3066 // DeclSpace instead of Type
3068 if (type == null) {
3069 Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, false);
3070 FullNamedExpression fne = ns.Lookup (ec.Compiler, name, loc);
3071 if (fne != null)
3072 type = fne.Type;
3075 return this;
3078 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
3080 return this;
3083 public override string GetSignatureForError ()
3085 if (type == null)
3086 return TypeManager.CSharpName (ns_name + "." + name, null);
3088 return base.GetSignatureForError ();
3092 /// <summary>
3093 /// This class denotes an expression which evaluates to a member
3094 /// of a struct or a class.
3095 /// </summary>
3096 public abstract class MemberExpr : Expression
3098 protected bool is_base;
3100 /// <summary>
3101 /// The name of this member.
3102 /// </summary>
3103 public abstract string Name {
3104 get;
3108 // When base.member is used
3110 public bool IsBase {
3111 get { return is_base; }
3112 set { is_base = value; }
3115 /// <summary>
3116 /// Whether this is an instance member.
3117 /// </summary>
3118 public abstract bool IsInstance {
3119 get;
3122 /// <summary>
3123 /// Whether this is a static member.
3124 /// </summary>
3125 public abstract bool IsStatic {
3126 get;
3129 /// <summary>
3130 /// The type which declares this member.
3131 /// </summary>
3132 public abstract Type DeclaringType {
3133 get;
3136 /// <summary>
3137 /// The instance expression associated with this member, if it's a
3138 /// non-static member.
3139 /// </summary>
3140 public Expression InstanceExpression;
3142 public static void error176 (ResolveContext ec, Location loc, string name)
3144 ec.Report.Error (176, loc, "Static member `{0}' cannot be accessed " +
3145 "with an instance reference, qualify it with a type name instead", name);
3148 public static void Error_BaseAccessInExpressionTree (ResolveContext ec, Location loc)
3150 ec.Report.Error (831, loc, "An expression tree may not contain a base access");
3153 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3155 if (InstanceExpression != null)
3156 InstanceExpression.MutateHoistedGenericType (storey);
3159 // TODO: possible optimalization
3160 // Cache resolved constant result in FieldBuilder <-> expression map
3161 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3162 SimpleName original)
3165 // Precondition:
3166 // original == null || original.Resolve (...) ==> left
3169 if (left is TypeExpr) {
3170 left = left.ResolveAsBaseTerminal (ec, false);
3171 if (left == null)
3172 return null;
3174 // TODO: Same problem as in class.cs, TypeTerminal does not
3175 // always do all necessary checks
3176 ObsoleteAttribute oa = AttributeTester.GetObsoleteAttribute (left.Type);
3177 if (oa != null && !ec.IsObsolete) {
3178 AttributeTester.Report_ObsoleteMessage (oa, left.GetSignatureForError (), loc, ec.Report);
3181 GenericTypeExpr ct = left as GenericTypeExpr;
3182 if (ct != null && !ct.CheckConstraints (ec))
3183 return null;
3186 if (!IsStatic) {
3187 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
3188 return null;
3191 return this;
3194 if (!IsInstance) {
3195 if (original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3196 return this;
3198 return ResolveExtensionMemberAccess (ec, left);
3201 InstanceExpression = left;
3202 return this;
3205 protected virtual MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3207 error176 (ec, loc, GetSignatureForError ());
3208 return this;
3211 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3213 if (IsStatic)
3214 return;
3216 if (InstanceExpression == EmptyExpression.Null) {
3217 // FIXME: This should not be here at all
3218 SimpleName.Error_ObjectRefRequired (new ResolveContext (ec.MemberContext), loc, GetSignatureForError ());
3219 return;
3222 if (TypeManager.IsValueType (InstanceExpression.Type)) {
3223 if (InstanceExpression is IMemoryLocation) {
3224 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
3225 } else {
3226 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
3227 InstanceExpression.Emit (ec);
3228 t.Store (ec);
3229 t.AddressOf (ec, AddressOp.Store);
3231 } else
3232 InstanceExpression.Emit (ec);
3234 if (prepare_for_load)
3235 ec.ig.Emit (OpCodes.Dup);
3238 public virtual void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3240 // TODO: need to get correct member type
3241 ec.Report.Error (307, loc, "The property `{0}' cannot be used with type arguments",
3242 GetSignatureForError ());
3246 ///
3247 /// Represents group of extension methods
3248 ///
3249 public class ExtensionMethodGroupExpr : MethodGroupExpr
3251 readonly NamespaceEntry namespace_entry;
3252 public Expression ExtensionExpression;
3253 Argument extension_argument;
3255 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, Type extensionType, Location l)
3256 : base (list, extensionType, l)
3258 this.namespace_entry = n;
3261 public override bool IsStatic {
3262 get { return true; }
3265 public bool IsTopLevel {
3266 get { return namespace_entry == null; }
3269 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
3271 extension_argument.Expr.MutateHoistedGenericType (storey);
3272 base.MutateHoistedGenericType (storey);
3275 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, bool may_fail, Location loc)
3277 if (arguments == null)
3278 arguments = new Arguments (1);
3280 arguments.Insert (0, new Argument (ExtensionExpression));
3281 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, namespace_entry, loc);
3283 // Store resolved argument and restore original arguments
3284 if (mg != null)
3285 ((ExtensionMethodGroupExpr)mg).extension_argument = arguments [0];
3286 else
3287 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
3289 return mg;
3292 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, NamespaceEntry ns, Location loc)
3294 // Use normal resolve rules
3295 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ns != null, loc);
3296 if (mg != null)
3297 return mg;
3299 if (ns == null)
3300 return null;
3302 // Search continues
3303 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, loc);
3304 if (e == null)
3305 return base.OverloadResolve (ec, ref arguments, false, loc);
3307 e.ExtensionExpression = ExtensionExpression;
3308 e.SetTypeArguments (ec, type_arguments);
3309 return e.ResolveOverloadExtensions (ec, ref arguments, e.namespace_entry, loc);
3313 /// <summary>
3314 /// MethodGroupExpr represents a group of method candidates which
3315 /// can be resolved to the best method overload
3316 /// </summary>
3317 public class MethodGroupExpr : MemberExpr
3319 public interface IErrorHandler
3321 bool AmbiguousCall (ResolveContext ec, MethodSpec ambiguous);
3322 bool NoExactMatch (ResolveContext ec, MethodSpec method);
3325 public IErrorHandler CustomErrorHandler;
3326 public MethodSpec [] Methods;
3327 MethodSpec best_candidate;
3328 // TODO: make private
3329 public TypeArguments type_arguments;
3330 bool identical_type_name;
3331 bool has_inaccessible_candidates_only;
3332 Type delegate_type;
3333 Type queried_type;
3335 public MethodGroupExpr (MethodSpec [] mi, Type type, Location l)
3336 : this (type, l)
3338 Methods = new MethodSpec[mi.Length];
3339 mi.CopyTo (Methods, 0);
3342 public MethodGroupExpr (MethodSpec[] mi, Type type, Location l, bool inacessibleCandidatesOnly)
3343 : this (mi, type, l)
3345 has_inaccessible_candidates_only = inacessibleCandidatesOnly;
3348 public MethodGroupExpr (List<MethodSpec> list, Type type, Location l)
3349 : this (type, l)
3351 try {
3352 Methods = list.ToArray ();
3353 } catch {
3354 //foreach (MemberInfo m in list){
3355 // if (!(m is MethodBase)){
3356 // Console.WriteLine ("Name " + m.Name);
3357 // Console.WriteLine ("Found a: " + m.GetType ().FullName);
3358 // }
3360 throw;
3366 protected MethodGroupExpr (Type type, Location loc)
3368 this.loc = loc;
3369 eclass = ExprClass.MethodGroup;
3370 this.type = InternalType.MethodGroup;
3371 queried_type = type;
3374 public override Type DeclaringType {
3375 get {
3376 return queried_type;
3380 public MethodSpec BestCandidate {
3381 get {
3382 return best_candidate;
3386 public Type DelegateType {
3387 set {
3388 delegate_type = value;
3392 public bool IdenticalTypeName {
3393 get {
3394 return identical_type_name;
3398 public override string GetSignatureForError ()
3400 if (best_candidate != null)
3401 return TypeManager.CSharpSignature (best_candidate.MetaInfo);
3403 return TypeManager.CSharpSignature (Methods [0].MetaInfo);
3406 public override string Name {
3407 get {
3408 return Methods [0].Name;
3412 public override bool IsInstance {
3413 get {
3414 if (best_candidate != null)
3415 return !best_candidate.IsStatic;
3417 foreach (var mb in Methods)
3418 if (!mb.IsStatic)
3419 return true;
3421 return false;
3425 public override bool IsStatic {
3426 get {
3427 if (best_candidate != null)
3428 return best_candidate.IsStatic;
3430 foreach (var mb in Methods)
3431 if (mb.IsStatic)
3432 return true;
3434 return false;
3438 public static explicit operator MethodSpec (MethodGroupExpr mg)
3440 return mg.best_candidate;
3444 // 7.4.3.3 Better conversion from expression
3445 // Returns : 1 if a->p is better,
3446 // 2 if a->q is better,
3447 // 0 if neither is better
3449 static int BetterExpressionConversion (ResolveContext ec, Argument a, Type p, Type q)
3451 Type argument_type = TypeManager.TypeToCoreType (a.Type);
3452 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3454 // Uwrap delegate from Expression<T>
3456 if (TypeManager.DropGenericTypeArguments (p) == TypeManager.expression_type) {
3457 p = TypeManager.GetTypeArguments (p) [0];
3459 if (TypeManager.DropGenericTypeArguments (q) == TypeManager.expression_type) {
3460 q = TypeManager.GetTypeArguments (q) [0];
3463 p = Delegate.GetInvokeMethod (ec.Compiler, null, p).ReturnType;
3464 q = Delegate.GetInvokeMethod (ec.Compiler, null, q).ReturnType;
3465 if (p == TypeManager.void_type && q != TypeManager.void_type)
3466 return 2;
3467 if (q == TypeManager.void_type && p != TypeManager.void_type)
3468 return 1;
3469 } else {
3470 if (argument_type == p)
3471 return 1;
3473 if (argument_type == q)
3474 return 2;
3477 return BetterTypeConversion (ec, p, q);
3481 // 7.4.3.4 Better conversion from type
3483 public static int BetterTypeConversion (ResolveContext ec, Type p, Type q)
3485 if (p == null || q == null)
3486 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3488 if (p == TypeManager.int32_type) {
3489 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3490 return 1;
3491 } else if (p == TypeManager.int64_type) {
3492 if (q == TypeManager.uint64_type)
3493 return 1;
3494 } else if (p == TypeManager.sbyte_type) {
3495 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3496 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3497 return 1;
3498 } else if (p == TypeManager.short_type) {
3499 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3500 q == TypeManager.uint64_type)
3501 return 1;
3502 } else if (p == InternalType.Dynamic) {
3503 if (q == TypeManager.object_type)
3504 return 2;
3507 if (q == TypeManager.int32_type) {
3508 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3509 return 2;
3510 } if (q == TypeManager.int64_type) {
3511 if (p == TypeManager.uint64_type)
3512 return 2;
3513 } else if (q == TypeManager.sbyte_type) {
3514 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3515 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3516 return 2;
3517 } if (q == TypeManager.short_type) {
3518 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3519 p == TypeManager.uint64_type)
3520 return 2;
3521 } else if (q == InternalType.Dynamic) {
3522 if (p == TypeManager.object_type)
3523 return 1;
3526 // TODO: this is expensive
3527 Expression p_tmp = new EmptyExpression (p);
3528 Expression q_tmp = new EmptyExpression (q);
3530 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3531 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3533 if (p_to_q && !q_to_p)
3534 return 1;
3536 if (q_to_p && !p_to_q)
3537 return 2;
3539 return 0;
3542 /// <summary>
3543 /// Determines "Better function" between candidate
3544 /// and the current best match
3545 /// </summary>
3546 /// <remarks>
3547 /// Returns a boolean indicating :
3548 /// false if candidate ain't better
3549 /// true if candidate is better than the current best match
3550 /// </remarks>
3551 static bool BetterFunction (ResolveContext ec, Arguments args, int argument_count,
3552 MethodSpec candidate, bool candidate_params,
3553 MethodSpec best, bool best_params)
3555 AParametersCollection candidate_pd = candidate.Parameters;
3556 AParametersCollection best_pd = best.Parameters;
3558 bool better_at_least_one = false;
3559 bool same = true;
3560 for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx)
3562 Argument a = args [j];
3564 // Provided default argument value is never better
3565 if (a.IsDefaultArgument && candidate_params == best_params)
3566 return false;
3568 Type ct = candidate_pd.Types [c_idx];
3569 Type bt = best_pd.Types [b_idx];
3571 if (candidate_params && candidate_pd.FixedParameters [c_idx].ModFlags == Parameter.Modifier.PARAMS)
3573 ct = TypeManager.GetElementType (ct);
3574 --c_idx;
3577 if (best_params && best_pd.FixedParameters [b_idx].ModFlags == Parameter.Modifier.PARAMS)
3579 bt = TypeManager.GetElementType (bt);
3580 --b_idx;
3583 if (TypeManager.IsEqual (ct, bt))
3584 continue;
3586 same = false;
3587 int result = BetterExpressionConversion (ec, a, ct, bt);
3589 // for each argument, the conversion to 'ct' should be no worse than
3590 // the conversion to 'bt'.
3591 if (result == 2)
3592 return false;
3594 // for at least one argument, the conversion to 'ct' should be better than
3595 // the conversion to 'bt'.
3596 if (result != 0)
3597 better_at_least_one = true;
3600 if (better_at_least_one)
3601 return true;
3604 // This handles the case
3606 // Add (float f1, float f2, float f3);
3607 // Add (params decimal [] foo);
3609 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3610 // first candidate would've chosen as better.
3612 if (!same)
3613 return false;
3616 // The two methods have equal parameter types. Now apply tie-breaking rules
3618 if (best.IsGenericMethod) {
3619 if (!candidate.IsGenericMethod)
3620 return true;
3621 } else if (candidate.IsGenericMethod) {
3622 return false;
3626 // This handles the following cases:
3628 // Trim () is better than Trim (params char[] chars)
3629 // Concat (string s1, string s2, string s3) is better than
3630 // Concat (string s1, params string [] srest)
3631 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3633 if (!candidate_params && best_params)
3634 return true;
3635 if (candidate_params && !best_params)
3636 return false;
3638 int candidate_param_count = candidate_pd.Count;
3639 int best_param_count = best_pd.Count;
3641 if (candidate_param_count != best_param_count)
3642 // can only happen if (candidate_params && best_params)
3643 return candidate_param_count > best_param_count && best_pd.HasParams;
3646 // now, both methods have the same number of parameters, and the parameters have the same types
3647 // Pick the "more specific" signature
3650 MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
3651 MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
3653 AParametersCollection orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
3654 AParametersCollection orig_best_pd = TypeManager.GetParameterData (orig_best);
3656 bool specific_at_least_once = false;
3657 for (int j = 0; j < candidate_param_count; ++j)
3659 Type ct = orig_candidate_pd.Types [j];
3660 Type bt = orig_best_pd.Types [j];
3661 if (ct.Equals (bt))
3662 continue;
3663 Type specific = MoreSpecific (ct, bt);
3664 if (specific == bt)
3665 return false;
3666 if (specific == ct)
3667 specific_at_least_once = true;
3670 if (specific_at_least_once)
3671 return true;
3673 // FIXME: handle lifted operators
3674 // ...
3676 return false;
3679 protected override MemberExpr ResolveExtensionMemberAccess (ResolveContext ec, Expression left)
3681 if (!IsStatic)
3682 return base.ResolveExtensionMemberAccess (ec, left);
3685 // When left side is an expression and at least one candidate method is
3686 // static, it can be extension method
3688 InstanceExpression = left;
3689 return this;
3692 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
3693 SimpleName original)
3695 if (!(left is TypeExpr) &&
3696 original != null && original.IdenticalNameAndTypeName (ec, left, loc))
3697 identical_type_name = true;
3699 return base.ResolveMemberAccess (ec, left, loc, original);
3702 public override Expression CreateExpressionTree (ResolveContext ec)
3704 if (best_candidate == null) {
3705 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3706 return null;
3709 IMethodData md = TypeManager.GetMethod (best_candidate.MetaInfo);
3710 if (md != null && md.IsExcluded ())
3711 ec.Report.Error (765, loc,
3712 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3714 return new TypeOfMethod (best_candidate, loc);
3717 protected override Expression DoResolve (ResolveContext ec)
3719 this.eclass = ExprClass.MethodGroup;
3721 if (InstanceExpression != null) {
3722 InstanceExpression = InstanceExpression.Resolve (ec);
3723 if (InstanceExpression == null)
3724 return null;
3727 return this;
3730 public void ReportUsageError (ResolveContext ec)
3732 ec.Report.Error (654, loc, "Method `" + DeclaringType + "." +
3733 Name + "()' is referenced without parentheses");
3736 override public void Emit (EmitContext ec)
3738 throw new NotSupportedException ();
3739 // ReportUsageError ();
3742 public void EmitCall (EmitContext ec, Arguments arguments)
3744 Invocation.EmitCall (ec, IsBase, InstanceExpression, best_candidate, arguments, loc);
3747 void Error_AmbiguousCall (ResolveContext ec, MethodSpec ambiguous)
3749 if (CustomErrorHandler != null && CustomErrorHandler.AmbiguousCall (ec, ambiguous))
3750 return;
3752 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
3753 ec.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3754 TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (best_candidate.MetaInfo));
3757 protected virtual void Error_InvalidArguments (ResolveContext ec, Location loc, int idx, MethodSpec method,
3758 Argument a, AParametersCollection expected_par, Type paramType)
3760 ExtensionMethodGroupExpr emg = this as ExtensionMethodGroupExpr;
3762 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3763 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3764 if ((expected_par.FixedParameters [idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3765 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3766 TypeManager.CSharpSignature (method));
3767 return;
3769 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3770 TypeManager.CSharpSignature (method));
3771 } else if (TypeManager.IsDelegateType (method.DeclaringType)) {
3772 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3773 TypeManager.CSharpName (method.DeclaringType));
3774 } else {
3775 ec.Report.SymbolRelatedToPreviousError (method.MetaInfo);
3776 if (emg != null) {
3777 ec.Report.Error (1928, loc,
3778 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3779 emg.ExtensionExpression.GetSignatureForError (),
3780 emg.Name, TypeManager.CSharpSignature (method));
3781 } else {
3782 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3783 TypeManager.CSharpSignature (method));
3787 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters [idx].ModFlags;
3789 string index = (idx + 1).ToString ();
3790 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3791 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3792 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3793 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3794 index, Parameter.GetModifierSignature (a.Modifier));
3795 else
3796 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3797 index, Parameter.GetModifierSignature (mod));
3798 } else {
3799 string p1 = a.GetSignatureForError ();
3800 string p2 = TypeManager.CSharpName (paramType);
3802 if (p1 == p2) {
3803 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3804 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3805 ec.Report.SymbolRelatedToPreviousError (paramType);
3808 if (idx == 0 && emg != null) {
3809 ec.Report.Error (1929, loc,
3810 "Extension method instance type `{0}' cannot be converted to `{1}'", p1, p2);
3811 } else {
3812 ec.Report.Error (1503, loc,
3813 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3818 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, Type target, bool expl)
3820 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3821 Name, TypeManager.CSharpName (target));
3824 void Error_ArgumentCountWrong (ResolveContext ec, int arg_count)
3826 ec.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
3827 Name, arg_count.ToString ());
3830 protected virtual int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
3832 return parameters.Count;
3835 public static bool IsAncestralType (Type first_type, Type second_type)
3837 return first_type != second_type &&
3838 (TypeManager.IsSubclassOf (second_type, first_type) ||
3839 TypeManager.ImplementsInterface (second_type, first_type));
3843 /// Determines if the candidate method is applicable (section 14.4.2.1)
3844 /// to the given set of arguments
3845 /// A return value rates candidate method compatibility,
3846 /// 0 = the best, int.MaxValue = the worst
3848 public int IsApplicable (ResolveContext ec,
3849 ref Arguments arguments, int arg_count, ref MethodSpec method, ref bool params_expanded_form)
3851 var candidate = method;
3853 AParametersCollection pd = candidate.Parameters;
3854 int param_count = GetApplicableParametersCount (candidate, pd);
3855 int optional_count = 0;
3857 if (arg_count != param_count) {
3858 for (int i = 0; i < pd.Count; ++i) {
3859 if (pd.FixedParameters [i].HasDefaultValue) {
3860 optional_count = pd.Count - i;
3861 break;
3865 int args_gap = System.Math.Abs (arg_count - param_count);
3866 if (optional_count != 0) {
3867 if (args_gap > optional_count)
3868 return int.MaxValue - 10000 + args_gap - optional_count;
3870 // Readjust expected number when params used
3871 if (pd.HasParams) {
3872 optional_count--;
3873 if (arg_count < param_count)
3874 param_count--;
3875 } else if (arg_count > param_count) {
3876 return int.MaxValue - 10000 + args_gap;
3878 } else if (arg_count != param_count) {
3879 if (!pd.HasParams)
3880 return int.MaxValue - 10000 + args_gap;
3881 if (arg_count < param_count - 1)
3882 return int.MaxValue - 10000 + args_gap;
3885 // Initialize expanded form of a method with 1 params parameter
3886 params_expanded_form = param_count == 1 && pd.HasParams;
3888 // Resize to fit optional arguments
3889 if (optional_count != 0) {
3890 Arguments resized;
3891 if (arguments == null) {
3892 resized = new Arguments (optional_count);
3893 } else {
3894 resized = new Arguments (param_count);
3895 resized.AddRange (arguments);
3898 for (int i = arg_count; i < param_count; ++i)
3899 resized.Add (null);
3900 arguments = resized;
3904 if (arg_count > 0) {
3906 // Shuffle named arguments to the right positions if there are any
3908 if (arguments [arg_count - 1] is NamedArgument) {
3909 arg_count = arguments.Count;
3911 for (int i = 0; i < arg_count; ++i) {
3912 bool arg_moved = false;
3913 while (true) {
3914 NamedArgument na = arguments[i] as NamedArgument;
3915 if (na == null)
3916 break;
3918 int index = pd.GetParameterIndexByName (na.Name);
3920 // Named parameter not found or already reordered
3921 if (index <= i)
3922 break;
3924 // When using parameters which should not be available to the user
3925 if (index >= param_count)
3926 break;
3928 if (!arg_moved) {
3929 arguments.MarkReorderedArgument (na);
3930 arg_moved = true;
3933 Argument temp = arguments[index];
3934 arguments[index] = arguments[i];
3935 arguments[i] = temp;
3937 if (temp == null)
3938 break;
3941 } else {
3942 arg_count = arguments.Count;
3944 } else if (arguments != null) {
3945 arg_count = arguments.Count;
3949 // 1. Handle generic method using type arguments when specified or type inference
3951 if (candidate.IsGenericMethod) {
3952 if (type_arguments != null) {
3953 Type [] g_args = candidate.GetGenericArguments ();
3954 if (g_args.Length != type_arguments.Count)
3955 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args.Length);
3957 method = candidate.Inflate (type_arguments.Arguments);
3958 candidate = method;
3959 pd = candidate.Parameters;
3960 } else {
3961 int score = TypeManager.InferTypeArguments (ec, arguments, ref candidate);
3962 if (score != 0)
3963 return score - 20000;
3965 if (TypeManager.IsGenericMethodDefinition (candidate.MetaInfo))
3966 throw new InternalErrorException ("A generic method `{0}' definition took part in overload resolution",
3967 TypeManager.CSharpSignature (candidate.MetaInfo));
3969 pd = candidate.Parameters;
3971 } else {
3972 if (type_arguments != null)
3973 return int.MaxValue - 15000;
3977 // 2. Each argument has to be implicitly convertible to method parameter
3979 method = candidate;
3980 Parameter.Modifier p_mod = 0;
3981 Type pt = null;
3982 for (int i = 0; i < arg_count; i++) {
3983 Argument a = arguments [i];
3984 if (a == null) {
3985 if (!pd.FixedParameters [i].HasDefaultValue)
3986 throw new InternalErrorException ();
3988 Expression e = pd.FixedParameters [i].DefaultValue as Constant;
3989 if (e == null)
3990 e = new DefaultValueExpression (new TypeExpression (pd.Types [i], loc), loc).Resolve (ec);
3992 arguments [i] = new Argument (e, Argument.AType.Default);
3993 continue;
3996 if (p_mod != Parameter.Modifier.PARAMS) {
3997 p_mod = pd.FixedParameters [i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3998 pt = pd.Types [i];
3999 } else {
4000 params_expanded_form = true;
4003 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4004 int score = 1;
4005 if (!params_expanded_form)
4006 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4008 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && delegate_type == null) {
4009 // It can be applicable in expanded form
4010 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
4011 if (score == 0)
4012 params_expanded_form = true;
4015 if (score != 0) {
4016 if (params_expanded_form)
4017 ++score;
4018 return (arg_count - i) * 2 + score;
4022 if (arg_count != param_count)
4023 params_expanded_form = true;
4025 return 0;
4028 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, Type parameter)
4031 // Types have to be identical when ref or out modifer is used
4033 if (arg_mod != 0 || param_mod != 0) {
4034 if (TypeManager.HasElementType (parameter))
4035 parameter = TypeManager.GetElementType (parameter);
4037 Type a_type = argument.Type;
4038 if (TypeManager.HasElementType (a_type))
4039 a_type = TypeManager.GetElementType (a_type);
4041 if (a_type != parameter) {
4042 if (TypeManager.IsDynamicType (a_type))
4043 return 0;
4045 return 2;
4047 } else {
4048 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4049 if (TypeManager.IsDynamicType (argument.Type))
4050 return 0;
4052 return 2;
4056 if (arg_mod != param_mod)
4057 return 1;
4059 return 0;
4062 public static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4064 if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4065 return false;
4067 AParametersCollection cand_pd = TypeManager.GetParameterData (cand_method);
4068 AParametersCollection base_pd = TypeManager.GetParameterData (base_method);
4070 if (cand_pd.Count != base_pd.Count)
4071 return false;
4073 for (int j = 0; j < cand_pd.Count; ++j)
4075 Parameter.Modifier cm = cand_pd.FixedParameters [j].ModFlags;
4076 Parameter.Modifier bm = base_pd.FixedParameters [j].ModFlags;
4077 Type ct = cand_pd.Types [j];
4078 Type bt = base_pd.Types [j];
4080 if (cm != bm || ct != bt)
4081 return false;
4084 return true;
4087 public static MethodGroupExpr MakeUnionSet (MethodGroupExpr mg1, MethodGroupExpr mg2, Location loc)
4089 if (mg1 == null) {
4090 if (mg2 == null)
4091 return null;
4092 return mg2;
4095 if (mg2 == null)
4096 return mg1;
4098 var all = new List<MethodSpec> (mg1.Methods);
4099 foreach (var m in mg2.Methods){
4100 if (!TypeManager.ArrayContainsMethod (mg1.Methods.Select (l => l.MetaInfo).ToArray (), m.MetaInfo, false))
4101 all.Add (m);
4104 return new MethodGroupExpr (all, null, loc);
4107 static Type MoreSpecific (Type p, Type q)
4109 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4110 return q;
4111 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4112 return p;
4114 if (TypeManager.HasElementType (p))
4116 Type pe = TypeManager.GetElementType (p);
4117 Type qe = TypeManager.GetElementType (q);
4118 Type specific = MoreSpecific (pe, qe);
4119 if (specific == pe)
4120 return p;
4121 if (specific == qe)
4122 return q;
4124 else if (TypeManager.IsGenericType (p))
4126 Type[] pargs = TypeManager.GetTypeArguments (p);
4127 Type[] qargs = TypeManager.GetTypeArguments (q);
4129 bool p_specific_at_least_once = false;
4130 bool q_specific_at_least_once = false;
4132 for (int i = 0; i < pargs.Length; i++)
4134 Type specific = MoreSpecific (TypeManager.TypeToCoreType (pargs [i]), TypeManager.TypeToCoreType (qargs [i]));
4135 if (specific == pargs [i])
4136 p_specific_at_least_once = true;
4137 if (specific == qargs [i])
4138 q_specific_at_least_once = true;
4141 if (p_specific_at_least_once && !q_specific_at_least_once)
4142 return p;
4143 if (!p_specific_at_least_once && q_specific_at_least_once)
4144 return q;
4147 return null;
4150 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
4152 base.MutateHoistedGenericType (storey);
4154 if (best_candidate.IsConstructor) {
4155 storey.MutateConstructor (best_candidate);
4156 } else {
4157 storey.MutateGenericMethod (best_candidate);
4161 /// <summary>
4162 /// Find the Applicable Function Members (7.4.2.1)
4164 /// me: Method Group expression with the members to select.
4165 /// it might contain constructors or methods (or anything
4166 /// that maps to a method).
4168 /// Arguments: ArrayList containing resolved Argument objects.
4170 /// loc: The location if we want an error to be reported, or a Null
4171 /// location for "probing" purposes.
4173 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4174 /// that is the best match of me on Arguments.
4176 /// </summary>
4177 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments Arguments,
4178 bool may_fail, Location loc)
4180 bool method_params = false;
4181 Type applicable_type = null;
4182 var candidates = new List<MethodSpec> (2);
4183 List<MethodSpec> candidate_overrides = null;
4186 // Used to keep a map between the candidate
4187 // and whether it is being considered in its
4188 // normal or expanded form
4190 // false is normal form, true is expanded form
4192 Dictionary<MethodSpec, MethodSpec> candidate_to_form = null;
4193 Dictionary<MethodSpec, Arguments> candidates_expanded = null;
4194 Arguments candidate_args = Arguments;
4196 int arg_count = Arguments != null ? Arguments.Count : 0;
4198 if (RootContext.Version == LanguageVersion.ISO_1 && Name == "Invoke" && TypeManager.IsDelegateType (DeclaringType)) {
4199 if (!may_fail)
4200 ec.Report.Error (1533, loc, "Invoke cannot be called directly on a delegate");
4201 return null;
4204 int nmethods = Methods.Length;
4206 if (!IsBase) {
4208 // Methods marked 'override' don't take part in 'applicable_type'
4209 // computation, nor in the actual overload resolution.
4210 // However, they still need to be emitted instead of a base virtual method.
4211 // So, we salt them away into the 'candidate_overrides' array.
4213 // In case of reflected methods, we replace each overriding method with
4214 // its corresponding base virtual method. This is to improve compatibility
4215 // with non-C# libraries which change the visibility of overrides (#75636)
4217 int j = 0;
4218 MethodBase mb = null;
4219 for (int i = 0; i < Methods.Length; ++i) {
4220 var m = Methods [i];
4221 mb = m.MetaInfo;
4222 if (TypeManager.IsOverride (m)) {
4223 if (candidate_overrides == null)
4224 candidate_overrides = new List<MethodSpec> ();
4225 candidate_overrides.Add (m);
4226 mb = TypeManager.TryGetBaseDefinition (mb);
4227 if (mb != null && Array.Exists (Methods, l => l.MetaInfo == mb))
4228 continue;
4230 if (mb != null)
4231 Methods [j++] = Import.CreateMethod (mb);
4233 nmethods = j;
4237 // Enable message recording, it's used mainly by lambda expressions
4239 SessionReportPrinter msg_recorder = new SessionReportPrinter ();
4240 ReportPrinter prev_recorder = ec.Report.SetPrinter (msg_recorder);
4243 // First we construct the set of applicable methods
4245 bool is_sorted = true;
4246 int best_candidate_rate = int.MaxValue;
4247 for (int i = 0; i < nmethods; i++) {
4248 Type decl_type = Methods [i].DeclaringType;
4251 // If we have already found an applicable method
4252 // we eliminate all base types (Section 14.5.5.1)
4254 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4255 continue;
4258 // Check if candidate is applicable (section 14.4.2.1)
4260 bool params_expanded_form = false;
4261 int candidate_rate = IsApplicable (ec, ref candidate_args, arg_count, ref Methods [i], ref params_expanded_form);
4263 if (candidate_rate < best_candidate_rate) {
4264 best_candidate_rate = candidate_rate;
4265 best_candidate = Methods [i];
4268 if (params_expanded_form) {
4269 if (candidate_to_form == null)
4270 candidate_to_form = new Dictionary<MethodSpec, MethodSpec> (4, ReferenceEquality<MethodSpec>.Default);
4271 var candidate = Methods [i];
4272 candidate_to_form [candidate] = candidate;
4275 if (candidate_args != Arguments) {
4276 if (candidates_expanded == null)
4277 candidates_expanded = new Dictionary<MethodSpec, Arguments> (4, ReferenceEquality<MethodSpec>.Default);
4279 candidates_expanded.Add (Methods [i], candidate_args);
4280 candidate_args = Arguments;
4283 if (candidate_rate != 0 || has_inaccessible_candidates_only) {
4284 if (msg_recorder != null)
4285 msg_recorder.EndSession ();
4286 continue;
4289 msg_recorder = null;
4290 candidates.Add (Methods [i]);
4292 if (applicable_type == null)
4293 applicable_type = decl_type;
4294 else if (applicable_type != decl_type) {
4295 is_sorted = false;
4296 if (IsAncestralType (applicable_type, decl_type))
4297 applicable_type = decl_type;
4301 ec.Report.SetPrinter (prev_recorder);
4302 if (msg_recorder != null && !msg_recorder.IsEmpty) {
4303 if (!may_fail)
4304 msg_recorder.Merge (prev_recorder);
4306 return null;
4309 int candidate_top = candidates.Count;
4311 if (applicable_type == null) {
4313 // When we found a top level method which does not match and it's
4314 // not an extension method. We start extension methods lookup from here
4316 if (InstanceExpression != null) {
4317 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (type, Name, loc);
4318 if (ex_method_lookup != null) {
4319 ex_method_lookup.ExtensionExpression = InstanceExpression;
4320 ex_method_lookup.SetTypeArguments (ec, type_arguments);
4321 return ex_method_lookup.OverloadResolve (ec, ref Arguments, may_fail, loc);
4325 if (may_fail)
4326 return null;
4329 // Okay so we have failed to find exact match so we
4330 // return error info about the closest match
4332 if (best_candidate != null) {
4333 if (CustomErrorHandler != null && !has_inaccessible_candidates_only && CustomErrorHandler.NoExactMatch (ec, best_candidate))
4334 return null;
4336 if (NoExactMatch (ec, ref Arguments, candidate_to_form))
4337 return null;
4341 // We failed to find any method with correct argument count
4343 if (Name == ConstructorInfo.ConstructorName) {
4344 ec.Report.SymbolRelatedToPreviousError (queried_type);
4345 ec.Report.Error (1729, loc,
4346 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4347 TypeManager.CSharpName (queried_type), arg_count);
4348 } else {
4349 Error_ArgumentCountWrong (ec, arg_count);
4352 return null;
4355 if (arg_count != 0 && Arguments.HasDynamic) {
4356 best_candidate = null;
4357 return this;
4360 if (!is_sorted) {
4362 // At this point, applicable_type is _one_ of the most derived types
4363 // in the set of types containing the methods in this MethodGroup.
4364 // Filter the candidates so that they only contain methods from the
4365 // most derived types.
4368 int finalized = 0; // Number of finalized candidates
4370 do {
4371 // Invariant: applicable_type is a most derived type
4373 // We'll try to complete Section 14.5.5.1 for 'applicable_type' by
4374 // eliminating all it's base types. At the same time, we'll also move
4375 // every unrelated type to the end of the array, and pick the next
4376 // 'applicable_type'.
4378 Type next_applicable_type = null;
4379 int j = finalized; // where to put the next finalized candidate
4380 int k = finalized; // where to put the next undiscarded candidate
4381 for (int i = finalized; i < candidate_top; ++i) {
4382 var candidate = candidates [i];
4383 Type decl_type = candidate.DeclaringType;
4385 if (decl_type == applicable_type) {
4386 candidates [k++] = candidates [j];
4387 candidates [j++] = candidates [i];
4388 continue;
4391 if (IsAncestralType (decl_type, applicable_type))
4392 continue;
4394 if (next_applicable_type != null &&
4395 IsAncestralType (decl_type, next_applicable_type))
4396 continue;
4398 candidates [k++] = candidates [i];
4400 if (next_applicable_type == null ||
4401 IsAncestralType (next_applicable_type, decl_type))
4402 next_applicable_type = decl_type;
4405 applicable_type = next_applicable_type;
4406 finalized = j;
4407 candidate_top = k;
4408 } while (applicable_type != null);
4412 // Now we actually find the best method
4415 best_candidate = candidates [0];
4416 method_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4419 // TODO: Broken inverse order of candidates logic does not work with optional
4420 // parameters used for method overrides and I am not going to fix it for SRE
4422 if (candidates_expanded != null && candidates_expanded.ContainsKey (best_candidate)) {
4423 candidate_args = candidates_expanded [best_candidate];
4424 arg_count = candidate_args.Count;
4427 for (int ix = 1; ix < candidate_top; ix++) {
4428 var candidate = candidates [ix];
4430 if (candidate.MetaInfo == best_candidate.MetaInfo)
4431 continue;
4433 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4435 if (BetterFunction (ec, candidate_args, arg_count,
4436 candidate, cand_params,
4437 best_candidate, method_params)) {
4438 best_candidate = candidate;
4439 method_params = cand_params;
4443 // Now check that there are no ambiguities i.e the selected method
4444 // should be better than all the others
4446 MethodSpec ambiguous = null;
4447 for (int ix = 1; ix < candidate_top; ix++) {
4448 var candidate = candidates [ix];
4450 if (candidate.MetaInfo == best_candidate.MetaInfo)
4451 continue;
4453 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (candidate);
4454 if (!BetterFunction (ec, candidate_args, arg_count,
4455 best_candidate, method_params,
4456 candidate, cand_params))
4458 if (!may_fail)
4459 ec.Report.SymbolRelatedToPreviousError (candidate.MetaInfo);
4460 ambiguous = candidate;
4464 if (ambiguous != null) {
4465 Error_AmbiguousCall (ec, ambiguous);
4466 return this;
4470 // If the method is a virtual function, pick an override closer to the LHS type.
4472 if (!IsBase && best_candidate.IsVirtual) {
4473 if (TypeManager.IsOverride (best_candidate))
4474 throw new InternalErrorException (
4475 "Should not happen. An 'override' method took part in overload resolution: " + best_candidate);
4477 if (candidate_overrides != null) {
4478 Type[] gen_args = null;
4479 bool gen_override = false;
4480 if (best_candidate.IsGenericMethod)
4481 gen_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4483 foreach (var candidate in candidate_overrides) {
4484 if (candidate.IsGenericMethod) {
4485 if (gen_args == null)
4486 continue;
4488 if (gen_args.Length != TypeManager.GetGenericArguments (candidate.MetaInfo).Length)
4489 continue;
4490 } else {
4491 if (gen_args != null)
4492 continue;
4495 if (IsOverride (candidate.MetaInfo, best_candidate.MetaInfo)) {
4496 gen_override = true;
4497 best_candidate = candidate;
4501 if (gen_override && gen_args != null) {
4502 best_candidate = best_candidate.Inflate (gen_args);
4508 // And now check if the arguments are all
4509 // compatible, perform conversions if
4510 // necessary etc. and return if everything is
4511 // all right
4513 if (!VerifyArgumentsCompat (ec, ref candidate_args, arg_count, best_candidate,
4514 method_params, may_fail, loc))
4515 return null;
4517 if (best_candidate == null)
4518 return null;
4520 MethodBase the_method = TypeManager.DropGenericMethodArguments (best_candidate);
4521 if (TypeManager.IsGenericMethodDefinition (the_method) &&
4522 !ConstraintChecker.CheckConstraints (ec, the_method, best_candidate.MetaInfo, loc))
4523 return null;
4526 // Check ObsoleteAttribute on the best method
4528 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (the_method);
4529 if (oa != null && !ec.IsObsolete)
4530 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
4532 IMethodData data = TypeManager.GetMethod (the_method);
4533 if (data != null)
4534 data.SetIsUsed ();
4536 Arguments = candidate_args;
4537 return this;
4540 bool NoExactMatch (ResolveContext ec, ref Arguments Arguments, IDictionary<MethodSpec, MethodSpec> candidate_to_form)
4542 AParametersCollection pd = best_candidate.Parameters;
4543 int arg_count = Arguments == null ? 0 : Arguments.Count;
4545 if (arg_count == pd.Count || pd.HasParams) {
4546 if (TypeManager.IsGenericMethodDefinition (best_candidate.MetaInfo)) {
4547 if (type_arguments == null) {
4548 ec.Report.Error (411, loc,
4549 "The type arguments for method `{0}' cannot be inferred from " +
4550 "the usage. Try specifying the type arguments explicitly",
4551 TypeManager.CSharpSignature (best_candidate.MetaInfo));
4552 return true;
4555 Type[] g_args = TypeManager.GetGenericArguments (best_candidate.MetaInfo);
4556 if (type_arguments.Count != g_args.Length) {
4557 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4558 ec.Report.Error (305, loc, "Using the generic method `{0}' requires `{1}' type argument(s)",
4559 TypeManager.CSharpSignature (best_candidate.MetaInfo),
4560 g_args.Length.ToString ());
4561 return true;
4563 } else {
4564 if (type_arguments != null && !best_candidate.IsGenericMethod) {
4565 Error_TypeArgumentsCannotBeUsed (ec.Report, loc);
4566 return true;
4570 if (has_inaccessible_candidates_only) {
4571 if (InstanceExpression != null && type != ec.CurrentType && TypeManager.IsNestedFamilyAccessible (ec.CurrentType, best_candidate.DeclaringType)) {
4572 // Although a derived class can access protected members of
4573 // its base class it cannot do so through an instance of the
4574 // base class (CS1540). If the qualifier_type is a base of the
4575 // ec.CurrentType and the lookup succeeds with the latter one,
4576 // then we are in this situation.
4577 Error_CannotAccessProtected (ec, loc, best_candidate.MetaInfo, queried_type, ec.CurrentType);
4578 } else {
4579 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4580 ErrorIsInaccesible (loc, GetSignatureForError (), ec.Report);
4584 bool cand_params = candidate_to_form != null && candidate_to_form.ContainsKey (best_candidate);
4585 if (!VerifyArgumentsCompat (ec, ref Arguments, arg_count, best_candidate, cand_params, false, loc))
4586 return true;
4588 if (has_inaccessible_candidates_only)
4589 return true;
4592 return false;
4595 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4597 type_arguments = ta;
4600 public bool VerifyArgumentsCompat (ResolveContext ec, ref Arguments arguments,
4601 int arg_count, MethodSpec method,
4602 bool chose_params_expanded,
4603 bool may_fail, Location loc)
4605 AParametersCollection pd = method.Parameters;
4606 int param_count = GetApplicableParametersCount (method, pd);
4608 int errors = ec.Report.Errors;
4609 Parameter.Modifier p_mod = 0;
4610 Type pt = null;
4611 int a_idx = 0, a_pos = 0;
4612 Argument a = null;
4613 ArrayInitializer params_initializers = null;
4614 bool has_unsafe_arg = method.ReturnType.IsPointer;
4616 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4617 a = arguments [a_idx];
4618 if (p_mod != Parameter.Modifier.PARAMS) {
4619 p_mod = pd.FixedParameters [a_idx].ModFlags;
4620 pt = pd.Types [a_idx];
4621 has_unsafe_arg |= pt.IsPointer;
4623 if (p_mod == Parameter.Modifier.PARAMS) {
4624 if (chose_params_expanded) {
4625 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4626 pt = TypeManager.GetElementType (pt);
4632 // Types have to be identical when ref or out modifer is used
4634 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4635 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4636 break;
4638 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4639 break;
4641 continue;
4642 } else {
4643 NamedArgument na = a as NamedArgument;
4644 if (na != null) {
4645 int name_index = pd.GetParameterIndexByName (na.Name);
4646 if (name_index < 0 || name_index >= param_count) {
4647 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType)) {
4648 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4649 ec.Report.Error (1746, na.Location,
4650 "The delegate `{0}' does not contain a parameter named `{1}'",
4651 TypeManager.CSharpName (DeclaringType), na.Name);
4652 } else {
4653 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4654 ec.Report.Error (1739, na.Location,
4655 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4656 TypeManager.CSharpSignature (method.MetaInfo), na.Name);
4658 } else if (arguments[name_index] != a) {
4659 if (DeclaringType != null && TypeManager.IsDelegateType (DeclaringType))
4660 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
4661 else
4662 ec.Report.SymbolRelatedToPreviousError (best_candidate.MetaInfo);
4664 ec.Report.Error (1744, na.Location,
4665 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4666 na.Name);
4671 if (TypeManager.IsDynamicType (a.Expr.Type))
4672 continue;
4674 if (delegate_type != null && !Delegate.IsTypeCovariant (a.Expr, pt))
4675 break;
4677 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4678 if (conv == null)
4679 break;
4682 // Convert params arguments to an array initializer
4684 if (params_initializers != null) {
4685 // we choose to use 'a.Expr' rather than 'conv' so that
4686 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4687 params_initializers.Add (a.Expr);
4688 arguments.RemoveAt (a_idx--);
4689 --arg_count;
4690 continue;
4693 // Update the argument with the implicit conversion
4694 a.Expr = conv;
4697 if (a_idx != arg_count) {
4698 if (!may_fail && ec.Report.Errors == errors) {
4699 if (CustomErrorHandler != null)
4700 CustomErrorHandler.NoExactMatch (ec, best_candidate);
4701 else
4702 Error_InvalidArguments (ec, loc, a_pos, method, a, pd, pt);
4704 return false;
4708 // Fill not provided arguments required by params modifier
4710 if (params_initializers == null && pd.HasParams && arg_count + 1 == param_count) {
4711 if (arguments == null)
4712 arguments = new Arguments (1);
4714 pt = pd.Types [param_count - 1];
4715 pt = TypeManager.GetElementType (pt);
4716 has_unsafe_arg |= pt.IsPointer;
4717 params_initializers = new ArrayInitializer (0, loc);
4721 // Append an array argument with all params arguments
4723 if (params_initializers != null) {
4724 arguments.Add (new Argument (
4725 new ArrayCreation (new TypeExpression (pt, loc), "[]", params_initializers, loc).Resolve (ec)));
4726 arg_count++;
4729 if (arg_count < param_count) {
4730 if (!may_fail)
4731 Error_ArgumentCountWrong (ec, arg_count);
4732 return false;
4735 if (has_unsafe_arg && !ec.IsUnsafe) {
4736 if (!may_fail)
4737 UnsafeError (ec, loc);
4738 return false;
4741 return true;
4745 public class ConstantExpr : MemberExpr
4747 ConstSpec constant;
4749 public ConstantExpr (ConstSpec constant, Location loc)
4751 this.constant = constant;
4752 this.loc = loc;
4755 public override string Name {
4756 get { throw new NotImplementedException (); }
4759 public override bool IsInstance {
4760 get { return !IsStatic; }
4763 public override bool IsStatic {
4764 get { return true; }
4767 public override Type DeclaringType {
4768 get { return constant.DeclaringType; }
4771 public override Expression CreateExpressionTree (ResolveContext ec)
4773 throw new NotSupportedException ("ET");
4776 protected override Expression DoResolve (ResolveContext rc)
4778 constant.MemberDefinition.SetIsUsed ();
4780 if (!rc.IsObsolete) {
4781 var oa = constant.GetObsoleteAttribute ();
4782 if (oa != null)
4783 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (constant.MetaInfo), loc, rc.Report);
4786 // Constants are resolved on-demand
4787 var c = constant.Value.Resolve (rc) as Constant;
4789 // Creates reference expression to the constant value
4790 return Constant.CreateConstant (rc, c.Type, c.GetValue (), loc);
4793 public override void Emit (EmitContext ec)
4795 throw new NotSupportedException ();
4798 public override string GetSignatureForError ()
4800 return TypeManager.GetFullNameSignature (constant.MetaInfo);
4804 /// <summary>
4805 /// Fully resolved expression that evaluates to a Field
4806 /// </summary>
4807 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4808 protected FieldSpec spec;
4809 readonly Type constructed_generic_type;
4810 VariableInfo variable_info;
4812 LocalTemporary temp;
4813 bool prepared;
4815 protected FieldExpr (Location l)
4817 loc = l;
4820 public FieldExpr (FieldSpec spec, Location loc)
4822 this.spec = spec;
4823 this.loc = loc;
4825 type = TypeManager.TypeToCoreType (spec.FieldType);
4828 public FieldExpr (FieldBase fi, Location l)
4829 : this (fi.Spec, l)
4831 loc = l;
4834 public FieldExpr (Field fi, Type genericType, Location l)
4835 : this (fi, l)
4837 if (TypeManager.IsGenericTypeDefinition (genericType))
4838 return;
4839 this.constructed_generic_type = genericType;
4842 public override string Name {
4843 get {
4844 return spec.Name;
4848 public override bool IsInstance {
4849 get {
4850 return !spec.IsStatic;
4854 public override bool IsStatic {
4855 get {
4856 return spec.IsStatic;
4860 public FieldSpec Spec {
4861 get {
4862 return spec;
4866 public override Type DeclaringType {
4867 get {
4868 return spec.MetaInfo.DeclaringType;
4872 public override string GetSignatureForError ()
4874 return TypeManager.GetFullNameSignature (spec.MetaInfo);
4877 public VariableInfo VariableInfo {
4878 get {
4879 return variable_info;
4883 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
4884 SimpleName original)
4886 FieldInfo fi = TypeManager.GetGenericFieldDefinition (spec.MetaInfo);
4887 Type t = fi.FieldType;
4889 if (t.IsPointer && !ec.IsUnsafe) {
4890 UnsafeError (ec, loc);
4893 return base.ResolveMemberAccess (ec, left, loc, original);
4896 public void SetHasAddressTaken ()
4898 IVariableReference vr = InstanceExpression as IVariableReference;
4899 if (vr != null)
4900 vr.SetHasAddressTaken ();
4903 public override Expression CreateExpressionTree (ResolveContext ec)
4905 Expression instance;
4906 if (InstanceExpression == null) {
4907 instance = new NullLiteral (loc);
4908 } else {
4909 instance = InstanceExpression.CreateExpressionTree (ec);
4912 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4913 instance,
4914 CreateTypeOfExpression ());
4916 return CreateExpressionFactoryCall (ec, "Field", args);
4919 public Expression CreateTypeOfExpression ()
4921 return new TypeOfField (Import.CreateField (GetConstructedFieldInfo ()), loc);
4924 protected override Expression DoResolve (ResolveContext ec)
4926 return DoResolve (ec, false, false);
4929 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4931 if (!IsStatic){
4932 if (InstanceExpression == null){
4934 // This can happen when referencing an instance field using
4935 // a fully qualified type expression: TypeName.InstanceField = xxx
4937 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
4938 return null;
4941 // Resolve the field's instance expression while flow analysis is turned
4942 // off: when accessing a field "a.b", we must check whether the field
4943 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4945 if (lvalue_instance) {
4946 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4947 Expression right_side =
4948 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4950 if (InstanceExpression != EmptyExpression.Null)
4951 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4953 } else {
4954 if (InstanceExpression != EmptyExpression.Null) {
4955 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4956 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4961 if (InstanceExpression == null)
4962 return null;
4964 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4965 InstanceExpression.CheckMarshalByRefAccess (ec);
4969 if (!ec.IsObsolete) {
4970 FieldBase f = TypeManager.GetField (spec.MetaInfo);
4971 if (f != null) {
4972 f.CheckObsoleteness (loc);
4973 } else {
4974 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
4975 if (oa != null)
4976 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (spec.MetaInfo), loc, ec.Report);
4980 var fb = spec as FixedFieldSpec;
4981 IVariableReference var = InstanceExpression as IVariableReference;
4983 if (fb != null) {
4984 IFixedExpression fe = InstanceExpression as IFixedExpression;
4985 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4986 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4989 if (InstanceExpression.eclass != ExprClass.Variable) {
4990 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
4991 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4992 TypeManager.GetFullNameSignature (spec.MetaInfo));
4993 } else if (var != null && var.IsHoisted) {
4994 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4997 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5000 eclass = ExprClass.Variable;
5002 // If the instance expression is a local variable or parameter.
5003 if (var == null || var.VariableInfo == null)
5004 return this;
5006 VariableInfo vi = var.VariableInfo;
5007 if (!vi.IsFieldAssigned (ec, Name, loc))
5008 return null;
5010 variable_info = vi.GetSubStruct (Name);
5011 return this;
5014 static readonly int [] codes = {
5015 191, // instance, write access
5016 192, // instance, out access
5017 198, // static, write access
5018 199, // static, out access
5019 1648, // member of value instance, write access
5020 1649, // member of value instance, out access
5021 1650, // member of value static, write access
5022 1651 // member of value static, out access
5025 static readonly string [] msgs = {
5026 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5027 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5028 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5029 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5030 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5031 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5032 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5033 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5036 // The return value is always null. Returning a value simplifies calling code.
5037 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5039 int i = 0;
5040 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
5041 i += 1;
5042 if (IsStatic)
5043 i += 2;
5044 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5045 i += 4;
5046 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5048 return null;
5051 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5053 IVariableReference var = InstanceExpression as IVariableReference;
5054 if (var != null && var.VariableInfo != null)
5055 var.VariableInfo.SetFieldAssigned (ec, Name);
5057 bool lvalue_instance = !spec.IsStatic && TypeManager.IsValueType (spec.MetaInfo.DeclaringType);
5058 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
5060 Expression e = DoResolve (ec, lvalue_instance, out_access);
5062 if (e == null)
5063 return null;
5065 FieldBase fb = TypeManager.GetField (spec.MetaInfo);
5066 if (fb != null) {
5067 fb.SetAssigned ();
5069 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
5070 (fb.ModFlags & Modifiers.VOLATILE) != 0) {
5071 ec.Report.Warning (420, 1, loc,
5072 "`{0}': A volatile field references will not be treated as volatile",
5073 fb.GetSignatureForError ());
5077 if (spec.IsReadOnly) {
5078 // InitOnly fields can only be assigned in constructors or initializers
5079 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5080 return Report_AssignToReadonly (ec, right_side);
5082 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5083 Type ctype = ec.CurrentType;
5085 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5086 if (!TypeManager.IsEqual (ctype, DeclaringType))
5087 return Report_AssignToReadonly (ec, right_side);
5088 // static InitOnly fields cannot be assigned-to in an instance constructor
5089 if (IsStatic && !ec.IsStatic)
5090 return Report_AssignToReadonly (ec, right_side);
5091 // instance constructors can't modify InitOnly fields of other instances of the same type
5092 if (!IsStatic && !(InstanceExpression is This))
5093 return Report_AssignToReadonly (ec, right_side);
5097 if (right_side == EmptyExpression.OutAccess.Instance &&
5098 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type)) {
5099 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5100 ec.Report.Warning (197, 1, loc,
5101 "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",
5102 GetSignatureForError ());
5105 eclass = ExprClass.Variable;
5106 return this;
5109 bool is_marshal_by_ref ()
5111 return !IsStatic && TypeManager.IsStruct (Type) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (DeclaringType, TypeManager.mbr_type);
5114 public override void CheckMarshalByRefAccess (ResolveContext ec)
5116 if (is_marshal_by_ref () && !(InstanceExpression is This)) {
5117 ec.Report.SymbolRelatedToPreviousError (DeclaringType);
5118 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",
5119 GetSignatureForError ());
5123 public override int GetHashCode ()
5125 return spec.GetHashCode ();
5128 public bool IsFixed {
5129 get {
5131 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5133 IVariableReference variable = InstanceExpression as IVariableReference;
5134 if (variable != null)
5135 return TypeManager.IsStruct (InstanceExpression.Type) && variable.IsFixed;
5137 IFixedExpression fe = InstanceExpression as IFixedExpression;
5138 return fe != null && fe.IsFixed;
5142 public bool IsHoisted {
5143 get {
5144 IVariableReference hv = InstanceExpression as IVariableReference;
5145 return hv != null && hv.IsHoisted;
5149 public override bool Equals (object obj)
5151 FieldExpr fe = obj as FieldExpr;
5152 if (fe == null)
5153 return false;
5155 if (spec.MetaInfo != fe.spec.MetaInfo)
5156 return false;
5158 if (InstanceExpression == null || fe.InstanceExpression == null)
5159 return true;
5161 return InstanceExpression.Equals (fe.InstanceExpression);
5164 public void Emit (EmitContext ec, bool leave_copy)
5166 ILGenerator ig = ec.ig;
5167 bool is_volatile = false;
5169 var f = TypeManager.GetField (spec.MetaInfo);
5170 if (f != null){
5171 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5172 is_volatile = true;
5174 f.SetIsUsed ();
5177 if (IsStatic){
5178 if (is_volatile)
5179 ig.Emit (OpCodes.Volatile);
5181 ig.Emit (OpCodes.Ldsfld, GetConstructedFieldInfo ());
5182 } else {
5183 if (!prepared)
5184 EmitInstance (ec, false);
5186 // Optimization for build-in types
5187 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
5188 LoadFromPtr (ig, type);
5189 } else {
5190 var ff = spec as FixedFieldSpec;
5191 if (ff != null) {
5192 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5193 ig.Emit (OpCodes.Ldflda, ff.Element);
5194 } else {
5195 if (is_volatile)
5196 ig.Emit (OpCodes.Volatile);
5198 ig.Emit (OpCodes.Ldfld, GetConstructedFieldInfo ());
5203 if (leave_copy) {
5204 ec.ig.Emit (OpCodes.Dup);
5205 if (!IsStatic) {
5206 temp = new LocalTemporary (this.Type);
5207 temp.Store (ec);
5212 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5214 //FieldAttributes fa = FieldInfo.Attributes;
5215 //bool is_static = (fa & FieldAttributes.Static) != 0;
5216 ILGenerator ig = ec.ig;
5218 prepared = prepare_for_load;
5219 EmitInstance (ec, prepared);
5221 source.Emit (ec);
5222 if (leave_copy) {
5223 ec.ig.Emit (OpCodes.Dup);
5224 if (!IsStatic) {
5225 temp = new LocalTemporary (this.Type);
5226 temp.Store (ec);
5230 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5231 if (f != null){
5232 if ((f.ModFlags & Modifiers.VOLATILE) != 0)
5233 ig.Emit (OpCodes.Volatile);
5235 f.SetAssigned ();
5238 if (IsStatic)
5239 ig.Emit (OpCodes.Stsfld, GetConstructedFieldInfo ());
5240 else
5241 ig.Emit (OpCodes.Stfld, GetConstructedFieldInfo ());
5243 if (temp != null) {
5244 temp.Emit (ec);
5245 temp.Release (ec);
5246 temp = null;
5250 public override void Emit (EmitContext ec)
5252 Emit (ec, false);
5255 public override void EmitSideEffect (EmitContext ec)
5257 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5258 bool is_volatile = f != null && (f.ModFlags & Modifiers.VOLATILE) != 0;
5260 if (is_volatile || is_marshal_by_ref ())
5261 base.EmitSideEffect (ec);
5264 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
5266 r.Error (844, loc,
5267 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
5268 name, GetSignatureForError ());
5271 public void AddressOf (EmitContext ec, AddressOp mode)
5273 ILGenerator ig = ec.ig;
5275 FieldBase f = TypeManager.GetField (spec.MetaInfo);
5276 if (f != null){
5277 if ((mode & AddressOp.Store) != 0)
5278 f.SetAssigned ();
5279 if ((mode & AddressOp.Load) != 0)
5280 f.SetIsUsed ();
5284 // Handle initonly fields specially: make a copy and then
5285 // get the address of the copy.
5287 bool need_copy;
5288 if (spec.IsReadOnly){
5289 need_copy = true;
5290 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5291 if (IsStatic){
5292 if (ec.IsStatic)
5293 need_copy = false;
5294 } else
5295 need_copy = false;
5297 } else
5298 need_copy = false;
5300 if (need_copy){
5301 LocalBuilder local;
5302 Emit (ec);
5303 local = ig.DeclareLocal (type);
5304 ig.Emit (OpCodes.Stloc, local);
5305 ig.Emit (OpCodes.Ldloca, local);
5306 return;
5310 if (IsStatic){
5311 ig.Emit (OpCodes.Ldsflda, GetConstructedFieldInfo ());
5312 } else {
5313 if (!prepared)
5314 EmitInstance (ec, false);
5315 ig.Emit (OpCodes.Ldflda, GetConstructedFieldInfo ());
5319 FieldInfo GetConstructedFieldInfo ()
5321 if (constructed_generic_type == null)
5322 return spec.MetaInfo;
5324 return TypeBuilder.GetField (constructed_generic_type, spec.MetaInfo);
5327 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5329 return MakeExpression (ctx);
5332 public override SLE.Expression MakeExpression (BuilderContext ctx)
5334 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.MetaInfo);
5337 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5339 storey.MutateField (spec);
5340 base.MutateHoistedGenericType (storey);
5345 /// <summary>
5346 /// Expression that evaluates to a Property. The Assign class
5347 /// might set the `Value' expression if we are in an assignment.
5349 /// This is not an LValue because we need to re-write the expression, we
5350 /// can not take data from the stack and store it.
5351 /// </summary>
5352 public class PropertyExpr : MemberExpr, IDynamicAssign
5354 PropertySpec spec;
5355 MethodSpec getter, setter;
5356 bool is_static;
5358 TypeArguments targs;
5360 LocalTemporary temp;
5361 bool prepared;
5363 public PropertyExpr (Type container_type, PropertySpec spec, Location l)
5365 this.spec = spec;
5366 loc = l;
5368 type = TypeManager.TypeToCoreType (spec.PropertyType);
5370 ResolveAccessors (container_type);
5373 public override string Name {
5374 get {
5375 return spec.Name;
5379 public override bool IsInstance {
5380 get {
5381 return !is_static;
5385 public override bool IsStatic {
5386 get {
5387 return is_static;
5391 public override Expression CreateExpressionTree (ResolveContext ec)
5393 Arguments args;
5394 if (IsSingleDimensionalArrayLength ()) {
5395 args = new Arguments (1);
5396 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5397 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5400 if (is_base) {
5401 Error_BaseAccessInExpressionTree (ec, loc);
5402 return null;
5405 args = new Arguments (2);
5406 if (InstanceExpression == null)
5407 args.Add (new Argument (new NullLiteral (loc)));
5408 else
5409 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5410 args.Add (new Argument (new TypeOfMethod (getter, loc)));
5411 return CreateExpressionFactoryCall (ec, "Property", args);
5414 public Expression CreateSetterTypeOfExpression ()
5416 return new TypeOfMethod (setter, loc);
5419 public override Type DeclaringType {
5420 get {
5421 return spec.DeclaringType;
5425 public override string GetSignatureForError ()
5427 return TypeManager.GetFullNameSignature (spec.MetaInfo);
5430 void FindAccessors (Type invocation_type)
5432 const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
5433 BindingFlags.Static | BindingFlags.Instance |
5434 BindingFlags.DeclaredOnly;
5436 Type current = spec.DeclaringType;
5437 for (; current != null; current = current.BaseType) {
5438 MemberInfo[] group = TypeManager.MemberLookup (
5439 invocation_type, invocation_type, current,
5440 MemberTypes.Property, flags, spec.Name, null);
5442 if (group == null)
5443 continue;
5445 if (group.Length != 1)
5446 // Oooops, can this ever happen ?
5447 return;
5449 PropertyInfo pi = (PropertyInfo) group [0];
5451 if (getter == null) {
5452 var m = pi.GetGetMethod (true);
5453 if (m != null)
5454 getter = Import.CreateMethod (m);
5457 if (setter == null) {
5458 var m = pi.GetSetMethod (true);
5459 if (m != null)
5460 setter = Import.CreateMethod (m);
5463 var accessor = getter != null ? getter : setter;
5465 if (!accessor.IsVirtual)
5466 return;
5471 // We also perform the permission checking here, as the PropertyInfo does not
5472 // hold the information for the accessibility of its setter/getter
5474 // TODO: Refactor to use some kind of cache together with GetPropertyFromAccessor
5475 void ResolveAccessors (Type container_type)
5477 FindAccessors (container_type);
5479 if (getter != null) {
5480 MethodBase the_getter = TypeManager.DropGenericMethodArguments (getter);
5481 IMethodData md = TypeManager.GetMethod (the_getter);
5482 if (md != null)
5483 md.SetIsUsed ();
5485 is_static = getter.IsStatic;
5488 if (setter != null) {
5489 MethodBase the_setter = TypeManager.DropGenericMethodArguments (setter);
5490 IMethodData md = TypeManager.GetMethod (the_setter);
5491 if (md != null)
5492 md.SetIsUsed ();
5494 is_static = setter.IsStatic;
5498 public SLE.Expression MakeAssignExpression (BuilderContext ctx)
5500 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) setter.MetaInfo);
5503 public override SLE.Expression MakeExpression (BuilderContext ctx)
5505 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) getter.MetaInfo);
5508 public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
5510 if (InstanceExpression != null)
5511 InstanceExpression.MutateHoistedGenericType (storey);
5513 type = storey.MutateType (type);
5514 if (getter != null)
5515 storey.MutateGenericMethod (getter);
5516 if (setter != null)
5517 storey.MutateGenericMethod (setter);
5520 public PropertyInfo PropertyInfo {
5521 get {
5522 return spec.MetaInfo;
5526 bool InstanceResolve (ResolveContext ec, bool lvalue_instance, bool must_do_cs1540_check)
5528 if (is_static) {
5529 InstanceExpression = null;
5530 return true;
5533 if (InstanceExpression == null) {
5534 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5535 return false;
5538 InstanceExpression = InstanceExpression.Resolve (ec);
5539 if (lvalue_instance && InstanceExpression != null)
5540 InstanceExpression = InstanceExpression.ResolveLValue (ec, EmptyExpression.LValueMemberAccess);
5542 if (InstanceExpression == null)
5543 return false;
5545 InstanceExpression.CheckMarshalByRefAccess (ec);
5547 if (must_do_cs1540_check && (InstanceExpression != EmptyExpression.Null) &&
5548 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5549 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5550 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5551 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5552 Error_CannotAccessProtected (ec, loc, spec.MetaInfo, InstanceExpression.Type, ec.CurrentType);
5553 return false;
5556 return true;
5559 void Error_PropertyNotFound (ResolveContext ec, MethodSpec mi, bool getter)
5561 // TODO: correctly we should compare arguments but it will lead to bigger changes
5562 if (mi.MetaInfo is MethodBuilder) {
5563 Error_TypeDoesNotContainDefinition (ec, loc, spec.DeclaringType, Name);
5564 return;
5567 StringBuilder sig = new StringBuilder (TypeManager.CSharpName (mi.DeclaringType));
5568 sig.Append ('.');
5569 AParametersCollection iparams = mi.Parameters;
5570 sig.Append (getter ? "get_" : "set_");
5571 sig.Append (Name);
5572 sig.Append (iparams.GetSignatureForError ());
5574 ec.Report.SymbolRelatedToPreviousError (mi.MetaInfo);
5575 ec.Report.Error (1546, loc, "Property `{0}' is not supported by the C# language. Try to call the accessor method `{1}' directly",
5576 Name, sig.ToString ());
5579 public bool IsAccessibleFrom (Type invocation_type, bool lvalue)
5581 bool dummy;
5582 var accessor = lvalue ? setter : getter;
5583 if (accessor == null && lvalue)
5584 accessor = getter;
5585 return accessor != null && IsAccessorAccessible (invocation_type, accessor, out dummy);
5588 bool IsSingleDimensionalArrayLength ()
5590 if (DeclaringType != TypeManager.array_type || getter == null || Name != "Length")
5591 return false;
5593 string t_name = InstanceExpression.Type.Name;
5594 int t_name_len = t_name.Length;
5595 return t_name_len > 2 && t_name [t_name_len - 2] == '[';
5598 protected override Expression DoResolve (ResolveContext ec)
5600 eclass = ExprClass.PropertyAccess;
5602 bool must_do_cs1540_check = false;
5603 ec.Report.DisableReporting ();
5604 bool res = ResolveGetter (ec, ref must_do_cs1540_check);
5605 ec.Report.EnableReporting ();
5607 if (!res) {
5608 if (InstanceExpression != null) {
5609 Type expr_type = InstanceExpression.Type;
5610 ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, loc);
5611 if (ex_method_lookup != null) {
5612 ex_method_lookup.ExtensionExpression = InstanceExpression;
5613 ex_method_lookup.SetTypeArguments (ec, targs);
5614 return ex_method_lookup.Resolve (ec);
5618 ResolveGetter (ec, ref must_do_cs1540_check);
5619 return null;
5622 if (!InstanceResolve (ec, false, must_do_cs1540_check))
5623 return null;
5626 // Only base will allow this invocation to happen.
5628 if (IsBase && getter.IsAbstract) {
5629 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5632 if (spec.PropertyType.IsPointer && !ec.IsUnsafe){
5633 UnsafeError (ec, loc);
5636 if (!ec.IsObsolete) {
5637 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5638 if (pb != null) {
5639 pb.CheckObsoleteness (loc);
5640 } else {
5641 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5642 if (oa != null)
5643 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5647 return this;
5650 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5652 eclass = ExprClass.PropertyAccess;
5654 if (right_side == EmptyExpression.OutAccess.Instance) {
5655 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5656 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5657 spec.Name);
5658 } else {
5659 right_side.DoResolveLValue (ec, this);
5661 return null;
5664 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5665 Error_CannotModifyIntermediateExpressionValue (ec);
5668 if (setter == null){
5670 // The following condition happens if the PropertyExpr was
5671 // created, but is invalid (ie, the property is inaccessible),
5672 // and we did not want to embed the knowledge about this in
5673 // the caller routine. This only avoids double error reporting.
5675 if (getter == null)
5676 return null;
5678 if (ec.CurrentBlock.Toplevel.GetParameterReference (spec.Name, loc) is MemberAccess) {
5679 ec.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5680 spec.Name);
5681 } else {
5682 ec.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read only)",
5683 GetSignatureForError ());
5685 return null;
5688 if (targs != null) {
5689 base.SetTypeArguments (ec, targs);
5690 return null;
5693 if (setter.Parameters.Count != 1){
5694 Error_PropertyNotFound (ec, setter, false);
5695 return null;
5698 bool must_do_cs1540_check;
5699 if (!IsAccessorAccessible (ec.CurrentType, setter, out must_do_cs1540_check)) {
5700 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (setter.MetaInfo) as PropertyBase.PropertyMethod;
5701 if (pm != null && pm.HasCustomAccessModifier) {
5702 ec.Report.SymbolRelatedToPreviousError (pm);
5703 ec.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5704 TypeManager.CSharpSignature (setter));
5706 else {
5707 ec.Report.SymbolRelatedToPreviousError (setter.MetaInfo);
5708 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (setter), ec.Report);
5710 return null;
5713 if (!InstanceResolve (ec, TypeManager.IsStruct (spec.DeclaringType), must_do_cs1540_check))
5714 return null;
5717 // Only base will allow this invocation to happen.
5719 if (IsBase && setter.IsAbstract){
5720 Error_CannotCallAbstractBase (ec, TypeManager.GetFullNameSignature (spec.MetaInfo));
5723 if (spec.PropertyType.IsPointer && !ec.IsUnsafe) {
5724 UnsafeError (ec, loc);
5727 if (!ec.IsObsolete) {
5728 PropertyBase pb = TypeManager.GetProperty (spec.MetaInfo);
5729 if (pb != null) {
5730 pb.CheckObsoleteness (loc);
5731 } else {
5732 ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (spec.MetaInfo);
5733 if (oa != null)
5734 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
5738 return this;
5741 public override void Emit (EmitContext ec)
5743 Emit (ec, false);
5746 public void Emit (EmitContext ec, bool leave_copy)
5749 // Special case: length of single dimension array property is turned into ldlen
5751 if (IsSingleDimensionalArrayLength ()) {
5752 if (!prepared)
5753 EmitInstance (ec, false);
5754 ec.ig.Emit (OpCodes.Ldlen);
5755 ec.ig.Emit (OpCodes.Conv_I4);
5756 return;
5759 Invocation.EmitCall (ec, IsBase, InstanceExpression, getter, null, loc, prepared, false);
5761 if (leave_copy) {
5762 ec.ig.Emit (OpCodes.Dup);
5763 if (!is_static) {
5764 temp = new LocalTemporary (this.Type);
5765 temp.Store (ec);
5771 // Implements the IAssignMethod interface for assignments
5773 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5775 Expression my_source = source;
5777 if (prepare_for_load) {
5778 prepared = true;
5779 source.Emit (ec);
5781 if (leave_copy) {
5782 ec.ig.Emit (OpCodes.Dup);
5783 if (!is_static) {
5784 temp = new LocalTemporary (this.Type);
5785 temp.Store (ec);
5788 } else if (leave_copy) {
5789 source.Emit (ec);
5790 temp = new LocalTemporary (this.Type);
5791 temp.Store (ec);
5792 my_source = temp;
5795 Arguments args = new Arguments (1);
5796 args.Add (new Argument (my_source));
5798 Invocation.EmitCall (ec, IsBase, InstanceExpression, setter, args, loc, false, prepared);
5800 if (temp != null) {
5801 temp.Emit (ec);
5802 temp.Release (ec);
5806 bool ResolveGetter (ResolveContext ec, ref bool must_do_cs1540_check)
5808 if (targs != null) {
5809 base.SetTypeArguments (ec, targs);
5810 return false;
5813 if (getter != null) {
5814 if (!getter.Parameters.IsEmpty) {
5815 Error_PropertyNotFound (ec, getter, true);
5816 return false;
5820 if (getter == null) {
5822 // The following condition happens if the PropertyExpr was
5823 // created, but is invalid (ie, the property is inaccessible),
5824 // and we did not want to embed the knowledge about this in
5825 // the caller routine. This only avoids double error reporting.
5827 if (setter == null)
5828 return false;
5830 if (InstanceExpression != EmptyExpression.Null) {
5831 ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5832 TypeManager.GetFullNameSignature (spec.MetaInfo));
5833 return false;
5837 if (getter != null &&
5838 !IsAccessorAccessible (ec.CurrentType, getter, out must_do_cs1540_check)) {
5839 PropertyBase.PropertyMethod pm = TypeManager.GetMethod (getter.MetaInfo) as PropertyBase.PropertyMethod;
5840 if (pm != null && pm.HasCustomAccessModifier) {
5841 ec.Report.SymbolRelatedToPreviousError (pm);
5842 ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5843 TypeManager.CSharpSignature (getter.MetaInfo));
5844 } else {
5845 ec.Report.SymbolRelatedToPreviousError (getter.MetaInfo);
5846 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (getter.MetaInfo), ec.Report);
5849 return false;
5852 return true;
5855 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5857 targs = ta;
5861 /// <summary>
5862 /// Fully resolved expression that evaluates to an Event
5863 /// </summary>
5864 public class EventExpr : MemberExpr
5866 readonly EventSpec spec;
5868 public EventExpr (EventSpec spec, Location loc)
5870 this.spec = spec;
5871 this.loc = loc;
5874 public override string Name {
5875 get {
5876 return spec.Name;
5880 public override bool IsInstance {
5881 get {
5882 return !spec.IsStatic;
5886 public override bool IsStatic {
5887 get {
5888 return spec.IsStatic;
5892 public override Type DeclaringType {
5893 get {
5894 return spec.DeclaringType;
5898 public void Error_AssignmentEventOnly (ResolveContext ec)
5900 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5901 GetSignatureForError ());
5904 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, Location loc,
5905 SimpleName original)
5908 // If the event is local to this class, we transform ourselves into a FieldExpr
5911 if (spec.DeclaringType == ec.CurrentType ||
5912 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5914 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5915 EventField mi = TypeManager.GetEventField (spec.MetaInfo).MemberDefinition as EventField;
5917 if (mi != null && mi.HasBackingField) {
5918 mi.SetIsUsed ();
5919 if (!ec.IsObsolete)
5920 mi.CheckObsoleteness (loc);
5922 if ((mi.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5923 Error_AssignmentEventOnly (ec);
5925 FieldExpr ml = new FieldExpr (mi.BackingField, loc);
5927 InstanceExpression = null;
5929 return ml.ResolveMemberAccess (ec, left, loc, original);
5933 if (left is This && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5934 Error_AssignmentEventOnly (ec);
5936 return base.ResolveMemberAccess (ec, left, loc, original);
5939 bool InstanceResolve (ResolveContext ec, bool must_do_cs1540_check)
5941 if (IsStatic) {
5942 InstanceExpression = null;
5943 return true;
5946 if (InstanceExpression == null) {
5947 SimpleName.Error_ObjectRefRequired (ec, loc, GetSignatureForError ());
5948 return false;
5951 InstanceExpression = InstanceExpression.Resolve (ec);
5952 if (InstanceExpression == null)
5953 return false;
5955 if (IsBase && spec.IsAbstract) {
5956 Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature(spec.MetaInfo));
5957 return false;
5961 // This is using the same mechanism as the CS1540 check in PropertyExpr.
5962 // However, in the Event case, we reported a CS0122 instead.
5964 // TODO: Exact copy from PropertyExpr
5966 if (must_do_cs1540_check && InstanceExpression != EmptyExpression.Null &&
5967 !TypeManager.IsInstantiationOfSameGenericType (InstanceExpression.Type, ec.CurrentType) &&
5968 !TypeManager.IsNestedChildOf (ec.CurrentType, InstanceExpression.Type) &&
5969 !TypeManager.IsSubclassOf (InstanceExpression.Type, ec.CurrentType)) {
5970 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
5971 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
5972 return false;
5975 return true;
5978 public bool IsAccessibleFrom (Type invocation_type)
5980 bool dummy;
5981 return IsAccessorAccessible (invocation_type, spec.AccessorAdd, out dummy) &&
5982 IsAccessorAccessible (invocation_type, spec.AccessorRemove, out dummy);
5985 public override Expression CreateExpressionTree (ResolveContext ec)
5987 throw new NotSupportedException ("ET");
5990 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5992 // contexts where an LValue is valid have already devolved to FieldExprs
5993 Error_CannotAssign (ec);
5994 return null;
5997 protected override Expression DoResolve (ResolveContext ec)
5999 eclass = ExprClass.EventAccess;
6001 bool must_do_cs1540_check;
6002 if (!(IsAccessorAccessible (ec.CurrentType, spec.AccessorAdd, out must_do_cs1540_check) &&
6003 IsAccessorAccessible (ec.CurrentType, spec.AccessorRemove, out must_do_cs1540_check))) {
6004 ec.Report.SymbolRelatedToPreviousError (spec.MetaInfo);
6005 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec.MetaInfo), ec.Report);
6006 return null;
6009 if (!InstanceResolve (ec, must_do_cs1540_check))
6010 return null;
6012 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6013 Error_CannotAssign (ec);
6014 return null;
6017 if (!ec.IsObsolete) {
6018 var oa = spec.GetObsoleteAttribute ();
6019 if (oa != null)
6020 AttributeTester.Report_ObsoleteMessage (oa, GetSignatureForError (), loc, ec.Report);
6023 spec.MemberDefinition.SetIsUsed ();
6024 type = spec.EventType;
6026 return this;
6029 public override void Emit (EmitContext ec)
6031 throw new NotSupportedException ();
6032 //Error_CannotAssign ();
6035 public void Error_CannotAssign (ResolveContext ec)
6037 ec.Report.Error (70, loc,
6038 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6039 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
6042 public override string GetSignatureForError ()
6044 return TypeManager.CSharpSignature (spec.MetaInfo);
6047 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
6049 Arguments args = new Arguments (1);
6050 args.Add (new Argument (source));
6051 Invocation.EmitCall (ec, IsBase, InstanceExpression,
6052 is_add ? spec.AccessorAdd : spec.AccessorRemove,
6053 args, loc);
6057 public class TemporaryVariable : VariableReference
6059 LocalInfo li;
6061 public TemporaryVariable (Type type, Location loc)
6063 this.type = type;
6064 this.loc = loc;
6067 public override Expression CreateExpressionTree (ResolveContext ec)
6069 throw new NotSupportedException ("ET");
6072 protected override Expression DoResolve (ResolveContext ec)
6074 eclass = ExprClass.Variable;
6076 TypeExpr te = new TypeExpression (type, loc);
6077 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
6078 if (!li.Resolve (ec))
6079 return null;
6082 // Don't capture temporary variables except when using
6083 // iterator redirection
6085 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6086 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6087 storey.CaptureLocalVariable (ec, li);
6090 return this;
6093 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6095 return Resolve (ec);
6098 public override void Emit (EmitContext ec)
6100 Emit (ec, false);
6103 public void EmitAssign (EmitContext ec, Expression source)
6105 EmitAssign (ec, source, false, false);
6108 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6110 return li.HoistedVariant;
6113 public override bool IsFixed {
6114 get { return true; }
6117 public override bool IsRef {
6118 get { return false; }
6121 public override string Name {
6122 get { throw new NotImplementedException (); }
6125 public override void SetHasAddressTaken ()
6127 throw new NotImplementedException ();
6130 protected override ILocalVariable Variable {
6131 get { return li; }
6134 public override VariableInfo VariableInfo {
6135 get { throw new NotImplementedException (); }
6139 ///
6140 /// Handles `var' contextual keyword; var becomes a keyword only
6141 /// if no type called var exists in a variable scope
6142 ///
6143 class VarExpr : SimpleName
6145 // Used for error reporting only
6146 int initializers_count;
6148 public VarExpr (Location loc)
6149 : base ("var", loc)
6151 initializers_count = 1;
6154 public int VariableInitializersCount {
6155 set {
6156 this.initializers_count = value;
6160 public bool InferType (ResolveContext ec, Expression right_side)
6162 if (type != null)
6163 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6165 type = right_side.Type;
6166 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6167 ec.Report.Error (815, loc, "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6168 right_side.GetSignatureForError ());
6169 return false;
6172 eclass = ExprClass.Variable;
6173 return true;
6176 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6178 if (RootContext.Version < LanguageVersion.V_3)
6179 base.Error_TypeOrNamespaceNotFound (ec);
6180 else
6181 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
6184 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
6186 TypeExpr te = base.ResolveAsContextualType (rc, true);
6187 if (te != null)
6188 return te;
6190 if (RootContext.Version < LanguageVersion.V_3)
6191 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
6193 if (initializers_count == 1)
6194 return null;
6196 if (initializers_count > 1) {
6197 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
6198 initializers_count = 1;
6199 return null;
6202 if (initializers_count == 0) {
6203 initializers_count = 1;
6204 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");
6205 return null;
6208 return null;