2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
67 // This is just as a hint to AddressOf of what will be done with the
70 public enum AddressOp {
77 /// This interface is implemented by variables
79 public interface IMemoryLocation {
81 /// The AddressOf method should generate code that loads
82 /// the address of the object and leaves it on the stack.
84 /// The `mode' argument is used to notify the expression
85 /// of whether this will be used to read from the address or
86 /// write to the address.
88 /// This is just a hint that can be used to provide good error
89 /// reporting, and should have no other side effects.
91 void AddressOf (EmitContext ec, AddressOp mode);
95 // An expressions resolved as a direct variable reference
97 public interface IVariableReference : IFixedExpression
99 bool IsHoisted { get; }
101 VariableInfo VariableInfo { get; }
103 void SetHasAddressTaken ();
107 // Implemented by an expression which could be or is always
110 public interface IFixedExpression
112 bool IsFixed { get; }
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
120 protected TypeSpec type;
121 protected Location loc;
123 public TypeSpec Type {
125 set { type = value; }
128 public Location Location {
132 // Not nice but we have broken hierarchy.
133 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public virtual bool IsNull {
149 /// Performs semantic analysis on the Expression
153 /// The Resolve method is invoked to perform the semantic analysis
156 /// The return value is an expression (it can be the
157 /// same expression in some cases) or a new
158 /// expression that better represents this node.
160 /// For example, optimizations of Unary (LiteralInt)
161 /// would return a new LiteralInt with a negated
164 /// If there is an error during semantic analysis,
165 /// then an error should be reported (using Report)
166 /// and a null value should be returned.
168 /// There are two side effects expected from calling
169 /// Resolve(): the the field variable "eclass" should
170 /// be set to any value of the enumeration
171 /// `ExprClass' and the type variable should be set
172 /// to a valid type (this is the type of the
175 protected abstract Expression DoResolve (ResolveContext rc);
177 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
183 // This is used if the expression should be resolved as a type or namespace name.
184 // the default implementation fails.
186 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
189 ResolveContext ec = new ResolveContext (rc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
199 // This is used to resolve the expression as a type, a null
200 // value will be returned if the expression is not a type
203 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
205 int errors = ec.Compiler.Report.Errors;
207 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
212 TypeExpr te = fne as TypeExpr;
214 if (!silent && errors == ec.Compiler.Report.Errors)
215 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
219 if (!te.CheckAccessLevel (ec)) {
220 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
221 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
227 // Obsolete checks cannot be done when resolving base context as they
228 // require type dependecies to be set but we are just resolving them
230 if (!silent && !(ec is TypeContainer.BaseContext)) {
231 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
232 if (obsolete_attr != null && !ec.IsObsolete) {
233 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
240 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
242 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
245 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
247 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
250 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
252 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
253 name, TypeManager.CSharpName (type));
256 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
258 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
259 "expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext ec)
264 Error_InvalidExpressionStatement (ec.Report, loc);
267 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
269 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
272 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
274 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
277 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
279 // The error was already reported as CS1660
280 if (type == InternalType.AnonymousMethod)
284 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
285 string sig1 = type.DeclaringMethod == null ?
286 TypeManager.CSharpName (type.DeclaringType) :
287 TypeManager.CSharpSignature (type.DeclaringMethod);
288 string sig2 = target.DeclaringMethod == null ?
289 TypeManager.CSharpName (target.DeclaringType) :
290 TypeManager.CSharpSignature (target.DeclaringMethod);
291 ec.Report.ExtraInformation (loc,
293 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
294 Type.Name, sig1, sig2));
295 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
296 ec.Report.ExtraInformation (loc,
298 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
299 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
303 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
308 ec.Report.DisableReporting ();
309 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
310 ec.Report.EnableReporting ();
313 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
314 "An explicit conversion exists (are you missing a cast?)",
315 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
319 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
320 type.GetSignatureForError (), target.GetSignatureForError ());
323 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
325 // Better message for possible generic expressions
326 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
327 report.SymbolRelatedToPreviousError (member);
328 if (member is TypeSpec)
329 member = ((TypeSpec) member).GetDefinition ();
331 member = ((MethodSpec) member).GetGenericMethodDefinition ();
333 string name = member.Kind == MemberKind.Method ? "method" : "type";
334 if (member.IsGeneric) {
335 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
336 name, member.GetSignatureForError (), member.Arity.ToString ());
338 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
339 name, member.GetSignatureForError ());
342 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
346 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
348 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
352 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
354 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
357 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
359 ec.Report.SymbolRelatedToPreviousError (type);
360 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
361 TypeManager.CSharpName (type), name);
364 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
366 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
369 protected void Error_VoidPointerOperation (ResolveContext rc)
371 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
374 public ResolveFlags ExprClassToResolveFlags {
378 case ExprClass.Namespace:
379 return ResolveFlags.Type;
381 case ExprClass.MethodGroup:
382 return ResolveFlags.MethodGroup;
384 case ExprClass.TypeParameter:
385 return ResolveFlags.TypeParameter;
387 case ExprClass.Value:
388 case ExprClass.Variable:
389 case ExprClass.PropertyAccess:
390 case ExprClass.EventAccess:
391 case ExprClass.IndexerAccess:
392 return ResolveFlags.VariableOrValue;
395 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
401 /// Resolves an expression and performs semantic analysis on it.
405 /// Currently Resolve wraps DoResolve to perform sanity
406 /// checking and assertion checking on what we expect from Resolve.
408 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
410 if (eclass != ExprClass.Unresolved)
420 if ((flags & e.ExprClassToResolveFlags) == 0) {
421 e.Error_UnexpectedKind (ec, flags, loc);
426 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
429 } catch (Exception ex) {
430 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
433 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
434 return EmptyExpression.Null; // TODO: Add location
439 /// Resolves an expression and performs semantic analysis on it.
441 public Expression Resolve (ResolveContext rc)
443 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
447 /// Resolves an expression for LValue assignment
451 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
452 /// checking and assertion checking on what we expect from Resolve
454 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
456 int errors = ec.Report.Errors;
457 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
459 Expression e = DoResolveLValue (ec, right_side);
461 if (e != null && out_access && !(e is IMemoryLocation)) {
462 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
463 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
465 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
466 // e.GetType () + " " + e.GetSignatureForError ());
471 if (errors == ec.Report.Errors) {
473 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
475 Error_ValueAssignment (ec, loc);
480 if (e.eclass == ExprClass.Unresolved)
481 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
483 if ((e.type == null) && !(e is GenericTypeExpr))
484 throw new Exception ("Expression " + e + " did not set its type after Resolve");
489 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
491 rc.Compiler.Report.Error (182, loc,
492 "An attribute argument must be a constant expression, typeof expression or array creation expression");
496 /// Emits the code for the expression
500 /// The Emit method is invoked to generate the code
501 /// for the expression.
503 public abstract void Emit (EmitContext ec);
506 // Emit code to branch to @target if this expression is equivalent to @on_true.
507 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
508 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
509 // including the use of conditional branches. Note also that a branch MUST be emitted
510 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
513 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
516 // Emit this expression for its side effects, not for its value.
517 // The default implementation is to emit the value, and then throw it away.
518 // Subclasses can provide more efficient implementations, but those MUST be equivalent
519 public virtual void EmitSideEffect (EmitContext ec)
522 ec.Emit (OpCodes.Pop);
526 /// Protected constructor. Only derivate types should
527 /// be able to be created
530 protected Expression ()
535 /// Returns a fully formed expression after a MemberLookup
538 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
540 if (spec is EventSpec)
541 return new EventExpr ((EventSpec) spec, loc);
542 if (spec is ConstSpec)
543 return new ConstantExpr ((ConstSpec) spec, loc);
544 if (spec is FieldSpec)
545 return new FieldExpr ((FieldSpec) spec, loc);
546 if (spec is PropertySpec)
547 return new PropertyExpr ((PropertySpec) spec, loc);
548 if (spec is TypeSpec)
549 return new TypeExpression (((TypeSpec) spec), loc);
554 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
556 var ctors = MemberCache.FindMembers (type, ConstructorInfo.ConstructorName, true);
558 rc.Report.SymbolRelatedToPreviousError (type);
560 // Report meaningful error for struct as they always have default ctor in C# context
561 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
563 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
564 type.GetSignatureForError ());
570 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
571 return r.ResolveMember<MethodSpec> (rc, ref args);
575 public enum MemberLookupRestrictions
584 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
585 // `qualifier_type' or null to lookup members in the current class.
587 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
589 var members = MemberCache.FindMembers (queried_type, name, false);
593 MemberSpec non_method = null;
594 MemberSpec ambig_non_method = null;
595 currentType = currentType ?? InternalType.FakeInternalType;
597 for (int i = 0; i < members.Count; ++i) {
598 var member = members[i];
600 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
601 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
604 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
607 if (rc != null && !member.IsAccessible (currentType))
610 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
611 if (member is MethodSpec)
612 return new MethodGroupExpr (members, queried_type, loc);
614 if (!Invocation.IsMemberInvocable (member))
618 if (non_method == null || member is MethodSpec) {
620 } else if (currentType != null) {
621 ambig_non_method = member;
625 if (non_method != null) {
626 if (ambig_non_method != null && rc != null) {
627 rc.Report.SymbolRelatedToPreviousError (non_method);
628 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
629 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
630 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
633 if (non_method is MethodSpec)
634 return new MethodGroupExpr (members, queried_type, loc);
636 return ExprClassFromMemberInfo (non_method, loc);
639 if (members[0].DeclaringType.BaseType == null)
642 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
644 } while (members != null);
649 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
651 throw new NotImplementedException ();
654 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
656 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
660 /// Returns an expression that can be used to invoke operator true
661 /// on the expression if it exists.
663 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
665 return GetOperatorTrueOrFalse (ec, e, true, loc);
669 /// Returns an expression that can be used to invoke operator false
670 /// on the expression if it exists.
672 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
674 return GetOperatorTrueOrFalse (ec, e, false, loc);
677 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
679 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
680 var methods = MemberCache.GetUserOperator (e.type, op, false);
684 Arguments arguments = new Arguments (1);
685 arguments.Add (new Argument (e));
687 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
688 var oper = res.ResolveOperator (ec, ref arguments);
693 return new UserOperatorCall (oper, arguments, null, loc);
696 public virtual string ExprClassName
700 case ExprClass.Unresolved:
702 case ExprClass.Value:
704 case ExprClass.Variable:
706 case ExprClass.Namespace:
710 case ExprClass.MethodGroup:
711 return "method group";
712 case ExprClass.PropertyAccess:
713 return "property access";
714 case ExprClass.EventAccess:
715 return "event access";
716 case ExprClass.IndexerAccess:
717 return "indexer access";
718 case ExprClass.Nothing:
720 case ExprClass.TypeParameter:
721 return "type parameter";
723 throw new Exception ("Should not happen");
728 /// Reports that we were expecting `expr' to be of class `expected'
730 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
732 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
735 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
739 name = mc.GetSignatureForError ();
741 name = GetSignatureForError ();
743 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
744 name, was, expected);
747 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
749 string [] valid = new string [4];
752 if ((flags & ResolveFlags.VariableOrValue) != 0) {
753 valid [count++] = "variable";
754 valid [count++] = "value";
757 if ((flags & ResolveFlags.Type) != 0)
758 valid [count++] = "type";
760 if ((flags & ResolveFlags.MethodGroup) != 0)
761 valid [count++] = "method group";
764 valid [count++] = "unknown";
766 StringBuilder sb = new StringBuilder (valid [0]);
767 for (int i = 1; i < count - 1; i++) {
769 sb.Append (valid [i]);
772 sb.Append ("' or `");
773 sb.Append (valid [count - 1]);
776 ec.Report.Error (119, loc,
777 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
780 public static void UnsafeError (ResolveContext ec, Location loc)
782 UnsafeError (ec.Report, loc);
785 public static void UnsafeError (Report Report, Location loc)
787 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
792 // Returns the size of type `t' if known, otherwise, 0
794 public static int GetTypeSize (TypeSpec t)
796 if (t == TypeManager.int32_type ||
797 t == TypeManager.uint32_type ||
798 t == TypeManager.float_type)
800 else if (t == TypeManager.int64_type ||
801 t == TypeManager.uint64_type ||
802 t == TypeManager.double_type)
804 else if (t == TypeManager.byte_type ||
805 t == TypeManager.sbyte_type ||
806 t == TypeManager.bool_type)
808 else if (t == TypeManager.short_type ||
809 t == TypeManager.char_type ||
810 t == TypeManager.ushort_type)
812 else if (t == TypeManager.decimal_type)
818 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
820 ec.Report.SymbolRelatedToPreviousError (type);
821 if (ec.CurrentInitializerVariable != null) {
822 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
823 TypeManager.CSharpName (type), GetSignatureForError ());
825 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
826 GetSignatureForError ());
831 // Converts `source' to an int, uint, long or ulong.
833 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
835 if (source.type == InternalType.Dynamic) {
836 Arguments args = new Arguments (1);
837 args.Add (new Argument (source));
838 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
841 Expression converted;
843 using (ec.Set (ResolveContext.Options.CheckedScope)) {
844 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
845 if (converted == null)
846 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
847 if (converted == null)
848 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
849 if (converted == null)
850 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
852 if (converted == null) {
853 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
859 // Only positive constants are allowed at compile time
861 Constant c = converted as Constant;
862 if (c != null && c.IsNegative)
863 Error_NegativeArrayIndex (ec, source.loc);
865 // No conversion needed to array index
866 if (converted.Type == TypeManager.int32_type)
869 return new ArrayIndexCast (converted).Resolve (ec);
873 // Derived classes implement this method by cloning the fields that
874 // could become altered during the Resolve stage
876 // Only expressions that are created for the parser need to implement
879 protected virtual void CloneTo (CloneContext clonectx, Expression target)
881 throw new NotImplementedException (
883 "CloneTo not implemented for expression {0}", this.GetType ()));
887 // Clones an expression created by the parser.
889 // We only support expressions created by the parser so far, not
890 // expressions that have been resolved (many more classes would need
891 // to implement CloneTo).
893 // This infrastructure is here merely for Lambda expressions which
894 // compile the same code using different type values for the same
895 // arguments to find the correct overload
897 public virtual Expression Clone (CloneContext clonectx)
899 Expression cloned = (Expression) MemberwiseClone ();
900 CloneTo (clonectx, cloned);
906 // Implementation of expression to expression tree conversion
908 public abstract Expression CreateExpressionTree (ResolveContext ec);
910 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
912 return CreateExpressionFactoryCall (ec, name, null, args, loc);
915 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
917 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
920 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
922 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
925 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
927 TypeExpr texpr = TypeManager.expression_type_expr;
929 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
933 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
940 // Implemented by all expressions which support conversion from
941 // compiler expression to invokable runtime expression. Used by
942 // dynamic C# binder.
944 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
946 throw new NotImplementedException ("MakeExpression for " + GetType ());
951 /// This is just a base class for expressions that can
952 /// appear on statements (invocations, object creation,
953 /// assignments, post/pre increment and decrement). The idea
954 /// being that they would support an extra Emition interface that
955 /// does not leave a result on the stack.
957 public abstract class ExpressionStatement : Expression {
959 public ExpressionStatement ResolveStatement (BlockContext ec)
961 Expression e = Resolve (ec);
965 ExpressionStatement es = e as ExpressionStatement;
967 Error_InvalidExpressionStatement (ec);
973 /// Requests the expression to be emitted in a `statement'
974 /// context. This means that no new value is left on the
975 /// stack after invoking this method (constrasted with
976 /// Emit that will always leave a value on the stack).
978 public abstract void EmitStatement (EmitContext ec);
980 public override void EmitSideEffect (EmitContext ec)
987 /// This kind of cast is used to encapsulate the child
988 /// whose type is child.Type into an expression that is
989 /// reported to return "return_type". This is used to encapsulate
990 /// expressions which have compatible types, but need to be dealt
991 /// at higher levels with.
993 /// For example, a "byte" expression could be encapsulated in one
994 /// of these as an "unsigned int". The type for the expression
995 /// would be "unsigned int".
998 public abstract class TypeCast : Expression
1000 protected readonly Expression child;
1002 protected TypeCast (Expression child, TypeSpec return_type)
1004 eclass = child.eclass;
1005 loc = child.Location;
1010 public Expression Child {
1016 public override Expression CreateExpressionTree (ResolveContext ec)
1018 Arguments args = new Arguments (2);
1019 args.Add (new Argument (child.CreateExpressionTree (ec)));
1020 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1022 if (type.IsPointer || child.Type.IsPointer)
1023 Error_PointerInsideExpressionTree (ec);
1025 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1028 protected override Expression DoResolve (ResolveContext ec)
1030 // This should never be invoked, we are born in fully
1031 // initialized state.
1036 public override void Emit (EmitContext ec)
1041 public override SLE.Expression MakeExpression (BuilderContext ctx)
1043 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1044 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1045 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1048 protected override void CloneTo (CloneContext clonectx, Expression t)
1053 public override bool IsNull {
1054 get { return child.IsNull; }
1058 public class EmptyCast : TypeCast {
1059 EmptyCast (Expression child, TypeSpec target_type)
1060 : base (child, target_type)
1064 public static Expression Create (Expression child, TypeSpec type)
1066 Constant c = child as Constant;
1068 return new EmptyConstantCast (c, type);
1070 EmptyCast e = child as EmptyCast;
1072 return new EmptyCast (e.child, type);
1074 return new EmptyCast (child, type);
1077 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1079 child.EmitBranchable (ec, label, on_true);
1082 public override void EmitSideEffect (EmitContext ec)
1084 child.EmitSideEffect (ec);
1089 // Used for predefined class library user casts (no obsolete check, etc.)
1091 public class OperatorCast : TypeCast {
1092 MethodSpec conversion_operator;
1094 public OperatorCast (Expression child, TypeSpec target_type)
1095 : this (child, target_type, false)
1099 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1100 : base (child, target_type)
1102 conversion_operator = GetConversionOperator (find_explicit);
1103 if (conversion_operator == null)
1104 throw new InternalErrorException ("Outer conversion routine is out of sync");
1107 // Returns the implicit operator that converts from
1108 // 'child.Type' to our target type (type)
1109 MethodSpec GetConversionOperator (bool find_explicit)
1111 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1113 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1115 mi = MemberCache.GetUserOperator (type, op, true);
1118 foreach (MethodSpec oper in mi) {
1119 if (oper.ReturnType != type)
1122 if (oper.Parameters.Types [0] == child.Type)
1129 public override void Emit (EmitContext ec)
1132 ec.Emit (OpCodes.Call, conversion_operator);
1137 /// This is a numeric cast to a Decimal
1139 public class CastToDecimal : OperatorCast {
1140 public CastToDecimal (Expression child)
1141 : this (child, false)
1145 public CastToDecimal (Expression child, bool find_explicit)
1146 : base (child, TypeManager.decimal_type, find_explicit)
1152 /// This is an explicit numeric cast from a Decimal
1154 public class CastFromDecimal : TypeCast
1156 static Dictionary<TypeSpec, MethodSpec> operators;
1158 public CastFromDecimal (Expression child, TypeSpec return_type)
1159 : base (child, return_type)
1161 if (child.Type != TypeManager.decimal_type)
1162 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1165 // Returns the explicit operator that converts from an
1166 // express of type System.Decimal to 'type'.
1167 public Expression Resolve ()
1169 if (operators == null) {
1170 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1172 operators = new Dictionary<TypeSpec, MethodSpec> ();
1173 foreach (MethodSpec oper in all_oper) {
1174 AParametersCollection pd = oper.Parameters;
1175 if (pd.Types [0] == TypeManager.decimal_type)
1176 operators.Add (oper.ReturnType, oper);
1180 return operators.ContainsKey (type) ? this : null;
1183 public override void Emit (EmitContext ec)
1187 ec.Emit (OpCodes.Call, operators [type]);
1190 public static void Reset ()
1198 // Constant specialization of EmptyCast.
1199 // We need to special case this since an empty cast of
1200 // a constant is still a constant.
1202 public class EmptyConstantCast : Constant
1204 public Constant child;
1206 public EmptyConstantCast (Constant child, TypeSpec type)
1207 : base (child.Location)
1210 throw new ArgumentNullException ("child");
1213 this.eclass = child.eclass;
1217 public override string AsString ()
1219 return child.AsString ();
1222 public override object GetValue ()
1224 return child.GetValue ();
1227 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1229 if (child.Type == target_type)
1232 // FIXME: check that 'type' can be converted to 'target_type' first
1233 return child.ConvertExplicitly (in_checked_context, target_type);
1236 public override Expression CreateExpressionTree (ResolveContext ec)
1238 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1239 child.CreateExpressionTree (ec),
1240 new TypeOf (new TypeExpression (type, loc), loc));
1243 Error_PointerInsideExpressionTree (ec);
1245 return CreateExpressionFactoryCall (ec, "Convert", args);
1248 public override bool IsDefaultValue {
1249 get { return child.IsDefaultValue; }
1252 public override bool IsNegative {
1253 get { return child.IsNegative; }
1256 public override bool IsNull {
1257 get { return child.IsNull; }
1260 public override bool IsOneInteger {
1261 get { return child.IsOneInteger; }
1264 public override bool IsZeroInteger {
1265 get { return child.IsZeroInteger; }
1268 protected override Expression DoResolve (ResolveContext rc)
1273 public override void Emit (EmitContext ec)
1278 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1280 child.EmitBranchable (ec, label, on_true);
1282 // Only to make verifier happy
1283 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1284 ec.Emit (OpCodes.Unbox_Any, type);
1287 public override void EmitSideEffect (EmitContext ec)
1289 child.EmitSideEffect (ec);
1292 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1294 // FIXME: Do we need to check user conversions?
1295 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1297 return child.ConvertImplicitly (rc, target_type);
1302 /// This class is used to wrap literals which belong inside Enums
1304 public class EnumConstant : Constant
1306 public Constant Child;
1308 public EnumConstant (Constant child, TypeSpec enum_type)
1309 : base (child.Location)
1312 this.type = enum_type;
1315 protected EnumConstant (Location loc)
1320 protected override Expression DoResolve (ResolveContext rc)
1322 Child = Child.Resolve (rc);
1323 this.eclass = ExprClass.Value;
1327 public override void Emit (EmitContext ec)
1332 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1334 Child.EncodeAttributeValue (rc, enc, Child.Type);
1337 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1339 Child.EmitBranchable (ec, label, on_true);
1342 public override void EmitSideEffect (EmitContext ec)
1344 Child.EmitSideEffect (ec);
1347 public override string GetSignatureForError()
1349 return TypeManager.CSharpName (Type);
1352 public override object GetValue ()
1354 return Child.GetValue ();
1357 public override object GetTypedValue ()
1359 // FIXME: runtime is not ready to work with just emited enums
1360 if (!RootContext.StdLib) {
1361 return Child.GetValue ();
1365 // Small workaround for big problem
1366 // System.Enum.ToObject cannot be called on dynamic types
1367 // EnumBuilder has to be used, but we cannot use EnumBuilder
1368 // because it does not properly support generics
1370 // This works only sometimes
1372 if (type.MemberDefinition is TypeContainer)
1373 return Child.GetValue ();
1376 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1379 public override string AsString ()
1381 return Child.AsString ();
1384 public EnumConstant Increment()
1386 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1389 public override bool IsDefaultValue {
1391 return Child.IsDefaultValue;
1395 public override bool IsZeroInteger {
1396 get { return Child.IsZeroInteger; }
1399 public override bool IsNegative {
1401 return Child.IsNegative;
1405 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1407 if (Child.Type == target_type)
1410 return Child.ConvertExplicitly (in_checked_context, target_type);
1413 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1415 if (this.type == type) {
1419 if (!Convert.ImplicitStandardConversionExists (this, type)){
1423 return Child.ConvertImplicitly (rc, type);
1428 /// This kind of cast is used to encapsulate Value Types in objects.
1430 /// The effect of it is to box the value type emitted by the previous
1433 public class BoxedCast : TypeCast {
1435 public BoxedCast (Expression expr, TypeSpec target_type)
1436 : base (expr, target_type)
1438 eclass = ExprClass.Value;
1441 protected override Expression DoResolve (ResolveContext ec)
1443 // This should never be invoked, we are born in fully
1444 // initialized state.
1449 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1451 enc.Encode (child.Type);
1452 child.EncodeAttributeValue (rc, enc, child.Type);
1455 public override void Emit (EmitContext ec)
1459 ec.Emit (OpCodes.Box, child.Type);
1462 public override void EmitSideEffect (EmitContext ec)
1464 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1465 // so, we need to emit the box+pop instructions in most cases
1466 if (TypeManager.IsStruct (child.Type) &&
1467 (type == TypeManager.object_type || type == TypeManager.value_type))
1468 child.EmitSideEffect (ec);
1470 base.EmitSideEffect (ec);
1474 public class UnboxCast : TypeCast {
1475 public UnboxCast (Expression expr, TypeSpec return_type)
1476 : base (expr, return_type)
1480 protected override Expression DoResolve (ResolveContext ec)
1482 // This should never be invoked, we are born in fully
1483 // initialized state.
1488 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1490 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1491 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1492 return base.DoResolveLValue (ec, right_side);
1495 public override void Emit (EmitContext ec)
1499 ec.Emit (OpCodes.Unbox_Any, type);
1504 /// This is used to perform explicit numeric conversions.
1506 /// Explicit numeric conversions might trigger exceptions in a checked
1507 /// context, so they should generate the conv.ovf opcodes instead of
1510 public class ConvCast : TypeCast {
1511 public enum Mode : byte {
1512 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1514 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1515 U2_I1, U2_U1, U2_I2, U2_CH,
1516 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1517 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1518 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1519 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1520 CH_I1, CH_U1, CH_I2,
1521 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1522 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1528 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1529 : base (child, return_type)
1534 protected override Expression DoResolve (ResolveContext ec)
1536 // This should never be invoked, we are born in fully
1537 // initialized state.
1542 public override string ToString ()
1544 return String.Format ("ConvCast ({0}, {1})", mode, child);
1547 public override void Emit (EmitContext ec)
1551 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1553 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1554 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1555 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1556 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1557 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1560 case Mode.U1_CH: /* nothing */ break;
1562 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1563 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1564 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1565 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1566 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1567 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1570 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1571 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1572 case Mode.U2_CH: /* nothing */ break;
1574 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1575 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1576 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1577 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1578 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1579 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1580 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1582 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1583 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1584 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1585 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1586 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1587 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1589 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1590 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1591 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1592 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1593 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1594 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1595 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1596 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1599 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1600 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1601 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1602 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1603 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1604 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1605 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1606 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1607 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1609 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1610 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1611 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1613 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1614 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1615 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1616 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1618 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1619 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1620 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1621 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1623 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1624 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1625 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1626 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1627 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1628 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1629 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1630 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1631 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1632 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1634 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1638 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1639 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1640 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1641 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1642 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1645 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1647 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1648 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1649 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1650 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1651 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1652 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1655 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1656 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1657 case Mode.U2_CH: /* nothing */ break;
1659 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1660 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1661 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1662 case Mode.I4_U4: /* nothing */ break;
1663 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1665 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1667 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1668 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1669 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1670 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.U4_I4: /* nothing */ break;
1672 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1675 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1676 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1677 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1679 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1680 case Mode.I8_U8: /* nothing */ break;
1681 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1684 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1685 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1686 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1687 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1689 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1690 case Mode.U8_I8: /* nothing */ break;
1691 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1694 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1695 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1696 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1698 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1705 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1706 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1708 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1709 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1710 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1711 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1713 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1714 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1715 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1716 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1717 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1719 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1725 class OpcodeCast : TypeCast
1729 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1730 : base (child, return_type)
1735 protected override Expression DoResolve (ResolveContext ec)
1737 // This should never be invoked, we are born in fully
1738 // initialized state.
1743 public override void Emit (EmitContext ec)
1749 public TypeSpec UnderlyingType {
1750 get { return child.Type; }
1755 // Opcode casts expression with 2 opcodes but only
1756 // single expression tree node
1758 class OpcodeCastDuplex : OpcodeCast
1760 readonly OpCode second;
1762 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1763 : base (child, returnType, first)
1765 this.second = second;
1768 public override void Emit (EmitContext ec)
1776 /// This kind of cast is used to encapsulate a child and cast it
1777 /// to the class requested
1779 public sealed class ClassCast : TypeCast {
1780 readonly bool forced;
1782 public ClassCast (Expression child, TypeSpec return_type)
1783 : base (child, return_type)
1787 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1788 : base (child, return_type)
1790 this.forced = forced;
1793 public override void Emit (EmitContext ec)
1797 bool gen = TypeManager.IsGenericParameter (child.Type);
1799 ec.Emit (OpCodes.Box, child.Type);
1801 if (type.IsGenericParameter) {
1802 ec.Emit (OpCodes.Unbox_Any, type);
1809 ec.Emit (OpCodes.Castclass, type);
1814 // Created during resolving pahse when an expression is wrapped or constantified
1815 // and original expression can be used later (e.g. for expression trees)
1817 public class ReducedExpression : Expression
1819 sealed class ReducedConstantExpression : EmptyConstantCast
1821 readonly Expression orig_expr;
1823 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1824 : base (expr, expr.Type)
1826 this.orig_expr = orig_expr;
1829 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1831 Constant c = base.ConvertImplicitly (rc, target_type);
1833 c = new ReducedConstantExpression (c, orig_expr);
1838 public override Expression CreateExpressionTree (ResolveContext ec)
1840 return orig_expr.CreateExpressionTree (ec);
1843 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1845 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1847 c = new ReducedConstantExpression (c, orig_expr);
1852 sealed class ReducedExpressionStatement : ExpressionStatement
1854 readonly Expression orig_expr;
1855 readonly ExpressionStatement stm;
1857 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1859 this.orig_expr = orig;
1861 this.loc = orig.Location;
1864 public override Expression CreateExpressionTree (ResolveContext ec)
1866 return orig_expr.CreateExpressionTree (ec);
1869 protected override Expression DoResolve (ResolveContext ec)
1871 eclass = stm.eclass;
1876 public override void Emit (EmitContext ec)
1881 public override void EmitStatement (EmitContext ec)
1883 stm.EmitStatement (ec);
1887 readonly Expression expr, orig_expr;
1889 private ReducedExpression (Expression expr, Expression orig_expr)
1892 this.eclass = expr.eclass;
1893 this.type = expr.Type;
1894 this.orig_expr = orig_expr;
1895 this.loc = orig_expr.Location;
1900 public Expression OriginalExpression {
1909 // Creates fully resolved expression switcher
1911 public static Constant Create (Constant expr, Expression original_expr)
1913 if (expr.eclass == ExprClass.Unresolved)
1914 throw new ArgumentException ("Unresolved expression");
1916 return new ReducedConstantExpression (expr, original_expr);
1919 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1921 return new ReducedExpressionStatement (s, orig);
1925 // Creates unresolved reduce expression. The original expression has to be
1928 public static Expression Create (Expression expr, Expression original_expr)
1930 Constant c = expr as Constant;
1932 return Create (c, original_expr);
1934 ExpressionStatement s = expr as ExpressionStatement;
1936 return Create (s, original_expr);
1938 if (expr.eclass == ExprClass.Unresolved)
1939 throw new ArgumentException ("Unresolved expression");
1941 return new ReducedExpression (expr, original_expr);
1944 public override Expression CreateExpressionTree (ResolveContext ec)
1946 return orig_expr.CreateExpressionTree (ec);
1949 protected override Expression DoResolve (ResolveContext ec)
1954 public override void Emit (EmitContext ec)
1959 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1961 expr.EmitBranchable (ec, target, on_true);
1964 public override SLE.Expression MakeExpression (BuilderContext ctx)
1966 return orig_expr.MakeExpression (ctx);
1971 // Standard composite pattern
1973 public abstract class CompositeExpression : Expression
1977 protected CompositeExpression (Expression expr)
1980 this.loc = expr.Location;
1983 public override Expression CreateExpressionTree (ResolveContext ec)
1985 return expr.CreateExpressionTree (ec);
1988 public Expression Child {
1989 get { return expr; }
1992 protected override Expression DoResolve (ResolveContext ec)
1994 expr = expr.Resolve (ec);
1997 eclass = expr.eclass;
2003 public override void Emit (EmitContext ec)
2008 public override bool IsNull {
2009 get { return expr.IsNull; }
2014 // Base of expressions used only to narrow resolve flow
2016 public abstract class ShimExpression : Expression
2018 protected Expression expr;
2020 protected ShimExpression (Expression expr)
2025 protected override void CloneTo (CloneContext clonectx, Expression t)
2030 ShimExpression target = (ShimExpression) t;
2031 target.expr = expr.Clone (clonectx);
2034 public override Expression CreateExpressionTree (ResolveContext ec)
2036 throw new NotSupportedException ("ET");
2039 public override void Emit (EmitContext ec)
2041 throw new InternalErrorException ("Missing Resolve call");
2044 public Expression Expr {
2045 get { return expr; }
2050 // Unresolved type name expressions
2052 public abstract class ATypeNameExpression : FullNamedExpression
2055 protected TypeArguments targs;
2057 protected ATypeNameExpression (string name, Location l)
2063 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2070 protected ATypeNameExpression (string name, int arity, Location l)
2071 : this (name, new UnboundTypeArguments (arity), l)
2077 protected int Arity {
2079 return targs == null ? 0 : targs.Count;
2083 public bool HasTypeArguments {
2085 return targs != null && !targs.IsEmpty;
2089 public string Name {
2098 public TypeArguments TypeArguments {
2106 public override bool Equals (object obj)
2108 ATypeNameExpression atne = obj as ATypeNameExpression;
2109 return atne != null && atne.Name == Name &&
2110 (targs == null || targs.Equals (atne.targs));
2113 public override int GetHashCode ()
2115 return Name.GetHashCode ();
2118 // TODO: Move it to MemberCore
2119 public static string GetMemberType (MemberCore mc)
2125 if (mc is FieldBase)
2127 if (mc is MethodCore)
2129 if (mc is EnumMember)
2137 public override string GetSignatureForError ()
2139 if (targs != null) {
2140 return Name + "<" + targs.GetSignatureForError () + ">";
2146 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2150 /// SimpleName expressions are formed of a single word and only happen at the beginning
2151 /// of a dotted-name.
2153 public class SimpleName : ATypeNameExpression
2155 public SimpleName (string name, Location l)
2160 public SimpleName (string name, TypeArguments args, Location l)
2161 : base (name, args, l)
2165 public SimpleName (string name, int arity, Location l)
2166 : base (name, arity, l)
2170 public SimpleName GetMethodGroup ()
2172 return new SimpleName (Name, targs, loc);
2175 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2177 if (ec.CurrentType != null) {
2178 if (ec.CurrentMemberDefinition != null) {
2179 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2181 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2187 // TODO MemberCache: Implement
2189 string ns = ec.CurrentType.Namespace;
2190 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2191 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2192 var type = a.GetType (fullname);
2194 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2195 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2200 if (ec.CurrentTypeDefinition != null) {
2201 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2203 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2210 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2211 if (retval != null) {
2212 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2214 var te = retval as TypeExpr;
2215 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2216 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2218 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2223 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2226 protected override Expression DoResolve (ResolveContext ec)
2228 return SimpleNameResolve (ec, null, false);
2231 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2233 return SimpleNameResolve (ec, right_side, false);
2236 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2238 int errors = ec.Compiler.Report.Errors;
2239 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2242 if (fne.Type != null && Arity > 0) {
2243 if (HasTypeArguments) {
2244 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2245 return ct.ResolveAsTypeStep (ec, false);
2248 return new GenericOpenTypeExpr (fne.Type, loc);
2252 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2254 if (!(fne is Namespace))
2258 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2259 if (!ec.Compiler.PredefinedAttributes.Dynamic.IsDefined) {
2260 ec.Compiler.Report.Error (1980, Location,
2261 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2262 ec.Compiler.PredefinedAttributes.Dynamic.GetSignatureForError ());
2265 return new DynamicTypeExpr (loc);
2271 if (silent || errors != ec.Compiler.Report.Errors)
2274 Error_TypeOrNamespaceNotFound (ec);
2278 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2280 int lookup_arity = Arity;
2281 bool errorMode = false;
2283 Block current_block = rc.CurrentBlock;
2284 INamedBlockVariable variable = null;
2285 bool variable_found = false;
2289 // Stage 1: binding to local variables or parameters
2291 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2293 if (current_block != null && lookup_arity == 0) {
2294 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2295 if (!variable.IsDeclared) {
2296 // We found local name in accessible block but it's not
2297 // initialized yet, maybe the user wanted to bind to something else
2299 variable_found = true;
2301 e = variable.CreateReferenceExpression (rc, loc);
2304 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2313 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2315 TypeSpec member_type = rc.CurrentType;
2316 TypeSpec current_type = member_type;
2317 for (; member_type != null; member_type = member_type.DeclaringType) {
2318 var me = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc) as MemberExpr;
2323 if (variable != null) {
2324 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2325 rc.Report.Error (844, loc,
2326 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2327 Name, me.GetSignatureForError ());
2331 } else if (me is MethodGroupExpr) {
2332 // Leave it to overload resolution to report correct error
2334 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2335 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2338 if (variable != null && (restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2339 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2340 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2344 // MemberLookup does not check accessors availability, this is actually needed for properties only
2346 var pe = me as PropertyExpr;
2349 // Break as there is no other overload available anyway
2350 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2351 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2354 pe.Getter = pe.PropertyInfo.Get;
2356 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2359 pe.Setter = pe.PropertyInfo.Set;
2364 // TODO: It's used by EventExpr -> FieldExpr transformation only
2365 // TODO: Should go to MemberAccess
2366 me = me.ResolveMemberAccess (rc, null, null);
2370 me.SetTypeArguments (rc, targs);
2377 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2379 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2380 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2386 if (variable_found) {
2387 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2389 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2395 if (RootContext.EvalMode) {
2396 var fi = Evaluator.LookupField (Name);
2398 return new FieldExpr (fi.Item1, loc);
2402 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2407 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2409 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2414 if (right_side != null) {
2415 if (e is TypeExpr) {
2416 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2420 e = e.ResolveLValue (ec, right_side);
2425 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2431 /// Represents a namespace or a type. The name of the class was inspired by
2432 /// section 10.8.1 (Fully Qualified Names).
2434 public abstract class FullNamedExpression : Expression
2436 protected override void CloneTo (CloneContext clonectx, Expression target)
2438 // Do nothing, most unresolved type expressions cannot be
2439 // resolved to different type
2442 public override Expression CreateExpressionTree (ResolveContext ec)
2444 throw new NotSupportedException ("ET");
2447 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2452 public override void Emit (EmitContext ec)
2454 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2455 GetSignatureForError ());
2460 /// Expression that evaluates to a type
2462 public abstract class TypeExpr : FullNamedExpression {
2463 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2465 TypeExpr t = DoResolveAsTypeStep (ec);
2469 eclass = ExprClass.Type;
2473 protected override Expression DoResolve (ResolveContext ec)
2475 return ResolveAsTypeTerminal (ec, false);
2478 public virtual bool CheckAccessLevel (IMemberContext mc)
2480 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2482 c = mc.CurrentMemberDefinition.Parent;
2484 return c.CheckAccessLevel (Type);
2487 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2489 public override bool Equals (object obj)
2491 TypeExpr tobj = obj as TypeExpr;
2495 return Type == tobj.Type;
2498 public override int GetHashCode ()
2500 return Type.GetHashCode ();
2505 /// Fully resolved Expression that already evaluated to a type
2507 public class TypeExpression : TypeExpr {
2508 public TypeExpression (TypeSpec t, Location l)
2511 eclass = ExprClass.Type;
2515 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2520 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2527 /// This class denotes an expression which evaluates to a member
2528 /// of a struct or a class.
2530 public abstract class MemberExpr : Expression
2533 // An instance expression associated with this member, if it's a
2534 // non-static member
2536 public Expression InstanceExpression;
2539 /// The name of this member.
2541 public abstract string Name {
2546 // When base.member is used
2548 public bool IsBase {
2549 get { return InstanceExpression is BaseThis; }
2553 /// Whether this is an instance member.
2555 public abstract bool IsInstance {
2560 /// Whether this is a static member.
2562 public abstract bool IsStatic {
2567 protected abstract TypeSpec DeclaringType {
2572 // Converts best base candidate for virtual method starting from QueriedBaseType
2574 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2577 // Only when base.member is used and method is virtual
2583 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2584 // means for base.member access we have to find the closest match after we found best candidate
2586 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2588 // The method could already be what we are looking for
2590 TypeSpec[] targs = null;
2591 if (method.DeclaringType != InstanceExpression.Type) {
2592 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2593 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2594 if (base_override.IsGeneric)
2595 targs = method.TypeArguments;
2597 method = base_override;
2601 // TODO: For now we do it for any hoisted call even if it's needed for
2602 // hoisted stories only but that requires a new expression wrapper
2603 if (rc.CurrentAnonymousMethod != null) {
2604 if (targs == null && method.IsGeneric) {
2605 targs = method.TypeArguments;
2606 method = method.GetGenericMethodDefinition ();
2609 if (method.Parameters.HasArglist)
2610 throw new NotImplementedException ("__arglist base call proxy");
2612 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2614 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2615 // get/set member expressions second call would fail to proxy because left expression
2616 // would be of 'this' and not 'base'
2617 if (rc.CurrentType.IsStruct)
2618 InstanceExpression = rc.GetThis (loc);
2622 method = method.MakeGenericMethod (targs);
2626 // Only base will allow this invocation to happen.
2628 if (method.IsAbstract) {
2629 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2635 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2637 if (InstanceExpression == null)
2640 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2641 var ct = rc.CurrentType;
2642 var expr_type = InstanceExpression.Type;
2643 if (ct != expr_type) {
2644 expr_type = expr_type.GetDefinition ();
2645 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2646 rc.Report.SymbolRelatedToPreviousError (member);
2647 rc.Report.Error (1540, loc,
2648 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2649 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2655 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2658 type = type.GetDefinition ();
2660 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2663 type = type.DeclaringType;
2664 } while (type != null);
2669 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2671 if (InstanceExpression != null) {
2672 InstanceExpression = InstanceExpression.Resolve (rc);
2673 CheckProtectedMemberAccess (rc, member);
2676 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2677 UnsafeError (rc, loc);
2680 if (!rc.IsObsolete) {
2681 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2683 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2686 if (!(member is FieldSpec))
2687 member.MemberDefinition.SetIsUsed ();
2690 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2692 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2696 // Implements identicial simple name and type-name
2698 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2701 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2704 // 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
2705 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2707 if (left is MemberExpr || left is VariableReference) {
2708 rc.Report.DisableReporting ();
2709 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2710 rc.Report.EnableReporting ();
2711 if (identical_type != null && identical_type.Type == left.Type)
2712 return identical_type;
2718 public bool ResolveInstanceExpression (ResolveContext rc)
2721 if (InstanceExpression != null) {
2722 if (InstanceExpression is TypeExpr) {
2723 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2724 if (oa != null && !rc.IsObsolete) {
2725 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2728 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2729 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2730 rc.Report.Error (176, loc,
2731 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2732 GetSignatureForError ());
2736 InstanceExpression = null;
2742 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2743 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2744 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2745 rc.Report.Error (236, loc,
2746 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2747 GetSignatureForError ());
2749 rc.Report.Error (120, loc,
2750 "An object reference is required to access non-static member `{0}'",
2751 GetSignatureForError ());
2756 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2757 rc.Report.Error (38, loc,
2758 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2759 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2762 InstanceExpression = rc.GetThis (loc);
2766 var me = InstanceExpression as MemberExpr;
2768 me.ResolveInstanceExpression (rc);
2770 var fe = me as FieldExpr;
2771 if (fe != null && fe.IsMarshalByRefAccess ()) {
2772 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2773 rc.Report.Warning (1690, 1, loc,
2774 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2775 me.GetSignatureForError ());
2782 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2784 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2785 ec.Report.Warning (1720, 1, left.Location,
2786 "Expression will always cause a `{0}'", "System.NullReferenceException");
2789 InstanceExpression = left;
2793 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2795 TypeSpec instance_type = InstanceExpression.Type;
2796 if (TypeManager.IsValueType (instance_type)) {
2797 if (InstanceExpression is IMemoryLocation) {
2798 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2800 LocalTemporary t = new LocalTemporary (instance_type);
2801 InstanceExpression.Emit (ec);
2803 t.AddressOf (ec, AddressOp.Store);
2806 InstanceExpression.Emit (ec);
2808 // Only to make verifier happy
2809 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2810 ec.Emit (OpCodes.Box, instance_type);
2813 if (prepare_for_load)
2814 ec.Emit (OpCodes.Dup);
2817 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2821 // Represents a group of extension method candidates for whole namespace
2823 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2825 NamespaceEntry namespace_entry;
2826 public readonly Expression ExtensionExpression;
2828 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2829 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2831 this.namespace_entry = n;
2832 this.ExtensionExpression = extensionExpr;
2835 public override bool IsStatic {
2836 get { return true; }
2839 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2841 if (namespace_entry == null)
2845 // For extension methodgroup we are not looking for base members but parent
2846 // namespace extension methods
2848 int arity = type_arguments == null ? 0 : type_arguments.Count;
2849 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2853 return found.Cast<MemberSpec> ().ToList ();
2856 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2858 // We are already here
2862 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2864 if (arguments == null)
2865 arguments = new Arguments (1);
2867 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2868 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2870 // Store resolved argument and restore original arguments
2872 // Clean-up modified arguments for error reporting
2873 arguments.RemoveAt (0);
2877 var me = ExtensionExpression as MemberExpr;
2879 me.ResolveInstanceExpression (ec);
2881 InstanceExpression = null;
2885 #region IErrorHandler Members
2887 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2892 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2894 rc.Report.SymbolRelatedToPreviousError (best);
2895 rc.Report.Error (1928, loc,
2896 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2897 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2900 rc.Report.Error (1929, loc,
2901 "Extension method instance type `{0}' cannot be converted to `{1}'",
2902 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2908 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2913 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2922 /// MethodGroupExpr represents a group of method candidates which
2923 /// can be resolved to the best method overload
2925 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2927 protected IList<MemberSpec> Methods;
2928 MethodSpec best_candidate;
2929 protected TypeArguments type_arguments;
2931 SimpleName simple_name;
2932 protected TypeSpec queried_type;
2934 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2938 this.type = InternalType.MethodGroup;
2940 eclass = ExprClass.MethodGroup;
2941 queried_type = type;
2944 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2945 : this (new MemberSpec[] { m }, type, loc)
2951 public MethodSpec BestCandidate {
2953 return best_candidate;
2957 protected override TypeSpec DeclaringType {
2959 return queried_type;
2963 public override bool IsInstance {
2965 if (best_candidate != null)
2966 return !best_candidate.IsStatic;
2972 public override bool IsStatic {
2974 if (best_candidate != null)
2975 return best_candidate.IsStatic;
2981 public override string Name {
2983 if (best_candidate != null)
2984 return best_candidate.Name;
2987 return Methods.First ().Name;
2994 // When best candidate is already know this factory can be used
2995 // to avoid expensive overload resolution to be called
2997 // NOTE: InstanceExpression has to be set manually
2999 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3001 return new MethodGroupExpr (best, queriedType, loc) {
3002 best_candidate = best
3006 public override string GetSignatureForError ()
3008 if (best_candidate != null)
3009 return best_candidate.GetSignatureForError ();
3011 return Methods.First ().GetSignatureForError ();
3014 public override Expression CreateExpressionTree (ResolveContext ec)
3016 if (best_candidate == null) {
3017 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3021 if (best_candidate.IsConditionallyExcluded (loc))
3022 ec.Report.Error (765, loc,
3023 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3025 return new TypeOfMethod (best_candidate, loc);
3028 protected override Expression DoResolve (ResolveContext ec)
3030 this.eclass = ExprClass.MethodGroup;
3032 if (InstanceExpression != null) {
3033 InstanceExpression = InstanceExpression.Resolve (ec);
3034 if (InstanceExpression == null)
3041 public override void Emit (EmitContext ec)
3043 throw new NotSupportedException ();
3046 public void EmitCall (EmitContext ec, Arguments arguments)
3048 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3051 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3053 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3054 Name, TypeManager.CSharpName (target));
3057 public static bool IsExtensionMethodArgument (Expression expr)
3060 // LAMESPEC: No details about which expressions are not allowed
3062 return !(expr is TypeExpr) && !(expr is BaseThis);
3066 /// Find the Applicable Function Members (7.4.2.1)
3068 /// me: Method Group expression with the members to select.
3069 /// it might contain constructors or methods (or anything
3070 /// that maps to a method).
3072 /// Arguments: ArrayList containing resolved Argument objects.
3074 /// loc: The location if we want an error to be reported, or a Null
3075 /// location for "probing" purposes.
3077 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3078 /// that is the best match of me on Arguments.
3081 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3083 // TODO: causes issues with probing mode, remove explicit Kind check
3084 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3087 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3088 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3089 r.BaseMembersProvider = this;
3092 if (cerrors != null)
3093 r.CustomErrors = cerrors;
3095 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3096 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3097 if (best_candidate == null)
3098 return r.BestCandidateIsDynamic ? this : null;
3100 // Overload resolver had to create a new method group, all checks bellow have already been executed
3101 if (r.BestCandidateNewMethodGroup != null)
3102 return r.BestCandidateNewMethodGroup;
3104 if (best_candidate.Kind == MemberKind.Method) {
3105 if (InstanceExpression != null) {
3106 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3107 InstanceExpression = null;
3109 if (best_candidate.IsStatic && simple_name != null) {
3110 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3113 InstanceExpression.Resolve (ec);
3117 ResolveInstanceExpression (ec);
3118 if (InstanceExpression != null)
3119 CheckProtectedMemberAccess (ec, best_candidate);
3122 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3126 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3128 simple_name = original;
3129 return base.ResolveMemberAccess (ec, left, original);
3132 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3134 type_arguments = ta;
3137 #region IBaseMembersProvider Members
3139 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3141 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3144 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3146 if (queried_type == member.DeclaringType)
3149 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3150 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3154 // Extension methods lookup after ordinary methods candidates failed to apply
3156 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3158 if (InstanceExpression == null)
3161 InstanceExpression = InstanceExpression.Resolve (rc);
3162 if (!IsExtensionMethodArgument (InstanceExpression))
3165 int arity = type_arguments == null ? 0 : type_arguments.Count;
3166 NamespaceEntry methods_scope = null;
3167 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3168 if (methods == null)
3171 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3172 emg.SetTypeArguments (rc, type_arguments);
3179 public struct OverloadResolver
3182 public enum Restrictions
3186 ProbingOnly = 1 << 1,
3187 CovariantDelegate = 1 << 2,
3188 NoBaseMembers = 1 << 3,
3189 BaseMembersIncluded = 1 << 4
3192 public interface IBaseMembersProvider
3194 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3195 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3196 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3199 public interface IErrorHandler
3201 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3202 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3203 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3204 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3207 sealed class NoBaseMembers : IBaseMembersProvider
3209 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3211 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3216 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3221 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3227 struct AmbiguousCandidate
3229 public readonly MemberSpec Member;
3230 public readonly bool Expanded;
3232 public AmbiguousCandidate (MemberSpec member, bool expanded)
3235 Expanded = expanded;
3240 IList<MemberSpec> members;
3241 TypeArguments type_arguments;
3242 IBaseMembersProvider base_provider;
3243 IErrorHandler custom_errors;
3244 Restrictions restrictions;
3245 MethodGroupExpr best_candidate_extension_group;
3247 SessionReportPrinter lambda_conv_msgs;
3248 ReportPrinter prev_recorder;
3250 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3251 : this (members, null, restrictions, loc)
3255 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3258 if (members == null || members.Count == 0)
3259 throw new ArgumentException ("empty members set");
3261 this.members = members;
3263 type_arguments = targs;
3264 this.restrictions = restrictions;
3265 if (IsDelegateInvoke)
3266 this.restrictions |= Restrictions.NoBaseMembers;
3268 base_provider = NoBaseMembers.Instance;
3273 public IBaseMembersProvider BaseMembersProvider {
3275 return base_provider;
3278 base_provider = value;
3282 public bool BestCandidateIsDynamic { get; set; }
3285 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3287 public MethodGroupExpr BestCandidateNewMethodGroup {
3289 return best_candidate_extension_group;
3293 public IErrorHandler CustomErrors {
3295 return custom_errors;
3298 custom_errors = value;
3302 TypeSpec DelegateType {
3304 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3305 throw new InternalErrorException ("Not running in delegate mode", loc);
3307 return members [0].DeclaringType;
3311 bool IsProbingOnly {
3313 return (restrictions & Restrictions.ProbingOnly) != 0;
3317 bool IsDelegateInvoke {
3319 return (restrictions & Restrictions.DelegateInvoke) != 0;
3326 // 7.4.3.3 Better conversion from expression
3327 // Returns : 1 if a->p is better,
3328 // 2 if a->q is better,
3329 // 0 if neither is better
3331 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3333 TypeSpec argument_type = a.Type;
3334 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3336 // Uwrap delegate from Expression<T>
3338 if (p.GetDefinition () == TypeManager.expression_type) {
3339 p = TypeManager.GetTypeArguments (p)[0];
3341 if (q.GetDefinition () == TypeManager.expression_type) {
3342 q = TypeManager.GetTypeArguments (q)[0];
3345 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3346 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3347 if (p == TypeManager.void_type && q != TypeManager.void_type)
3349 if (q == TypeManager.void_type && p != TypeManager.void_type)
3352 if (argument_type == p)
3355 if (argument_type == q)
3359 return BetterTypeConversion (ec, p, q);
3363 // 7.4.3.4 Better conversion from type
3365 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3367 if (p == null || q == null)
3368 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3370 if (p == TypeManager.int32_type) {
3371 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3373 } else if (p == TypeManager.int64_type) {
3374 if (q == TypeManager.uint64_type)
3376 } else if (p == TypeManager.sbyte_type) {
3377 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3378 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3380 } else if (p == TypeManager.short_type) {
3381 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3382 q == TypeManager.uint64_type)
3384 } else if (p == InternalType.Dynamic) {
3385 // Dynamic is never better
3389 if (q == TypeManager.int32_type) {
3390 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3392 } if (q == TypeManager.int64_type) {
3393 if (p == TypeManager.uint64_type)
3395 } else if (q == TypeManager.sbyte_type) {
3396 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3397 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3399 } if (q == TypeManager.short_type) {
3400 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3401 p == TypeManager.uint64_type)
3403 } else if (q == InternalType.Dynamic) {
3404 // Dynamic is never better
3408 // TODO: this is expensive
3409 Expression p_tmp = new EmptyExpression (p);
3410 Expression q_tmp = new EmptyExpression (q);
3412 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3413 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3415 if (p_to_q && !q_to_p)
3418 if (q_to_p && !p_to_q)
3425 /// Determines "Better function" between candidate
3426 /// and the current best match
3429 /// Returns a boolean indicating :
3430 /// false if candidate ain't better
3431 /// true if candidate is better than the current best match
3433 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3434 MemberSpec best, bool best_params)
3436 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3437 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3439 bool better_at_least_one = false;
3441 int args_count = args == null ? 0 : args.Count;
3443 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3444 Argument a = args[j];
3446 // Default arguments are ignored for better decision
3447 if (a.IsDefaultArgument)
3450 TypeSpec ct = candidate_pd.Types[c_idx];
3451 TypeSpec bt = best_pd.Types[b_idx];
3453 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3454 ct = TypeManager.GetElementType (ct);
3458 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3459 bt = TypeManager.GetElementType (bt);
3467 int result = BetterExpressionConversion (ec, a, ct, bt);
3469 // for each argument, the conversion to 'ct' should be no worse than
3470 // the conversion to 'bt'.
3474 // for at least one argument, the conversion to 'ct' should be better than
3475 // the conversion to 'bt'.
3477 better_at_least_one = true;
3480 if (better_at_least_one)
3484 // This handles the case
3486 // Add (float f1, float f2, float f3);
3487 // Add (params decimal [] foo);
3489 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3490 // first candidate would've chosen as better.
3496 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3500 // This handles the following cases:
3502 // Foo (int i) is better than Foo (int i, long l = 0)
3503 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3505 // Prefer non-optional version
3507 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3508 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3509 if (candidate_pd.Count >= best_pd.Count)
3512 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3519 // One is a non-generic method and second is a generic method, then non-generic is better
3521 if (best.IsGeneric != candidate.IsGeneric)
3522 return best.IsGeneric;
3525 // This handles the following cases:
3527 // Trim () is better than Trim (params char[] chars)
3528 // Concat (string s1, string s2, string s3) is better than
3529 // Concat (string s1, params string [] srest)
3530 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3532 // Prefer non-expanded version
3534 if (candidate_params != best_params)
3537 int candidate_param_count = candidate_pd.Count;
3538 int best_param_count = best_pd.Count;
3540 if (candidate_param_count != best_param_count)
3541 // can only happen if (candidate_params && best_params)
3542 return candidate_param_count > best_param_count && best_pd.HasParams;
3545 // Both methods have the same number of parameters, and the parameters have equal types
3546 // Pick the "more specific" signature using rules over original (non-inflated) types
3548 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3549 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3551 bool specific_at_least_once = false;
3552 for (j = 0; j < candidate_param_count; ++j) {
3553 var ct = candidate_def_pd.Types[j];
3554 var bt = best_def_pd.Types[j];
3557 TypeSpec specific = MoreSpecific (ct, bt);
3561 specific_at_least_once = true;
3564 if (specific_at_least_once)
3567 // FIXME: handle lifted operators
3573 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3575 rc.Report.Error (1729, loc,
3576 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3577 type.GetSignatureForError (), argCount.ToString ());
3581 // Determines if the candidate method is applicable to the given set of arguments
3582 // There could be two different set of parameters for same candidate where one
3583 // is the closest override for default values and named arguments checks and second
3584 // one being the virtual base for the parameter types and modifiers.
3586 // A return value rates candidate method compatibility,
3587 // 0 = the best, int.MaxValue = the worst
3589 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, AParametersCollection pd, ref bool params_expanded_form, ref bool dynamicArgument)
3591 int param_count = pd.Count;
3592 int optional_count = 0;
3594 Arguments orig_args = arguments;
3596 if (arg_count != param_count) {
3597 for (int i = 0; i < pd.Count; ++i) {
3598 if (pd.FixedParameters[i].HasDefaultValue) {
3599 optional_count = pd.Count - i;
3604 int args_gap = System.Math.Abs (arg_count - param_count);
3605 if (optional_count != 0) {
3606 if (args_gap > optional_count)
3607 return int.MaxValue - 10000 + args_gap - optional_count;
3609 // Readjust expected number when params used
3612 if (arg_count < param_count)
3614 } else if (arg_count > param_count) {
3615 return int.MaxValue - 10000 + args_gap;
3617 } else if (arg_count != param_count) {
3619 return int.MaxValue - 10000 + args_gap;
3620 if (arg_count < param_count - 1)
3621 return int.MaxValue - 10000 + args_gap;
3624 // Resize to fit optional arguments
3625 if (optional_count != 0) {
3626 if (arguments == null) {
3627 arguments = new Arguments (optional_count);
3629 // Have to create a new container, so the next run can do same
3630 var resized = new Arguments (param_count);
3631 resized.AddRange (arguments);
3632 arguments = resized;
3635 for (int i = arg_count; i < param_count; ++i)
3636 arguments.Add (null);
3640 if (arg_count > 0) {
3642 // Shuffle named arguments to the right positions if there are any
3644 if (arguments[arg_count - 1] is NamedArgument) {
3645 arg_count = arguments.Count;
3647 for (int i = 0; i < arg_count; ++i) {
3648 bool arg_moved = false;
3650 NamedArgument na = arguments[i] as NamedArgument;
3654 int index = pd.GetParameterIndexByName (na.Name);
3656 // Named parameter not found
3660 // already reordered
3665 if (index >= param_count) {
3666 // When using parameters which should not be available to the user
3667 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3670 arguments.Add (null);
3674 temp = arguments[index];
3676 // The slot has been taken by positional argument
3677 if (temp != null && !(temp is NamedArgument))
3682 arguments = arguments.MarkOrderedArgument (na);
3686 arguments[index] = arguments[i];
3687 arguments[i] = temp;
3694 arg_count = arguments.Count;
3696 } else if (arguments != null) {
3697 arg_count = arguments.Count;
3701 // 1. Handle generic method using type arguments when specified or type inference
3703 var ms = candidate as MethodSpec;
3704 if (ms != null && ms.IsGeneric) {
3705 // Setup constraint checker for probing only
3706 ConstraintChecker cc = new ConstraintChecker (null);
3708 if (type_arguments != null) {
3709 var g_args_count = ms.Arity;
3710 if (g_args_count != type_arguments.Count)
3711 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3713 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3716 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3717 // for now it simplifies things. I should probably add a callback to ResolveContext
3718 if (lambda_conv_msgs == null) {
3719 lambda_conv_msgs = new SessionReportPrinter ();
3720 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3723 var ti = new TypeInference (arguments);
3724 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3725 lambda_conv_msgs.EndSession ();
3728 return ti.InferenceScore - 20000;
3730 if (i_args.Length != 0) {
3731 candidate = ms = ms.MakeGenericMethod (i_args);
3735 cc.IgnoreInferredDynamic = true;
3739 // Type arguments constraints have to match for the method to be applicable
3741 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
3742 return int.MaxValue - 25000;
3745 if (type_arguments != null)
3746 return int.MaxValue - 15000;
3750 // 2. Each argument has to be implicitly convertible to method parameter
3752 Parameter.Modifier p_mod = 0;
3754 TypeSpec[] ptypes = ((IParametersMember) candidate).Parameters.Types;
3756 for (int i = 0; i < arg_count; i++) {
3757 Argument a = arguments[i];
3759 if (!pd.FixedParameters[i].HasDefaultValue) {
3760 arguments = orig_args;
3761 return arg_count * 2 + 2;
3765 // Get the default value expression, we can use the same expression
3766 // if the type matches
3768 Expression e = pd.FixedParameters[i].DefaultValue;
3769 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3771 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3773 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3774 e = new MemberAccess (new MemberAccess (new MemberAccess (
3775 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3777 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3783 arguments[i] = new Argument (e, Argument.AType.Default);
3787 if (p_mod != Parameter.Modifier.PARAMS) {
3788 p_mod = pd.FixedParameters[i].ModFlags;
3790 } else if (!params_expanded_form) {
3791 params_expanded_form = true;
3792 pt = ((ElementTypeSpec) pt).Element;
3798 if (!params_expanded_form) {
3799 if (a.ArgType == Argument.AType.ExtensionType) {
3801 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3804 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3805 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3806 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3811 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3814 dynamicArgument = true;
3819 // It can be applicable in expanded form (when not doing exact match like for delegates)
3821 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3822 if (!params_expanded_form)
3823 pt = ((ElementTypeSpec) pt).Element;
3826 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3829 params_expanded_form = true;
3833 if (params_expanded_form)
3835 return (arg_count - i) * 2 + score;
3840 // When params parameter has no argument it will be provided later if the method is the best candidate
3842 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3843 params_expanded_form = true;
3846 // Restore original arguments for dynamic binder to keep the intention of original source code
3848 if (dynamicArgument)
3849 arguments = orig_args;
3855 // Tests argument compatibility with the parameter
3856 // The possible return values are
3858 // 1 - modifier mismatch
3859 // 2 - type mismatch
3860 // -1 - dynamic binding required
3862 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3865 // Types have to be identical when ref or out modifer
3866 // is used and argument is not of dynamic type
3868 if ((argument.Modifier | param_mod) != 0) {
3869 if (argument.Type != parameter) {
3871 // Do full equality check after quick path
3873 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
3875 // Using dynamic for ref/out parameter can still succeed at runtime
3877 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
3884 if (argument.Modifier != param_mod) {
3886 // Using dynamic for ref/out parameter can still succeed at runtime
3888 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
3895 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
3899 // Deploy custom error reporting for lambda methods. When probing lambda methods
3900 // keep all errors reported in separate set and once we are done and no best
3901 // candidate found, this set is used to report more details about what was wrong
3904 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3905 if (lambda_conv_msgs == null) {
3906 lambda_conv_msgs = new SessionReportPrinter ();
3907 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3911 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3912 if (lambda_conv_msgs != null) {
3913 lambda_conv_msgs.EndSession ();
3923 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3925 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3927 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3930 var ac_p = p as ArrayContainer;
3932 var ac_q = ((ArrayContainer) q);
3933 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3934 if (specific == ac_p.Element)
3936 if (specific == ac_q.Element)
3938 } else if (TypeManager.IsGenericType (p)) {
3939 var pargs = TypeManager.GetTypeArguments (p);
3940 var qargs = TypeManager.GetTypeArguments (q);
3942 bool p_specific_at_least_once = false;
3943 bool q_specific_at_least_once = false;
3945 for (int i = 0; i < pargs.Length; i++) {
3946 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3947 if (specific == pargs[i])
3948 p_specific_at_least_once = true;
3949 if (specific == qargs[i])
3950 q_specific_at_least_once = true;
3953 if (p_specific_at_least_once && !q_specific_at_least_once)
3955 if (!p_specific_at_least_once && q_specific_at_least_once)
3963 // Find the best method from candidate list
3965 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3967 List<AmbiguousCandidate> ambiguous_candidates = null;
3969 MemberSpec best_candidate;
3970 Arguments best_candidate_args = null;
3971 bool best_candidate_params = false;
3972 bool best_candidate_dynamic = false;
3973 int best_candidate_rate;
3974 IParametersMember best_parameter_member = null;
3976 int args_count = args != null ? args.Count : 0;
3978 Arguments candidate_args = args;
3979 bool error_mode = false;
3980 var current_type = rc.CurrentType;
3981 MemberSpec invocable_member = null;
3983 // Be careful, cannot return until error reporter is restored
3985 best_candidate = null;
3986 best_candidate_rate = int.MaxValue;
3988 var type_members = members;
3992 for (int i = 0; i < type_members.Count; ++i) {
3993 var member = type_members[i];
3996 // Methods in a base class are not candidates if any method in a derived
3997 // class is applicable
3999 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4002 if (!member.IsAccessible (current_type) && !error_mode)
4005 IParametersMember pm = member as IParametersMember;
4008 // Will use it later to report ambiguity between best method and invocable member
4010 if (Invocation.IsMemberInvocable (member))
4011 invocable_member = member;
4017 // Overload resolution is looking for base member but using parameter names
4018 // and default values from the closest member. That means to do expensive lookup
4019 // for the closest override for virtual or abstract members
4021 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4022 var override_params = base_provider.GetOverrideMemberParameters (member);
4023 if (override_params != null)
4024 pm = override_params;
4028 // Check if the member candidate is applicable
4030 bool params_expanded_form = false;
4031 bool dynamic_argument = false;
4032 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm.Parameters, ref params_expanded_form, ref dynamic_argument);
4035 // How does it score compare to others
4037 if (candidate_rate < best_candidate_rate) {
4038 best_candidate_rate = candidate_rate;
4039 best_candidate = member;
4040 best_candidate_args = candidate_args;
4041 best_candidate_params = params_expanded_form;
4042 best_candidate_dynamic = dynamic_argument;
4043 best_parameter_member = pm;
4044 } else if (candidate_rate == 0) {
4046 // The member look is done per type for most operations but sometimes
4047 // it's not possible like for binary operators overload because they
4048 // are unioned between 2 sides
4050 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4051 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4055 // Is the new candidate better
4056 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
4057 best_candidate = member;
4058 best_candidate_args = candidate_args;
4059 best_candidate_params = params_expanded_form;
4060 best_candidate_dynamic = dynamic_argument;
4061 best_parameter_member = pm;
4063 // It's not better but any other found later could be but we are not sure yet
4064 if (ambiguous_candidates == null)
4065 ambiguous_candidates = new List<AmbiguousCandidate> ();
4067 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
4071 // Restore expanded arguments
4072 if (candidate_args != args)
4073 candidate_args = args;
4075 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4077 if (prev_recorder != null)
4078 rc.Report.SetPrinter (prev_recorder);
4082 // We've found exact match
4084 if (best_candidate_rate == 0)
4088 // Try extension methods lookup when no ordinary method match was found and provider enables it
4091 var emg = base_provider.LookupExtensionMethod (rc);
4093 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4095 best_candidate_extension_group = emg;
4096 return (T) (MemberSpec) emg.BestCandidate;
4101 // Don't run expensive error reporting mode for probing
4108 lambda_conv_msgs = null;
4113 // No best member match found, report an error
4115 if (best_candidate_rate != 0 || error_mode) {
4116 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4120 if (best_candidate_dynamic) {
4121 if (args[0].ArgType == Argument.AType.ExtensionType) {
4122 rc.Report.Error (1973, loc,
4123 "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",
4124 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4127 BestCandidateIsDynamic = true;
4131 if (ambiguous_candidates != null) {
4133 // Now check that there are no ambiguities i.e the selected method
4134 // should be better than all the others
4136 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4137 var candidate = ambiguous_candidates [ix];
4139 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
4140 var ambiguous = candidate.Member;
4141 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4142 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4143 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4144 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4145 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4148 return (T) best_candidate;
4153 if (invocable_member != null) {
4154 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4155 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4156 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4157 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4161 // And now check if the arguments are all
4162 // compatible, perform conversions if
4163 // necessary etc. and return if everything is
4166 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4169 if (best_candidate == null)
4173 // Check ObsoleteAttribute on the best method
4175 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4176 if (oa != null && !rc.IsObsolete)
4177 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4179 best_candidate.MemberDefinition.SetIsUsed ();
4181 args = best_candidate_args;
4182 return (T) best_candidate;
4185 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4187 return ResolveMember<MethodSpec> (rc, ref args);
4190 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4191 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4193 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4196 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4197 ec.Report.SymbolRelatedToPreviousError (method);
4198 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4199 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4200 TypeManager.CSharpSignature (method));
4203 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4204 TypeManager.CSharpSignature (method));
4205 } else if (IsDelegateInvoke) {
4206 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4207 DelegateType.GetSignatureForError ());
4209 ec.Report.SymbolRelatedToPreviousError (method);
4210 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4211 method.GetSignatureForError ());
4214 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4216 string index = (idx + 1).ToString ();
4217 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4218 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4219 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4220 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4221 index, Parameter.GetModifierSignature (a.Modifier));
4223 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4224 index, Parameter.GetModifierSignature (mod));
4226 string p1 = a.GetSignatureForError ();
4227 string p2 = TypeManager.CSharpName (paramType);
4230 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4231 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4232 ec.Report.SymbolRelatedToPreviousError (paramType);
4235 ec.Report.Error (1503, loc,
4236 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4241 // We have failed to find exact match so we return error info about the closest match
4243 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4245 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4246 int arg_count = args == null ? 0 : args.Count;
4248 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4249 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4250 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4254 if (lambda_conv_msgs != null) {
4255 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4260 // For candidates which match on parameters count report more details about incorrect arguments
4263 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4264 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4265 // Reject any inaccessible member
4266 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4267 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4268 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4272 var ms = best_candidate as MethodSpec;
4273 if (ms != null && ms.IsGeneric) {
4274 bool constr_ok = true;
4275 if (ms.TypeArguments != null)
4276 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4278 if (ta_count == 0) {
4279 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4283 rc.Report.Error (411, loc,
4284 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4285 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4292 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4298 // We failed to find any method with correct argument count, report best candidate
4300 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4303 if (best_candidate.Kind == MemberKind.Constructor) {
4304 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4305 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4306 } else if (IsDelegateInvoke) {
4307 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4308 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4309 DelegateType.GetSignatureForError (), arg_count.ToString ());
4311 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4312 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4313 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4314 name, arg_count.ToString ());
4318 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4320 var pd = pm.Parameters;
4321 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4323 Parameter.Modifier p_mod = 0;
4325 int a_idx = 0, a_pos = 0;
4327 ArrayInitializer params_initializers = null;
4328 bool has_unsafe_arg = pm.MemberType.IsPointer;
4329 int arg_count = args == null ? 0 : args.Count;
4331 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4333 if (p_mod != Parameter.Modifier.PARAMS) {
4334 p_mod = pd.FixedParameters[a_idx].ModFlags;
4336 has_unsafe_arg |= pt.IsPointer;
4338 if (p_mod == Parameter.Modifier.PARAMS) {
4339 if (chose_params_expanded) {
4340 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4341 pt = TypeManager.GetElementType (pt);
4347 // Types have to be identical when ref or out modifer is used
4349 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4350 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4353 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4359 NamedArgument na = a as NamedArgument;
4361 int name_index = pd.GetParameterIndexByName (na.Name);
4362 if (name_index < 0 || name_index >= pd.Count) {
4363 if (IsDelegateInvoke) {
4364 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4365 ec.Report.Error (1746, na.Location,
4366 "The delegate `{0}' does not contain a parameter named `{1}'",
4367 DelegateType.GetSignatureForError (), na.Name);
4369 ec.Report.SymbolRelatedToPreviousError (member);
4370 ec.Report.Error (1739, na.Location,
4371 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4372 TypeManager.CSharpSignature (member), na.Name);
4374 } else if (args[name_index] != a) {
4375 if (IsDelegateInvoke)
4376 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4378 ec.Report.SymbolRelatedToPreviousError (member);
4380 ec.Report.Error (1744, na.Location,
4381 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4386 if (a.Expr.Type == InternalType.Dynamic)
4389 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4390 custom_errors.NoArgumentMatch (ec, member);
4394 Expression conv = null;
4395 if (a.ArgType == Argument.AType.ExtensionType) {
4396 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4399 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4401 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4404 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4411 // Convert params arguments to an array initializer
4413 if (params_initializers != null) {
4414 // we choose to use 'a.Expr' rather than 'conv' so that
4415 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4416 params_initializers.Add (a.Expr);
4417 args.RemoveAt (a_idx--);
4422 // Update the argument with the implicit conversion
4426 if (a_idx != arg_count) {
4427 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4432 // Fill not provided arguments required by params modifier
4434 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4436 args = new Arguments (1);
4438 pt = ptypes[pd.Count - 1];
4439 pt = TypeManager.GetElementType (pt);
4440 has_unsafe_arg |= pt.IsPointer;
4441 params_initializers = new ArrayInitializer (0, loc);
4445 // Append an array argument with all params arguments
4447 if (params_initializers != null) {
4448 args.Add (new Argument (
4449 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4453 if (has_unsafe_arg && !ec.IsUnsafe) {
4454 Expression.UnsafeError (ec, loc);
4458 // We could infer inaccesible type arguments
4460 if (type_arguments == null && member.IsGeneric) {
4461 var ms = (MethodSpec) member;
4462 foreach (var ta in ms.TypeArguments) {
4463 if (!ta.IsAccessible (ec.CurrentType)) {
4464 ec.Report.SymbolRelatedToPreviousError (ta);
4465 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4475 public class ConstantExpr : MemberExpr
4479 public ConstantExpr (ConstSpec constant, Location loc)
4481 this.constant = constant;
4485 public override string Name {
4486 get { throw new NotImplementedException (); }
4489 public override bool IsInstance {
4490 get { return !IsStatic; }
4493 public override bool IsStatic {
4494 get { return true; }
4497 protected override TypeSpec DeclaringType {
4498 get { return constant.DeclaringType; }
4501 public override Expression CreateExpressionTree (ResolveContext ec)
4503 throw new NotSupportedException ("ET");
4506 protected override Expression DoResolve (ResolveContext rc)
4508 ResolveInstanceExpression (rc);
4509 DoBestMemberChecks (rc, constant);
4511 var c = constant.GetConstant (rc);
4513 // Creates reference expression to the constant value
4514 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4517 public override void Emit (EmitContext ec)
4519 throw new NotSupportedException ();
4522 public override string GetSignatureForError ()
4524 return constant.GetSignatureForError ();
4527 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4529 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4534 /// Fully resolved expression that evaluates to a Field
4536 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4537 protected FieldSpec spec;
4538 VariableInfo variable_info;
4540 LocalTemporary temp;
4543 protected FieldExpr (Location l)
4548 public FieldExpr (FieldSpec spec, Location loc)
4553 type = spec.MemberType;
4556 public FieldExpr (FieldBase fi, Location l)
4563 public override string Name {
4569 public bool IsHoisted {
4571 IVariableReference hv = InstanceExpression as IVariableReference;
4572 return hv != null && hv.IsHoisted;
4576 public override bool IsInstance {
4578 return !spec.IsStatic;
4582 public override bool IsStatic {
4584 return spec.IsStatic;
4588 public FieldSpec Spec {
4594 protected override TypeSpec DeclaringType {
4596 return spec.DeclaringType;
4600 public VariableInfo VariableInfo {
4602 return variable_info;
4608 public override string GetSignatureForError ()
4610 return TypeManager.GetFullNameSignature (spec);
4613 public bool IsMarshalByRefAccess ()
4615 // Checks possible ldflda of field access expression
4616 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4617 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4618 !(InstanceExpression is This);
4621 public void SetHasAddressTaken ()
4623 IVariableReference vr = InstanceExpression as IVariableReference;
4625 vr.SetHasAddressTaken ();
4628 public override Expression CreateExpressionTree (ResolveContext ec)
4630 Expression instance;
4631 if (InstanceExpression == null) {
4632 instance = new NullLiteral (loc);
4634 instance = InstanceExpression.CreateExpressionTree (ec);
4637 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4639 CreateTypeOfExpression ());
4641 return CreateExpressionFactoryCall (ec, "Field", args);
4644 public Expression CreateTypeOfExpression ()
4646 return new TypeOfField (spec, loc);
4649 protected override Expression DoResolve (ResolveContext ec)
4651 return DoResolve (ec, false, false);
4654 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4656 if (ResolveInstanceExpression (ec)) {
4657 // Resolve the field's instance expression while flow analysis is turned
4658 // off: when accessing a field "a.b", we must check whether the field
4659 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4661 if (lvalue_instance) {
4662 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4663 Expression right_side =
4664 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4666 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4669 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4670 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4674 if (InstanceExpression == null)
4677 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4678 InstanceExpression.CheckMarshalByRefAccess (ec);
4682 DoBestMemberChecks (ec, spec);
4684 var fb = spec as FixedFieldSpec;
4685 IVariableReference var = InstanceExpression as IVariableReference;
4687 if (lvalue_instance && var != null && var.VariableInfo != null) {
4688 var.VariableInfo.SetFieldAssigned (ec, Name);
4692 IFixedExpression fe = InstanceExpression as IFixedExpression;
4693 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4694 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4697 if (InstanceExpression.eclass != ExprClass.Variable) {
4698 ec.Report.SymbolRelatedToPreviousError (spec);
4699 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4700 TypeManager.GetFullNameSignature (spec));
4701 } else if (var != null && var.IsHoisted) {
4702 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4705 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4708 eclass = ExprClass.Variable;
4710 // If the instance expression is a local variable or parameter.
4711 if (var == null || var.VariableInfo == null)
4714 VariableInfo vi = var.VariableInfo;
4715 if (!vi.IsFieldAssigned (ec, Name, loc))
4718 variable_info = vi.GetSubStruct (Name);
4722 static readonly int [] codes = {
4723 191, // instance, write access
4724 192, // instance, out access
4725 198, // static, write access
4726 199, // static, out access
4727 1648, // member of value instance, write access
4728 1649, // member of value instance, out access
4729 1650, // member of value static, write access
4730 1651 // member of value static, out access
4733 static readonly string [] msgs = {
4734 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4735 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4736 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4737 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4738 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4739 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4740 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4741 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4744 // The return value is always null. Returning a value simplifies calling code.
4745 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4748 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4752 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4754 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4759 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4761 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4762 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4764 Expression e = DoResolve (ec, lvalue_instance, out_access);
4769 spec.MemberDefinition.SetIsAssigned ();
4771 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4772 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4773 ec.Report.Warning (420, 1, loc,
4774 "`{0}': A volatile field references will not be treated as volatile",
4775 spec.GetSignatureForError ());
4778 if (spec.IsReadOnly) {
4779 // InitOnly fields can only be assigned in constructors or initializers
4780 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4781 return Report_AssignToReadonly (ec, right_side);
4783 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4785 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4786 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4787 return Report_AssignToReadonly (ec, right_side);
4788 // static InitOnly fields cannot be assigned-to in an instance constructor
4789 if (IsStatic && !ec.IsStatic)
4790 return Report_AssignToReadonly (ec, right_side);
4791 // instance constructors can't modify InitOnly fields of other instances of the same type
4792 if (!IsStatic && !(InstanceExpression is This))
4793 return Report_AssignToReadonly (ec, right_side);
4797 if (right_side == EmptyExpression.OutAccess.Instance &&
4798 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4799 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4800 ec.Report.Warning (197, 1, loc,
4801 "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",
4802 GetSignatureForError ());
4805 eclass = ExprClass.Variable;
4809 public override int GetHashCode ()
4811 return spec.GetHashCode ();
4814 public bool IsFixed {
4817 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4819 IVariableReference variable = InstanceExpression as IVariableReference;
4820 if (variable != null)
4821 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4823 IFixedExpression fe = InstanceExpression as IFixedExpression;
4824 return fe != null && fe.IsFixed;
4828 public override bool Equals (object obj)
4830 FieldExpr fe = obj as FieldExpr;
4834 if (spec != fe.spec)
4837 if (InstanceExpression == null || fe.InstanceExpression == null)
4840 return InstanceExpression.Equals (fe.InstanceExpression);
4843 public void Emit (EmitContext ec, bool leave_copy)
4845 bool is_volatile = false;
4847 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4850 spec.MemberDefinition.SetIsUsed ();
4854 ec.Emit (OpCodes.Volatile);
4856 ec.Emit (OpCodes.Ldsfld, spec);
4859 EmitInstance (ec, false);
4861 // Optimization for build-in types
4862 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4863 ec.EmitLoadFromPtr (type);
4865 var ff = spec as FixedFieldSpec;
4867 ec.Emit (OpCodes.Ldflda, spec);
4868 ec.Emit (OpCodes.Ldflda, ff.Element);
4871 ec.Emit (OpCodes.Volatile);
4873 ec.Emit (OpCodes.Ldfld, spec);
4879 ec.Emit (OpCodes.Dup);
4881 temp = new LocalTemporary (this.Type);
4887 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4889 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
4891 EmitInstance (ec, prepared);
4895 ec.Emit (OpCodes.Dup);
4897 temp = new LocalTemporary (this.Type);
4902 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4903 ec.Emit (OpCodes.Volatile);
4905 spec.MemberDefinition.SetIsAssigned ();
4908 ec.Emit (OpCodes.Stsfld, spec);
4910 ec.Emit (OpCodes.Stfld, spec);
4919 public override void Emit (EmitContext ec)
4924 public override void EmitSideEffect (EmitContext ec)
4926 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4928 if (is_volatile) // || is_marshal_by_ref ())
4929 base.EmitSideEffect (ec);
4932 public void AddressOf (EmitContext ec, AddressOp mode)
4934 if ((mode & AddressOp.Store) != 0)
4935 spec.MemberDefinition.SetIsAssigned ();
4936 if ((mode & AddressOp.Load) != 0)
4937 spec.MemberDefinition.SetIsUsed ();
4940 // Handle initonly fields specially: make a copy and then
4941 // get the address of the copy.
4944 if (spec.IsReadOnly){
4946 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4959 local = ec.DeclareLocal (type, false);
4960 ec.Emit (OpCodes.Stloc, local);
4961 ec.Emit (OpCodes.Ldloca, local);
4967 ec.Emit (OpCodes.Ldsflda, spec);
4970 EmitInstance (ec, false);
4971 ec.Emit (OpCodes.Ldflda, spec);
4975 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4977 return MakeExpression (ctx);
4980 public override SLE.Expression MakeExpression (BuilderContext ctx)
4982 return SLE.Expression.Field (
4983 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
4984 spec.GetMetaInfo ());
4987 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4989 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4995 /// Expression that evaluates to a Property. The Assign class
4996 /// might set the `Value' expression if we are in an assignment.
4998 /// This is not an LValue because we need to re-write the expression, we
4999 /// can not take data from the stack and store it.
5001 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5003 public PropertyExpr (PropertySpec spec, Location l)
5006 best_candidate = spec;
5007 type = spec.MemberType;
5012 protected override TypeSpec DeclaringType {
5014 return best_candidate.DeclaringType;
5018 public override string Name {
5020 return best_candidate.Name;
5024 public override bool IsInstance {
5030 public override bool IsStatic {
5032 return best_candidate.IsStatic;
5036 public PropertySpec PropertyInfo {
5038 return best_candidate;
5044 public override Expression CreateExpressionTree (ResolveContext ec)
5047 if (IsSingleDimensionalArrayLength ()) {
5048 args = new Arguments (1);
5049 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5050 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5053 args = new Arguments (2);
5054 if (InstanceExpression == null)
5055 args.Add (new Argument (new NullLiteral (loc)));
5057 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5058 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5059 return CreateExpressionFactoryCall (ec, "Property", args);
5062 public Expression CreateSetterTypeOfExpression ()
5064 return new TypeOfMethod (Setter, loc);
5067 public override string GetSignatureForError ()
5069 return best_candidate.GetSignatureForError ();
5072 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5074 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5077 public override SLE.Expression MakeExpression (BuilderContext ctx)
5079 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5082 void Error_PropertyNotValid (ResolveContext ec)
5084 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5085 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5086 GetSignatureForError ());
5089 bool IsSingleDimensionalArrayLength ()
5091 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5094 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5095 return ac != null && ac.Rank == 1;
5098 public override void Emit (EmitContext ec, bool leave_copy)
5101 // Special case: length of single dimension array property is turned into ldlen
5103 if (IsSingleDimensionalArrayLength ()) {
5105 EmitInstance (ec, false);
5106 ec.Emit (OpCodes.Ldlen);
5107 ec.Emit (OpCodes.Conv_I4);
5111 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5114 ec.Emit (OpCodes.Dup);
5116 temp = new LocalTemporary (this.Type);
5122 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5126 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5127 args = new Arguments (0);
5132 ec.Emit (OpCodes.Dup);
5134 temp = new LocalTemporary (this.Type);
5139 args = new Arguments (1);
5143 temp = new LocalTemporary (this.Type);
5145 args.Add (new Argument (temp));
5147 args.Add (new Argument (source));
5151 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5159 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5161 eclass = ExprClass.PropertyAccess;
5163 if (best_candidate.IsNotRealProperty) {
5164 Error_PropertyNotValid (rc);
5167 if (ResolveInstanceExpression (rc)) {
5168 if (right_side != null && best_candidate.DeclaringType.IsStruct)
5169 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
5172 DoBestMemberChecks (rc, best_candidate);
5176 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5178 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5182 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5184 // getter and setter can be different for base calls
5185 MethodSpec getter, setter;
5186 protected T best_candidate;
5188 protected LocalTemporary temp;
5189 protected bool prepared;
5191 protected PropertyOrIndexerExpr (Location l)
5198 public MethodSpec Getter {
5207 public MethodSpec Setter {
5218 protected override Expression DoResolve (ResolveContext ec)
5220 if (eclass == ExprClass.Unresolved) {
5221 var expr = OverloadResolve (ec, null);
5225 if (InstanceExpression != null)
5226 InstanceExpression.CheckMarshalByRefAccess (ec);
5229 return expr.Resolve (ec);
5232 if (!ResolveGetter (ec))
5238 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5240 if (right_side == EmptyExpression.OutAccess.Instance) {
5241 // TODO: best_candidate can be null at this point
5242 INamedBlockVariable variable = null;
5243 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5244 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5245 best_candidate.Name);
5247 right_side.DoResolveLValue (ec, this);
5252 // if the property/indexer returns a value type, and we try to set a field in it
5253 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5254 Error_CannotModifyIntermediateExpressionValue (ec);
5257 if (eclass == ExprClass.Unresolved) {
5258 var expr = OverloadResolve (ec, right_side);
5263 return expr.ResolveLValue (ec, right_side);
5266 if (!ResolveSetter (ec))
5273 // Implements the IAssignMethod interface for assignments
5275 public abstract void Emit (EmitContext ec, bool leave_copy);
5276 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5278 public override void Emit (EmitContext ec)
5283 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5285 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5287 bool ResolveGetter (ResolveContext rc)
5289 if (!best_candidate.HasGet) {
5290 if (InstanceExpression != EmptyExpression.Null) {
5291 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5292 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5293 best_candidate.GetSignatureForError ());
5296 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5297 if (best_candidate.HasDifferentAccessibility) {
5298 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5299 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5300 TypeManager.CSharpSignature (best_candidate));
5302 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5303 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5307 if (best_candidate.HasDifferentAccessibility) {
5308 CheckProtectedMemberAccess (rc, best_candidate.Get);
5311 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5315 bool ResolveSetter (ResolveContext rc)
5317 if (!best_candidate.HasSet) {
5318 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5319 GetSignatureForError ());
5323 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5324 if (best_candidate.HasDifferentAccessibility) {
5325 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5326 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5327 GetSignatureForError ());
5329 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5330 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5334 if (best_candidate.HasDifferentAccessibility)
5335 CheckProtectedMemberAccess (rc, best_candidate.Set);
5337 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5343 /// Fully resolved expression that evaluates to an Event
5345 public class EventExpr : MemberExpr, IAssignMethod
5347 readonly EventSpec spec;
5350 public EventExpr (EventSpec spec, Location loc)
5358 protected override TypeSpec DeclaringType {
5360 return spec.DeclaringType;
5364 public override string Name {
5370 public override bool IsInstance {
5372 return !spec.IsStatic;
5376 public override bool IsStatic {
5378 return spec.IsStatic;
5382 public MethodSpec Operator {
5390 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5393 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5395 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5396 if (spec.BackingField != null &&
5397 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType))) {
5399 spec.MemberDefinition.SetIsUsed ();
5401 if (!ec.IsObsolete) {
5402 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5404 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5407 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5408 Error_AssignmentEventOnly (ec);
5410 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5412 InstanceExpression = null;
5414 return ml.ResolveMemberAccess (ec, left, original);
5417 Error_AssignmentEventOnly (ec);
5420 return base.ResolveMemberAccess (ec, left, original);
5423 public override Expression CreateExpressionTree (ResolveContext ec)
5425 throw new NotSupportedException ("ET");
5428 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5430 if (right_side == EmptyExpression.EventAddition) {
5431 op = spec.AccessorAdd;
5432 } else if (right_side == EmptyExpression.EventSubtraction) {
5433 op = spec.AccessorRemove;
5437 Error_AssignmentEventOnly (ec);
5441 op = CandidateToBaseOverride (ec, op);
5445 protected override Expression DoResolve (ResolveContext ec)
5447 eclass = ExprClass.EventAccess;
5448 type = spec.MemberType;
5450 ResolveInstanceExpression (ec);
5452 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5453 Error_CannotAssign (ec);
5456 DoBestMemberChecks (ec, spec);
5460 public override void Emit (EmitContext ec)
5462 throw new NotSupportedException ();
5463 //Error_CannotAssign ();
5466 #region IAssignMethod Members
5468 public void Emit (EmitContext ec, bool leave_copy)
5470 throw new NotImplementedException ();
5473 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5475 if (leave_copy || !prepare_for_load)
5476 throw new NotImplementedException ("EventExpr::EmitAssign");
5478 Arguments args = new Arguments (1);
5479 args.Add (new Argument (source));
5480 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5485 void Error_AssignmentEventOnly (ResolveContext ec)
5487 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5488 GetSignatureForError ());
5491 public void Error_CannotAssign (ResolveContext ec)
5493 ec.Report.Error (70, loc,
5494 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5495 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5498 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5500 name = name.Substring (0, name.LastIndexOf ('.'));
5501 base.Error_CannotCallAbstractBase (rc, name);
5504 public override string GetSignatureForError ()
5506 return TypeManager.CSharpSignature (spec);
5509 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5511 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5515 public class TemporaryVariableReference : VariableReference
5517 public class Declarator : Statement
5519 TemporaryVariableReference variable;
5521 public Declarator (TemporaryVariableReference variable)
5523 this.variable = variable;
5527 protected override void DoEmit (EmitContext ec)
5529 variable.li.CreateBuilder (ec);
5532 protected override void CloneTo (CloneContext clonectx, Statement target)
5540 public TemporaryVariableReference (LocalVariable li, Location loc)
5543 this.type = li.Type;
5547 public LocalVariable LocalInfo {
5553 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5555 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5556 return new TemporaryVariableReference (li, loc);
5559 public override Expression CreateExpressionTree (ResolveContext ec)
5561 throw new NotSupportedException ("ET");
5564 protected override Expression DoResolve (ResolveContext ec)
5566 eclass = ExprClass.Variable;
5569 // Don't capture temporary variables except when using
5570 // iterator redirection
5572 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5573 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5574 storey.CaptureLocalVariable (ec, li);
5580 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5582 return Resolve (ec);
5585 public override void Emit (EmitContext ec)
5587 li.CreateBuilder (ec);
5592 public void EmitAssign (EmitContext ec, Expression source)
5594 li.CreateBuilder (ec);
5596 EmitAssign (ec, source, false, false);
5599 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5601 return li.HoistedVariant;
5604 public override bool IsFixed {
5605 get { return true; }
5608 public override bool IsRef {
5609 get { return false; }
5612 public override string Name {
5613 get { throw new NotImplementedException (); }
5616 public override void SetHasAddressTaken ()
5618 throw new NotImplementedException ();
5621 protected override ILocalVariable Variable {
5625 public override VariableInfo VariableInfo {
5626 get { throw new NotImplementedException (); }
5631 /// Handles `var' contextual keyword; var becomes a keyword only
5632 /// if no type called var exists in a variable scope
5634 class VarExpr : SimpleName
5636 public VarExpr (Location loc)
5641 public bool InferType (ResolveContext ec, Expression right_side)
5644 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5646 type = right_side.Type;
5647 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5648 ec.Report.Error (815, loc,
5649 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5650 type.GetSignatureForError ());
5654 eclass = ExprClass.Variable;
5658 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5660 if (RootContext.Version < LanguageVersion.V_3)
5661 base.Error_TypeOrNamespaceNotFound (ec);
5663 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");