2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
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,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
67 // This is just as a hint to AddressOf of what will be done with the
70 public enum AddressOp {
77 /// This interface is implemented by variables
79 public interface IMemoryLocation {
81 /// The AddressOf method should generate code that loads
82 /// the address of the object and leaves it on the stack.
84 /// The `mode' argument is used to notify the expression
85 /// of whether this will be used to read from the address or
86 /// write to the address.
88 /// This is just a hint that can be used to provide good error
89 /// reporting, and should have no other side effects.
91 void AddressOf (EmitContext ec, AddressOp mode);
95 // An expressions resolved as a direct variable reference
97 public interface IVariableReference : IFixedExpression
99 bool IsHoisted { get; }
101 VariableInfo VariableInfo { get; }
103 void SetHasAddressTaken ();
107 // Implemented by an expression which could be or is always
110 public interface IFixedExpression
112 bool IsFixed { get; }
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
120 protected TypeSpec type;
121 protected Location loc;
123 public TypeSpec Type {
125 set { type = value; }
128 public Location Location {
132 // Not nice but we have broken hierarchy.
133 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public virtual bool IsNull {
149 /// Performs semantic analysis on the Expression
153 /// The Resolve method is invoked to perform the semantic analysis
156 /// The return value is an expression (it can be the
157 /// same expression in some cases) or a new
158 /// expression that better represents this node.
160 /// For example, optimizations of Unary (LiteralInt)
161 /// would return a new LiteralInt with a negated
164 /// If there is an error during semantic analysis,
165 /// then an error should be reported (using Report)
166 /// and a null value should be returned.
168 /// There are two side effects expected from calling
169 /// Resolve(): the the field variable "eclass" should
170 /// be set to any value of the enumeration
171 /// `ExprClass' and the type variable should be set
172 /// to a valid type (this is the type of the
175 protected abstract Expression DoResolve (ResolveContext rc);
177 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
183 // This is used if the expression should be resolved as a type or namespace name.
184 // the default implementation fails.
186 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
189 ResolveContext ec = new ResolveContext (rc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
199 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
200 // same name exists or as a keyword when no type was found
202 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
204 return ResolveAsTypeTerminal (rc, silent);
208 // This is used to resolve the expression as a type, a null
209 // value will be returned if the expression is not a type
212 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
214 int errors = ec.Compiler.Report.Errors;
216 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
221 TypeExpr te = fne as TypeExpr;
223 if (!silent && errors == ec.Compiler.Report.Errors)
224 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
228 if (!te.CheckAccessLevel (ec)) {
229 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
230 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
236 // Obsolete checks cannot be done when resolving base context as they
237 // require type dependecies to be set but we are just resolving them
239 if (!silent && !(ec is TypeContainer.BaseContext)) {
240 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
241 if (obsolete_attr != null && !ec.IsObsolete) {
242 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
249 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
251 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
254 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
256 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
259 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
261 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
262 name, TypeManager.CSharpName (type));
265 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
267 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
268 "expressions can be used as a statement");
271 public void Error_InvalidExpressionStatement (BlockContext ec)
273 Error_InvalidExpressionStatement (ec.Report, loc);
276 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
278 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
281 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
283 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
286 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
288 // The error was already reported as CS1660
289 if (type == InternalType.AnonymousMethod)
293 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
294 string sig1 = type.DeclaringMethod == null ?
295 TypeManager.CSharpName (type.DeclaringType) :
296 TypeManager.CSharpSignature (type.DeclaringMethod);
297 string sig2 = target.DeclaringMethod == null ?
298 TypeManager.CSharpName (target.DeclaringType) :
299 TypeManager.CSharpSignature (target.DeclaringMethod);
300 ec.Report.ExtraInformation (loc,
302 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
303 Type.Name, sig1, sig2));
304 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
305 ec.Report.ExtraInformation (loc,
307 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
308 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
312 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
313 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
317 ec.Report.DisableReporting ();
318 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
319 ec.Report.EnableReporting ();
322 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
323 "An explicit conversion exists (are you missing a cast?)",
324 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
328 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
329 type.GetSignatureForError (), target.GetSignatureForError ());
332 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
334 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
337 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
339 // Better message for possible generic expressions
340 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
341 report.SymbolRelatedToPreviousError (member);
342 if (member is TypeSpec)
343 member = ((TypeSpec) member).GetDefinition ();
345 member = ((MethodSpec) member).GetGenericMethodDefinition ();
347 string name = member.Kind == MemberKind.Method ? "method" : "type";
348 if (member.IsGeneric) {
349 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
350 name, member.GetSignatureForError (), member.Arity.ToString ());
352 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
353 name, member.GetSignatureForError ());
356 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
360 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
362 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
366 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
368 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
371 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
373 ec.Report.SymbolRelatedToPreviousError (type);
374 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
375 TypeManager.CSharpName (type), name);
378 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
380 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
383 public ResolveFlags ExprClassToResolveFlags {
387 case ExprClass.Namespace:
388 return ResolveFlags.Type;
390 case ExprClass.MethodGroup:
391 return ResolveFlags.MethodGroup;
393 case ExprClass.TypeParameter:
394 return ResolveFlags.TypeParameter;
396 case ExprClass.Value:
397 case ExprClass.Variable:
398 case ExprClass.PropertyAccess:
399 case ExprClass.EventAccess:
400 case ExprClass.IndexerAccess:
401 return ResolveFlags.VariableOrValue;
404 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
410 /// Resolves an expression and performs semantic analysis on it.
414 /// Currently Resolve wraps DoResolve to perform sanity
415 /// checking and assertion checking on what we expect from Resolve.
417 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
419 if (eclass != ExprClass.Unresolved)
429 if ((flags & e.ExprClassToResolveFlags) == 0) {
430 e.Error_UnexpectedKind (ec, flags, loc);
435 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
438 } catch (Exception ex) {
439 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
442 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
443 return EmptyExpression.Null;
448 /// Resolves an expression and performs semantic analysis on it.
450 public Expression Resolve (ResolveContext rc)
452 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
456 /// Resolves an expression for LValue assignment
460 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
461 /// checking and assertion checking on what we expect from Resolve
463 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
465 int errors = ec.Report.Errors;
466 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
468 Expression e = DoResolveLValue (ec, right_side);
470 if (e != null && out_access && !(e is IMemoryLocation)) {
471 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
472 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
474 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
475 // e.GetType () + " " + e.GetSignatureForError ());
480 if (errors == ec.Report.Errors) {
482 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
484 Error_ValueAssignment (ec, loc);
489 if (e.eclass == ExprClass.Unresolved)
490 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
492 if ((e.type == null) && !(e is GenericTypeExpr))
493 throw new Exception ("Expression " + e + " did not set its type after Resolve");
498 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
500 Attribute.Error_AttributeArgumentNotValid (rc, loc);
504 /// Emits the code for the expression
508 /// The Emit method is invoked to generate the code
509 /// for the expression.
511 public abstract void Emit (EmitContext ec);
514 // Emit code to branch to @target if this expression is equivalent to @on_true.
515 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
516 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
517 // including the use of conditional branches. Note also that a branch MUST be emitted
518 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
521 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
524 // Emit this expression for its side effects, not for its value.
525 // The default implementation is to emit the value, and then throw it away.
526 // Subclasses can provide more efficient implementations, but those MUST be equivalent
527 public virtual void EmitSideEffect (EmitContext ec)
530 ec.Emit (OpCodes.Pop);
534 /// Protected constructor. Only derivate types should
535 /// be able to be created
538 protected Expression ()
543 /// Returns a fully formed expression after a MemberLookup
546 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
548 if (spec is EventSpec)
549 return new EventExpr ((EventSpec) spec, loc);
550 if (spec is ConstSpec)
551 return new ConstantExpr ((ConstSpec) spec, loc);
552 if (spec is FieldSpec)
553 return new FieldExpr ((FieldSpec) spec, loc);
554 if (spec is PropertySpec)
555 return new PropertyExpr ((PropertySpec) spec, loc);
556 if (spec is TypeSpec)
557 return new TypeExpression (((TypeSpec) spec), loc);
562 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
564 var ctors = MemberCache.FindMembers (type, ConstructorInfo.ConstructorName, true);
566 rc.Report.SymbolRelatedToPreviousError (type);
568 // Report meaningful error for struct as they always have default ctor in C# context
569 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
571 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
572 type.GetSignatureForError ());
578 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
579 return r.ResolveMember<MethodSpec> (rc, ref args);
583 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
584 // `qualifier_type' or null to lookup members in the current class.
586 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, bool invocableOnly, Location loc)
588 var members = MemberCache.FindMembers (queried_type, name, false);
592 MemberSpec non_method = null;
593 MemberSpec ambig_non_method = null;
594 currentType = currentType ?? InternalType.FakeInternalType;
596 for (int i = 0; i < members.Count; ++i) {
597 var member = members[i];
599 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
600 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
603 if (arity > 0 && member.Arity != arity)
606 if (rc != null && !member.IsAccessible (currentType))
610 if (member is MethodSpec)
611 return new MethodGroupExpr (members, queried_type, loc);
613 if (!Invocation.IsMemberInvocable (member))
617 if (non_method == null || member is MethodSpec) {
619 } else if (currentType != null) {
620 ambig_non_method = member;
624 if (non_method != null) {
625 if (ambig_non_method != null && rc != null) {
626 rc.Report.SymbolRelatedToPreviousError (non_method);
627 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
628 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
629 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
632 if (non_method is MethodSpec)
633 return new MethodGroupExpr (members, queried_type, loc);
635 return ExprClassFromMemberInfo (non_method, loc);
638 if (members[0].DeclaringType.BaseType == null)
641 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
643 } while (members != null);
648 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
650 throw new NotImplementedException ();
653 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
655 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
659 /// Returns an expression that can be used to invoke operator true
660 /// on the expression if it exists.
662 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
664 return GetOperatorTrueOrFalse (ec, e, true, loc);
668 /// Returns an expression that can be used to invoke operator false
669 /// on the expression if it exists.
671 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
673 return GetOperatorTrueOrFalse (ec, e, false, loc);
676 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
678 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
679 var methods = MemberCache.GetUserOperator (e.type, op, false);
683 Arguments arguments = new Arguments (1);
684 arguments.Add (new Argument (e));
686 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
687 var oper = res.ResolveOperator (ec, ref arguments);
692 return new UserOperatorCall (oper, arguments, null, loc);
695 public virtual string ExprClassName
699 case ExprClass.Unresolved:
701 case ExprClass.Value:
703 case ExprClass.Variable:
705 case ExprClass.Namespace:
709 case ExprClass.MethodGroup:
710 return "method group";
711 case ExprClass.PropertyAccess:
712 return "property access";
713 case ExprClass.EventAccess:
714 return "event access";
715 case ExprClass.IndexerAccess:
716 return "indexer access";
717 case ExprClass.Nothing:
719 case ExprClass.TypeParameter:
720 return "type parameter";
722 throw new Exception ("Should not happen");
727 /// Reports that we were expecting `expr' to be of class `expected'
729 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
731 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
734 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
738 name = mc.GetSignatureForError ();
740 name = GetSignatureForError ();
742 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
743 name, was, expected);
746 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
748 string [] valid = new string [4];
751 if ((flags & ResolveFlags.VariableOrValue) != 0) {
752 valid [count++] = "variable";
753 valid [count++] = "value";
756 if ((flags & ResolveFlags.Type) != 0)
757 valid [count++] = "type";
759 if ((flags & ResolveFlags.MethodGroup) != 0)
760 valid [count++] = "method group";
763 valid [count++] = "unknown";
765 StringBuilder sb = new StringBuilder (valid [0]);
766 for (int i = 1; i < count - 1; i++) {
768 sb.Append (valid [i]);
771 sb.Append ("' or `");
772 sb.Append (valid [count - 1]);
775 ec.Report.Error (119, loc,
776 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
779 public static void UnsafeError (ResolveContext ec, Location loc)
781 UnsafeError (ec.Report, loc);
784 public static void UnsafeError (Report Report, Location loc)
786 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
791 // Returns the size of type `t' if known, otherwise, 0
793 public static int GetTypeSize (TypeSpec t)
795 if (t == TypeManager.int32_type ||
796 t == TypeManager.uint32_type ||
797 t == TypeManager.float_type)
799 else if (t == TypeManager.int64_type ||
800 t == TypeManager.uint64_type ||
801 t == TypeManager.double_type)
803 else if (t == TypeManager.byte_type ||
804 t == TypeManager.sbyte_type ||
805 t == TypeManager.bool_type)
807 else if (t == TypeManager.short_type ||
808 t == TypeManager.char_type ||
809 t == TypeManager.ushort_type)
811 else if (t == TypeManager.decimal_type)
817 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
819 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
822 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
824 ec.Report.SymbolRelatedToPreviousError (type);
825 if (ec.CurrentInitializerVariable != null) {
826 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
827 TypeManager.CSharpName (type), GetSignatureForError ());
829 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
830 GetSignatureForError ());
835 // Converts `source' to an int, uint, long or ulong.
837 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
839 if (source.type == InternalType.Dynamic) {
840 Arguments args = new Arguments (1);
841 args.Add (new Argument (source));
842 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
845 Expression converted;
847 using (ec.Set (ResolveContext.Options.CheckedScope)) {
848 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
849 if (converted == null)
850 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
851 if (converted == null)
852 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
853 if (converted == null)
854 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
856 if (converted == null) {
857 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
863 // Only positive constants are allowed at compile time
865 Constant c = converted as Constant;
866 if (c != null && c.IsNegative)
867 Error_NegativeArrayIndex (ec, source.loc);
869 // No conversion needed to array index
870 if (converted.Type == TypeManager.int32_type)
873 return new ArrayIndexCast (converted).Resolve (ec);
877 // Derived classes implement this method by cloning the fields that
878 // could become altered during the Resolve stage
880 // Only expressions that are created for the parser need to implement
883 protected virtual void CloneTo (CloneContext clonectx, Expression target)
885 throw new NotImplementedException (
887 "CloneTo not implemented for expression {0}", this.GetType ()));
891 // Clones an expression created by the parser.
893 // We only support expressions created by the parser so far, not
894 // expressions that have been resolved (many more classes would need
895 // to implement CloneTo).
897 // This infrastructure is here merely for Lambda expressions which
898 // compile the same code using different type values for the same
899 // arguments to find the correct overload
901 public Expression Clone (CloneContext clonectx)
903 Expression cloned = (Expression) MemberwiseClone ();
904 CloneTo (clonectx, cloned);
910 // Implementation of expression to expression tree conversion
912 public abstract Expression CreateExpressionTree (ResolveContext ec);
914 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
916 return CreateExpressionFactoryCall (ec, name, null, args, loc);
919 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
921 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
924 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
926 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
929 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
931 TypeExpr texpr = TypeManager.expression_type_expr;
933 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
937 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
944 // Implemented by all expressions which support conversion from
945 // compiler expression to invokable runtime expression. Used by
946 // dynamic C# binder.
948 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
950 throw new NotImplementedException ("MakeExpression for " + GetType ());
955 /// This is just a base class for expressions that can
956 /// appear on statements (invocations, object creation,
957 /// assignments, post/pre increment and decrement). The idea
958 /// being that they would support an extra Emition interface that
959 /// does not leave a result on the stack.
961 public abstract class ExpressionStatement : Expression {
963 public ExpressionStatement ResolveStatement (BlockContext ec)
965 Expression e = Resolve (ec);
969 ExpressionStatement es = e as ExpressionStatement;
971 Error_InvalidExpressionStatement (ec);
977 /// Requests the expression to be emitted in a `statement'
978 /// context. This means that no new value is left on the
979 /// stack after invoking this method (constrasted with
980 /// Emit that will always leave a value on the stack).
982 public abstract void EmitStatement (EmitContext ec);
984 public override void EmitSideEffect (EmitContext ec)
991 /// This kind of cast is used to encapsulate the child
992 /// whose type is child.Type into an expression that is
993 /// reported to return "return_type". This is used to encapsulate
994 /// expressions which have compatible types, but need to be dealt
995 /// at higher levels with.
997 /// For example, a "byte" expression could be encapsulated in one
998 /// of these as an "unsigned int". The type for the expression
999 /// would be "unsigned int".
1002 public abstract class TypeCast : Expression
1004 protected readonly Expression child;
1006 protected TypeCast (Expression child, TypeSpec return_type)
1008 eclass = child.eclass;
1009 loc = child.Location;
1014 public Expression Child {
1020 public override Expression CreateExpressionTree (ResolveContext ec)
1022 Arguments args = new Arguments (2);
1023 args.Add (new Argument (child.CreateExpressionTree (ec)));
1024 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1026 if (type.IsPointer || child.Type.IsPointer)
1027 Error_PointerInsideExpressionTree (ec);
1029 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1032 protected override Expression DoResolve (ResolveContext ec)
1034 // This should never be invoked, we are born in fully
1035 // initialized state.
1040 public override void Emit (EmitContext ec)
1045 public override SLE.Expression MakeExpression (BuilderContext ctx)
1047 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1048 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1049 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1052 protected override void CloneTo (CloneContext clonectx, Expression t)
1057 public override bool IsNull {
1058 get { return child.IsNull; }
1062 public class EmptyCast : TypeCast {
1063 EmptyCast (Expression child, TypeSpec target_type)
1064 : base (child, target_type)
1068 public static Expression Create (Expression child, TypeSpec type)
1070 Constant c = child as Constant;
1072 return new EmptyConstantCast (c, type);
1074 EmptyCast e = child as EmptyCast;
1076 return new EmptyCast (e.child, type);
1078 return new EmptyCast (child, type);
1081 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1083 child.EmitBranchable (ec, label, on_true);
1086 public override void EmitSideEffect (EmitContext ec)
1088 child.EmitSideEffect (ec);
1093 // Used for predefined class library user casts (no obsolete check, etc.)
1095 public class OperatorCast : TypeCast {
1096 MethodSpec conversion_operator;
1098 public OperatorCast (Expression child, TypeSpec target_type)
1099 : this (child, target_type, false)
1103 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1104 : base (child, target_type)
1106 conversion_operator = GetConversionOperator (find_explicit);
1107 if (conversion_operator == null)
1108 throw new InternalErrorException ("Outer conversion routine is out of sync");
1111 // Returns the implicit operator that converts from
1112 // 'child.Type' to our target type (type)
1113 MethodSpec GetConversionOperator (bool find_explicit)
1115 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1117 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1119 mi = MemberCache.GetUserOperator (type, op, true);
1122 foreach (MethodSpec oper in mi) {
1123 if (oper.ReturnType != type)
1126 if (oper.Parameters.Types [0] == child.Type)
1133 public override void Emit (EmitContext ec)
1136 ec.Emit (OpCodes.Call, conversion_operator);
1141 /// This is a numeric cast to a Decimal
1143 public class CastToDecimal : OperatorCast {
1144 public CastToDecimal (Expression child)
1145 : this (child, false)
1149 public CastToDecimal (Expression child, bool find_explicit)
1150 : base (child, TypeManager.decimal_type, find_explicit)
1156 /// This is an explicit numeric cast from a Decimal
1158 public class CastFromDecimal : TypeCast
1160 static Dictionary<TypeSpec, MethodSpec> operators;
1162 public CastFromDecimal (Expression child, TypeSpec return_type)
1163 : base (child, return_type)
1165 if (child.Type != TypeManager.decimal_type)
1166 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1169 // Returns the explicit operator that converts from an
1170 // express of type System.Decimal to 'type'.
1171 public Expression Resolve ()
1173 if (operators == null) {
1174 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1176 operators = new Dictionary<TypeSpec, MethodSpec> ();
1177 foreach (MethodSpec oper in all_oper) {
1178 AParametersCollection pd = oper.Parameters;
1179 if (pd.Types [0] == TypeManager.decimal_type)
1180 operators.Add (oper.ReturnType, oper);
1184 return operators.ContainsKey (type) ? this : null;
1187 public override void Emit (EmitContext ec)
1191 ec.Emit (OpCodes.Call, operators [type]);
1194 public static void Reset ()
1202 // Constant specialization of EmptyCast.
1203 // We need to special case this since an empty cast of
1204 // a constant is still a constant.
1206 public class EmptyConstantCast : Constant
1208 public Constant child;
1210 public EmptyConstantCast (Constant child, TypeSpec type)
1211 : base (child.Location)
1214 throw new ArgumentNullException ("child");
1217 this.eclass = child.eclass;
1221 public override string AsString ()
1223 return child.AsString ();
1226 public override object GetValue ()
1228 return child.GetValue ();
1231 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1233 if (child.Type == target_type)
1236 // FIXME: check that 'type' can be converted to 'target_type' first
1237 return child.ConvertExplicitly (in_checked_context, target_type);
1240 public override Expression CreateExpressionTree (ResolveContext ec)
1242 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1243 child.CreateExpressionTree (ec),
1244 new TypeOf (new TypeExpression (type, loc), loc));
1247 Error_PointerInsideExpressionTree (ec);
1249 return CreateExpressionFactoryCall (ec, "Convert", args);
1252 public override bool IsDefaultValue {
1253 get { return child.IsDefaultValue; }
1256 public override bool IsNegative {
1257 get { return child.IsNegative; }
1260 public override bool IsNull {
1261 get { return child.IsNull; }
1264 public override bool IsOneInteger {
1265 get { return child.IsOneInteger; }
1268 public override bool IsZeroInteger {
1269 get { return child.IsZeroInteger; }
1272 protected override Expression DoResolve (ResolveContext rc)
1277 public override void Emit (EmitContext ec)
1282 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1284 child.EmitBranchable (ec, label, on_true);
1286 // Only to make verifier happy
1287 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1288 ec.Emit (OpCodes.Unbox_Any, type);
1291 public override void EmitSideEffect (EmitContext ec)
1293 child.EmitSideEffect (ec);
1296 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1298 // FIXME: Do we need to check user conversions?
1299 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1301 return child.ConvertImplicitly (rc, target_type);
1306 /// This class is used to wrap literals which belong inside Enums
1308 public class EnumConstant : Constant
1310 public Constant Child;
1312 public EnumConstant (Constant child, TypeSpec enum_type)
1313 : base (child.Location)
1316 this.type = enum_type;
1319 protected EnumConstant (Location loc)
1324 protected override Expression DoResolve (ResolveContext rc)
1326 Child = Child.Resolve (rc);
1327 this.eclass = ExprClass.Value;
1331 public override void Emit (EmitContext ec)
1336 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1338 Child.EncodeAttributeValue (rc, enc, Child.Type);
1341 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1343 Child.EmitBranchable (ec, label, on_true);
1346 public override void EmitSideEffect (EmitContext ec)
1348 Child.EmitSideEffect (ec);
1351 public override string GetSignatureForError()
1353 return TypeManager.CSharpName (Type);
1356 public override object GetValue ()
1358 return Child.GetValue ();
1361 public override object GetTypedValue ()
1363 // FIXME: runtime is not ready to work with just emited enums
1364 if (!RootContext.StdLib) {
1365 return Child.GetValue ();
1369 // Small workaround for big problem
1370 // System.Enum.ToObject cannot be called on dynamic types
1371 // EnumBuilder has to be used, but we cannot use EnumBuilder
1372 // because it does not properly support generics
1374 // This works only sometimes
1376 if (type.MemberDefinition is TypeContainer)
1377 return Child.GetValue ();
1380 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1383 public override string AsString ()
1385 return Child.AsString ();
1388 public EnumConstant Increment()
1390 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1393 public override bool IsDefaultValue {
1395 return Child.IsDefaultValue;
1399 public override bool IsZeroInteger {
1400 get { return Child.IsZeroInteger; }
1403 public override bool IsNegative {
1405 return Child.IsNegative;
1409 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1411 if (Child.Type == target_type)
1414 return Child.ConvertExplicitly (in_checked_context, target_type);
1417 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1419 if (this.type == type) {
1423 if (!Convert.ImplicitStandardConversionExists (this, type)){
1427 return Child.ConvertImplicitly (rc, type);
1432 /// This kind of cast is used to encapsulate Value Types in objects.
1434 /// The effect of it is to box the value type emitted by the previous
1437 public class BoxedCast : TypeCast {
1439 public BoxedCast (Expression expr, TypeSpec target_type)
1440 : base (expr, target_type)
1442 eclass = ExprClass.Value;
1445 protected override Expression DoResolve (ResolveContext ec)
1447 // This should never be invoked, we are born in fully
1448 // initialized state.
1453 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1455 enc.Encode (child.Type);
1456 child.EncodeAttributeValue (rc, enc, child.Type);
1459 public override void Emit (EmitContext ec)
1463 ec.Emit (OpCodes.Box, child.Type);
1466 public override void EmitSideEffect (EmitContext ec)
1468 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1469 // so, we need to emit the box+pop instructions in most cases
1470 if (TypeManager.IsStruct (child.Type) &&
1471 (type == TypeManager.object_type || type == TypeManager.value_type))
1472 child.EmitSideEffect (ec);
1474 base.EmitSideEffect (ec);
1478 public class UnboxCast : TypeCast {
1479 public UnboxCast (Expression expr, TypeSpec return_type)
1480 : base (expr, return_type)
1484 protected override Expression DoResolve (ResolveContext ec)
1486 // This should never be invoked, we are born in fully
1487 // initialized state.
1492 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1494 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1495 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1496 return base.DoResolveLValue (ec, right_side);
1499 public override void Emit (EmitContext ec)
1503 ec.Emit (OpCodes.Unbox_Any, type);
1508 /// This is used to perform explicit numeric conversions.
1510 /// Explicit numeric conversions might trigger exceptions in a checked
1511 /// context, so they should generate the conv.ovf opcodes instead of
1514 public class ConvCast : TypeCast {
1515 public enum Mode : byte {
1516 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1518 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1519 U2_I1, U2_U1, U2_I2, U2_CH,
1520 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1521 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1522 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1523 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1524 CH_I1, CH_U1, CH_I2,
1525 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1526 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1532 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1533 : base (child, return_type)
1538 protected override Expression DoResolve (ResolveContext ec)
1540 // This should never be invoked, we are born in fully
1541 // initialized state.
1546 public override string ToString ()
1548 return String.Format ("ConvCast ({0}, {1})", mode, child);
1551 public override void Emit (EmitContext ec)
1555 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1557 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1558 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1560 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1561 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1563 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1564 case Mode.U1_CH: /* nothing */ break;
1566 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1567 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1568 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1570 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1571 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1573 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1574 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1575 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1576 case Mode.U2_CH: /* nothing */ break;
1578 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1579 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1580 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1581 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1582 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1584 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1586 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1587 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1588 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1589 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1590 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1591 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1593 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1594 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1595 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1596 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1598 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1599 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1600 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1601 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1603 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1604 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1605 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1606 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1607 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1608 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1609 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1610 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1611 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1613 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1614 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1615 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1617 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1618 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1619 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1620 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1622 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1623 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1624 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1625 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1627 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1628 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1629 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1630 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1631 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1632 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1633 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1634 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1635 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1638 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1642 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1643 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1645 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1646 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1649 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1651 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1652 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1653 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1655 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1656 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1658 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1659 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1660 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1661 case Mode.U2_CH: /* nothing */ break;
1663 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1664 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1665 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1666 case Mode.I4_U4: /* nothing */ break;
1667 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1669 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1672 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1673 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1674 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1675 case Mode.U4_I4: /* nothing */ break;
1676 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1683 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1684 case Mode.I8_U8: /* nothing */ break;
1685 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1688 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1689 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1690 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1691 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1693 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1694 case Mode.U8_I8: /* nothing */ break;
1695 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1696 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1698 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1702 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1703 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1704 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1705 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1707 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1708 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1709 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1710 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1713 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1714 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1715 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1716 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1717 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1718 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1719 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1720 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1723 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1729 public class OpcodeCast : TypeCast {
1732 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1733 : base (child, return_type)
1738 protected override Expression DoResolve (ResolveContext ec)
1740 // This should never be invoked, we are born in fully
1741 // initialized state.
1746 public override void Emit (EmitContext ec)
1752 public TypeSpec UnderlyingType {
1753 get { return child.Type; }
1758 /// This kind of cast is used to encapsulate a child and cast it
1759 /// to the class requested
1761 public sealed class ClassCast : TypeCast {
1762 readonly bool forced;
1764 public ClassCast (Expression child, TypeSpec return_type)
1765 : base (child, return_type)
1769 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1770 : base (child, return_type)
1772 this.forced = forced;
1775 public override void Emit (EmitContext ec)
1779 bool gen = TypeManager.IsGenericParameter (child.Type);
1781 ec.Emit (OpCodes.Box, child.Type);
1783 if (type.IsGenericParameter) {
1784 ec.Emit (OpCodes.Unbox_Any, type);
1791 ec.Emit (OpCodes.Castclass, type);
1796 // Created during resolving pahse when an expression is wrapped or constantified
1797 // and original expression can be used later (e.g. for expression trees)
1799 public class ReducedExpression : Expression
1801 sealed class ReducedConstantExpression : EmptyConstantCast
1803 readonly Expression orig_expr;
1805 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1806 : base (expr, expr.Type)
1808 this.orig_expr = orig_expr;
1811 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1813 Constant c = base.ConvertImplicitly (rc, target_type);
1815 c = new ReducedConstantExpression (c, orig_expr);
1820 public override Expression CreateExpressionTree (ResolveContext ec)
1822 return orig_expr.CreateExpressionTree (ec);
1825 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1827 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1829 c = new ReducedConstantExpression (c, orig_expr);
1834 sealed class ReducedExpressionStatement : ExpressionStatement
1836 readonly Expression orig_expr;
1837 readonly ExpressionStatement stm;
1839 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1841 this.orig_expr = orig;
1843 this.loc = orig.Location;
1846 public override Expression CreateExpressionTree (ResolveContext ec)
1848 return orig_expr.CreateExpressionTree (ec);
1851 protected override Expression DoResolve (ResolveContext ec)
1853 eclass = stm.eclass;
1858 public override void Emit (EmitContext ec)
1863 public override void EmitStatement (EmitContext ec)
1865 stm.EmitStatement (ec);
1869 readonly Expression expr, orig_expr;
1871 private ReducedExpression (Expression expr, Expression orig_expr)
1874 this.eclass = expr.eclass;
1875 this.type = expr.Type;
1876 this.orig_expr = orig_expr;
1877 this.loc = orig_expr.Location;
1881 // Creates fully resolved expression switcher
1883 public static Constant Create (Constant expr, Expression original_expr)
1885 if (expr.eclass == ExprClass.Unresolved)
1886 throw new ArgumentException ("Unresolved expression");
1888 return new ReducedConstantExpression (expr, original_expr);
1891 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1893 return new ReducedExpressionStatement (s, orig);
1897 // Creates unresolved reduce expression. The original expression has to be
1900 public static Expression Create (Expression expr, Expression original_expr)
1902 Constant c = expr as Constant;
1904 return Create (c, original_expr);
1906 ExpressionStatement s = expr as ExpressionStatement;
1908 return Create (s, original_expr);
1910 if (expr.eclass == ExprClass.Unresolved)
1911 throw new ArgumentException ("Unresolved expression");
1913 return new ReducedExpression (expr, original_expr);
1916 public override Expression CreateExpressionTree (ResolveContext ec)
1918 return orig_expr.CreateExpressionTree (ec);
1921 protected override Expression DoResolve (ResolveContext ec)
1926 public override void Emit (EmitContext ec)
1931 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1933 expr.EmitBranchable (ec, target, on_true);
1936 public override SLE.Expression MakeExpression (BuilderContext ctx)
1938 return orig_expr.MakeExpression (ctx);
1943 // Standard composite pattern
1945 public abstract class CompositeExpression : Expression
1949 protected CompositeExpression (Expression expr)
1952 this.loc = expr.Location;
1955 public override Expression CreateExpressionTree (ResolveContext ec)
1957 return expr.CreateExpressionTree (ec);
1960 public Expression Child {
1961 get { return expr; }
1964 protected override Expression DoResolve (ResolveContext ec)
1966 expr = expr.Resolve (ec);
1969 eclass = expr.eclass;
1975 public override void Emit (EmitContext ec)
1980 public override bool IsNull {
1981 get { return expr.IsNull; }
1986 // Base of expressions used only to narrow resolve flow
1988 public abstract class ShimExpression : Expression
1990 protected Expression expr;
1992 protected ShimExpression (Expression expr)
1997 protected override void CloneTo (CloneContext clonectx, Expression t)
2002 ShimExpression target = (ShimExpression) t;
2003 target.expr = expr.Clone (clonectx);
2006 public override Expression CreateExpressionTree (ResolveContext ec)
2008 throw new NotSupportedException ("ET");
2011 public override void Emit (EmitContext ec)
2013 throw new InternalErrorException ("Missing Resolve call");
2016 public Expression Expr {
2017 get { return expr; }
2022 // Unresolved type name expressions
2024 public abstract class ATypeNameExpression : FullNamedExpression
2027 protected TypeArguments targs;
2029 protected ATypeNameExpression (string name, Location l)
2035 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2042 protected ATypeNameExpression (string name, int arity, Location l)
2043 : this (name, new UnboundTypeArguments (arity), l)
2049 protected int Arity {
2051 return targs == null ? 0 : targs.Count;
2055 public bool HasTypeArguments {
2057 return targs != null && !targs.IsEmpty;
2061 public string Name {
2070 public TypeArguments TypeArguments {
2078 public override bool Equals (object obj)
2080 ATypeNameExpression atne = obj as ATypeNameExpression;
2081 return atne != null && atne.Name == Name &&
2082 (targs == null || targs.Equals (atne.targs));
2085 public override int GetHashCode ()
2087 return Name.GetHashCode ();
2090 // TODO: Move it to MemberCore
2091 public static string GetMemberType (MemberCore mc)
2097 if (mc is FieldBase)
2099 if (mc is MethodCore)
2101 if (mc is EnumMember)
2109 public override string GetSignatureForError ()
2111 if (targs != null) {
2112 return Name + "<" + targs.GetSignatureForError () + ">";
2118 public abstract Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly);
2122 /// SimpleName expressions are formed of a single word and only happen at the beginning
2123 /// of a dotted-name.
2125 public class SimpleName : ATypeNameExpression
2127 public SimpleName (string name, Location l)
2132 public SimpleName (string name, TypeArguments args, Location l)
2133 : base (name, args, l)
2137 public SimpleName (string name, int arity, Location l)
2138 : base (name, arity, l)
2142 public SimpleName GetMethodGroup ()
2144 return new SimpleName (Name, targs, loc);
2147 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2149 if (ec.CurrentType != null) {
2150 if (ec.CurrentMemberDefinition != null) {
2151 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2153 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2159 // TODO MemberCache: Implement
2161 string ns = ec.CurrentType.Namespace;
2162 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2163 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2164 var type = a.GetType (fullname);
2166 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2167 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2172 if (ec.CurrentTypeDefinition != null) {
2173 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2175 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2182 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2183 if (retval != null) {
2184 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2186 var te = retval as TypeExpr;
2187 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2188 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2190 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2195 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2198 protected override Expression DoResolve (ResolveContext ec)
2200 return SimpleNameResolve (ec, null, false);
2203 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2205 return SimpleNameResolve (ec, right_side, false);
2208 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2210 int errors = ec.Compiler.Report.Errors;
2211 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2214 if (fne.Type != null && Arity > 0) {
2215 if (HasTypeArguments) {
2216 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2217 return ct.ResolveAsTypeStep (ec, false);
2220 return new GenericOpenTypeExpr (fne.Type, loc);
2224 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2226 if (!(fne is Namespace))
2230 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2231 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2232 ec.Compiler.Report.Error (1980, Location,
2233 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2234 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2237 return new DynamicTypeExpr (loc);
2243 if (silent || errors != ec.Compiler.Report.Errors)
2246 Error_TypeOrNamespaceNotFound (ec);
2250 public override Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly)
2252 int lookup_arity = Arity;
2253 bool errorMode = false;
2255 Block current_block = rc.CurrentBlock;
2259 // Stage 1: binding to local variables or parameters
2261 if (current_block != null && lookup_arity == 0) {
2262 LocalInfo vi = current_block.GetLocalInfo (Name);
2264 // TODO: pass vi in to speed things up
2265 e = new LocalVariableReference (rc.CurrentBlock, Name, loc);
2267 e = current_block.Toplevel.GetParameterReference (Name, loc);
2272 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2278 current_block.CheckInvariantMeaningInBlock (Name, this, loc);
2282 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2284 LocalInfo li = ikv as LocalInfo;
2285 // Supress CS0219 warning
2289 Error_VariableIsUsedBeforeItIsDeclared (rc.Report, Name);
2297 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2299 TypeSpec member_type = rc.CurrentType;
2300 TypeSpec current_type = member_type;
2301 for (; member_type != null; member_type = member_type.DeclaringType) {
2302 var me = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, invocableOnly, loc) as MemberExpr;
2307 if (me is MethodGroupExpr) {
2308 // Leave it to overload resolution to report correct error
2310 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2311 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2315 // MemberLookup does not check accessors availability, this is actually needed for properties only
2317 var pe = me as PropertyExpr;
2320 // Break as there is no other overload available anyway
2322 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2325 pe.Getter = pe.PropertyInfo.Get;
2327 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2330 pe.Setter = pe.PropertyInfo.Set;
2335 // TODO: It's used by EventExpr -> FieldExpr transformation only
2336 // TODO: Should go to MemberAccess
2337 me = me.ResolveMemberAccess (rc, null, null);
2341 me.SetTypeArguments (rc, targs);
2348 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2350 if (!invocableOnly) {
2351 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2357 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2361 if (RootContext.EvalMode) {
2362 var fi = Evaluator.LookupField (Name);
2364 return new FieldExpr (fi.Item1, loc);
2368 invocableOnly = false;
2373 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2375 Expression e = LookupNameExpression (ec, right_side == null, false);
2380 if (right_side != null)
2381 e = e.ResolveLValue (ec, right_side);
2385 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2391 /// Represents a namespace or a type. The name of the class was inspired by
2392 /// section 10.8.1 (Fully Qualified Names).
2394 public abstract class FullNamedExpression : Expression
2396 protected override void CloneTo (CloneContext clonectx, Expression target)
2398 // Do nothing, most unresolved type expressions cannot be
2399 // resolved to different type
2402 public override Expression CreateExpressionTree (ResolveContext ec)
2404 throw new NotSupportedException ("ET");
2407 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2412 public override void Emit (EmitContext ec)
2414 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2415 GetSignatureForError ());
2420 /// Expression that evaluates to a type
2422 public abstract class TypeExpr : FullNamedExpression {
2423 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2425 TypeExpr t = DoResolveAsTypeStep (ec);
2429 eclass = ExprClass.Type;
2433 protected override Expression DoResolve (ResolveContext ec)
2435 return ResolveAsTypeTerminal (ec, false);
2438 public virtual bool CheckAccessLevel (IMemberContext mc)
2440 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2442 c = mc.CurrentMemberDefinition.Parent;
2444 return c.CheckAccessLevel (Type);
2447 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2449 public override bool Equals (object obj)
2451 TypeExpr tobj = obj as TypeExpr;
2455 return Type == tobj.Type;
2458 public override int GetHashCode ()
2460 return Type.GetHashCode ();
2465 /// Fully resolved Expression that already evaluated to a type
2467 public class TypeExpression : TypeExpr {
2468 public TypeExpression (TypeSpec t, Location l)
2471 eclass = ExprClass.Type;
2475 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2480 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2487 /// This class denotes an expression which evaluates to a member
2488 /// of a struct or a class.
2490 public abstract class MemberExpr : Expression
2493 // An instance expression associated with this member, if it's a
2494 // non-static member
2496 public Expression InstanceExpression;
2499 /// The name of this member.
2501 public abstract string Name {
2506 // When base.member is used
2508 public bool IsBase {
2509 get { return InstanceExpression is BaseThis; }
2513 /// Whether this is an instance member.
2515 public abstract bool IsInstance {
2520 /// Whether this is a static member.
2522 public abstract bool IsStatic {
2527 protected abstract TypeSpec DeclaringType {
2532 // Converts best base candidate for virtual method starting from QueriedBaseType
2534 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2537 // Only when base.member is used and method is virtual
2543 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2544 // means for base.member access we have to find the closest match after we found best candidate
2546 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC && method.DeclaringType != InstanceExpression.Type) {
2547 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2548 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2549 if (base_override.IsGeneric)
2550 base_override = base_override.MakeGenericMethod (method.TypeArguments);
2552 if (rc.CurrentAnonymousMethod != null)
2553 throw new NotImplementedException ("base call hoisting");
2555 return base_override;
2560 // Only base will allow this invocation to happen.
2562 if (method.IsAbstract) {
2563 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2569 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2571 if (InstanceExpression == null)
2574 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2575 var ct = rc.CurrentType;
2576 var expr_type = InstanceExpression.Type;
2577 if (ct != expr_type && !TypeManager.IsSubclassOf (expr_type, ct)) {
2578 expr_type = expr_type.GetDefinition ();
2579 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2580 rc.Report.SymbolRelatedToPreviousError (member);
2581 rc.Report.Error (1540, loc,
2582 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2583 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2589 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2592 type = type.GetDefinition ();
2594 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2597 type = type.DeclaringType;
2598 } while (type != null);
2603 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2605 if (InstanceExpression != null) {
2606 InstanceExpression = InstanceExpression.Resolve (rc);
2607 CheckProtectedMemberAccess (rc, member);
2610 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2611 UnsafeError (rc, loc);
2614 if (!rc.IsObsolete) {
2615 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2617 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2620 if (!(member is FieldSpec))
2621 member.MemberDefinition.SetIsUsed ();
2625 // Implements identicial simple name and type-name
2627 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2630 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2633 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
2634 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2636 if (left is MemberExpr || left is VariableReference) {
2637 rc.Report.DisableReporting ();
2638 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2639 rc.Report.EnableReporting ();
2640 if (identical_type != null && identical_type.Type == left.Type)
2641 return identical_type;
2647 public bool ResolveInstanceExpression (ResolveContext rc)
2650 if (InstanceExpression != null) {
2651 if (InstanceExpression is TypeExpr) {
2652 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2653 if (oa != null && !rc.IsObsolete) {
2654 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2657 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2658 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2659 rc.Report.Error (176, loc,
2660 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2661 GetSignatureForError ());
2665 InstanceExpression = null;
2671 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2672 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2673 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2674 rc.Report.Error (236, loc,
2675 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2676 GetSignatureForError ());
2678 rc.Report.Error (120, loc,
2679 "An object reference is required to access non-static member `{0}'",
2680 GetSignatureForError ());
2685 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2686 rc.Report.Error (38, loc,
2687 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2688 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2691 InstanceExpression = rc.GetThis (loc);
2695 var me = InstanceExpression as MemberExpr;
2697 me.ResolveInstanceExpression (rc);
2699 var fe = me as FieldExpr;
2700 if (fe != null && fe.IsMarshalByRefAccess ()) {
2701 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2702 rc.Report.Warning (1690, 1, loc,
2703 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2704 me.GetSignatureForError ());
2711 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2713 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2714 ec.Report.Warning (1720, 1, left.Location,
2715 "Expression will always cause a `{0}'", "System.NullReferenceException");
2718 InstanceExpression = left;
2722 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2724 if (TypeManager.IsValueType (InstanceExpression.Type)) {
2725 if (InstanceExpression is IMemoryLocation) {
2726 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2728 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2729 InstanceExpression.Emit (ec);
2731 t.AddressOf (ec, AddressOp.Store);
2734 InstanceExpression.Emit (ec);
2736 if (prepare_for_load)
2737 ec.Emit (OpCodes.Dup);
2740 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2744 /// Represents group of extension method candidates
2746 public class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2748 readonly NamespaceEntry namespace_entry;
2749 public Expression ExtensionExpression;
2751 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, TypeSpec extensionType, Location l)
2752 : base (list.Cast<MemberSpec>().ToList (), extensionType, l)
2754 this.namespace_entry = n;
2757 public override bool IsStatic {
2758 get { return true; }
2761 public bool IsTopLevel {
2762 get { return namespace_entry == null; }
2765 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2767 if (arguments == null)
2768 arguments = new Arguments (1);
2770 arguments.Insert (0, new Argument (ExtensionExpression));
2771 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, ehandler ?? this, namespace_entry, loc);
2773 // Store resolved argument and restore original arguments
2775 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
2777 var me = ExtensionExpression as MemberExpr;
2779 me.ResolveInstanceExpression (ec);
2785 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, NamespaceEntry ns, Location loc)
2787 // Use normal resolve rules
2788 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ehandler, ns != null ? OverloadResolver.Restrictions.ProbingOnly : OverloadResolver.Restrictions.None);
2796 int arity = type_arguments == null ? 0 : type_arguments.Count;
2797 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, arity, loc);
2799 return base.OverloadResolve (ec, ref arguments, ehandler, OverloadResolver.Restrictions.None);
2801 e.ExtensionExpression = ExtensionExpression;
2802 e.SetTypeArguments (ec, type_arguments);
2803 return e.ResolveOverloadExtensions (ec, ref arguments, ehandler, e.namespace_entry, loc);
2806 #region IErrorHandler Members
2808 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2813 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2815 rc.Report.SymbolRelatedToPreviousError (best);
2816 rc.Report.Error (1928, loc,
2817 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2818 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2821 rc.Report.Error (1929, loc,
2822 "Extension method instance type `{0}' cannot be converted to `{1}'",
2823 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2829 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2834 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2843 /// MethodGroupExpr represents a group of method candidates which
2844 /// can be resolved to the best method overload
2846 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2848 protected IList<MemberSpec> Methods;
2849 MethodSpec best_candidate;
2850 protected TypeArguments type_arguments;
2852 SimpleName simple_name;
2853 protected TypeSpec queried_type;
2855 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2859 this.type = InternalType.MethodGroup;
2861 eclass = ExprClass.MethodGroup;
2862 queried_type = type;
2865 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2866 : this (new MemberSpec[] { m }, type, loc)
2872 public MethodSpec BestCandidate {
2874 return best_candidate;
2878 protected override TypeSpec DeclaringType {
2880 return queried_type;
2884 public override bool IsInstance {
2886 if (best_candidate != null)
2887 return !best_candidate.IsStatic;
2893 public override bool IsStatic {
2895 if (best_candidate != null)
2896 return best_candidate.IsStatic;
2902 public override string Name {
2904 if (best_candidate != null)
2905 return best_candidate.Name;
2908 return Methods.First ().Name;
2915 // When best candidate is already know this factory can be used
2916 // to avoid expensive overload resolution to be called
2918 // NOTE: InstanceExpression has to be set manually
2920 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2922 return new MethodGroupExpr (best, queriedType, loc) {
2923 best_candidate = best
2927 public override string GetSignatureForError ()
2929 if (best_candidate != null)
2930 return best_candidate.GetSignatureForError ();
2932 return Methods.First ().GetSignatureForError ();
2935 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2937 simple_name = original;
2939 return base.ResolveMemberAccess (ec, left, original);
2942 public override Expression CreateExpressionTree (ResolveContext ec)
2944 if (best_candidate == null) {
2945 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
2949 if (best_candidate.IsConditionallyExcluded (loc))
2950 ec.Report.Error (765, loc,
2951 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
2953 return new TypeOfMethod (best_candidate, loc);
2956 protected override Expression DoResolve (ResolveContext ec)
2958 this.eclass = ExprClass.MethodGroup;
2960 if (InstanceExpression != null) {
2961 InstanceExpression = InstanceExpression.Resolve (ec);
2962 if (InstanceExpression == null)
2969 public override void Emit (EmitContext ec)
2971 throw new NotSupportedException ();
2974 public void EmitCall (EmitContext ec, Arguments arguments)
2976 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
2979 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
2981 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
2982 Name, TypeManager.CSharpName (target));
2985 public static bool IsExtensionMethodArgument (Expression expr)
2988 // LAMESPEC: No details about which expressions are not allowed
2990 return !(expr is BaseThis);
2994 /// Find the Applicable Function Members (7.4.2.1)
2996 /// me: Method Group expression with the members to select.
2997 /// it might contain constructors or methods (or anything
2998 /// that maps to a method).
3000 /// Arguments: ArrayList containing resolved Argument objects.
3002 /// loc: The location if we want an error to be reported, or a Null
3003 /// location for "probing" purposes.
3005 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3006 /// that is the best match of me on Arguments.
3009 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3011 // TODO: causes issues with probing mode, remove explicit Kind check
3012 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3015 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3016 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3017 r.BaseMembersProvider = this;
3020 if (cerrors != null)
3021 r.CustomErrors = cerrors;
3023 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3024 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3025 if (best_candidate == null)
3026 return r.BestCandidateIsDynamic ? this : null;
3028 if (best_candidate.Kind == MemberKind.Method) {
3029 if (InstanceExpression != null) {
3030 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3031 InstanceExpression = null;
3033 if (best_candidate.IsStatic && simple_name != null) {
3034 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3037 InstanceExpression.Resolve (ec);
3041 ResolveInstanceExpression (ec);
3042 if (InstanceExpression != null)
3043 CheckProtectedMemberAccess (ec, best_candidate);
3045 if (best_candidate.IsGeneric) {
3046 ConstraintChecker.CheckAll (ec.MemberContext, best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments,
3047 best_candidate.Constraints, loc);
3051 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3055 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3057 type_arguments = ta;
3060 #region IBaseMembersProvider Members
3062 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
3064 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3067 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc, int arity)
3069 if (InstanceExpression == null)
3072 InstanceExpression = InstanceExpression.Resolve (rc);
3073 if (!IsExtensionMethodArgument (InstanceExpression))
3076 var emg = rc.LookupExtensionMethod (InstanceExpression.Type, Methods [0].Name, arity, loc);
3078 emg.ExtensionExpression = InstanceExpression;
3079 emg.SetTypeArguments (rc, type_arguments);
3088 public struct OverloadResolver
3091 public enum Restrictions
3095 ProbingOnly = 1 << 1,
3097 NoBaseMembers = 1 << 3
3100 public interface IBaseMembersProvider
3102 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3103 MethodGroupExpr LookupExtensionMethod (ResolveContext rc, int arity);
3106 public interface IErrorHandler
3108 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3109 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3110 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3111 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3114 sealed class NoBaseMembers : IBaseMembersProvider
3116 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3118 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3123 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc, int arity)
3129 struct AmbiguousCandidate
3131 public readonly MemberSpec Member;
3132 public readonly bool Expanded;
3134 public AmbiguousCandidate (MemberSpec member, bool expanded)
3137 Expanded = expanded;
3142 IList<MemberSpec> members;
3143 TypeArguments type_arguments;
3144 IBaseMembersProvider base_provider;
3145 IErrorHandler custom_errors;
3146 Restrictions restrictions;
3148 SessionReportPrinter lambda_conv_msgs;
3149 ReportPrinter prev_recorder;
3151 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3152 : this (members, null, restrictions, loc)
3156 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3159 if (members == null || members.Count == 0)
3160 throw new ArgumentException ("empty members set");
3162 this.members = members;
3164 type_arguments = targs;
3165 this.restrictions = restrictions;
3166 if (IsDelegateInvoke)
3167 this.restrictions |= Restrictions.NoBaseMembers;
3169 base_provider = NoBaseMembers.Instance;
3174 public IBaseMembersProvider BaseMembersProvider {
3176 return base_provider;
3179 base_provider = value;
3183 public bool BestCandidateIsDynamic { get; set; }
3185 public IErrorHandler CustomErrors {
3187 return custom_errors;
3190 custom_errors = value;
3194 TypeSpec DelegateType {
3196 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3197 throw new InternalErrorException ("Not running in delegate mode", loc);
3199 return members [0].DeclaringType;
3203 bool IsProbingOnly {
3205 return (restrictions & Restrictions.ProbingOnly) != 0;
3209 bool IsDelegateInvoke {
3211 return (restrictions & Restrictions.DelegateInvoke) != 0;
3218 // 7.4.3.3 Better conversion from expression
3219 // Returns : 1 if a->p is better,
3220 // 2 if a->q is better,
3221 // 0 if neither is better
3223 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3225 TypeSpec argument_type = a.Type;
3226 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3228 // Uwrap delegate from Expression<T>
3230 if (p.GetDefinition () == TypeManager.expression_type) {
3231 p = TypeManager.GetTypeArguments (p)[0];
3233 if (q.GetDefinition () == TypeManager.expression_type) {
3234 q = TypeManager.GetTypeArguments (q)[0];
3237 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3238 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3239 if (p == TypeManager.void_type && q != TypeManager.void_type)
3241 if (q == TypeManager.void_type && p != TypeManager.void_type)
3244 if (argument_type == p)
3247 if (argument_type == q)
3251 return BetterTypeConversion (ec, p, q);
3255 // 7.4.3.4 Better conversion from type
3257 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3259 if (p == null || q == null)
3260 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3262 if (p == TypeManager.int32_type) {
3263 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3265 } else if (p == TypeManager.int64_type) {
3266 if (q == TypeManager.uint64_type)
3268 } else if (p == TypeManager.sbyte_type) {
3269 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3270 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3272 } else if (p == TypeManager.short_type) {
3273 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3274 q == TypeManager.uint64_type)
3276 } else if (p == InternalType.Dynamic) {
3277 if (q == TypeManager.object_type)
3281 if (q == TypeManager.int32_type) {
3282 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3284 } if (q == TypeManager.int64_type) {
3285 if (p == TypeManager.uint64_type)
3287 } else if (q == TypeManager.sbyte_type) {
3288 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3289 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3291 } if (q == TypeManager.short_type) {
3292 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3293 p == TypeManager.uint64_type)
3295 } else if (q == InternalType.Dynamic) {
3296 if (p == TypeManager.object_type)
3300 // TODO: this is expensive
3301 Expression p_tmp = new EmptyExpression (p);
3302 Expression q_tmp = new EmptyExpression (q);
3304 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3305 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3307 if (p_to_q && !q_to_p)
3310 if (q_to_p && !p_to_q)
3317 /// Determines "Better function" between candidate
3318 /// and the current best match
3321 /// Returns a boolean indicating :
3322 /// false if candidate ain't better
3323 /// true if candidate is better than the current best match
3325 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3326 MemberSpec best, bool best_params)
3328 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3329 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3331 bool better_at_least_one = false;
3333 int args_count = args == null ? 0 : args.Count;
3334 for (int j = 0, c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3335 Argument a = args[j];
3337 // Provided default argument value is never better
3338 if (a.IsDefaultArgument && candidate_params == best_params)
3341 TypeSpec ct = candidate_pd.Types[c_idx];
3342 TypeSpec bt = best_pd.Types[b_idx];
3344 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3345 ct = TypeManager.GetElementType (ct);
3349 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3350 bt = TypeManager.GetElementType (bt);
3354 if (TypeManager.IsEqual (ct, bt))
3358 int result = BetterExpressionConversion (ec, a, ct, bt);
3360 // for each argument, the conversion to 'ct' should be no worse than
3361 // the conversion to 'bt'.
3365 // for at least one argument, the conversion to 'ct' should be better than
3366 // the conversion to 'bt'.
3368 better_at_least_one = true;
3371 if (better_at_least_one)
3375 // This handles the case
3377 // Add (float f1, float f2, float f3);
3378 // Add (params decimal [] foo);
3380 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3381 // first candidate would've chosen as better.
3387 // The two methods have equal parameter types. Now apply tie-breaking rules
3389 if (best.IsGeneric) {
3390 if (!candidate.IsGeneric)
3392 } else if (candidate.IsGeneric) {
3397 // This handles the following cases:
3399 // Trim () is better than Trim (params char[] chars)
3400 // Concat (string s1, string s2, string s3) is better than
3401 // Concat (string s1, params string [] srest)
3402 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3404 if (!candidate_params && best_params)
3406 if (candidate_params && !best_params)
3409 int candidate_param_count = candidate_pd.Count;
3410 int best_param_count = best_pd.Count;
3412 if (candidate_param_count != best_param_count)
3413 // can only happen if (candidate_params && best_params)
3414 return candidate_param_count > best_param_count && best_pd.HasParams;
3417 // Both methods have the same number of parameters, and the parameters have equal types
3418 // Pick the "more specific" signature using rules over original (non-inflated) types
3420 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3421 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3423 bool specific_at_least_once = false;
3424 for (int j = 0; j < candidate_param_count; ++j) {
3425 var ct = candidate_def_pd.Types[j];
3426 var bt = best_def_pd.Types[j];
3429 TypeSpec specific = MoreSpecific (ct, bt);
3433 specific_at_least_once = true;
3436 if (specific_at_least_once)
3439 // FIXME: handle lifted operators
3445 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3447 rc.Report.Error (1729, loc,
3448 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3449 type.GetSignatureForError (), argCount.ToString ());
3453 /// Determines if the candidate method is applicable (section 14.4.2.1)
3454 /// to the given set of arguments
3455 /// A return value rates candidate method compatibility,
3456 /// 0 = the best, int.MaxValue = the worst
3458 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3460 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3461 int param_count = pd.Count;
3462 int optional_count = 0;
3464 if (arg_count != param_count) {
3465 for (int i = 0; i < pd.Count; ++i) {
3466 if (pd.FixedParameters[i].HasDefaultValue) {
3467 optional_count = pd.Count - i;
3472 int args_gap = System.Math.Abs (arg_count - param_count);
3473 if (optional_count != 0) {
3474 if (args_gap > optional_count)
3475 return int.MaxValue - 10000 + args_gap - optional_count;
3477 // Readjust expected number when params used
3480 if (arg_count < param_count)
3482 } else if (arg_count > param_count) {
3483 return int.MaxValue - 10000 + args_gap;
3485 } else if (arg_count != param_count) {
3487 return int.MaxValue - 10000 + args_gap;
3488 if (arg_count < param_count - 1)
3489 return int.MaxValue - 10000 + args_gap;
3492 // Initialize expanded form of a method with 1 params parameter
3493 params_expanded_form = param_count == 1 && pd.HasParams;
3495 // Resize to fit optional arguments
3496 if (optional_count != 0) {
3498 if (arguments == null) {
3499 resized = new Arguments (optional_count);
3501 resized = new Arguments (param_count);
3502 resized.AddRange (arguments);
3505 for (int i = arg_count; i < param_count; ++i)
3507 arguments = resized;
3511 if (arg_count > 0) {
3513 // Shuffle named arguments to the right positions if there are any
3515 if (arguments[arg_count - 1] is NamedArgument) {
3516 arg_count = arguments.Count;
3518 for (int i = 0; i < arg_count; ++i) {
3519 bool arg_moved = false;
3521 NamedArgument na = arguments[i] as NamedArgument;
3525 int index = pd.GetParameterIndexByName (na.Name);
3527 // Named parameter not found or already reordered
3531 // When using parameters which should not be available to the user
3532 if (index >= param_count)
3536 arguments.MarkReorderedArgument (na);
3540 Argument temp = arguments[index];
3541 arguments[index] = arguments[i];
3542 arguments[i] = temp;
3549 arg_count = arguments.Count;
3551 } else if (arguments != null) {
3552 arg_count = arguments.Count;
3556 // 1. Handle generic method using type arguments when specified or type inference
3558 var ms = candidate as MethodSpec;
3559 if (ms != null && ms.IsGeneric) {
3560 if (type_arguments != null) {
3561 var g_args_count = ms.Arity;
3562 if (g_args_count != type_arguments.Count)
3563 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3565 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3568 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3569 // for now it simplifies things. I should probably add a callback to ResolveContext
3570 if (lambda_conv_msgs == null) {
3571 lambda_conv_msgs = new SessionReportPrinter ();
3572 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3575 int score = TypeManager.InferTypeArguments (ec, arguments, ref ms);
3576 lambda_conv_msgs.EndSession ();
3579 return score - 20000;
3585 if (type_arguments != null)
3586 return int.MaxValue - 15000;
3590 // 2. Each argument has to be implicitly convertible to method parameter
3592 Parameter.Modifier p_mod = 0;
3594 for (int i = 0; i < arg_count; i++) {
3595 Argument a = arguments[i];
3597 if (!pd.FixedParameters[i].HasDefaultValue)
3598 throw new InternalErrorException ();
3600 Expression e = pd.FixedParameters[i].DefaultValue as Constant;
3602 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc).Resolve (ec);
3604 arguments[i] = new Argument (e, Argument.AType.Default);
3608 if (p_mod != Parameter.Modifier.PARAMS) {
3609 p_mod = pd.FixedParameters[i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3612 params_expanded_form = true;
3615 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3617 if (!params_expanded_form)
3618 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3621 // It can be applicable in expanded form (when not doing exact match like for delegates)
3623 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.Covariant) == 0) {
3624 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3626 params_expanded_form = true;
3630 if (params_expanded_form)
3632 return (arg_count - i) * 2 + score;
3636 if (arg_count != param_count)
3637 params_expanded_form = true;
3642 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3645 // Types have to be identical when ref or out modifer is used
3647 if ((arg_mod | param_mod) != 0) {
3648 if (argument.Type != parameter) {
3649 if (argument.Type == InternalType.Dynamic)
3656 // Deploy custom error reporting for lambda methods. When probing lambda methods
3657 // keep all errors reported in separate set and once we are done and no best
3658 // candidate found, this set is used to report more details about what was wrong
3661 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3662 if (lambda_conv_msgs == null) {
3663 lambda_conv_msgs = new SessionReportPrinter ();
3664 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3668 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3669 if (lambda_conv_msgs != null) {
3670 lambda_conv_msgs.EndSession ();
3673 if (argument.Type == InternalType.Dynamic)
3680 if (arg_mod != param_mod)
3686 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3688 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3690 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3693 var ac_p = p as ArrayContainer;
3695 var ac_q = ((ArrayContainer) q);
3696 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3697 if (specific == ac_p.Element)
3699 if (specific == ac_q.Element)
3701 } else if (TypeManager.IsGenericType (p)) {
3702 var pargs = TypeManager.GetTypeArguments (p);
3703 var qargs = TypeManager.GetTypeArguments (q);
3705 bool p_specific_at_least_once = false;
3706 bool q_specific_at_least_once = false;
3708 for (int i = 0; i < pargs.Length; i++) {
3709 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3710 if (specific == pargs[i])
3711 p_specific_at_least_once = true;
3712 if (specific == qargs[i])
3713 q_specific_at_least_once = true;
3716 if (p_specific_at_least_once && !q_specific_at_least_once)
3718 if (!p_specific_at_least_once && q_specific_at_least_once)
3726 // Find the best method from candidate list
3728 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3730 List<AmbiguousCandidate> ambiguous_candidates = null;
3732 MemberSpec best_candidate;
3733 Arguments best_candidate_args = null;
3734 bool best_candidate_params = false;
3735 int best_candidate_rate;
3737 int args_count = args != null ? args.Count : 0;
3738 Arguments candidate_args = args;
3739 bool error_mode = false;
3740 var current_type = rc.CurrentType;
3741 MemberSpec invocable_member = null;
3743 // Cannot return until error reporter is restored
3745 best_candidate = null;
3746 best_candidate_rate = int.MaxValue;
3748 var type_members = members;
3751 for (int i = 0; i < type_members.Count; ++i) {
3752 var member = type_members [i];
3755 // Methods in a base class are not candidates if any method in a derived
3756 // class is applicable
3758 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3761 if (!member.IsAccessible (current_type) && !error_mode)
3764 if (!(member is IParametersMember)) {
3766 // Will use it later to report ambiguity between best method and invocable member
3768 if (Invocation.IsMemberInvocable (member))
3769 invocable_member = member;
3775 // Check if candidate is applicable
3777 bool params_expanded_form = false;
3778 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3781 // How does it score compare to others
3783 if (candidate_rate < best_candidate_rate) {
3784 best_candidate_rate = candidate_rate;
3785 best_candidate = member;
3786 best_candidate_args = candidate_args;
3787 best_candidate_params = params_expanded_form;
3788 } else if (candidate_rate == 0) {
3789 // Is new candidate better
3790 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3791 best_candidate = member;
3792 best_candidate_args = candidate_args;
3793 best_candidate_params = params_expanded_form;
3795 // It's not better but any other found later could be but we are not sure yet
3796 if (ambiguous_candidates == null)
3797 ambiguous_candidates = new List<AmbiguousCandidate> ();
3799 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3803 // Restore expanded arguments
3804 if (candidate_args != args)
3805 candidate_args = args;
3807 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3809 if (prev_recorder != null)
3810 rc.Report.SetPrinter (prev_recorder);
3813 // We've found exact match
3815 if (best_candidate_rate == 0)
3819 // Extension methods lookup when no ordinary method match was found
3822 var emg = base_provider.LookupExtensionMethod (rc, type_arguments == null ? 0 : type_arguments.Count);
3824 emg = emg.OverloadResolve (rc, ref args, custom_errors, error_mode ? Restrictions.ProbingOnly : Restrictions.None);
3826 return (T) (MemberSpec) emg.BestCandidate;
3830 // Don't run expensive error reporting mode for probing
3837 lambda_conv_msgs = null;
3842 // No best member match found, report an error
3844 if (best_candidate_rate != 0 || error_mode) {
3845 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
3850 if (args_count != 0 && args.HasDynamic) {
3851 BestCandidateIsDynamic = true;
3855 if (ambiguous_candidates != null) {
3857 // Now check that there are no ambiguities i.e the selected method
3858 // should be better than all the others
3860 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
3861 var candidate = ambiguous_candidates [ix];
3863 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
3864 var ambiguous = candidate.Member;
3865 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
3866 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3867 rc.Report.SymbolRelatedToPreviousError (ambiguous);
3868 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3869 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
3872 return (T) best_candidate;
3877 if (invocable_member != null) {
3878 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3879 rc.Report.SymbolRelatedToPreviousError (invocable_member);
3880 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
3881 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
3885 // And now check if the arguments are all
3886 // compatible, perform conversions if
3887 // necessary etc. and return if everything is
3890 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
3893 if (best_candidate == null)
3897 // Check ObsoleteAttribute on the best method
3899 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
3900 if (oa != null && !rc.IsObsolete)
3901 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
3903 best_candidate.MemberDefinition.SetIsUsed ();
3905 args = best_candidate_args;
3906 return (T) best_candidate;
3909 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
3911 return ResolveMember<MethodSpec> (rc, ref args);
3914 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
3915 Argument a, AParametersCollection expected_par, TypeSpec paramType)
3917 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
3920 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3921 ec.Report.SymbolRelatedToPreviousError (method);
3922 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3923 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3924 TypeManager.CSharpSignature (method));
3927 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3928 TypeManager.CSharpSignature (method));
3929 } else if (IsDelegateInvoke) {
3930 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3931 DelegateType.GetSignatureForError ());
3933 ec.Report.SymbolRelatedToPreviousError (method);
3934 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3935 method.GetSignatureForError ());
3938 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
3940 string index = (idx + 1).ToString ();
3941 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3942 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3943 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3944 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3945 index, Parameter.GetModifierSignature (a.Modifier));
3947 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3948 index, Parameter.GetModifierSignature (mod));
3950 string p1 = a.GetSignatureForError ();
3951 string p2 = TypeManager.CSharpName (paramType);
3954 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3955 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3956 ec.Report.SymbolRelatedToPreviousError (paramType);
3959 ec.Report.Error (1503, loc,
3960 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3965 // We have failed to find exact match so we return error info about the closest match
3967 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
3969 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
3970 int arg_count = args == null ? 0 : args.Count;
3972 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
3973 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
3974 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
3978 if (lambda_conv_msgs != null) {
3979 if (lambda_conv_msgs.Merge (rc.Report.Printer))
3984 // For candidates which match on parameters count report more details about incorrect arguments
3986 var pm = best_candidate as IParametersMember;
3988 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
3989 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
3990 // Reject any inaccessible member
3991 if (!best_candidate.IsAccessible (rc.CurrentType)) {
3992 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3993 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
3997 var ms = best_candidate as MethodSpec;
3998 if (ms != null && ms.IsGeneric && ta_count == 0) {
3999 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4002 rc.Report.Error (411, loc,
4003 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4004 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4008 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4014 // We failed to find any method with correct argument count, report best candidate
4016 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4019 if (best_candidate.Kind == MemberKind.Constructor) {
4020 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4021 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4022 } else if (IsDelegateInvoke) {
4023 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4024 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4025 DelegateType.GetSignatureForError (), arg_count.ToString ());
4027 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4028 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4029 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4030 name, arg_count.ToString ());
4034 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4036 var pm = member as IParametersMember;
4037 var pd = pm.Parameters;
4039 Parameter.Modifier p_mod = 0;
4041 int a_idx = 0, a_pos = 0;
4043 ArrayInitializer params_initializers = null;
4044 bool has_unsafe_arg = pm.MemberType.IsPointer;
4045 int arg_count = args == null ? 0 : args.Count;
4047 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4049 if (p_mod != Parameter.Modifier.PARAMS) {
4050 p_mod = pd.FixedParameters[a_idx].ModFlags;
4051 pt = pd.Types[a_idx];
4052 has_unsafe_arg |= pt.IsPointer;
4054 if (p_mod == Parameter.Modifier.PARAMS) {
4055 if (chose_params_expanded) {
4056 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4057 pt = TypeManager.GetElementType (pt);
4063 // Types have to be identical when ref or out modifer is used
4065 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4066 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4069 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4075 NamedArgument na = a as NamedArgument;
4077 int name_index = pd.GetParameterIndexByName (na.Name);
4078 if (name_index < 0 || name_index >= pd.Count) {
4079 if (IsDelegateInvoke) {
4080 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4081 ec.Report.Error (1746, na.Location,
4082 "The delegate `{0}' does not contain a parameter named `{1}'",
4083 DelegateType.GetSignatureForError (), na.Name);
4085 ec.Report.SymbolRelatedToPreviousError (member);
4086 ec.Report.Error (1739, na.Location,
4087 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4088 TypeManager.CSharpSignature (member), na.Name);
4090 } else if (args[name_index] != a) {
4091 if (IsDelegateInvoke)
4092 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4094 ec.Report.SymbolRelatedToPreviousError (member);
4096 ec.Report.Error (1744, na.Location,
4097 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4102 if (a.Expr.Type == InternalType.Dynamic)
4105 if ((restrictions & Restrictions.Covariant) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4106 custom_errors.NoArgumentMatch (ec, member);
4110 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4115 // Convert params arguments to an array initializer
4117 if (params_initializers != null) {
4118 // we choose to use 'a.Expr' rather than 'conv' so that
4119 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4120 params_initializers.Add (a.Expr);
4121 args.RemoveAt (a_idx--);
4126 // Update the argument with the implicit conversion
4130 if (a_idx != arg_count) {
4131 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4136 // Fill not provided arguments required by params modifier
4138 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4140 args = new Arguments (1);
4142 pt = pd.Types[pd.Count - 1];
4143 pt = TypeManager.GetElementType (pt);
4144 has_unsafe_arg |= pt.IsPointer;
4145 params_initializers = new ArrayInitializer (0, loc);
4149 // Append an array argument with all params arguments
4151 if (params_initializers != null) {
4152 args.Add (new Argument (
4153 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4157 if (has_unsafe_arg && !ec.IsUnsafe) {
4158 Expression.UnsafeError (ec, loc);
4165 public class ConstantExpr : MemberExpr
4169 public ConstantExpr (ConstSpec constant, Location loc)
4171 this.constant = constant;
4175 public override string Name {
4176 get { throw new NotImplementedException (); }
4179 public override bool IsInstance {
4180 get { return !IsStatic; }
4183 public override bool IsStatic {
4184 get { return true; }
4187 protected override TypeSpec DeclaringType {
4188 get { return constant.DeclaringType; }
4191 public override Expression CreateExpressionTree (ResolveContext ec)
4193 throw new NotSupportedException ("ET");
4196 protected override Expression DoResolve (ResolveContext rc)
4198 ResolveInstanceExpression (rc);
4199 DoBestMemberChecks (rc, constant);
4201 var c = constant.GetConstant (rc);
4203 // Creates reference expression to the constant value
4204 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4207 public override void Emit (EmitContext ec)
4209 throw new NotSupportedException ();
4212 public override string GetSignatureForError ()
4214 return constant.GetSignatureForError ();
4217 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4219 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4224 /// Fully resolved expression that evaluates to a Field
4226 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4227 protected FieldSpec spec;
4228 VariableInfo variable_info;
4230 LocalTemporary temp;
4233 protected FieldExpr (Location l)
4238 public FieldExpr (FieldSpec spec, Location loc)
4243 type = spec.MemberType;
4246 public FieldExpr (FieldBase fi, Location l)
4253 public override string Name {
4259 public bool IsHoisted {
4261 IVariableReference hv = InstanceExpression as IVariableReference;
4262 return hv != null && hv.IsHoisted;
4266 public override bool IsInstance {
4268 return !spec.IsStatic;
4272 public override bool IsStatic {
4274 return spec.IsStatic;
4278 public FieldSpec Spec {
4284 protected override TypeSpec DeclaringType {
4286 return spec.DeclaringType;
4290 public VariableInfo VariableInfo {
4292 return variable_info;
4298 public override string GetSignatureForError ()
4300 return TypeManager.GetFullNameSignature (spec);
4303 public bool IsMarshalByRefAccess ()
4305 // Checks possible ldflda of field access expression
4306 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4307 TypeManager.IsSubclassOf (spec.DeclaringType, TypeManager.mbr_type) &&
4308 !(InstanceExpression is This);
4311 public void SetHasAddressTaken ()
4313 IVariableReference vr = InstanceExpression as IVariableReference;
4315 vr.SetHasAddressTaken ();
4318 public override Expression CreateExpressionTree (ResolveContext ec)
4320 Expression instance;
4321 if (InstanceExpression == null) {
4322 instance = new NullLiteral (loc);
4324 instance = InstanceExpression.CreateExpressionTree (ec);
4327 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4329 CreateTypeOfExpression ());
4331 return CreateExpressionFactoryCall (ec, "Field", args);
4334 public Expression CreateTypeOfExpression ()
4336 return new TypeOfField (spec, loc);
4339 protected override Expression DoResolve (ResolveContext ec)
4341 return DoResolve (ec, false, false);
4344 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4346 if (ResolveInstanceExpression (ec)) {
4347 // Resolve the field's instance expression while flow analysis is turned
4348 // off: when accessing a field "a.b", we must check whether the field
4349 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4351 if (lvalue_instance) {
4352 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4353 Expression right_side =
4354 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4356 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4359 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4360 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4364 if (InstanceExpression == null)
4367 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4368 InstanceExpression.CheckMarshalByRefAccess (ec);
4372 DoBestMemberChecks (ec, spec);
4374 var fb = spec as FixedFieldSpec;
4375 IVariableReference var = InstanceExpression as IVariableReference;
4377 if (lvalue_instance && var != null && var.VariableInfo != null) {
4378 var.VariableInfo.SetFieldAssigned (ec, Name);
4382 IFixedExpression fe = InstanceExpression as IFixedExpression;
4383 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4384 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4387 if (InstanceExpression.eclass != ExprClass.Variable) {
4388 ec.Report.SymbolRelatedToPreviousError (spec);
4389 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4390 TypeManager.GetFullNameSignature (spec));
4391 } else if (var != null && var.IsHoisted) {
4392 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4395 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4398 eclass = ExprClass.Variable;
4400 // If the instance expression is a local variable or parameter.
4401 if (var == null || var.VariableInfo == null)
4404 VariableInfo vi = var.VariableInfo;
4405 if (!vi.IsFieldAssigned (ec, Name, loc))
4408 variable_info = vi.GetSubStruct (Name);
4412 static readonly int [] codes = {
4413 191, // instance, write access
4414 192, // instance, out access
4415 198, // static, write access
4416 199, // static, out access
4417 1648, // member of value instance, write access
4418 1649, // member of value instance, out access
4419 1650, // member of value static, write access
4420 1651 // member of value static, out access
4423 static readonly string [] msgs = {
4424 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4425 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4426 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4427 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4428 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4429 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4430 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4431 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4434 // The return value is always null. Returning a value simplifies calling code.
4435 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4438 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4442 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4444 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4449 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4451 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4452 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4454 Expression e = DoResolve (ec, lvalue_instance, out_access);
4459 spec.MemberDefinition.SetIsAssigned ();
4461 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4462 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4463 ec.Report.Warning (420, 1, loc,
4464 "`{0}': A volatile field references will not be treated as volatile",
4465 spec.GetSignatureForError ());
4468 if (spec.IsReadOnly) {
4469 // InitOnly fields can only be assigned in constructors or initializers
4470 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4471 return Report_AssignToReadonly (ec, right_side);
4473 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4475 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4476 if (!TypeManager.IsEqual (ec.CurrentMemberDefinition.Parent.Definition, spec.DeclaringType.GetDefinition ()))
4477 return Report_AssignToReadonly (ec, right_side);
4478 // static InitOnly fields cannot be assigned-to in an instance constructor
4479 if (IsStatic && !ec.IsStatic)
4480 return Report_AssignToReadonly (ec, right_side);
4481 // instance constructors can't modify InitOnly fields of other instances of the same type
4482 if (!IsStatic && !(InstanceExpression is This))
4483 return Report_AssignToReadonly (ec, right_side);
4487 if (right_side == EmptyExpression.OutAccess.Instance &&
4488 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (spec.DeclaringType, TypeManager.mbr_type)) {
4489 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4490 ec.Report.Warning (197, 1, loc,
4491 "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",
4492 GetSignatureForError ());
4495 eclass = ExprClass.Variable;
4499 public override int GetHashCode ()
4501 return spec.GetHashCode ();
4504 public bool IsFixed {
4507 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4509 IVariableReference variable = InstanceExpression as IVariableReference;
4510 if (variable != null)
4511 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4513 IFixedExpression fe = InstanceExpression as IFixedExpression;
4514 return fe != null && fe.IsFixed;
4518 public override bool Equals (object obj)
4520 FieldExpr fe = obj as FieldExpr;
4524 if (spec != fe.spec)
4527 if (InstanceExpression == null || fe.InstanceExpression == null)
4530 return InstanceExpression.Equals (fe.InstanceExpression);
4533 public void Emit (EmitContext ec, bool leave_copy)
4535 bool is_volatile = false;
4537 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4540 spec.MemberDefinition.SetIsUsed ();
4544 ec.Emit (OpCodes.Volatile);
4546 ec.Emit (OpCodes.Ldsfld, spec);
4549 EmitInstance (ec, false);
4551 // Optimization for build-in types
4552 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
4553 ec.EmitLoadFromPtr (type);
4555 var ff = spec as FixedFieldSpec;
4557 ec.Emit (OpCodes.Ldflda, spec);
4558 ec.Emit (OpCodes.Ldflda, ff.Element);
4561 ec.Emit (OpCodes.Volatile);
4563 ec.Emit (OpCodes.Ldfld, spec);
4569 ec.Emit (OpCodes.Dup);
4571 temp = new LocalTemporary (this.Type);
4577 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4579 prepared = prepare_for_load;
4581 EmitInstance (ec, prepared);
4585 ec.Emit (OpCodes.Dup);
4587 temp = new LocalTemporary (this.Type);
4592 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4593 ec.Emit (OpCodes.Volatile);
4595 spec.MemberDefinition.SetIsAssigned ();
4598 ec.Emit (OpCodes.Stsfld, spec);
4600 ec.Emit (OpCodes.Stfld, spec);
4609 public override void Emit (EmitContext ec)
4614 public override void EmitSideEffect (EmitContext ec)
4616 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4618 if (is_volatile) // || is_marshal_by_ref ())
4619 base.EmitSideEffect (ec);
4622 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
4625 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
4626 name, GetSignatureForError ());
4629 public void AddressOf (EmitContext ec, AddressOp mode)
4631 if ((mode & AddressOp.Store) != 0)
4632 spec.MemberDefinition.SetIsAssigned ();
4633 if ((mode & AddressOp.Load) != 0)
4634 spec.MemberDefinition.SetIsUsed ();
4637 // Handle initonly fields specially: make a copy and then
4638 // get the address of the copy.
4641 if (spec.IsReadOnly){
4643 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4656 local = ec.DeclareLocal (type, false);
4657 ec.Emit (OpCodes.Stloc, local);
4658 ec.Emit (OpCodes.Ldloca, local);
4664 ec.Emit (OpCodes.Ldsflda, spec);
4667 EmitInstance (ec, false);
4668 ec.Emit (OpCodes.Ldflda, spec);
4672 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4674 return MakeExpression (ctx);
4677 public override SLE.Expression MakeExpression (BuilderContext ctx)
4679 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4682 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4684 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4690 /// Expression that evaluates to a Property. The Assign class
4691 /// might set the `Value' expression if we are in an assignment.
4693 /// This is not an LValue because we need to re-write the expression, we
4694 /// can not take data from the stack and store it.
4696 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4698 public PropertyExpr (PropertySpec spec, Location l)
4701 best_candidate = spec;
4702 type = spec.MemberType;
4707 protected override TypeSpec DeclaringType {
4709 return best_candidate.DeclaringType;
4713 public override string Name {
4715 return best_candidate.Name;
4719 public override bool IsInstance {
4725 public override bool IsStatic {
4727 return best_candidate.IsStatic;
4731 public PropertySpec PropertyInfo {
4733 return best_candidate;
4739 public override Expression CreateExpressionTree (ResolveContext ec)
4742 if (IsSingleDimensionalArrayLength ()) {
4743 args = new Arguments (1);
4744 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4745 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4748 args = new Arguments (2);
4749 if (InstanceExpression == null)
4750 args.Add (new Argument (new NullLiteral (loc)));
4752 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4753 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4754 return CreateExpressionFactoryCall (ec, "Property", args);
4757 public Expression CreateSetterTypeOfExpression ()
4759 return new TypeOfMethod (Setter, loc);
4762 public override string GetSignatureForError ()
4764 return best_candidate.GetSignatureForError ();
4767 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4769 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4772 public override SLE.Expression MakeExpression (BuilderContext ctx)
4774 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4777 void Error_PropertyNotValid (ResolveContext ec)
4779 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4780 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4781 GetSignatureForError ());
4784 bool IsSingleDimensionalArrayLength ()
4786 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4789 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4790 return ac != null && ac.Rank == 1;
4793 public override void Emit (EmitContext ec, bool leave_copy)
4796 // Special case: length of single dimension array property is turned into ldlen
4798 if (IsSingleDimensionalArrayLength ()) {
4800 EmitInstance (ec, false);
4801 ec.Emit (OpCodes.Ldlen);
4802 ec.Emit (OpCodes.Conv_I4);
4806 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
4809 ec.Emit (OpCodes.Dup);
4811 temp = new LocalTemporary (this.Type);
4817 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4819 Expression my_source = source;
4821 if (prepare_for_load) {
4826 ec.Emit (OpCodes.Dup);
4828 temp = new LocalTemporary (this.Type);
4832 } else if (leave_copy) {
4834 temp = new LocalTemporary (this.Type);
4839 Arguments args = new Arguments (1);
4840 args.Add (new Argument (my_source));
4842 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
4850 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
4852 eclass = ExprClass.PropertyAccess;
4854 if (best_candidate.IsNotRealProperty) {
4855 Error_PropertyNotValid (rc);
4858 if (ResolveInstanceExpression (rc)) {
4859 if (right_side != null && best_candidate.DeclaringType.IsStruct)
4860 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
4863 DoBestMemberChecks (rc, best_candidate);
4867 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4869 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
4873 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
4875 // getter and setter can be different for base calls
4876 MethodSpec getter, setter;
4877 protected T best_candidate;
4879 protected LocalTemporary temp;
4880 protected bool prepared;
4882 protected PropertyOrIndexerExpr (Location l)
4889 public MethodSpec Getter {
4898 public MethodSpec Setter {
4909 protected override Expression DoResolve (ResolveContext ec)
4911 if (eclass == ExprClass.Unresolved) {
4912 var expr = OverloadResolve (ec, null);
4916 if (InstanceExpression != null)
4917 InstanceExpression.CheckMarshalByRefAccess (ec);
4920 return expr.Resolve (ec);
4923 if (!ResolveGetter (ec))
4929 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4931 if (right_side == EmptyExpression.OutAccess.Instance) {
4932 // TODO: best_candidate can be null at this point
4933 if (best_candidate != null && ec.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
4934 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
4935 best_candidate.Name);
4937 right_side.DoResolveLValue (ec, this);
4942 // if the property/indexer returns a value type, and we try to set a field in it
4943 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4944 Error_CannotModifyIntermediateExpressionValue (ec);
4947 if (eclass == ExprClass.Unresolved) {
4948 var expr = OverloadResolve (ec, right_side);
4953 return expr.ResolveLValue (ec, right_side);
4956 if (!ResolveSetter (ec))
4963 // Implements the IAssignMethod interface for assignments
4965 public abstract void Emit (EmitContext ec, bool leave_copy);
4966 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
4968 public override void Emit (EmitContext ec)
4973 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
4975 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
4977 bool ResolveGetter (ResolveContext rc)
4979 if (!best_candidate.HasGet) {
4980 if (InstanceExpression != EmptyExpression.Null) {
4981 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4982 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
4983 best_candidate.GetSignatureForError ());
4986 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
4987 if (best_candidate.HasDifferentAccessibility) {
4988 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
4989 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
4990 TypeManager.CSharpSignature (best_candidate));
4992 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
4993 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
4997 if (best_candidate.HasDifferentAccessibility) {
4998 CheckProtectedMemberAccess (rc, best_candidate.Get);
5001 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5005 bool ResolveSetter (ResolveContext rc)
5007 if (!best_candidate.HasSet) {
5008 if (rc.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5009 rc.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5010 best_candidate.Name);
5012 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5013 GetSignatureForError ());
5018 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5019 if (best_candidate.HasDifferentAccessibility) {
5020 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5021 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5022 GetSignatureForError ());
5024 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5025 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5029 if (best_candidate.HasDifferentAccessibility)
5030 CheckProtectedMemberAccess (rc, best_candidate.Set);
5032 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5038 /// Fully resolved expression that evaluates to an Event
5040 public class EventExpr : MemberExpr
5042 readonly EventSpec spec;
5044 public EventExpr (EventSpec spec, Location loc)
5050 public override string Name {
5056 public override bool IsInstance {
5058 return !spec.IsStatic;
5062 public override bool IsStatic {
5064 return spec.IsStatic;
5068 protected override TypeSpec DeclaringType {
5070 return spec.DeclaringType;
5074 public void Error_AssignmentEventOnly (ResolveContext ec)
5076 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5077 GetSignatureForError ());
5080 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5083 // If the event is local to this class, we transform ourselves into a FieldExpr
5086 if (spec.DeclaringType == ec.CurrentType ||
5087 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5089 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5090 // EventField mi = spec.MemberDefinition as EventField;
5092 if (spec.BackingField != null) {
5093 spec.MemberDefinition.SetIsUsed ();
5095 if (!ec.IsObsolete) {
5096 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5098 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5101 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5102 Error_AssignmentEventOnly (ec);
5104 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5106 InstanceExpression = null;
5108 return ml.ResolveMemberAccess (ec, left, original);
5112 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5113 Error_AssignmentEventOnly (ec);
5115 return base.ResolveMemberAccess (ec, left, original);
5118 public override Expression CreateExpressionTree (ResolveContext ec)
5120 throw new NotSupportedException ("ET");
5123 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5125 // contexts where an LValue is valid have already devolved to FieldExprs
5126 Error_CannotAssign (ec);
5130 protected override Expression DoResolve (ResolveContext ec)
5132 eclass = ExprClass.EventAccess;
5133 type = spec.MemberType;
5135 if (!spec.IsAccessible (ec.CurrentType)) {
5136 ec.Report.SymbolRelatedToPreviousError (spec);
5137 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec), ec.Report);
5140 if (IsBase && spec.IsAbstract) {
5141 Error_CannotCallAbstractBase (ec, GetSignatureForError ());
5144 ResolveInstanceExpression (ec);
5146 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5147 Error_CannotAssign (ec);
5150 DoBestMemberChecks (ec, spec);
5154 public override void Emit (EmitContext ec)
5156 throw new NotSupportedException ();
5157 //Error_CannotAssign ();
5160 public void Error_CannotAssign (ResolveContext ec)
5162 ec.Report.Error (70, loc,
5163 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5164 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5167 public override string GetSignatureForError ()
5169 return TypeManager.CSharpSignature (spec);
5172 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5174 Arguments args = new Arguments (1);
5175 args.Add (new Argument (source));
5176 Invocation.EmitCall (ec, InstanceExpression, is_add ? spec.AccessorAdd : spec.AccessorRemove, args, loc);
5179 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5181 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5185 public class TemporaryVariable : VariableReference
5189 public TemporaryVariable (TypeSpec type, Location loc)
5195 public override Expression CreateExpressionTree (ResolveContext ec)
5197 throw new NotSupportedException ("ET");
5200 protected override Expression DoResolve (ResolveContext ec)
5202 eclass = ExprClass.Variable;
5204 TypeExpr te = new TypeExpression (type, loc);
5205 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5206 if (!li.Resolve (ec))
5210 // Don't capture temporary variables except when using
5211 // iterator redirection
5213 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5214 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5215 storey.CaptureLocalVariable (ec, li);
5221 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5223 return Resolve (ec);
5226 public override void Emit (EmitContext ec)
5231 public void EmitAssign (EmitContext ec, Expression source)
5233 EmitAssign (ec, source, false, false);
5236 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5238 return li.HoistedVariant;
5241 public override bool IsFixed {
5242 get { return true; }
5245 public override bool IsRef {
5246 get { return false; }
5249 public override string Name {
5250 get { throw new NotImplementedException (); }
5253 public override void SetHasAddressTaken ()
5255 throw new NotImplementedException ();
5258 protected override ILocalVariable Variable {
5262 public override VariableInfo VariableInfo {
5263 get { throw new NotImplementedException (); }
5268 /// Handles `var' contextual keyword; var becomes a keyword only
5269 /// if no type called var exists in a variable scope
5271 class VarExpr : SimpleName
5273 // Used for error reporting only
5274 int initializers_count;
5276 public VarExpr (Location loc)
5279 initializers_count = 1;
5282 public int VariableInitializersCount {
5284 this.initializers_count = value;
5288 public bool InferType (ResolveContext ec, Expression right_side)
5291 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5293 type = right_side.Type;
5294 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5295 ec.Report.Error (815, loc,
5296 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5297 type.GetSignatureForError ());
5301 eclass = ExprClass.Variable;
5305 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5307 if (RootContext.Version < LanguageVersion.V_3)
5308 base.Error_TypeOrNamespaceNotFound (ec);
5310 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5313 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
5315 TypeExpr te = base.ResolveAsContextualType (rc, true);
5319 if (RootContext.Version < LanguageVersion.V_3)
5320 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5322 if (initializers_count == 1)
5325 if (initializers_count > 1) {
5326 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5327 initializers_count = 1;
5331 if (initializers_count == 0) {
5332 initializers_count = 1;
5333 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");