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;
16 using SLE = System.Linq.Expressions;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// The ExprClass class contains the is used to pass the
31 /// classification of an expression (value, variable, namespace,
32 /// type, method group, property access, event access, indexer access,
35 public enum ExprClass : byte {
51 /// This is used to tell Resolve in which types of expressions we're
55 public enum ResolveFlags {
56 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
59 // Returns a type expression.
62 // Returns a method group.
65 TypeParameter = 1 << 3,
67 // Mask of all the expression class flags.
68 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 // An expressions resolved as a direct variable reference
102 public interface IVariableReference : IFixedExpression
104 bool IsHoisted { get; }
106 VariableInfo VariableInfo { get; }
108 void SetHasAddressTaken ();
112 // Implemented by an expression which could be or is always
115 public interface IFixedExpression
117 bool IsFixed { get; }
121 /// Base class for expressions
123 public abstract class Expression {
124 public ExprClass eclass;
125 protected TypeSpec type;
126 protected Location loc;
128 public TypeSpec Type {
130 set { type = value; }
133 public virtual bool IsSideEffectFree {
139 public Location Location {
143 public virtual bool IsNull {
150 // Returns true when the expression during Emit phase breaks stack
151 // by using await expression
153 public virtual bool ContainsEmitWithAwait ()
159 /// Performs semantic analysis on the Expression
163 /// The Resolve method is invoked to perform the semantic analysis
166 /// The return value is an expression (it can be the
167 /// same expression in some cases) or a new
168 /// expression that better represents this node.
170 /// For example, optimizations of Unary (LiteralInt)
171 /// would return a new LiteralInt with a negated
174 /// If there is an error during semantic analysis,
175 /// then an error should be reported (using Report)
176 /// and a null value should be returned.
178 /// There are two side effects expected from calling
179 /// Resolve(): the the field variable "eclass" should
180 /// be set to any value of the enumeration
181 /// `ExprClass' and the type variable should be set
182 /// to a valid type (this is the type of the
185 protected abstract Expression DoResolve (ResolveContext rc);
187 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
193 // This is used if the expression should be resolved as a type or namespace name.
194 // the default implementation fails.
196 public virtual TypeSpec ResolveAsType (IMemberContext mc)
198 ResolveContext ec = new ResolveContext (mc);
199 Expression e = Resolve (ec);
201 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
206 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
208 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
211 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
213 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
216 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
218 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
219 name, TypeManager.CSharpName (type));
222 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
224 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
225 "expressions can be used as a statement");
228 public void Error_InvalidExpressionStatement (BlockContext ec)
230 Error_InvalidExpressionStatement (ec.Report, loc);
233 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
235 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
238 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
240 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
243 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
245 // The error was already reported as CS1660
246 if (type == InternalType.AnonymousMethod)
249 string from_type = type.GetSignatureForError ();
250 string to_type = target.GetSignatureForError ();
251 if (from_type == to_type) {
252 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
253 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
257 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
262 ec.Report.DisableReporting ();
263 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
264 ec.Report.EnableReporting ();
267 ec.Report.Error (266, loc,
268 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
271 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
276 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
278 // Better message for possible generic expressions
279 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
280 var report = context.Module.Compiler.Report;
281 report.SymbolRelatedToPreviousError (member);
282 if (member is TypeSpec)
283 member = ((TypeSpec) member).GetDefinition ();
285 member = ((MethodSpec) member).GetGenericMethodDefinition ();
287 string name = member.Kind == MemberKind.Method ? "method" : "type";
288 if (member.IsGeneric) {
289 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
290 name, member.GetSignatureForError (), member.Arity.ToString ());
292 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
293 name, member.GetSignatureForError ());
296 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
300 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
302 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
306 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
308 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
311 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
313 ec.Report.SymbolRelatedToPreviousError (type);
314 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
315 TypeManager.CSharpName (type), name);
318 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
320 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
323 protected void Error_VoidPointerOperation (ResolveContext rc)
325 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
328 public ResolveFlags ExprClassToResolveFlags {
332 case ExprClass.Namespace:
333 return ResolveFlags.Type;
335 case ExprClass.MethodGroup:
336 return ResolveFlags.MethodGroup;
338 case ExprClass.TypeParameter:
339 return ResolveFlags.TypeParameter;
341 case ExprClass.Value:
342 case ExprClass.Variable:
343 case ExprClass.PropertyAccess:
344 case ExprClass.EventAccess:
345 case ExprClass.IndexerAccess:
346 return ResolveFlags.VariableOrValue;
349 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
354 public virtual string GetSignatureForError ()
356 return type.GetDefinition ().GetSignatureForError ();
360 /// Resolves an expression and performs semantic analysis on it.
364 /// Currently Resolve wraps DoResolve to perform sanity
365 /// checking and assertion checking on what we expect from Resolve.
367 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
369 if (eclass != ExprClass.Unresolved)
379 if ((flags & e.ExprClassToResolveFlags) == 0) {
380 e.Error_UnexpectedKind (ec, flags, loc);
385 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
388 } catch (Exception ex) {
389 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
392 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
393 return EmptyExpression.Null; // TODO: Add location
398 /// Resolves an expression and performs semantic analysis on it.
400 public Expression Resolve (ResolveContext rc)
402 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
406 /// Resolves an expression for LValue assignment
410 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
411 /// checking and assertion checking on what we expect from Resolve
413 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
415 int errors = ec.Report.Errors;
416 bool out_access = right_side == EmptyExpression.OutAccess;
418 Expression e = DoResolveLValue (ec, right_side);
420 if (e != null && out_access && !(e is IMemoryLocation)) {
421 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
422 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
424 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
425 // e.GetType () + " " + e.GetSignatureForError ());
430 if (errors == ec.Report.Errors) {
432 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
434 Error_ValueAssignment (ec, loc);
439 if (e.eclass == ExprClass.Unresolved)
440 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
442 if ((e.type == null) && !(e is GenericTypeExpr))
443 throw new Exception ("Expression " + e + " did not set its type after Resolve");
448 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
450 rc.Module.Compiler.Report.Error (182, loc,
451 "An attribute argument must be a constant expression, typeof expression or array creation expression");
455 /// Emits the code for the expression
459 /// The Emit method is invoked to generate the code
460 /// for the expression.
462 public abstract void Emit (EmitContext ec);
465 // Emit code to branch to @target if this expression is equivalent to @on_true.
466 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
467 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
468 // including the use of conditional branches. Note also that a branch MUST be emitted
469 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
472 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
475 // Emit this expression for its side effects, not for its value.
476 // The default implementation is to emit the value, and then throw it away.
477 // Subclasses can provide more efficient implementations, but those MUST be equivalent
478 public virtual void EmitSideEffect (EmitContext ec)
481 ec.Emit (OpCodes.Pop);
485 // Emits the expression into temporary field variable. The method
486 // should be used for await expressions only
488 public virtual Expression EmitToField (EmitContext ec)
491 // This is the await prepare Emit method. When emitting code like
492 // a + b we emit code like
498 // For await a + await b we have to interfere the flow to keep the
499 // stack clean because await yields from the expression. The emit
502 // a = a.EmitToField () // a is changed to temporary field access
503 // b = b.EmitToField ()
509 // The idea is to emit expression and leave the stack empty with
510 // result value still available.
512 // Expressions should override this default implementation when
513 // optimized version can be provided (e.g. FieldExpr)
516 // We can optimize for side-effect free expressions, they can be
517 // emitted out of order
519 if (IsSideEffectFree)
522 // Emit original code
523 EmitToFieldSource (ec);
525 // Create temporary local (we cannot load this before Emit)
526 var temp = ec.GetTemporaryLocal (type);
527 ec.Emit (OpCodes.Stloc, temp);
530 // Store the result to temporary field
532 var field = ec.GetTemporaryField (type);
534 ec.Emit (OpCodes.Ldloc, temp);
535 field.EmitAssignFromStack (ec);
537 ec.FreeTemporaryLocal (temp, type);
542 protected virtual void EmitToFieldSource (EmitContext ec)
545 // Default implementation calls Emit method
550 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
552 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
553 bool contains_await = false;
555 for (int i = 1; i < expressions.Count; ++i) {
556 if (expressions[i].ContainsEmitWithAwait ()) {
557 contains_await = true;
562 if (contains_await) {
563 for (int i = 0; i < expressions.Count; ++i) {
564 expressions[i] = expressions[i].EmitToField (ec);
569 for (int i = 0; i < expressions.Count; ++i) {
570 expressions[i].Emit (ec);
575 /// Protected constructor. Only derivate types should
576 /// be able to be created
579 protected Expression ()
584 /// Returns a fully formed expression after a MemberLookup
587 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
589 if (spec is EventSpec)
590 return new EventExpr ((EventSpec) spec, loc);
591 if (spec is ConstSpec)
592 return new ConstantExpr ((ConstSpec) spec, loc);
593 if (spec is FieldSpec)
594 return new FieldExpr ((FieldSpec) spec, loc);
595 if (spec is PropertySpec)
596 return new PropertyExpr ((PropertySpec) spec, loc);
597 if (spec is TypeSpec)
598 return new TypeExpression (((TypeSpec) spec), loc);
603 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
605 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
607 rc.Report.SymbolRelatedToPreviousError (type);
609 // Report meaningful error for struct as they always have default ctor in C# context
610 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
612 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
613 type.GetSignatureForError ());
619 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
620 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
624 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
625 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
632 public enum MemberLookupRestrictions
641 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
642 // `qualifier_type' or null to lookup members in the current class.
644 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
646 var members = MemberCache.FindMembers (queried_type, name, false);
650 MemberSpec non_method = null;
651 MemberSpec ambig_non_method = null;
653 for (int i = 0; i < members.Count; ++i) {
654 var member = members[i];
656 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
657 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
660 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
664 if (!member.IsAccessible (rc))
668 // With runtime binder we can have a situation where queried type is inaccessible
669 // because it came via dynamic object, the check about inconsisted accessibility
670 // had no effect as the type was unknown during compilation
673 // private class N { }
675 // public dynamic Foo ()
681 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
685 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
686 if (member is MethodSpec)
687 return new MethodGroupExpr (members, queried_type, loc);
689 if (!Invocation.IsMemberInvocable (member))
693 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
695 } else if (!errorMode && !member.IsNotCSharpCompatible) {
696 ambig_non_method = member;
700 if (non_method != null) {
701 if (ambig_non_method != null && rc != null) {
702 var report = rc.Module.Compiler.Report;
703 report.SymbolRelatedToPreviousError (non_method);
704 report.SymbolRelatedToPreviousError (ambig_non_method);
705 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
706 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
709 if (non_method is MethodSpec)
710 return new MethodGroupExpr (members, queried_type, loc);
712 return ExprClassFromMemberInfo (non_method, loc);
715 if (members[0].DeclaringType.BaseType == null)
718 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
720 } while (members != null);
725 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
727 throw new NotImplementedException ();
730 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
732 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
736 /// Returns an expression that can be used to invoke operator true
737 /// on the expression if it exists.
739 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
741 return GetOperatorTrueOrFalse (ec, e, true, loc);
745 /// Returns an expression that can be used to invoke operator false
746 /// on the expression if it exists.
748 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
750 return GetOperatorTrueOrFalse (ec, e, false, loc);
753 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
755 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
756 var methods = MemberCache.GetUserOperator (e.type, op, false);
760 Arguments arguments = new Arguments (1);
761 arguments.Add (new Argument (e));
763 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
764 var oper = res.ResolveOperator (ec, ref arguments);
769 return new UserOperatorCall (oper, arguments, null, loc);
772 public virtual string ExprClassName
776 case ExprClass.Unresolved:
778 case ExprClass.Value:
780 case ExprClass.Variable:
782 case ExprClass.Namespace:
786 case ExprClass.MethodGroup:
787 return "method group";
788 case ExprClass.PropertyAccess:
789 return "property access";
790 case ExprClass.EventAccess:
791 return "event access";
792 case ExprClass.IndexerAccess:
793 return "indexer access";
794 case ExprClass.Nothing:
796 case ExprClass.TypeParameter:
797 return "type parameter";
799 throw new Exception ("Should not happen");
804 /// Reports that we were expecting `expr' to be of class `expected'
806 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
808 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
811 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
815 name = mc.GetSignatureForError ();
817 name = GetSignatureForError ();
819 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
820 name, was, expected);
823 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
825 string [] valid = new string [4];
828 if ((flags & ResolveFlags.VariableOrValue) != 0) {
829 valid [count++] = "variable";
830 valid [count++] = "value";
833 if ((flags & ResolveFlags.Type) != 0)
834 valid [count++] = "type";
836 if ((flags & ResolveFlags.MethodGroup) != 0)
837 valid [count++] = "method group";
840 valid [count++] = "unknown";
842 StringBuilder sb = new StringBuilder (valid [0]);
843 for (int i = 1; i < count - 1; i++) {
845 sb.Append (valid [i]);
848 sb.Append ("' or `");
849 sb.Append (valid [count - 1]);
852 ec.Report.Error (119, loc,
853 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
856 public static void UnsafeError (ResolveContext ec, Location loc)
858 UnsafeError (ec.Report, loc);
861 public static void UnsafeError (Report Report, Location loc)
863 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
866 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
868 ec.Report.SymbolRelatedToPreviousError (type);
869 if (ec.CurrentInitializerVariable != null) {
870 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
871 TypeManager.CSharpName (type), GetSignatureForError ());
873 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
874 GetSignatureForError ());
879 // Converts `source' to an int, uint, long or ulong.
881 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
883 var btypes = ec.BuiltinTypes;
885 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
886 Arguments args = new Arguments (1);
887 args.Add (new Argument (source));
888 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
891 Expression converted;
893 using (ec.Set (ResolveContext.Options.CheckedScope)) {
894 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
895 if (converted == null)
896 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
897 if (converted == null)
898 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
899 if (converted == null)
900 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
902 if (converted == null) {
903 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
909 // Only positive constants are allowed at compile time
911 Constant c = converted as Constant;
912 if (c != null && c.IsNegative)
913 Error_NegativeArrayIndex (ec, source.loc);
915 // No conversion needed to array index
916 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
919 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
923 // Derived classes implement this method by cloning the fields that
924 // could become altered during the Resolve stage
926 // Only expressions that are created for the parser need to implement
929 protected virtual void CloneTo (CloneContext clonectx, Expression target)
931 throw new NotImplementedException (
933 "CloneTo not implemented for expression {0}", this.GetType ()));
937 // Clones an expression created by the parser.
939 // We only support expressions created by the parser so far, not
940 // expressions that have been resolved (many more classes would need
941 // to implement CloneTo).
943 // This infrastructure is here merely for Lambda expressions which
944 // compile the same code using different type values for the same
945 // arguments to find the correct overload
947 public virtual Expression Clone (CloneContext clonectx)
949 Expression cloned = (Expression) MemberwiseClone ();
950 CloneTo (clonectx, cloned);
956 // Implementation of expression to expression tree conversion
958 public abstract Expression CreateExpressionTree (ResolveContext ec);
960 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
962 return CreateExpressionFactoryCall (ec, name, null, args, loc);
965 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
967 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
970 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
972 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
975 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
977 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
981 return new TypeExpression (t, loc);
985 // Implemented by all expressions which support conversion from
986 // compiler expression to invokable runtime expression. Used by
987 // dynamic C# binder.
989 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
991 throw new NotImplementedException ("MakeExpression for " + GetType ());
996 /// This is just a base class for expressions that can
997 /// appear on statements (invocations, object creation,
998 /// assignments, post/pre increment and decrement). The idea
999 /// being that they would support an extra Emition interface that
1000 /// does not leave a result on the stack.
1002 public abstract class ExpressionStatement : Expression {
1004 public ExpressionStatement ResolveStatement (BlockContext ec)
1006 Expression e = Resolve (ec);
1010 ExpressionStatement es = e as ExpressionStatement;
1012 Error_InvalidExpressionStatement (ec);
1018 /// Requests the expression to be emitted in a `statement'
1019 /// context. This means that no new value is left on the
1020 /// stack after invoking this method (constrasted with
1021 /// Emit that will always leave a value on the stack).
1023 public abstract void EmitStatement (EmitContext ec);
1025 public override void EmitSideEffect (EmitContext ec)
1032 /// This kind of cast is used to encapsulate the child
1033 /// whose type is child.Type into an expression that is
1034 /// reported to return "return_type". This is used to encapsulate
1035 /// expressions which have compatible types, but need to be dealt
1036 /// at higher levels with.
1038 /// For example, a "byte" expression could be encapsulated in one
1039 /// of these as an "unsigned int". The type for the expression
1040 /// would be "unsigned int".
1043 public abstract class TypeCast : Expression
1045 protected readonly Expression child;
1047 protected TypeCast (Expression child, TypeSpec return_type)
1049 eclass = child.eclass;
1050 loc = child.Location;
1055 public Expression Child {
1061 public override bool ContainsEmitWithAwait ()
1063 return child.ContainsEmitWithAwait ();
1066 public override Expression CreateExpressionTree (ResolveContext ec)
1068 Arguments args = new Arguments (2);
1069 args.Add (new Argument (child.CreateExpressionTree (ec)));
1070 args.Add (new Argument (new TypeOf (type, loc)));
1072 if (type.IsPointer || child.Type.IsPointer)
1073 Error_PointerInsideExpressionTree (ec);
1075 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1078 protected override Expression DoResolve (ResolveContext ec)
1080 // This should never be invoked, we are born in fully
1081 // initialized state.
1086 public override void Emit (EmitContext ec)
1091 public override SLE.Expression MakeExpression (BuilderContext ctx)
1094 return base.MakeExpression (ctx);
1096 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1097 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1098 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1102 protected override void CloneTo (CloneContext clonectx, Expression t)
1107 public override bool IsNull {
1108 get { return child.IsNull; }
1112 public class EmptyCast : TypeCast {
1113 EmptyCast (Expression child, TypeSpec target_type)
1114 : base (child, target_type)
1118 public static Expression Create (Expression child, TypeSpec type)
1120 Constant c = child as Constant;
1122 return new EmptyConstantCast (c, type);
1124 EmptyCast e = child as EmptyCast;
1126 return new EmptyCast (e.child, type);
1128 return new EmptyCast (child, type);
1131 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1133 child.EmitBranchable (ec, label, on_true);
1136 public override void EmitSideEffect (EmitContext ec)
1138 child.EmitSideEffect (ec);
1143 // Used for predefined type user operator (no obsolete check, etc.)
1145 public class OperatorCast : TypeCast
1147 readonly MethodSpec conversion_operator;
1149 public OperatorCast (Expression expr, TypeSpec target_type)
1150 : this (expr, target_type, target_type, false)
1154 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1155 : this (expr, target_type, target_type, find_explicit)
1159 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1160 : base (expr, returnType)
1162 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1163 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1166 foreach (MethodSpec oper in mi) {
1167 if (oper.ReturnType != returnType)
1170 if (oper.Parameters.Types[0] == expr.Type) {
1171 conversion_operator = oper;
1177 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1178 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1181 public override void Emit (EmitContext ec)
1184 ec.Emit (OpCodes.Call, conversion_operator);
1189 // Constant specialization of EmptyCast.
1190 // We need to special case this since an empty cast of
1191 // a constant is still a constant.
1193 public class EmptyConstantCast : Constant
1195 public readonly Constant child;
1197 public EmptyConstantCast (Constant child, TypeSpec type)
1198 : base (child.Location)
1201 throw new ArgumentNullException ("child");
1204 this.eclass = child.eclass;
1208 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1210 if (child.Type == target_type)
1213 // FIXME: check that 'type' can be converted to 'target_type' first
1214 return child.ConvertExplicitly (in_checked_context, target_type);
1217 public override Expression CreateExpressionTree (ResolveContext ec)
1219 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1220 child.CreateExpressionTree (ec),
1221 new TypeOf (type, loc));
1224 Error_PointerInsideExpressionTree (ec);
1226 return CreateExpressionFactoryCall (ec, "Convert", args);
1229 public override bool IsDefaultValue {
1230 get { return child.IsDefaultValue; }
1233 public override bool IsNegative {
1234 get { return child.IsNegative; }
1237 public override bool IsNull {
1238 get { return child.IsNull; }
1241 public override bool IsOneInteger {
1242 get { return child.IsOneInteger; }
1245 public override bool IsSideEffectFree {
1247 return child.IsSideEffectFree;
1251 public override bool IsZeroInteger {
1252 get { return child.IsZeroInteger; }
1255 public override void Emit (EmitContext ec)
1260 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1262 child.EmitBranchable (ec, label, on_true);
1264 // Only to make verifier happy
1265 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1266 ec.Emit (OpCodes.Unbox_Any, type);
1269 public override void EmitSideEffect (EmitContext ec)
1271 child.EmitSideEffect (ec);
1274 public override object GetValue ()
1276 return child.GetValue ();
1279 public override string GetValueAsLiteral ()
1281 return child.GetValueAsLiteral ();
1284 public override long GetValueAsLong ()
1286 return child.GetValueAsLong ();
1289 public override Constant ConvertImplicitly (TypeSpec target_type)
1291 if (type == target_type)
1294 // FIXME: Do we need to check user conversions?
1295 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1298 return child.ConvertImplicitly (target_type);
1303 /// This class is used to wrap literals which belong inside Enums
1305 public class EnumConstant : Constant
1307 public Constant Child;
1309 public EnumConstant (Constant child, TypeSpec enum_type)
1310 : base (child.Location)
1314 this.eclass = ExprClass.Value;
1315 this.type = enum_type;
1318 protected EnumConstant (Location loc)
1323 public override void Emit (EmitContext ec)
1328 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1330 Child.EncodeAttributeValue (rc, enc, Child.Type);
1333 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1335 Child.EmitBranchable (ec, label, on_true);
1338 public override void EmitSideEffect (EmitContext ec)
1340 Child.EmitSideEffect (ec);
1343 public override string GetSignatureForError()
1345 return TypeManager.CSharpName (Type);
1348 public override object GetValue ()
1350 return Child.GetValue ();
1354 public override object GetTypedValue ()
1357 // The method can be used in dynamic context only (on closed types)
1359 // System.Enum.ToObject cannot be called on dynamic types
1360 // EnumBuilder has to be used, but we cannot use EnumBuilder
1361 // because it does not properly support generics
1363 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1367 public override string GetValueAsLiteral ()
1369 return Child.GetValueAsLiteral ();
1372 public override long GetValueAsLong ()
1374 return Child.GetValueAsLong ();
1377 public EnumConstant Increment()
1379 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1382 public override bool IsDefaultValue {
1384 return Child.IsDefaultValue;
1388 public override bool IsSideEffectFree {
1390 return Child.IsSideEffectFree;
1394 public override bool IsZeroInteger {
1395 get { return Child.IsZeroInteger; }
1398 public override bool IsNegative {
1400 return Child.IsNegative;
1404 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1406 if (Child.Type == target_type)
1409 return Child.ConvertExplicitly (in_checked_context, target_type);
1412 public override Constant ConvertImplicitly (TypeSpec type)
1414 if (this.type == type) {
1418 if (!Convert.ImplicitStandardConversionExists (this, type)){
1422 return Child.ConvertImplicitly (type);
1427 /// This kind of cast is used to encapsulate Value Types in objects.
1429 /// The effect of it is to box the value type emitted by the previous
1432 public class BoxedCast : TypeCast {
1434 public BoxedCast (Expression expr, TypeSpec target_type)
1435 : base (expr, target_type)
1437 eclass = ExprClass.Value;
1440 protected override Expression DoResolve (ResolveContext ec)
1442 // This should never be invoked, we are born in fully
1443 // initialized state.
1448 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1450 // Only boxing to object type is supported
1451 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1452 base.EncodeAttributeValue (rc, enc, targetType);
1456 enc.Encode (child.Type);
1457 child.EncodeAttributeValue (rc, enc, child.Type);
1460 public override void Emit (EmitContext ec)
1464 ec.Emit (OpCodes.Box, child.Type);
1467 public override void EmitSideEffect (EmitContext ec)
1469 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1470 // so, we need to emit the box+pop instructions in most cases
1471 if (child.Type.IsStruct &&
1472 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1473 child.EmitSideEffect (ec);
1475 base.EmitSideEffect (ec);
1479 public class UnboxCast : TypeCast {
1480 public UnboxCast (Expression expr, TypeSpec return_type)
1481 : base (expr, return_type)
1485 protected override Expression DoResolve (ResolveContext ec)
1487 // This should never be invoked, we are born in fully
1488 // initialized state.
1493 public override void Emit (EmitContext ec)
1497 ec.Emit (OpCodes.Unbox_Any, type);
1502 /// This is used to perform explicit numeric conversions.
1504 /// Explicit numeric conversions might trigger exceptions in a checked
1505 /// context, so they should generate the conv.ovf opcodes instead of
1508 public class ConvCast : TypeCast {
1509 public enum Mode : byte {
1510 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1512 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1513 U2_I1, U2_U1, U2_I2, U2_CH,
1514 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1515 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1516 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1517 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1518 CH_I1, CH_U1, CH_I2,
1519 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1520 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1526 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1527 : base (child, return_type)
1532 protected override Expression DoResolve (ResolveContext ec)
1534 // This should never be invoked, we are born in fully
1535 // initialized state.
1540 public override string ToString ()
1542 return String.Format ("ConvCast ({0}, {1})", mode, child);
1545 public override void Emit (EmitContext ec)
1549 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1551 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1552 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1553 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1554 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1555 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1557 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1558 case Mode.U1_CH: /* nothing */ break;
1560 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1561 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1562 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1563 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1564 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1565 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1567 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1568 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1569 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1570 case Mode.U2_CH: /* nothing */ break;
1572 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1573 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1574 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1575 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1576 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1577 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1578 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1580 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1581 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1582 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1583 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1584 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1585 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1587 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1588 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1589 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1590 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1592 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1593 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1594 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1595 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1597 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1598 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1599 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1600 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1601 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1602 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1603 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1604 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1605 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1607 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1608 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1609 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1611 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1612 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1613 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1614 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1615 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1616 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1617 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1618 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1619 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1622 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1623 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1624 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1626 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1627 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1628 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1629 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1632 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1636 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1637 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1638 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1639 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1640 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1642 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1643 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1645 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1646 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1647 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1649 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1650 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1652 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1653 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1654 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1655 case Mode.U2_CH: /* nothing */ break;
1657 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1659 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1660 case Mode.I4_U4: /* nothing */ break;
1661 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1662 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1663 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1665 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1666 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1667 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1668 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.U4_I4: /* nothing */ break;
1670 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1673 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1674 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1675 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1677 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1678 case Mode.I8_U8: /* nothing */ break;
1679 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1682 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1683 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1684 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1685 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1687 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1688 case Mode.U8_I8: /* nothing */ break;
1689 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1692 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1693 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1694 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1697 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1698 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1699 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1700 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1701 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1702 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1703 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1704 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1707 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1708 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1709 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1710 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1711 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1712 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1713 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1714 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1717 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1723 class OpcodeCast : TypeCast
1727 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1728 : base (child, return_type)
1733 protected override Expression DoResolve (ResolveContext ec)
1735 // This should never be invoked, we are born in fully
1736 // initialized state.
1741 public override void Emit (EmitContext ec)
1747 public TypeSpec UnderlyingType {
1748 get { return child.Type; }
1753 // Opcode casts expression with 2 opcodes but only
1754 // single expression tree node
1756 class OpcodeCastDuplex : OpcodeCast
1758 readonly OpCode second;
1760 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1761 : base (child, returnType, first)
1763 this.second = second;
1766 public override void Emit (EmitContext ec)
1774 /// This kind of cast is used to encapsulate a child and cast it
1775 /// to the class requested
1777 public sealed class ClassCast : TypeCast {
1778 readonly bool forced;
1780 public ClassCast (Expression child, TypeSpec return_type)
1781 : base (child, return_type)
1785 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1786 : base (child, return_type)
1788 this.forced = forced;
1791 public override void Emit (EmitContext ec)
1795 bool gen = TypeManager.IsGenericParameter (child.Type);
1797 ec.Emit (OpCodes.Box, child.Type);
1799 if (type.IsGenericParameter) {
1800 ec.Emit (OpCodes.Unbox_Any, type);
1807 ec.Emit (OpCodes.Castclass, type);
1812 // Created during resolving pahse when an expression is wrapped or constantified
1813 // and original expression can be used later (e.g. for expression trees)
1815 public class ReducedExpression : Expression
1817 sealed class ReducedConstantExpression : EmptyConstantCast
1819 readonly Expression orig_expr;
1821 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1822 : base (expr, expr.Type)
1824 this.orig_expr = orig_expr;
1827 public override Constant ConvertImplicitly (TypeSpec target_type)
1829 Constant c = base.ConvertImplicitly (target_type);
1831 c = new ReducedConstantExpression (c, orig_expr);
1836 public override Expression CreateExpressionTree (ResolveContext ec)
1838 return orig_expr.CreateExpressionTree (ec);
1841 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1843 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1845 c = new ReducedConstantExpression (c, orig_expr);
1850 sealed class ReducedExpressionStatement : ExpressionStatement
1852 readonly Expression orig_expr;
1853 readonly ExpressionStatement stm;
1855 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1857 this.orig_expr = orig;
1859 this.eclass = stm.eclass;
1860 this.type = stm.Type;
1862 this.loc = orig.Location;
1865 public override bool ContainsEmitWithAwait ()
1867 return stm.ContainsEmitWithAwait ();
1870 public override Expression CreateExpressionTree (ResolveContext ec)
1872 return orig_expr.CreateExpressionTree (ec);
1875 protected override Expression DoResolve (ResolveContext ec)
1880 public override void Emit (EmitContext ec)
1885 public override void EmitStatement (EmitContext ec)
1887 stm.EmitStatement (ec);
1891 readonly Expression expr, orig_expr;
1893 private ReducedExpression (Expression expr, Expression orig_expr)
1896 this.eclass = expr.eclass;
1897 this.type = expr.Type;
1898 this.orig_expr = orig_expr;
1899 this.loc = orig_expr.Location;
1904 public Expression OriginalExpression {
1912 public override bool ContainsEmitWithAwait ()
1914 return expr.ContainsEmitWithAwait ();
1918 // Creates fully resolved expression switcher
1920 public static Constant Create (Constant expr, Expression original_expr)
1922 if (expr.eclass == ExprClass.Unresolved)
1923 throw new ArgumentException ("Unresolved expression");
1925 return new ReducedConstantExpression (expr, original_expr);
1928 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1930 return new ReducedExpressionStatement (s, orig);
1933 public static Expression Create (Expression expr, Expression original_expr)
1935 return Create (expr, original_expr, true);
1939 // Creates unresolved reduce expression. The original expression has to be
1940 // already resolved. Created expression is constant based based on `expr'
1941 // value unless canBeConstant is used
1943 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1945 if (canBeConstant) {
1946 Constant c = expr as Constant;
1948 return Create (c, original_expr);
1951 ExpressionStatement s = expr as ExpressionStatement;
1953 return Create (s, original_expr);
1955 if (expr.eclass == ExprClass.Unresolved)
1956 throw new ArgumentException ("Unresolved expression");
1958 return new ReducedExpression (expr, original_expr);
1961 public override Expression CreateExpressionTree (ResolveContext ec)
1963 return orig_expr.CreateExpressionTree (ec);
1966 protected override Expression DoResolve (ResolveContext ec)
1971 public override void Emit (EmitContext ec)
1976 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1978 expr.EmitBranchable (ec, target, on_true);
1981 public override SLE.Expression MakeExpression (BuilderContext ctx)
1983 return orig_expr.MakeExpression (ctx);
1988 // Standard composite pattern
1990 public abstract class CompositeExpression : Expression
1992 protected Expression expr;
1994 protected CompositeExpression (Expression expr)
1997 this.loc = expr.Location;
2000 public override bool ContainsEmitWithAwait ()
2002 return expr.ContainsEmitWithAwait ();
2005 public override Expression CreateExpressionTree (ResolveContext rc)
2007 return expr.CreateExpressionTree (rc);
2010 public Expression Child {
2011 get { return expr; }
2014 protected override Expression DoResolve (ResolveContext rc)
2016 expr = expr.Resolve (rc);
2019 eclass = expr.eclass;
2025 public override void Emit (EmitContext ec)
2030 public override bool IsNull {
2031 get { return expr.IsNull; }
2036 // Base of expressions used only to narrow resolve flow
2038 public abstract class ShimExpression : Expression
2040 protected Expression expr;
2042 protected ShimExpression (Expression expr)
2047 public Expression Expr {
2053 protected override void CloneTo (CloneContext clonectx, Expression t)
2058 ShimExpression target = (ShimExpression) t;
2059 target.expr = expr.Clone (clonectx);
2062 public override bool ContainsEmitWithAwait ()
2064 return expr.ContainsEmitWithAwait ();
2067 public override Expression CreateExpressionTree (ResolveContext ec)
2069 throw new NotSupportedException ("ET");
2072 public override void Emit (EmitContext ec)
2074 throw new InternalErrorException ("Missing Resolve call");
2080 // Unresolved type name expressions
2082 public abstract class ATypeNameExpression : FullNamedExpression
2085 protected TypeArguments targs;
2087 protected ATypeNameExpression (string name, Location l)
2093 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2100 protected ATypeNameExpression (string name, int arity, Location l)
2101 : this (name, new UnboundTypeArguments (arity), l)
2107 protected int Arity {
2109 return targs == null ? 0 : targs.Count;
2113 public bool HasTypeArguments {
2115 return targs != null && !targs.IsEmpty;
2119 public string Name {
2128 public TypeArguments TypeArguments {
2136 public override bool Equals (object obj)
2138 ATypeNameExpression atne = obj as ATypeNameExpression;
2139 return atne != null && atne.Name == Name &&
2140 (targs == null || targs.Equals (atne.targs));
2143 public override int GetHashCode ()
2145 return Name.GetHashCode ();
2148 // TODO: Move it to MemberCore
2149 public static string GetMemberType (MemberCore mc)
2155 if (mc is FieldBase)
2157 if (mc is MethodCore)
2159 if (mc is EnumMember)
2167 public override string GetSignatureForError ()
2169 if (targs != null) {
2170 return Name + "<" + targs.GetSignatureForError () + ">";
2176 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2180 /// SimpleName expressions are formed of a single word and only happen at the beginning
2181 /// of a dotted-name.
2183 public class SimpleName : ATypeNameExpression
2185 public SimpleName (string name, Location l)
2190 public SimpleName (string name, TypeArguments args, Location l)
2191 : base (name, args, l)
2195 public SimpleName (string name, int arity, Location l)
2196 : base (name, arity, l)
2200 public SimpleName GetMethodGroup ()
2202 return new SimpleName (Name, targs, loc);
2205 protected override Expression DoResolve (ResolveContext ec)
2207 return SimpleNameResolve (ec, null, false);
2210 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2212 return SimpleNameResolve (ec, right_side, false);
2215 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2217 if (ctx.CurrentType != null) {
2218 if (ctx.CurrentMemberDefinition != null) {
2219 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2221 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2227 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2228 if (retval != null) {
2229 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2230 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2234 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2235 if (retval != null) {
2236 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2240 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2243 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2245 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2248 if (fne.Type != null && Arity > 0) {
2249 if (HasTypeArguments) {
2250 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2251 if (ct.ResolveAsType (ec) == null)
2257 return new GenericOpenTypeExpr (fne.Type, loc);
2261 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2263 if (!(fne is Namespace))
2267 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2268 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2269 ec.Module.Compiler.Report.Error (1980, Location,
2270 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2271 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2274 fne = new DynamicTypeExpr (loc);
2275 fne.ResolveAsType (ec);
2281 Error_TypeOrNamespaceNotFound (ec);
2285 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2287 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2290 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2292 int lookup_arity = Arity;
2293 bool errorMode = false;
2295 Block current_block = rc.CurrentBlock;
2296 INamedBlockVariable variable = null;
2297 bool variable_found = false;
2301 // Stage 1: binding to local variables or parameters
2303 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2305 if (current_block != null && lookup_arity == 0) {
2306 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2307 if (!variable.IsDeclared) {
2308 // We found local name in accessible block but it's not
2309 // initialized yet, maybe the user wanted to bind to something else
2311 variable_found = true;
2313 e = variable.CreateReferenceExpression (rc, loc);
2316 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2325 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2327 TypeSpec member_type = rc.CurrentType;
2328 for (; member_type != null; member_type = member_type.DeclaringType) {
2329 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2333 var me = e as MemberExpr;
2335 // The name matches a type, defer to ResolveAsTypeStep
2343 if (variable != null) {
2344 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2345 rc.Report.Error (844, loc,
2346 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2347 Name, me.GetSignatureForError ());
2351 } else if (me is MethodGroupExpr) {
2352 // Leave it to overload resolution to report correct error
2354 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2355 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2358 // LAMESPEC: again, ignores InvocableOnly
2359 if (variable != null) {
2360 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2361 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2365 // MemberLookup does not check accessors availability, this is actually needed for properties only
2367 var pe = me as PropertyExpr;
2370 // Break as there is no other overload available anyway
2371 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2372 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2375 pe.Getter = pe.PropertyInfo.Get;
2377 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2380 pe.Setter = pe.PropertyInfo.Set;
2385 // TODO: It's used by EventExpr -> FieldExpr transformation only
2386 // TODO: Should go to MemberAccess
2387 me = me.ResolveMemberAccess (rc, null, null);
2391 me.SetTypeArguments (rc, targs);
2398 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2400 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2401 if (IsPossibleTypeOrNamespace (rc)) {
2402 if (variable != null) {
2403 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2404 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2407 return ResolveAsTypeOrNamespace (rc);
2412 if (variable_found) {
2413 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2416 TypeParameter[] tparams = rc.CurrentTypeParameters;
2417 if (tparams != null) {
2418 foreach (var ctp in tparams) {
2419 if (ctp.Name == Name) {
2420 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2426 var ct = rc.CurrentType;
2428 if (ct.MemberDefinition.TypeParametersCount > 0) {
2429 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2430 if (ctp.Name == Name) {
2431 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2437 ct = ct.DeclaringType;
2438 } while (ct != null);
2441 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2442 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2444 rc.Report.SymbolRelatedToPreviousError (e.Type);
2445 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2450 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2452 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2453 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2458 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2461 return ErrorExpression.Instance;
2464 if (rc.Module.Evaluator != null) {
2465 var fi = rc.Module.Evaluator.LookupField (Name);
2467 return new FieldExpr (fi.Item1, loc);
2475 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2477 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2482 if (right_side != null) {
2483 if (e is TypeExpr) {
2484 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2488 e = e.ResolveLValue (ec, right_side);
2493 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2499 /// Represents a namespace or a type. The name of the class was inspired by
2500 /// section 10.8.1 (Fully Qualified Names).
2502 public abstract class FullNamedExpression : Expression
2504 protected override void CloneTo (CloneContext clonectx, Expression target)
2506 // Do nothing, most unresolved type expressions cannot be
2507 // resolved to different type
2510 public override bool ContainsEmitWithAwait ()
2515 public override Expression CreateExpressionTree (ResolveContext ec)
2517 throw new NotSupportedException ("ET");
2520 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2523 // This is used to resolve the expression as a type, a null
2524 // value will be returned if the expression is not a type
2527 public override TypeSpec ResolveAsType (IMemberContext mc)
2529 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2534 TypeExpr te = fne as TypeExpr;
2536 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2544 var dep = type.GetMissingDependencies ();
2546 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2550 // Obsolete checks cannot be done when resolving base context as they
2551 // require type dependencies to be set but we are in process of resolving them
2553 if (!(mc is TypeContainer.BaseContext)) {
2554 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2555 if (obsolete_attr != null && !mc.IsObsolete) {
2556 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2564 public override void Emit (EmitContext ec)
2566 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2567 GetSignatureForError ());
2572 /// Expression that evaluates to a type
2574 public abstract class TypeExpr : FullNamedExpression
2576 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2582 protected sealed override Expression DoResolve (ResolveContext ec)
2588 public override bool Equals (object obj)
2590 TypeExpr tobj = obj as TypeExpr;
2594 return Type == tobj.Type;
2597 public override int GetHashCode ()
2599 return Type.GetHashCode ();
2604 /// Fully resolved Expression that already evaluated to a type
2606 public class TypeExpression : TypeExpr
2608 public TypeExpression (TypeSpec t, Location l)
2611 eclass = ExprClass.Type;
2615 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2622 /// This class denotes an expression which evaluates to a member
2623 /// of a struct or a class.
2625 public abstract class MemberExpr : Expression
2628 // An instance expression associated with this member, if it's a
2629 // non-static member
2631 public Expression InstanceExpression;
2634 /// The name of this member.
2636 public abstract string Name {
2641 // When base.member is used
2643 public bool IsBase {
2644 get { return InstanceExpression is BaseThis; }
2648 /// Whether this is an instance member.
2650 public abstract bool IsInstance {
2655 /// Whether this is a static member.
2657 public abstract bool IsStatic {
2661 protected abstract TypeSpec DeclaringType {
2666 // Converts best base candidate for virtual method starting from QueriedBaseType
2668 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2671 // Only when base.member is used and method is virtual
2677 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2678 // means for base.member access we have to find the closest match after we found best candidate
2680 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2682 // The method could already be what we are looking for
2684 TypeSpec[] targs = null;
2685 if (method.DeclaringType != InstanceExpression.Type) {
2686 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2687 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2688 if (base_override.IsGeneric)
2689 targs = method.TypeArguments;
2691 method = base_override;
2695 // TODO: For now we do it for any hoisted call even if it's needed for
2696 // hoisted stories only but that requires a new expression wrapper
2697 if (rc.CurrentAnonymousMethod != null) {
2698 if (targs == null && method.IsGeneric) {
2699 targs = method.TypeArguments;
2700 method = method.GetGenericMethodDefinition ();
2703 if (method.Parameters.HasArglist)
2704 throw new NotImplementedException ("__arglist base call proxy");
2706 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2708 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2709 // get/set member expressions second call would fail to proxy because left expression
2710 // would be of 'this' and not 'base'
2711 if (rc.CurrentType.IsStruct)
2712 InstanceExpression = new This (loc).Resolve (rc);
2716 method = method.MakeGenericMethod (rc, targs);
2720 // Only base will allow this invocation to happen.
2722 if (method.IsAbstract) {
2723 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2729 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2731 if (InstanceExpression == null)
2734 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2735 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2739 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2741 var ct = rc.CurrentType;
2742 if (ct == qualifier)
2745 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2748 qualifier = qualifier.GetDefinition ();
2749 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2750 rc.Report.SymbolRelatedToPreviousError (member);
2751 rc.Report.Error (1540, loc,
2752 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2753 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2757 public override bool ContainsEmitWithAwait ()
2759 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2762 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2765 type = type.GetDefinition ();
2767 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2770 type = type.DeclaringType;
2771 } while (type != null);
2776 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2778 if (InstanceExpression != null) {
2779 InstanceExpression = InstanceExpression.Resolve (rc);
2780 CheckProtectedMemberAccess (rc, member);
2783 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2784 UnsafeError (rc, loc);
2787 var dep = member.GetMissingDependencies ();
2789 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2792 if (!rc.IsObsolete) {
2793 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2795 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2798 if (!(member is FieldSpec))
2799 member.MemberDefinition.SetIsUsed ();
2802 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2804 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2808 // Implements identicial simple name and type-name
2810 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2813 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2816 // 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
2817 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2819 if (left is MemberExpr || left is VariableReference) {
2820 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2821 if (identical_type != null && identical_type.Type == left.Type)
2822 return identical_type;
2828 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2831 if (InstanceExpression != null) {
2832 if (InstanceExpression is TypeExpr) {
2833 var t = InstanceExpression.Type;
2835 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2836 if (oa != null && !rc.IsObsolete) {
2837 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2840 t = t.DeclaringType;
2841 } while (t != null);
2843 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2844 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2845 rc.Report.Error (176, loc,
2846 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2847 GetSignatureForError ());
2851 InstanceExpression = null;
2857 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2858 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2859 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2860 rc.Report.Error (236, loc,
2861 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2862 GetSignatureForError ());
2864 rc.Report.Error (120, loc,
2865 "An object reference is required to access non-static member `{0}'",
2866 GetSignatureForError ());
2871 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2872 rc.Report.Error (38, loc,
2873 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2874 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2877 InstanceExpression = new This (loc);
2878 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2879 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2880 InstanceExpression = InstanceExpression.Resolve (rc);
2883 InstanceExpression = InstanceExpression.Resolve (rc);
2889 var me = InstanceExpression as MemberExpr;
2891 me.ResolveInstanceExpression (rc, rhs);
2893 var fe = me as FieldExpr;
2894 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2895 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2896 rc.Report.Warning (1690, 1, loc,
2897 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2898 me.GetSignatureForError ());
2905 // Run member-access postponed check once we know that
2906 // the expression is not field expression which is the only
2907 // expression which can use uninitialized this
2909 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2910 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2914 // Additional checks for l-value member access
2918 // TODO: It should be recursive but that would break csc compatibility
2920 if (InstanceExpression is UnboxCast) {
2921 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2928 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2930 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2931 ec.Report.Warning (1720, 1, left.Location,
2932 "Expression will always cause a `{0}'", "System.NullReferenceException");
2935 InstanceExpression = left;
2939 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2941 TypeSpec instance_type = InstanceExpression.Type;
2942 if (TypeSpec.IsValueType (instance_type)) {
2943 if (InstanceExpression is IMemoryLocation) {
2944 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2946 LocalTemporary t = new LocalTemporary (instance_type);
2947 InstanceExpression.Emit (ec);
2949 t.AddressOf (ec, AddressOp.Store);
2953 InstanceExpression.Emit (ec);
2955 // Only to make verifier happy
2956 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2957 ec.Emit (OpCodes.Box, instance_type);
2960 if (prepare_for_load)
2961 ec.Emit (OpCodes.Dup);
2964 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2967 public class ExtensionMethodCandidates
2969 NamespaceContainer container;
2971 IList<MethodSpec> methods;
2973 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
2974 : this (methods, nsContainer, null)
2978 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
2980 this.methods = methods;
2981 this.container = nsContainer;
2985 public NamespaceContainer Container {
2991 public bool HasUninspectedMembers { get; set; }
2993 public Namespace Namespace {
2999 public IList<MethodSpec> Methods {
3007 // Represents a group of extension method candidates for whole namespace
3009 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3011 ExtensionMethodCandidates candidates;
3012 public readonly Expression ExtensionExpression;
3014 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3015 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3017 this.candidates = candidates;
3018 this.ExtensionExpression = extensionExpr;
3021 public override bool IsStatic {
3022 get { return true; }
3026 // For extension methodgroup we are not looking for base members but parent
3027 // namespace extension methods
3029 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3031 // TODO: candidates are null only when doing error reporting, that's
3032 // incorrect. We have to discover same extension methods in error mode
3033 if (candidates == null)
3036 int arity = type_arguments == null ? 0 : type_arguments.Count;
3039 // Here we try to resume the search for extension method at the point
3040 // where the last bunch of candidates was found. It's more tricky than
3041 // it seems as we have to check both namespace containers and namespace
3042 // in correct order.
3048 // namespace B.C.D {
3049 // <our first search found candidates in A.B.C.D
3053 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3054 // checked before we hit A.N1 using
3056 if (candidates.Namespace == null) {
3058 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3059 if (methods != null) {
3060 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3061 return methods.Cast<MemberSpec> ().ToList ();
3065 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3066 if (ns_container == null)
3069 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3070 if (candidates == null)
3073 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3076 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3078 // We are already here
3082 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3084 if (arguments == null)
3085 arguments = new Arguments (1);
3087 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3088 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3090 // Store resolved argument and restore original arguments
3092 // Clean-up modified arguments for error reporting
3093 arguments.RemoveAt (0);
3097 var me = ExtensionExpression as MemberExpr;
3099 me.ResolveInstanceExpression (ec, null);
3101 InstanceExpression = null;
3105 #region IErrorHandler Members
3107 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3112 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3114 rc.Report.SymbolRelatedToPreviousError (best);
3115 rc.Report.Error (1928, loc,
3116 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3117 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3120 rc.Report.Error (1929, loc,
3121 "Extension method instance type `{0}' cannot be converted to `{1}'",
3122 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3128 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3133 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3142 /// MethodGroupExpr represents a group of method candidates which
3143 /// can be resolved to the best method overload
3145 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3147 protected IList<MemberSpec> Methods;
3148 MethodSpec best_candidate;
3149 TypeSpec best_candidate_return;
3150 protected TypeArguments type_arguments;
3152 SimpleName simple_name;
3153 protected TypeSpec queried_type;
3155 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3159 this.type = InternalType.MethodGroup;
3161 eclass = ExprClass.MethodGroup;
3162 queried_type = type;
3165 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3166 : this (new MemberSpec[] { m }, type, loc)
3172 public MethodSpec BestCandidate {
3174 return best_candidate;
3178 public TypeSpec BestCandidateReturnType {
3180 return best_candidate_return;
3184 public IList<MemberSpec> Candidates {
3190 protected override TypeSpec DeclaringType {
3192 return queried_type;
3196 public override bool IsInstance {
3198 if (best_candidate != null)
3199 return !best_candidate.IsStatic;
3205 public override bool IsStatic {
3207 if (best_candidate != null)
3208 return best_candidate.IsStatic;
3214 public override string Name {
3216 if (best_candidate != null)
3217 return best_candidate.Name;
3220 return Methods.First ().Name;
3227 // When best candidate is already know this factory can be used
3228 // to avoid expensive overload resolution to be called
3230 // NOTE: InstanceExpression has to be set manually
3232 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3234 return new MethodGroupExpr (best, queriedType, loc) {
3235 best_candidate = best,
3236 best_candidate_return = best.ReturnType
3240 public override string GetSignatureForError ()
3242 if (best_candidate != null)
3243 return best_candidate.GetSignatureForError ();
3245 return Methods.First ().GetSignatureForError ();
3248 public override Expression CreateExpressionTree (ResolveContext ec)
3250 if (best_candidate == null) {
3251 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3255 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3256 ec.Report.Error (765, loc,
3257 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3259 return new TypeOfMethod (best_candidate, loc);
3262 protected override Expression DoResolve (ResolveContext ec)
3264 this.eclass = ExprClass.MethodGroup;
3266 if (InstanceExpression != null) {
3267 InstanceExpression = InstanceExpression.Resolve (ec);
3268 if (InstanceExpression == null)
3275 public override void Emit (EmitContext ec)
3277 throw new NotSupportedException ();
3280 public void EmitCall (EmitContext ec, Arguments arguments)
3282 var call = new CallEmitter ();
3283 call.InstanceExpression = InstanceExpression;
3284 call.Emit (ec, best_candidate, arguments, loc);
3287 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3289 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3290 Name, TypeManager.CSharpName (target));
3293 public static bool IsExtensionMethodArgument (Expression expr)
3296 // LAMESPEC: No details about which expressions are not allowed
3298 return !(expr is TypeExpr) && !(expr is BaseThis);
3302 /// Find the Applicable Function Members (7.4.2.1)
3304 /// me: Method Group expression with the members to select.
3305 /// it might contain constructors or methods (or anything
3306 /// that maps to a method).
3308 /// Arguments: ArrayList containing resolved Argument objects.
3310 /// loc: The location if we want an error to be reported, or a Null
3311 /// location for "probing" purposes.
3313 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3314 /// that is the best match of me on Arguments.
3317 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3319 // TODO: causes issues with probing mode, remove explicit Kind check
3320 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3323 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3324 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3325 r.BaseMembersProvider = this;
3328 if (cerrors != null)
3329 r.CustomErrors = cerrors;
3331 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3332 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3333 if (best_candidate == null)
3334 return r.BestCandidateIsDynamic ? this : null;
3336 // Overload resolver had to create a new method group, all checks bellow have already been executed
3337 if (r.BestCandidateNewMethodGroup != null)
3338 return r.BestCandidateNewMethodGroup;
3340 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3341 if (InstanceExpression != null) {
3342 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3343 InstanceExpression = null;
3345 if (best_candidate.IsStatic && simple_name != null) {
3346 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3349 InstanceExpression.Resolve (ec);
3353 ResolveInstanceExpression (ec, null);
3354 if (InstanceExpression != null)
3355 CheckProtectedMemberAccess (ec, best_candidate);
3358 var base_override = CandidateToBaseOverride (ec, best_candidate);
3359 if (base_override == best_candidate) {
3360 best_candidate_return = r.BestCandidateReturnType;
3362 best_candidate = base_override;
3363 best_candidate_return = best_candidate.ReturnType;
3369 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3371 simple_name = original;
3372 return base.ResolveMemberAccess (ec, left, original);
3375 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3377 type_arguments = ta;
3380 #region IBaseMembersProvider Members
3382 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3384 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3387 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3389 if (queried_type == member.DeclaringType)
3392 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3393 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3397 // Extension methods lookup after ordinary methods candidates failed to apply
3399 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3401 if (InstanceExpression == null)
3404 InstanceExpression = InstanceExpression.Resolve (rc);
3405 if (!IsExtensionMethodArgument (InstanceExpression))
3408 int arity = type_arguments == null ? 0 : type_arguments.Count;
3409 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3410 if (methods == null)
3413 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3414 emg.SetTypeArguments (rc, type_arguments);
3421 public struct OverloadResolver
3424 public enum Restrictions
3428 ProbingOnly = 1 << 1,
3429 CovariantDelegate = 1 << 2,
3430 NoBaseMembers = 1 << 3,
3431 BaseMembersIncluded = 1 << 4
3434 public interface IBaseMembersProvider
3436 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3437 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3438 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3441 public interface IErrorHandler
3443 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3444 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3445 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3446 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3449 sealed class NoBaseMembers : IBaseMembersProvider
3451 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3453 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3458 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3463 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3469 struct AmbiguousCandidate
3471 public readonly MemberSpec Member;
3472 public readonly bool Expanded;
3473 public readonly AParametersCollection Parameters;
3475 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3478 Parameters = parameters;
3479 Expanded = expanded;
3484 IList<MemberSpec> members;
3485 TypeArguments type_arguments;
3486 IBaseMembersProvider base_provider;
3487 IErrorHandler custom_errors;
3488 Restrictions restrictions;
3489 MethodGroupExpr best_candidate_extension_group;
3490 TypeSpec best_candidate_return_type;
3492 SessionReportPrinter lambda_conv_msgs;
3493 ReportPrinter prev_recorder;
3495 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3496 : this (members, null, restrictions, loc)
3500 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3503 if (members == null || members.Count == 0)
3504 throw new ArgumentException ("empty members set");
3506 this.members = members;
3508 type_arguments = targs;
3509 this.restrictions = restrictions;
3510 if (IsDelegateInvoke)
3511 this.restrictions |= Restrictions.NoBaseMembers;
3513 base_provider = NoBaseMembers.Instance;
3518 public IBaseMembersProvider BaseMembersProvider {
3520 return base_provider;
3523 base_provider = value;
3527 public bool BestCandidateIsDynamic { get; set; }
3530 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3532 public MethodGroupExpr BestCandidateNewMethodGroup {
3534 return best_candidate_extension_group;
3539 // Return type can be different between best candidate and closest override
3541 public TypeSpec BestCandidateReturnType {
3543 return best_candidate_return_type;
3547 public IErrorHandler CustomErrors {
3549 return custom_errors;
3552 custom_errors = value;
3556 TypeSpec DelegateType {
3558 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3559 throw new InternalErrorException ("Not running in delegate mode", loc);
3561 return members [0].DeclaringType;
3565 bool IsProbingOnly {
3567 return (restrictions & Restrictions.ProbingOnly) != 0;
3571 bool IsDelegateInvoke {
3573 return (restrictions & Restrictions.DelegateInvoke) != 0;
3580 // 7.4.3.3 Better conversion from expression
3581 // Returns : 1 if a->p is better,
3582 // 2 if a->q is better,
3583 // 0 if neither is better
3585 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3587 TypeSpec argument_type = a.Type;
3590 // If argument is an anonymous function
3592 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3594 // p and q are delegate types or expression tree types
3596 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3597 if (q.MemberDefinition != p.MemberDefinition) {
3602 // Uwrap delegate from Expression<T>
3604 q = TypeManager.GetTypeArguments (q)[0];
3605 p = TypeManager.GetTypeArguments (p)[0];
3608 var p_m = Delegate.GetInvokeMethod (p);
3609 var q_m = Delegate.GetInvokeMethod (q);
3612 // With identical parameter lists
3614 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3621 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3623 if (p.Kind == MemberKind.Void) {
3624 return q.Kind != MemberKind.Void ? 2 : 0;
3628 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3630 if (q.Kind == MemberKind.Void) {
3631 return p.Kind != MemberKind.Void ? 1: 0;
3635 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3636 // better conversion is performed between underlying types Y1 and Y2
3638 if (p.IsGenericTask || q.IsGenericTask) {
3639 if (p.IsGenericTask != q.IsGenericTask) {
3643 var async_am = a.Expr as AnonymousMethodExpression;
3644 if (async_am == null || !async_am.IsAsync)
3647 q = q.TypeArguments[0];
3648 p = p.TypeArguments[0];
3652 // The parameters are identicial and return type is not void, use better type conversion
3653 // on return type to determine better one
3656 if (argument_type == p)
3659 if (argument_type == q)
3663 return BetterTypeConversion (ec, p, q);
3667 // 7.4.3.4 Better conversion from type
3669 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3671 if (p == null || q == null)
3672 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3674 switch (p.BuiltinType) {
3675 case BuiltinTypeSpec.Type.Int:
3676 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3679 case BuiltinTypeSpec.Type.Long:
3680 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3683 case BuiltinTypeSpec.Type.SByte:
3684 switch (q.BuiltinType) {
3685 case BuiltinTypeSpec.Type.Byte:
3686 case BuiltinTypeSpec.Type.UShort:
3687 case BuiltinTypeSpec.Type.UInt:
3688 case BuiltinTypeSpec.Type.ULong:
3692 case BuiltinTypeSpec.Type.Short:
3693 switch (q.BuiltinType) {
3694 case BuiltinTypeSpec.Type.UShort:
3695 case BuiltinTypeSpec.Type.UInt:
3696 case BuiltinTypeSpec.Type.ULong:
3700 case BuiltinTypeSpec.Type.Dynamic:
3701 // Dynamic is never better
3705 switch (q.BuiltinType) {
3706 case BuiltinTypeSpec.Type.Int:
3707 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3710 case BuiltinTypeSpec.Type.Long:
3711 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3714 case BuiltinTypeSpec.Type.SByte:
3715 switch (p.BuiltinType) {
3716 case BuiltinTypeSpec.Type.Byte:
3717 case BuiltinTypeSpec.Type.UShort:
3718 case BuiltinTypeSpec.Type.UInt:
3719 case BuiltinTypeSpec.Type.ULong:
3723 case BuiltinTypeSpec.Type.Short:
3724 switch (p.BuiltinType) {
3725 case BuiltinTypeSpec.Type.UShort:
3726 case BuiltinTypeSpec.Type.UInt:
3727 case BuiltinTypeSpec.Type.ULong:
3731 case BuiltinTypeSpec.Type.Dynamic:
3732 // Dynamic is never better
3736 // FIXME: handle lifted operators
3738 // TODO: this is expensive
3739 Expression p_tmp = new EmptyExpression (p);
3740 Expression q_tmp = new EmptyExpression (q);
3742 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3743 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3745 if (p_to_q && !q_to_p)
3748 if (q_to_p && !p_to_q)
3755 /// Determines "Better function" between candidate
3756 /// and the current best match
3759 /// Returns a boolean indicating :
3760 /// false if candidate ain't better
3761 /// true if candidate is better than the current best match
3763 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3764 MemberSpec best, AParametersCollection bparam, bool best_params)
3766 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3767 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3769 bool better_at_least_one = false;
3771 int args_count = args == null ? 0 : args.Count;
3775 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3778 // Default arguments are ignored for better decision
3779 if (a.IsDefaultArgument)
3783 // When comparing named argument the parameter type index has to be looked up
3784 // in original parameter set (override version for virtual members)
3786 NamedArgument na = a as NamedArgument;
3788 int idx = cparam.GetParameterIndexByName (na.Name);
3789 ct = candidate_pd.Types[idx];
3790 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3791 ct = TypeManager.GetElementType (ct);
3793 idx = bparam.GetParameterIndexByName (na.Name);
3794 bt = best_pd.Types[idx];
3795 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3796 bt = TypeManager.GetElementType (bt);
3798 ct = candidate_pd.Types[c_idx];
3799 bt = best_pd.Types[b_idx];
3801 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3802 ct = TypeManager.GetElementType (ct);
3806 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3807 bt = TypeManager.GetElementType (bt);
3812 if (TypeSpecComparer.IsEqual (ct, bt))
3816 int result = BetterExpressionConversion (ec, a, ct, bt);
3818 // for each argument, the conversion to 'ct' should be no worse than
3819 // the conversion to 'bt'.
3823 // for at least one argument, the conversion to 'ct' should be better than
3824 // the conversion to 'bt'.
3826 better_at_least_one = true;
3829 if (better_at_least_one)
3833 // This handles the case
3835 // Add (float f1, float f2, float f3);
3836 // Add (params decimal [] foo);
3838 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3839 // first candidate would've chosen as better.
3841 if (!same && !a.IsDefaultArgument)
3845 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3849 // This handles the following cases:
3851 // Foo (int i) is better than Foo (int i, long l = 0)
3852 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3854 // Prefer non-optional version
3856 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3858 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3859 if (candidate_pd.Count >= best_pd.Count)
3862 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3869 // One is a non-generic method and second is a generic method, then non-generic is better
3871 if (best.IsGeneric != candidate.IsGeneric)
3872 return best.IsGeneric;
3875 // This handles the following cases:
3877 // Trim () is better than Trim (params char[] chars)
3878 // Concat (string s1, string s2, string s3) is better than
3879 // Concat (string s1, params string [] srest)
3880 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3882 // Prefer non-expanded version
3884 if (candidate_params != best_params)
3887 int candidate_param_count = candidate_pd.Count;
3888 int best_param_count = best_pd.Count;
3890 if (candidate_param_count != best_param_count)
3891 // can only happen if (candidate_params && best_params)
3892 return candidate_param_count > best_param_count && best_pd.HasParams;
3895 // Both methods have the same number of parameters, and the parameters have equal types
3896 // Pick the "more specific" signature using rules over original (non-inflated) types
3898 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3899 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3901 bool specific_at_least_once = false;
3902 for (j = 0; j < args_count; ++j) {
3903 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3905 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3906 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3908 ct = candidate_def_pd.Types[j];
3909 bt = best_def_pd.Types[j];
3914 TypeSpec specific = MoreSpecific (ct, bt);
3918 specific_at_least_once = true;
3921 if (specific_at_least_once)
3927 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3929 rc.Report.Error (1729, loc,
3930 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3931 type.GetSignatureForError (), argCount.ToString ());
3935 // Determines if the candidate method is applicable to the given set of arguments
3936 // There could be two different set of parameters for same candidate where one
3937 // is the closest override for default values and named arguments checks and second
3938 // one being the virtual base for the parameter types and modifiers.
3940 // A return value rates candidate method compatibility,
3941 // 0 = the best, int.MaxValue = the worst
3943 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
3945 // Parameters of most-derived type used mainly for named and optional parameters
3946 var pd = pm.Parameters;
3948 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3949 // params modifier instead of most-derived type
3950 var cpd = ((IParametersMember) candidate).Parameters;
3951 int param_count = pd.Count;
3952 int optional_count = 0;
3954 Arguments orig_args = arguments;
3956 if (arg_count != param_count) {
3957 for (int i = 0; i < pd.Count; ++i) {
3958 if (pd.FixedParameters[i].HasDefaultValue) {
3959 optional_count = pd.Count - i;
3964 if (optional_count != 0) {
3965 // Readjust expected number when params used
3966 if (cpd.HasParams) {
3968 if (arg_count < param_count)
3970 } else if (arg_count > param_count) {
3971 int args_gap = System.Math.Abs (arg_count - param_count);
3972 return int.MaxValue - 10000 + args_gap;
3974 } else if (arg_count != param_count) {
3975 int args_gap = System.Math.Abs (arg_count - param_count);
3977 return int.MaxValue - 10000 + args_gap;
3978 if (arg_count < param_count - 1)
3979 return int.MaxValue - 10000 + args_gap;
3982 // Resize to fit optional arguments
3983 if (optional_count != 0) {
3984 if (arguments == null) {
3985 arguments = new Arguments (optional_count);
3987 // Have to create a new container, so the next run can do same
3988 var resized = new Arguments (param_count);
3989 resized.AddRange (arguments);
3990 arguments = resized;
3993 for (int i = arg_count; i < param_count; ++i)
3994 arguments.Add (null);
3998 if (arg_count > 0) {
4000 // Shuffle named arguments to the right positions if there are any
4002 if (arguments[arg_count - 1] is NamedArgument) {
4003 arg_count = arguments.Count;
4005 for (int i = 0; i < arg_count; ++i) {
4006 bool arg_moved = false;
4008 NamedArgument na = arguments[i] as NamedArgument;
4012 int index = pd.GetParameterIndexByName (na.Name);
4014 // Named parameter not found
4018 // already reordered
4023 if (index >= param_count) {
4024 // When using parameters which should not be available to the user
4025 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4028 arguments.Add (null);
4032 temp = arguments[index];
4034 // The slot has been taken by positional argument
4035 if (temp != null && !(temp is NamedArgument))
4040 arguments = arguments.MarkOrderedArgument (na);
4044 arguments[index] = arguments[i];
4045 arguments[i] = temp;
4052 arg_count = arguments.Count;
4054 } else if (arguments != null) {
4055 arg_count = arguments.Count;
4059 // 1. Handle generic method using type arguments when specified or type inference
4062 var ms = candidate as MethodSpec;
4063 if (ms != null && ms.IsGeneric) {
4064 // Setup constraint checker for probing only
4065 ConstraintChecker cc = new ConstraintChecker (null);
4067 if (type_arguments != null) {
4068 var g_args_count = ms.Arity;
4069 if (g_args_count != type_arguments.Count)
4070 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4072 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4074 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4075 // for now it simplifies things. I should probably add a callback to ResolveContext
4076 if (lambda_conv_msgs == null) {
4077 lambda_conv_msgs = new SessionReportPrinter ();
4078 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4081 var ti = new TypeInference (arguments);
4082 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4083 lambda_conv_msgs.EndSession ();
4086 return ti.InferenceScore - 20000;
4088 if (i_args.Length != 0) {
4089 ms = ms.MakeGenericMethod (ec, i_args);
4092 cc.IgnoreInferredDynamic = true;
4096 // Type arguments constraints have to match for the method to be applicable
4098 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4100 return int.MaxValue - 25000;
4104 // We have a generic return type and at same time the method is override which
4105 // means we have to also inflate override return type in case the candidate is
4106 // best candidate and override return type is different to base return type.
4108 // virtual Foo<T, object> with override Foo<T, dynamic>
4110 if (candidate != pm) {
4111 MethodSpec override_ms = (MethodSpec) pm;
4112 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4113 returnType = inflator.Inflate (returnType);
4115 returnType = ms.ReturnType;
4119 ptypes = ms.Parameters.Types;
4121 if (type_arguments != null)
4122 return int.MaxValue - 15000;
4128 // 2. Each argument has to be implicitly convertible to method parameter
4130 Parameter.Modifier p_mod = 0;
4133 for (int i = 0; i < arg_count; i++) {
4134 Argument a = arguments[i];
4136 if (!pd.FixedParameters[i].HasDefaultValue) {
4137 arguments = orig_args;
4138 return arg_count * 2 + 2;
4142 // Get the default value expression, we can use the same expression
4143 // if the type matches
4145 Expression e = pd.FixedParameters[i].DefaultValue;
4146 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4148 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4150 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4151 e = new MemberAccess (new MemberAccess (new MemberAccess (
4152 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4154 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4160 arguments[i] = new Argument (e, Argument.AType.Default);
4164 if (p_mod != Parameter.Modifier.PARAMS) {
4165 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4167 } else if (!params_expanded_form) {
4168 params_expanded_form = true;
4169 pt = ((ElementTypeSpec) pt).Element;
4175 if (!params_expanded_form) {
4176 if (a.ArgType == Argument.AType.ExtensionType) {
4178 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4181 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4182 Convert.ImplicitReferenceConversionExists (at, pt) ||
4183 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4188 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4191 dynamicArgument = true;
4196 // It can be applicable in expanded form (when not doing exact match like for delegates)
4198 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4199 if (!params_expanded_form)
4200 pt = ((ElementTypeSpec) pt).Element;
4203 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4206 params_expanded_form = true;
4207 } else if (score < 0) {
4208 params_expanded_form = true;
4209 dynamicArgument = true;
4214 if (params_expanded_form)
4216 return (arg_count - i) * 2 + score;
4221 // When params parameter has no argument it will be provided later if the method is the best candidate
4223 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4224 params_expanded_form = true;
4227 // Restore original arguments for dynamic binder to keep the intention of original source code
4229 if (dynamicArgument)
4230 arguments = orig_args;
4236 // Tests argument compatibility with the parameter
4237 // The possible return values are
4239 // 1 - modifier mismatch
4240 // 2 - type mismatch
4241 // -1 - dynamic binding required
4243 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4246 // Types have to be identical when ref or out modifer
4247 // is used and argument is not of dynamic type
4249 if ((argument.Modifier | param_mod) != 0) {
4250 if (argument.Type != parameter) {
4252 // Do full equality check after quick path
4254 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4256 // Using dynamic for ref/out parameter can still succeed at runtime
4258 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4265 if (argument.Modifier != param_mod) {
4267 // Using dynamic for ref/out parameter can still succeed at runtime
4269 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4276 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4280 // Deploy custom error reporting for lambda methods. When probing lambda methods
4281 // keep all errors reported in separate set and once we are done and no best
4282 // candidate was found, this set is used to report more details about what was wrong
4285 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4286 if (lambda_conv_msgs == null) {
4287 lambda_conv_msgs = new SessionReportPrinter ();
4288 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4293 // Use implicit conversion in all modes to return same candidates when the expression
4294 // is used as argument or delegate conversion
4296 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4297 if (lambda_conv_msgs != null) {
4298 lambda_conv_msgs.EndSession ();
4308 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4310 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4312 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4315 var ac_p = p as ArrayContainer;
4317 var ac_q = ((ArrayContainer) q);
4318 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4319 if (specific == ac_p.Element)
4321 if (specific == ac_q.Element)
4323 } else if (TypeManager.IsGenericType (p)) {
4324 var pargs = TypeManager.GetTypeArguments (p);
4325 var qargs = TypeManager.GetTypeArguments (q);
4327 bool p_specific_at_least_once = false;
4328 bool q_specific_at_least_once = false;
4330 for (int i = 0; i < pargs.Length; i++) {
4331 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4332 if (specific == pargs[i])
4333 p_specific_at_least_once = true;
4334 if (specific == qargs[i])
4335 q_specific_at_least_once = true;
4338 if (p_specific_at_least_once && !q_specific_at_least_once)
4340 if (!p_specific_at_least_once && q_specific_at_least_once)
4348 // Find the best method from candidate list
4350 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4352 List<AmbiguousCandidate> ambiguous_candidates = null;
4354 MemberSpec best_candidate;
4355 Arguments best_candidate_args = null;
4356 bool best_candidate_params = false;
4357 bool best_candidate_dynamic = false;
4358 int best_candidate_rate;
4359 IParametersMember best_parameter_member = null;
4361 int args_count = args != null ? args.Count : 0;
4363 Arguments candidate_args = args;
4364 bool error_mode = false;
4365 MemberSpec invocable_member = null;
4367 // Be careful, cannot return until error reporter is restored
4369 best_candidate = null;
4370 best_candidate_rate = int.MaxValue;
4372 var type_members = members;
4376 for (int i = 0; i < type_members.Count; ++i) {
4377 var member = type_members[i];
4380 // Methods in a base class are not candidates if any method in a derived
4381 // class is applicable
4383 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4387 if (!member.IsAccessible (rc))
4390 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4394 IParametersMember pm = member as IParametersMember;
4397 // Will use it later to report ambiguity between best method and invocable member
4399 if (Invocation.IsMemberInvocable (member))
4400 invocable_member = member;
4406 // Overload resolution is looking for base member but using parameter names
4407 // and default values from the closest member. That means to do expensive lookup
4408 // for the closest override for virtual or abstract members
4410 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4411 var override_params = base_provider.GetOverrideMemberParameters (member);
4412 if (override_params != null)
4413 pm = override_params;
4417 // Check if the member candidate is applicable
4419 bool params_expanded_form = false;
4420 bool dynamic_argument = false;
4421 TypeSpec rt = pm.MemberType;
4422 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4425 // How does it score compare to others
4427 if (candidate_rate < best_candidate_rate) {
4428 best_candidate_rate = candidate_rate;
4429 best_candidate = member;
4430 best_candidate_args = candidate_args;
4431 best_candidate_params = params_expanded_form;
4432 best_candidate_dynamic = dynamic_argument;
4433 best_parameter_member = pm;
4434 best_candidate_return_type = rt;
4435 } else if (candidate_rate == 0) {
4437 // The member look is done per type for most operations but sometimes
4438 // it's not possible like for binary operators overload because they
4439 // are unioned between 2 sides
4441 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4442 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4447 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4449 // We pack all interface members into top level type which makes the overload resolution
4450 // more complicated for interfaces. We compensate it by removing methods with same
4451 // signature when building the cache hence this path should not really be hit often
4454 // interface IA { void Foo (int arg); }
4455 // interface IB : IA { void Foo (params int[] args); }
4457 // IB::Foo is the best overload when calling IB.Foo (1)
4460 if (ambiguous_candidates != null) {
4461 foreach (var amb_cand in ambiguous_candidates) {
4462 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4471 ambiguous_candidates = null;
4474 // Is the new candidate better
4475 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4479 best_candidate = member;
4480 best_candidate_args = candidate_args;
4481 best_candidate_params = params_expanded_form;
4482 best_candidate_dynamic = dynamic_argument;
4483 best_parameter_member = pm;
4484 best_candidate_return_type = rt;
4486 // It's not better but any other found later could be but we are not sure yet
4487 if (ambiguous_candidates == null)
4488 ambiguous_candidates = new List<AmbiguousCandidate> ();
4490 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4494 // Restore expanded arguments
4495 if (candidate_args != args)
4496 candidate_args = args;
4498 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4500 if (prev_recorder != null)
4501 rc.Report.SetPrinter (prev_recorder);
4505 // We've found exact match
4507 if (best_candidate_rate == 0)
4511 // Try extension methods lookup when no ordinary method match was found and provider enables it
4514 var emg = base_provider.LookupExtensionMethod (rc);
4516 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4518 best_candidate_extension_group = emg;
4519 return (T) (MemberSpec) emg.BestCandidate;
4524 // Don't run expensive error reporting mode for probing
4531 lambda_conv_msgs = null;
4536 // No best member match found, report an error
4538 if (best_candidate_rate != 0 || error_mode) {
4539 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4543 if (best_candidate_dynamic) {
4544 if (args[0].ArgType == Argument.AType.ExtensionType) {
4545 rc.Report.Error (1973, loc,
4546 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' cannot be dynamically dispatched. Consider calling the method without the extension method syntax",
4547 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4550 BestCandidateIsDynamic = true;
4555 // These flags indicates we are running delegate probing conversion. No need to
4556 // do more expensive checks
4558 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4559 return (T) best_candidate;
4561 if (ambiguous_candidates != null) {
4563 // Now check that there are no ambiguities i.e the selected method
4564 // should be better than all the others
4566 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4567 var candidate = ambiguous_candidates [ix];
4569 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4570 var ambiguous = candidate.Member;
4571 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4572 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4573 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4574 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4575 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4578 return (T) best_candidate;
4583 if (invocable_member != null) {
4584 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4585 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4586 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4587 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4591 // And now check if the arguments are all
4592 // compatible, perform conversions if
4593 // necessary etc. and return if everything is
4596 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4599 if (best_candidate == null)
4603 // Check ObsoleteAttribute on the best method
4605 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4606 if (oa != null && !rc.IsObsolete)
4607 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4609 var dep = best_candidate.GetMissingDependencies ();
4611 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4614 best_candidate.MemberDefinition.SetIsUsed ();
4616 args = best_candidate_args;
4617 return (T) best_candidate;
4620 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4622 return ResolveMember<MethodSpec> (rc, ref args);
4625 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4626 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4628 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4631 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4632 ec.Report.SymbolRelatedToPreviousError (method);
4633 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4634 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4635 TypeManager.CSharpSignature (method));
4638 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4639 TypeManager.CSharpSignature (method));
4640 } else if (IsDelegateInvoke) {
4641 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4642 DelegateType.GetSignatureForError ());
4644 ec.Report.SymbolRelatedToPreviousError (method);
4645 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4646 method.GetSignatureForError ());
4649 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4651 string index = (idx + 1).ToString ();
4652 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4653 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4654 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4655 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4656 index, Parameter.GetModifierSignature (a.Modifier));
4658 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4659 index, Parameter.GetModifierSignature (mod));
4660 } else if (a.Expr != ErrorExpression.Instance) {
4661 string p1 = a.GetSignatureForError ();
4662 string p2 = TypeManager.CSharpName (paramType);
4665 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4666 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4669 ec.Report.Error (1503, loc,
4670 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4675 // We have failed to find exact match so we return error info about the closest match
4677 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4679 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4680 int arg_count = args == null ? 0 : args.Count;
4682 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4683 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4684 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4688 if (lambda_conv_msgs != null) {
4689 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4694 // For candidates which match on parameters count report more details about incorrect arguments
4697 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4698 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4699 // Reject any inaccessible member
4700 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4701 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4702 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4706 var ms = best_candidate as MethodSpec;
4707 if (ms != null && ms.IsGeneric) {
4708 bool constr_ok = true;
4709 if (ms.TypeArguments != null)
4710 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4712 if (ta_count == 0) {
4713 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4717 rc.Report.Error (411, loc,
4718 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4719 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4726 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4732 // We failed to find any method with correct argument count, report best candidate
4734 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4737 if (best_candidate.Kind == MemberKind.Constructor) {
4738 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4739 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4740 } else if (IsDelegateInvoke) {
4741 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4742 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4743 DelegateType.GetSignatureForError (), arg_count.ToString ());
4745 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4746 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4747 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4748 name, arg_count.ToString ());
4752 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4754 var pd = pm.Parameters;
4755 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4757 Parameter.Modifier p_mod = 0;
4759 int a_idx = 0, a_pos = 0;
4761 ArrayInitializer params_initializers = null;
4762 bool has_unsafe_arg = pm.MemberType.IsPointer;
4763 int arg_count = args == null ? 0 : args.Count;
4765 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4767 if (p_mod != Parameter.Modifier.PARAMS) {
4768 p_mod = pd.FixedParameters[a_idx].ModFlags;
4770 has_unsafe_arg |= pt.IsPointer;
4772 if (p_mod == Parameter.Modifier.PARAMS) {
4773 if (chose_params_expanded) {
4774 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4775 pt = TypeManager.GetElementType (pt);
4781 // Types have to be identical when ref or out modifer is used
4783 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4784 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4787 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4793 NamedArgument na = a as NamedArgument;
4795 int name_index = pd.GetParameterIndexByName (na.Name);
4796 if (name_index < 0 || name_index >= pd.Count) {
4797 if (IsDelegateInvoke) {
4798 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4799 ec.Report.Error (1746, na.Location,
4800 "The delegate `{0}' does not contain a parameter named `{1}'",
4801 DelegateType.GetSignatureForError (), na.Name);
4803 ec.Report.SymbolRelatedToPreviousError (member);
4804 ec.Report.Error (1739, na.Location,
4805 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4806 TypeManager.CSharpSignature (member), na.Name);
4808 } else if (args[name_index] != a) {
4809 if (IsDelegateInvoke)
4810 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4812 ec.Report.SymbolRelatedToPreviousError (member);
4814 ec.Report.Error (1744, na.Location,
4815 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4820 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4823 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4824 custom_errors.NoArgumentMatch (ec, member);
4828 Expression conv = null;
4829 if (a.ArgType == Argument.AType.ExtensionType) {
4830 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4833 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4835 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4838 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4845 // Convert params arguments to an array initializer
4847 if (params_initializers != null) {
4848 // we choose to use 'a.Expr' rather than 'conv' so that
4849 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4850 params_initializers.Add (a.Expr);
4851 args.RemoveAt (a_idx--);
4856 // Update the argument with the implicit conversion
4860 if (a_idx != arg_count) {
4861 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4866 // Fill not provided arguments required by params modifier
4868 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4870 args = new Arguments (1);
4872 pt = ptypes[pd.Count - 1];
4873 pt = TypeManager.GetElementType (pt);
4874 has_unsafe_arg |= pt.IsPointer;
4875 params_initializers = new ArrayInitializer (0, loc);
4879 // Append an array argument with all params arguments
4881 if (params_initializers != null) {
4882 args.Add (new Argument (
4883 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4887 if (has_unsafe_arg && !ec.IsUnsafe) {
4888 Expression.UnsafeError (ec, loc);
4892 // We could infer inaccesible type arguments
4894 if (type_arguments == null && member.IsGeneric) {
4895 var ms = (MethodSpec) member;
4896 foreach (var ta in ms.TypeArguments) {
4897 if (!ta.IsAccessible (ec)) {
4898 ec.Report.SymbolRelatedToPreviousError (ta);
4899 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4909 public class ConstantExpr : MemberExpr
4911 readonly ConstSpec constant;
4913 public ConstantExpr (ConstSpec constant, Location loc)
4915 this.constant = constant;
4919 public override string Name {
4920 get { throw new NotImplementedException (); }
4923 public override bool IsInstance {
4924 get { return !IsStatic; }
4927 public override bool IsStatic {
4928 get { return true; }
4931 protected override TypeSpec DeclaringType {
4932 get { return constant.DeclaringType; }
4935 public override Expression CreateExpressionTree (ResolveContext ec)
4937 throw new NotSupportedException ("ET");
4940 protected override Expression DoResolve (ResolveContext rc)
4942 ResolveInstanceExpression (rc, null);
4943 DoBestMemberChecks (rc, constant);
4945 var c = constant.GetConstant (rc);
4947 // Creates reference expression to the constant value
4948 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4951 public override void Emit (EmitContext ec)
4953 throw new NotSupportedException ();
4956 public override string GetSignatureForError ()
4958 return constant.GetSignatureForError ();
4961 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4963 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4968 // Fully resolved expression that references a Field
4970 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
4972 protected FieldSpec spec;
4973 VariableInfo variable_info;
4975 LocalTemporary temp;
4978 protected FieldExpr (Location l)
4983 public FieldExpr (FieldSpec spec, Location loc)
4988 type = spec.MemberType;
4991 public FieldExpr (FieldBase fi, Location l)
4998 public override string Name {
5004 public bool IsHoisted {
5006 IVariableReference hv = InstanceExpression as IVariableReference;
5007 return hv != null && hv.IsHoisted;
5011 public override bool IsInstance {
5013 return !spec.IsStatic;
5017 public override bool IsStatic {
5019 return spec.IsStatic;
5023 public FieldSpec Spec {
5029 protected override TypeSpec DeclaringType {
5031 return spec.DeclaringType;
5035 public VariableInfo VariableInfo {
5037 return variable_info;
5043 public override string GetSignatureForError ()
5045 return TypeManager.GetFullNameSignature (spec);
5048 public bool IsMarshalByRefAccess (ResolveContext rc)
5050 // Checks possible ldflda of field access expression
5051 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5052 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5053 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5056 public void SetHasAddressTaken ()
5058 IVariableReference vr = InstanceExpression as IVariableReference;
5060 vr.SetHasAddressTaken ();
5063 public override Expression CreateExpressionTree (ResolveContext ec)
5065 Expression instance;
5066 if (InstanceExpression == null) {
5067 instance = new NullLiteral (loc);
5069 instance = InstanceExpression.CreateExpressionTree (ec);
5072 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5074 CreateTypeOfExpression ());
5076 return CreateExpressionFactoryCall (ec, "Field", args);
5079 public Expression CreateTypeOfExpression ()
5081 return new TypeOfField (spec, loc);
5084 protected override Expression DoResolve (ResolveContext ec)
5086 return DoResolve (ec, null);
5089 Expression DoResolve (ResolveContext ec, Expression rhs)
5091 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5094 if (ResolveInstanceExpression (ec, rhs)) {
5095 // Resolve the field's instance expression while flow analysis is turned
5096 // off: when accessing a field "a.b", we must check whether the field
5097 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5099 if (lvalue_instance) {
5100 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5101 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5103 Expression right_side =
5104 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5106 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5109 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5110 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5114 if (InstanceExpression == null)
5118 DoBestMemberChecks (ec, spec);
5121 var fb = spec as FixedFieldSpec;
5122 IVariableReference var = InstanceExpression as IVariableReference;
5124 if (lvalue_instance && var != null && var.VariableInfo != null) {
5125 var.VariableInfo.SetFieldAssigned (ec, Name);
5129 IFixedExpression fe = InstanceExpression as IFixedExpression;
5130 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5131 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5134 if (InstanceExpression.eclass != ExprClass.Variable) {
5135 ec.Report.SymbolRelatedToPreviousError (spec);
5136 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5137 TypeManager.GetFullNameSignature (spec));
5138 } else if (var != null && var.IsHoisted) {
5139 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5142 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5145 eclass = ExprClass.Variable;
5147 // If the instance expression is a local variable or parameter.
5148 if (var == null || var.VariableInfo == null)
5151 VariableInfo vi = var.VariableInfo;
5152 if (!vi.IsFieldAssigned (ec, Name, loc))
5155 variable_info = vi.GetSubStruct (Name);
5159 static readonly int [] codes = {
5160 191, // instance, write access
5161 192, // instance, out access
5162 198, // static, write access
5163 199, // static, out access
5164 1648, // member of value instance, write access
5165 1649, // member of value instance, out access
5166 1650, // member of value static, write access
5167 1651 // member of value static, out access
5170 static readonly string [] msgs = {
5171 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5172 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5173 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5174 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5175 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5176 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5177 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5178 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5181 // The return value is always null. Returning a value simplifies calling code.
5182 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5185 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5189 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5191 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5196 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5198 Expression e = DoResolve (ec, right_side);
5203 spec.MemberDefinition.SetIsAssigned ();
5205 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5206 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5207 ec.Report.Warning (420, 1, loc,
5208 "`{0}': A volatile field references will not be treated as volatile",
5209 spec.GetSignatureForError ());
5212 if (spec.IsReadOnly) {
5213 // InitOnly fields can only be assigned in constructors or initializers
5214 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5215 return Report_AssignToReadonly (ec, right_side);
5217 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5219 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5220 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5221 return Report_AssignToReadonly (ec, right_side);
5222 // static InitOnly fields cannot be assigned-to in an instance constructor
5223 if (IsStatic && !ec.IsStatic)
5224 return Report_AssignToReadonly (ec, right_side);
5225 // instance constructors can't modify InitOnly fields of other instances of the same type
5226 if (!IsStatic && !(InstanceExpression is This))
5227 return Report_AssignToReadonly (ec, right_side);
5231 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5232 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5233 ec.Report.Warning (197, 1, loc,
5234 "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",
5235 GetSignatureForError ());
5238 eclass = ExprClass.Variable;
5242 public override int GetHashCode ()
5244 return spec.GetHashCode ();
5247 public bool IsFixed {
5250 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5252 IVariableReference variable = InstanceExpression as IVariableReference;
5253 if (variable != null)
5254 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5256 IFixedExpression fe = InstanceExpression as IFixedExpression;
5257 return fe != null && fe.IsFixed;
5261 public override bool Equals (object obj)
5263 FieldExpr fe = obj as FieldExpr;
5267 if (spec != fe.spec)
5270 if (InstanceExpression == null || fe.InstanceExpression == null)
5273 return InstanceExpression.Equals (fe.InstanceExpression);
5276 public void Emit (EmitContext ec, bool leave_copy)
5278 bool is_volatile = false;
5280 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5283 spec.MemberDefinition.SetIsUsed ();
5287 ec.Emit (OpCodes.Volatile);
5289 ec.Emit (OpCodes.Ldsfld, spec);
5292 EmitInstance (ec, false);
5294 // Optimization for build-in types
5295 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5296 ec.EmitLoadFromPtr (type);
5298 var ff = spec as FixedFieldSpec;
5300 ec.Emit (OpCodes.Ldflda, spec);
5301 ec.Emit (OpCodes.Ldflda, ff.Element);
5304 ec.Emit (OpCodes.Volatile);
5306 ec.Emit (OpCodes.Ldfld, spec);
5312 ec.Emit (OpCodes.Dup);
5314 temp = new LocalTemporary (this.Type);
5320 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5322 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5323 if (isCompound && !(source is DynamicExpressionStatement)) {
5324 if (has_await_source) {
5326 InstanceExpression = InstanceExpression.EmitToField (ec);
5333 if (has_await_source)
5334 source = source.EmitToField (ec);
5336 EmitInstance (ec, prepared);
5342 ec.Emit (OpCodes.Dup);
5344 temp = new LocalTemporary (this.Type);
5349 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5350 ec.Emit (OpCodes.Volatile);
5352 spec.MemberDefinition.SetIsAssigned ();
5355 ec.Emit (OpCodes.Stsfld, spec);
5357 ec.Emit (OpCodes.Stfld, spec);
5367 // Emits store to field with prepared values on stack
5369 public void EmitAssignFromStack (EmitContext ec)
5372 ec.Emit (OpCodes.Stsfld, spec);
5374 ec.Emit (OpCodes.Stfld, spec);
5378 public override void Emit (EmitContext ec)
5383 public override void EmitSideEffect (EmitContext ec)
5385 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5387 if (is_volatile) // || is_marshal_by_ref ())
5388 base.EmitSideEffect (ec);
5391 public void AddressOf (EmitContext ec, AddressOp mode)
5393 if ((mode & AddressOp.Store) != 0)
5394 spec.MemberDefinition.SetIsAssigned ();
5395 if ((mode & AddressOp.Load) != 0)
5396 spec.MemberDefinition.SetIsUsed ();
5399 // Handle initonly fields specially: make a copy and then
5400 // get the address of the copy.
5403 if (spec.IsReadOnly){
5405 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5417 var temp = ec.GetTemporaryLocal (type);
5418 ec.Emit (OpCodes.Stloc, temp);
5419 ec.Emit (OpCodes.Ldloca, temp);
5420 ec.FreeTemporaryLocal (temp, type);
5426 ec.Emit (OpCodes.Ldsflda, spec);
5429 EmitInstance (ec, false);
5430 ec.Emit (OpCodes.Ldflda, spec);
5434 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5436 return MakeExpression (ctx);
5439 public override SLE.Expression MakeExpression (BuilderContext ctx)
5442 return base.MakeExpression (ctx);
5444 return SLE.Expression.Field (
5445 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5446 spec.GetMetaInfo ());
5450 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5452 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5458 // Expression that evaluates to a Property.
5460 // This is not an LValue because we need to re-write the expression. We
5461 // can not take data from the stack and store it.
5463 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5465 public PropertyExpr (PropertySpec spec, Location l)
5468 best_candidate = spec;
5469 type = spec.MemberType;
5474 protected override Arguments Arguments {
5482 protected override TypeSpec DeclaringType {
5484 return best_candidate.DeclaringType;
5488 public override string Name {
5490 return best_candidate.Name;
5494 public override bool IsInstance {
5500 public override bool IsStatic {
5502 return best_candidate.IsStatic;
5506 public PropertySpec PropertyInfo {
5508 return best_candidate;
5514 public override Expression CreateExpressionTree (ResolveContext ec)
5517 if (IsSingleDimensionalArrayLength ()) {
5518 args = new Arguments (1);
5519 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5520 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5523 args = new Arguments (2);
5524 if (InstanceExpression == null)
5525 args.Add (new Argument (new NullLiteral (loc)));
5527 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5528 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5529 return CreateExpressionFactoryCall (ec, "Property", args);
5532 public Expression CreateSetterTypeOfExpression ()
5534 return new TypeOfMethod (Setter, loc);
5537 public override string GetSignatureForError ()
5539 return best_candidate.GetSignatureForError ();
5542 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5545 return base.MakeExpression (ctx);
5547 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5551 public override SLE.Expression MakeExpression (BuilderContext ctx)
5554 return base.MakeExpression (ctx);
5556 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5560 void Error_PropertyNotValid (ResolveContext ec)
5562 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5563 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5564 GetSignatureForError ());
5567 bool IsSingleDimensionalArrayLength ()
5569 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5572 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5573 return ac != null && ac.Rank == 1;
5576 public override void Emit (EmitContext ec, bool leave_copy)
5579 // Special case: length of single dimension array property is turned into ldlen
5581 if (IsSingleDimensionalArrayLength ()) {
5582 EmitInstance (ec, false);
5583 ec.Emit (OpCodes.Ldlen);
5584 ec.Emit (OpCodes.Conv_I4);
5588 base.Emit (ec, leave_copy);
5591 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5594 LocalTemporary await_source_arg = null;
5596 if (isCompound && !(source is DynamicExpressionStatement)) {
5597 emitting_compound_assignment = true;
5600 if (has_await_arguments) {
5601 await_source_arg = new LocalTemporary (Type);
5602 await_source_arg.Store (ec);
5604 args = new Arguments (1);
5605 args.Add (new Argument (await_source_arg));
5608 temp = await_source_arg;
5611 has_await_arguments = false;
5616 ec.Emit (OpCodes.Dup);
5617 temp = new LocalTemporary (this.Type);
5622 args = new Arguments (1);
5626 temp = new LocalTemporary (this.Type);
5628 args.Add (new Argument (temp));
5630 args.Add (new Argument (source));
5634 emitting_compound_assignment = false;
5636 var call = new CallEmitter ();
5637 call.InstanceExpression = InstanceExpression;
5639 call.InstanceExpressionOnStack = true;
5641 call.Emit (ec, Setter, args, loc);
5648 if (await_source_arg != null) {
5649 await_source_arg.Release (ec);
5653 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5655 eclass = ExprClass.PropertyAccess;
5657 if (best_candidate.IsNotCSharpCompatible) {
5658 Error_PropertyNotValid (rc);
5661 ResolveInstanceExpression (rc, right_side);
5663 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5664 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5665 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5667 type = p.MemberType;
5671 DoBestMemberChecks (rc, best_candidate);
5675 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5677 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5681 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5683 // getter and setter can be different for base calls
5684 MethodSpec getter, setter;
5685 protected T best_candidate;
5687 protected LocalTemporary temp;
5688 protected bool emitting_compound_assignment;
5689 protected bool has_await_arguments;
5691 protected PropertyOrIndexerExpr (Location l)
5698 protected abstract Arguments Arguments { get; set; }
5700 public MethodSpec Getter {
5709 public MethodSpec Setter {
5720 protected override Expression DoResolve (ResolveContext ec)
5722 if (eclass == ExprClass.Unresolved) {
5723 var expr = OverloadResolve (ec, null);
5728 return expr.Resolve (ec);
5731 if (!ResolveGetter (ec))
5737 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5739 if (right_side == EmptyExpression.OutAccess) {
5740 // TODO: best_candidate can be null at this point
5741 INamedBlockVariable variable = null;
5742 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5743 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5744 best_candidate.Name);
5746 right_side.DoResolveLValue (ec, this);
5751 // if the property/indexer returns a value type, and we try to set a field in it
5752 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5753 Error_CannotModifyIntermediateExpressionValue (ec);
5756 if (eclass == ExprClass.Unresolved) {
5757 var expr = OverloadResolve (ec, right_side);
5762 return expr.ResolveLValue (ec, right_side);
5765 if (!ResolveSetter (ec))
5772 // Implements the IAssignMethod interface for assignments
5774 public virtual void Emit (EmitContext ec, bool leave_copy)
5776 var call = new CallEmitter ();
5777 call.InstanceExpression = InstanceExpression;
5778 if (has_await_arguments)
5779 call.HasAwaitArguments = true;
5781 call.DuplicateArguments = emitting_compound_assignment;
5783 call.Emit (ec, Getter, Arguments, loc);
5785 if (call.HasAwaitArguments) {
5786 InstanceExpression = call.InstanceExpression;
5787 Arguments = call.EmittedArguments;
5788 has_await_arguments = true;
5792 ec.Emit (OpCodes.Dup);
5793 temp = new LocalTemporary (Type);
5798 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5800 public override void Emit (EmitContext ec)
5805 protected override void EmitToFieldSource (EmitContext ec)
5807 has_await_arguments = true;
5811 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5813 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5815 bool ResolveGetter (ResolveContext rc)
5817 if (!best_candidate.HasGet) {
5818 if (InstanceExpression != EmptyExpression.Null) {
5819 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5820 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5821 best_candidate.GetSignatureForError ());
5824 } else if (!best_candidate.Get.IsAccessible (rc)) {
5825 if (best_candidate.HasDifferentAccessibility) {
5826 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5827 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5828 TypeManager.CSharpSignature (best_candidate));
5830 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5831 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5835 if (best_candidate.HasDifferentAccessibility) {
5836 CheckProtectedMemberAccess (rc, best_candidate.Get);
5839 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5843 bool ResolveSetter (ResolveContext rc)
5845 if (!best_candidate.HasSet) {
5846 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5847 GetSignatureForError ());
5851 if (!best_candidate.Set.IsAccessible (rc)) {
5852 if (best_candidate.HasDifferentAccessibility) {
5853 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5854 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5855 GetSignatureForError ());
5857 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5858 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5862 if (best_candidate.HasDifferentAccessibility)
5863 CheckProtectedMemberAccess (rc, best_candidate.Set);
5865 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5871 /// Fully resolved expression that evaluates to an Event
5873 public class EventExpr : MemberExpr, IAssignMethod
5875 readonly EventSpec spec;
5878 public EventExpr (EventSpec spec, Location loc)
5886 protected override TypeSpec DeclaringType {
5888 return spec.DeclaringType;
5892 public override string Name {
5898 public override bool IsInstance {
5900 return !spec.IsStatic;
5904 public override bool IsStatic {
5906 return spec.IsStatic;
5910 public MethodSpec Operator {
5918 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5921 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5923 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5924 if (spec.BackingField != null &&
5925 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5927 spec.MemberDefinition.SetIsUsed ();
5929 if (!ec.IsObsolete) {
5930 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5932 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5935 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5936 Error_AssignmentEventOnly (ec);
5938 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5940 InstanceExpression = null;
5942 return ml.ResolveMemberAccess (ec, left, original);
5946 return base.ResolveMemberAccess (ec, left, original);
5949 public override Expression CreateExpressionTree (ResolveContext ec)
5951 throw new NotSupportedException ("ET");
5954 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5956 if (right_side == EmptyExpression.EventAddition) {
5957 op = spec.AccessorAdd;
5958 } else if (right_side == EmptyExpression.EventSubtraction) {
5959 op = spec.AccessorRemove;
5963 Error_AssignmentEventOnly (ec);
5967 op = CandidateToBaseOverride (ec, op);
5971 protected override Expression DoResolve (ResolveContext ec)
5973 eclass = ExprClass.EventAccess;
5974 type = spec.MemberType;
5976 ResolveInstanceExpression (ec, null);
5978 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5979 Error_AssignmentEventOnly (ec);
5982 DoBestMemberChecks (ec, spec);
5986 public override void Emit (EmitContext ec)
5988 throw new NotSupportedException ();
5989 //Error_CannotAssign ();
5992 #region IAssignMethod Members
5994 public void Emit (EmitContext ec, bool leave_copy)
5996 throw new NotImplementedException ();
5999 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6001 if (leave_copy || !isCompound)
6002 throw new NotImplementedException ("EventExpr::EmitAssign");
6004 Arguments args = new Arguments (1);
6005 args.Add (new Argument (source));
6007 var call = new CallEmitter ();
6008 call.InstanceExpression = InstanceExpression;
6009 call.Emit (ec, op, args, loc);
6014 void Error_AssignmentEventOnly (ResolveContext ec)
6016 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6017 ec.Report.Error (79, loc,
6018 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6019 GetSignatureForError ());
6021 ec.Report.Error (70, loc,
6022 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6023 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6027 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6029 name = name.Substring (0, name.LastIndexOf ('.'));
6030 base.Error_CannotCallAbstractBase (rc, name);
6033 public override string GetSignatureForError ()
6035 return TypeManager.CSharpSignature (spec);
6038 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6040 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6044 public class TemporaryVariableReference : VariableReference
6046 public class Declarator : Statement
6048 TemporaryVariableReference variable;
6050 public Declarator (TemporaryVariableReference variable)
6052 this.variable = variable;
6056 protected override void DoEmit (EmitContext ec)
6058 variable.li.CreateBuilder (ec);
6061 protected override void CloneTo (CloneContext clonectx, Statement target)
6069 public TemporaryVariableReference (LocalVariable li, Location loc)
6072 this.type = li.Type;
6076 public override bool IsLockedByStatement {
6084 public LocalVariable LocalInfo {
6090 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6092 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6093 return new TemporaryVariableReference (li, loc);
6096 public override Expression CreateExpressionTree (ResolveContext ec)
6098 throw new NotSupportedException ("ET");
6101 protected override Expression DoResolve (ResolveContext ec)
6103 eclass = ExprClass.Variable;
6106 // Don't capture temporary variables except when using
6107 // iterator redirection
6109 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
6110 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6111 storey.CaptureLocalVariable (ec, li);
6117 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6119 return Resolve (ec);
6122 public override void Emit (EmitContext ec)
6124 li.CreateBuilder (ec);
6129 public void EmitAssign (EmitContext ec, Expression source)
6131 li.CreateBuilder (ec);
6133 EmitAssign (ec, source, false, false);
6136 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6138 return li.HoistedVariant;
6141 public override bool IsFixed {
6142 get { return true; }
6145 public override bool IsRef {
6146 get { return false; }
6149 public override string Name {
6150 get { throw new NotImplementedException (); }
6153 public override void SetHasAddressTaken ()
6155 throw new NotImplementedException ();
6158 protected override ILocalVariable Variable {
6162 public override VariableInfo VariableInfo {
6163 get { throw new NotImplementedException (); }
6168 /// Handles `var' contextual keyword; var becomes a keyword only
6169 /// if no type called var exists in a variable scope
6171 class VarExpr : SimpleName
6173 public VarExpr (Location loc)
6178 public bool InferType (ResolveContext ec, Expression right_side)
6181 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6183 type = right_side.Type;
6184 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6185 ec.Report.Error (815, loc,
6186 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6187 type.GetSignatureForError ());
6191 eclass = ExprClass.Variable;
6195 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6197 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6198 base.Error_TypeOrNamespaceNotFound (ec);
6200 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");