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);
3145 // Extension methods lookup after ordinary methods candidates failed to apply
3147 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3149 if (InstanceExpression == null)
3152 InstanceExpression = InstanceExpression.Resolve (rc);
3153 if (!IsExtensionMethodArgument (InstanceExpression))
3156 int arity = type_arguments == null ? 0 : type_arguments.Count;
3157 NamespaceEntry methods_scope = null;
3158 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3159 if (methods == null)
3162 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3163 emg.SetTypeArguments (rc, type_arguments);
3170 public struct OverloadResolver
3173 public enum Restrictions
3177 ProbingOnly = 1 << 1,
3178 CovariantDelegate = 1 << 2,
3179 NoBaseMembers = 1 << 3,
3180 BaseMembersIncluded = 1 << 4
3183 public interface IBaseMembersProvider
3185 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3186 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3189 public interface IErrorHandler
3191 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3192 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3193 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3194 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3197 sealed class NoBaseMembers : IBaseMembersProvider
3199 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3201 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3206 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3212 struct AmbiguousCandidate
3214 public readonly MemberSpec Member;
3215 public readonly bool Expanded;
3217 public AmbiguousCandidate (MemberSpec member, bool expanded)
3220 Expanded = expanded;
3225 IList<MemberSpec> members;
3226 TypeArguments type_arguments;
3227 IBaseMembersProvider base_provider;
3228 IErrorHandler custom_errors;
3229 Restrictions restrictions;
3230 MethodGroupExpr best_candidate_extension_group;
3232 SessionReportPrinter lambda_conv_msgs;
3233 ReportPrinter prev_recorder;
3235 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3236 : this (members, null, restrictions, loc)
3240 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3243 if (members == null || members.Count == 0)
3244 throw new ArgumentException ("empty members set");
3246 this.members = members;
3248 type_arguments = targs;
3249 this.restrictions = restrictions;
3250 if (IsDelegateInvoke)
3251 this.restrictions |= Restrictions.NoBaseMembers;
3253 base_provider = NoBaseMembers.Instance;
3258 public IBaseMembersProvider BaseMembersProvider {
3260 return base_provider;
3263 base_provider = value;
3267 public bool BestCandidateIsDynamic { get; set; }
3270 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3272 public MethodGroupExpr BestCandidateNewMethodGroup {
3274 return best_candidate_extension_group;
3278 public IErrorHandler CustomErrors {
3280 return custom_errors;
3283 custom_errors = value;
3287 TypeSpec DelegateType {
3289 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3290 throw new InternalErrorException ("Not running in delegate mode", loc);
3292 return members [0].DeclaringType;
3296 bool IsProbingOnly {
3298 return (restrictions & Restrictions.ProbingOnly) != 0;
3302 bool IsDelegateInvoke {
3304 return (restrictions & Restrictions.DelegateInvoke) != 0;
3311 // 7.4.3.3 Better conversion from expression
3312 // Returns : 1 if a->p is better,
3313 // 2 if a->q is better,
3314 // 0 if neither is better
3316 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3318 TypeSpec argument_type = a.Type;
3319 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3321 // Uwrap delegate from Expression<T>
3323 if (p.GetDefinition () == TypeManager.expression_type) {
3324 p = TypeManager.GetTypeArguments (p)[0];
3326 if (q.GetDefinition () == TypeManager.expression_type) {
3327 q = TypeManager.GetTypeArguments (q)[0];
3330 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3331 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3332 if (p == TypeManager.void_type && q != TypeManager.void_type)
3334 if (q == TypeManager.void_type && p != TypeManager.void_type)
3337 if (argument_type == p)
3340 if (argument_type == q)
3344 return BetterTypeConversion (ec, p, q);
3348 // 7.4.3.4 Better conversion from type
3350 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3352 if (p == null || q == null)
3353 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3355 if (p == TypeManager.int32_type) {
3356 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3358 } else if (p == TypeManager.int64_type) {
3359 if (q == TypeManager.uint64_type)
3361 } else if (p == TypeManager.sbyte_type) {
3362 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3363 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3365 } else if (p == TypeManager.short_type) {
3366 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3367 q == TypeManager.uint64_type)
3369 } else if (p == InternalType.Dynamic) {
3370 // Dynamic is never better
3374 if (q == TypeManager.int32_type) {
3375 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3377 } if (q == TypeManager.int64_type) {
3378 if (p == TypeManager.uint64_type)
3380 } else if (q == TypeManager.sbyte_type) {
3381 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3382 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3384 } if (q == TypeManager.short_type) {
3385 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3386 p == TypeManager.uint64_type)
3388 } else if (q == InternalType.Dynamic) {
3389 // Dynamic is never better
3393 // TODO: this is expensive
3394 Expression p_tmp = new EmptyExpression (p);
3395 Expression q_tmp = new EmptyExpression (q);
3397 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3398 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3400 if (p_to_q && !q_to_p)
3403 if (q_to_p && !p_to_q)
3410 /// Determines "Better function" between candidate
3411 /// and the current best match
3414 /// Returns a boolean indicating :
3415 /// false if candidate ain't better
3416 /// true if candidate is better than the current best match
3418 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3419 MemberSpec best, bool best_params)
3421 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3422 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3424 bool better_at_least_one = false;
3426 int args_count = args == null ? 0 : args.Count;
3428 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3429 Argument a = args[j];
3431 // Default arguments are ignored for better decision
3432 if (a.IsDefaultArgument)
3435 TypeSpec ct = candidate_pd.Types[c_idx];
3436 TypeSpec bt = best_pd.Types[b_idx];
3438 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3439 ct = TypeManager.GetElementType (ct);
3443 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3444 bt = TypeManager.GetElementType (bt);
3452 int result = BetterExpressionConversion (ec, a, ct, bt);
3454 // for each argument, the conversion to 'ct' should be no worse than
3455 // the conversion to 'bt'.
3459 // for at least one argument, the conversion to 'ct' should be better than
3460 // the conversion to 'bt'.
3462 better_at_least_one = true;
3465 if (better_at_least_one)
3469 // This handles the case
3471 // Add (float f1, float f2, float f3);
3472 // Add (params decimal [] foo);
3474 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3475 // first candidate would've chosen as better.
3481 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3485 // This handles the following cases:
3487 // Foo (int i) is better than Foo (int i, long l = 0)
3488 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3490 // Prefer non-optional version
3492 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3493 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3494 if (candidate_pd.Count >= best_pd.Count)
3497 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3504 // One is a non-generic method and second is a generic method, then non-generic is better
3506 if (best.IsGeneric != candidate.IsGeneric)
3507 return best.IsGeneric;
3510 // This handles the following cases:
3512 // Trim () is better than Trim (params char[] chars)
3513 // Concat (string s1, string s2, string s3) is better than
3514 // Concat (string s1, params string [] srest)
3515 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3517 // Prefer non-expanded version
3519 if (candidate_params != best_params)
3522 int candidate_param_count = candidate_pd.Count;
3523 int best_param_count = best_pd.Count;
3525 if (candidate_param_count != best_param_count)
3526 // can only happen if (candidate_params && best_params)
3527 return candidate_param_count > best_param_count && best_pd.HasParams;
3530 // Both methods have the same number of parameters, and the parameters have equal types
3531 // Pick the "more specific" signature using rules over original (non-inflated) types
3533 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3534 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3536 bool specific_at_least_once = false;
3537 for (j = 0; j < candidate_param_count; ++j) {
3538 var ct = candidate_def_pd.Types[j];
3539 var bt = best_def_pd.Types[j];
3542 TypeSpec specific = MoreSpecific (ct, bt);
3546 specific_at_least_once = true;
3549 if (specific_at_least_once)
3552 // FIXME: handle lifted operators
3558 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3560 rc.Report.Error (1729, loc,
3561 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3562 type.GetSignatureForError (), argCount.ToString ());
3566 /// Determines if the candidate method is applicable (section 14.4.2.1)
3567 /// to the given set of arguments
3568 /// A return value rates candidate method compatibility,
3569 /// 0 = the best, int.MaxValue = the worst
3571 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3573 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3574 int param_count = pd.Count;
3575 int optional_count = 0;
3578 if (arg_count != param_count) {
3579 for (int i = 0; i < pd.Count; ++i) {
3580 if (pd.FixedParameters[i].HasDefaultValue) {
3581 optional_count = pd.Count - i;
3586 int args_gap = System.Math.Abs (arg_count - param_count);
3587 if (optional_count != 0) {
3588 if (args_gap > optional_count)
3589 return int.MaxValue - 10000 + args_gap - optional_count;
3591 // Readjust expected number when params used
3594 if (arg_count < param_count)
3596 } else if (arg_count > param_count) {
3597 return int.MaxValue - 10000 + args_gap;
3599 } else if (arg_count != param_count) {
3601 return int.MaxValue - 10000 + args_gap;
3602 if (arg_count < param_count - 1)
3603 return int.MaxValue - 10000 + args_gap;
3606 // Resize to fit optional arguments
3607 if (optional_count != 0) {
3608 if (arguments == null) {
3609 arguments = new Arguments (optional_count);
3611 // Have to create a new container, so the next run can do same
3612 var resized = new Arguments (param_count);
3613 resized.AddRange (arguments);
3614 arguments = resized;
3617 for (int i = arg_count; i < param_count; ++i)
3618 arguments.Add (null);
3622 if (arg_count > 0) {
3624 // Shuffle named arguments to the right positions if there are any
3626 if (arguments[arg_count - 1] is NamedArgument) {
3627 arg_count = arguments.Count;
3629 for (int i = 0; i < arg_count; ++i) {
3630 bool arg_moved = false;
3632 NamedArgument na = arguments[i] as NamedArgument;
3636 int index = pd.GetParameterIndexByName (na.Name);
3638 // Named parameter not found or already reordered
3639 if (index == i || index < 0)
3643 if (index >= param_count) {
3644 // When using parameters which should not be available to the user
3645 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3648 arguments.Add (null);
3652 temp = arguments[index];
3654 // The slot has been taken by positional argument
3655 if (temp != null && !(temp is NamedArgument))
3660 arguments.MarkReorderedArgument (na);
3664 arguments[index] = arguments[i];
3665 arguments[i] = temp;
3672 arg_count = arguments.Count;
3674 } else if (arguments != null) {
3675 arg_count = arguments.Count;
3679 // 1. Handle generic method using type arguments when specified or type inference
3681 var ms = candidate as MethodSpec;
3682 if (ms != null && ms.IsGeneric) {
3683 // Setup constraint checker for probing only
3684 ConstraintChecker cc = new ConstraintChecker (null);
3686 if (type_arguments != null) {
3687 var g_args_count = ms.Arity;
3688 if (g_args_count != type_arguments.Count)
3689 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3691 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3694 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3695 // for now it simplifies things. I should probably add a callback to ResolveContext
3696 if (lambda_conv_msgs == null) {
3697 lambda_conv_msgs = new SessionReportPrinter ();
3698 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3701 var ti = new TypeInference (arguments);
3702 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3703 lambda_conv_msgs.EndSession ();
3706 return ti.InferenceScore - 20000;
3708 if (i_args.Length != 0) {
3709 candidate = ms = ms.MakeGenericMethod (i_args);
3713 cc.IgnoreInferredDynamic = true;
3717 // Type arguments constraints have to match for the method to be applicable
3719 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
3720 return int.MaxValue - 25000;
3723 if (type_arguments != null)
3724 return int.MaxValue - 15000;
3728 // 2. Each argument has to be implicitly convertible to method parameter
3730 Parameter.Modifier p_mod = 0;
3732 for (int i = 0; i < arg_count; i++) {
3733 Argument a = arguments[i];
3735 if (!pd.FixedParameters[i].HasDefaultValue)
3736 throw new InternalErrorException ();
3739 // Get the default value expression, we can use the same expression
3740 // if the type matches
3742 Expression e = pd.FixedParameters[i].DefaultValue;
3743 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3745 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3747 if (e == EmptyExpression.MissingValue && pd.Types[i] == TypeManager.object_type) {
3748 e = new MemberAccess (new MemberAccess (new MemberAccess (
3749 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3751 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc);
3757 arguments[i] = new Argument (e, Argument.AType.Default);
3761 if (p_mod != Parameter.Modifier.PARAMS) {
3762 p_mod = pd.FixedParameters[i].ModFlags;
3764 } else if (!params_expanded_form) {
3765 params_expanded_form = true;
3766 pt = ((ElementTypeSpec) pt).Element;
3772 if (!params_expanded_form)
3773 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3776 // It can be applicable in expanded form (when not doing exact match like for delegates)
3778 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3779 if (!params_expanded_form)
3780 pt = ((ElementTypeSpec) pt).Element;
3782 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3784 params_expanded_form = true;
3788 if (params_expanded_form)
3790 return (arg_count - i) * 2 + score;
3795 // When params parameter has notargument, will be provided later if the method is the best candidate
3797 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3798 params_expanded_form = true;
3803 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3806 // Types have to be identical when ref or out modifer
3807 // is used and argument is not of dynamic type
3809 if ((argument.Modifier | param_mod) != 0) {
3811 // Defer to dynamic binder
3813 if (argument.Type == InternalType.Dynamic)
3816 if (argument.Type != parameter) {
3818 // Do full equality check after quick path
3820 if (!TypeSpecComparer.IsEqual (argument.Type, parameter))
3825 // Deploy custom error reporting for lambda methods. When probing lambda methods
3826 // keep all errors reported in separate set and once we are done and no best
3827 // candidate found, this set is used to report more details about what was wrong
3830 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3831 if (lambda_conv_msgs == null) {
3832 lambda_conv_msgs = new SessionReportPrinter ();
3833 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3837 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3838 if (lambda_conv_msgs != null) {
3839 lambda_conv_msgs.EndSession ();
3846 if (argument.Modifier != param_mod)
3852 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3854 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3856 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3859 var ac_p = p as ArrayContainer;
3861 var ac_q = ((ArrayContainer) q);
3862 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3863 if (specific == ac_p.Element)
3865 if (specific == ac_q.Element)
3867 } else if (TypeManager.IsGenericType (p)) {
3868 var pargs = TypeManager.GetTypeArguments (p);
3869 var qargs = TypeManager.GetTypeArguments (q);
3871 bool p_specific_at_least_once = false;
3872 bool q_specific_at_least_once = false;
3874 for (int i = 0; i < pargs.Length; i++) {
3875 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3876 if (specific == pargs[i])
3877 p_specific_at_least_once = true;
3878 if (specific == qargs[i])
3879 q_specific_at_least_once = true;
3882 if (p_specific_at_least_once && !q_specific_at_least_once)
3884 if (!p_specific_at_least_once && q_specific_at_least_once)
3892 // Find the best method from candidate list
3894 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3896 List<AmbiguousCandidate> ambiguous_candidates = null;
3898 MemberSpec best_candidate;
3899 Arguments best_candidate_args = null;
3900 bool best_candidate_params = false;
3901 int best_candidate_rate;
3903 int args_count = args != null ? args.Count : 0;
3904 Arguments candidate_args = args;
3905 bool error_mode = false;
3906 var current_type = rc.CurrentType;
3907 MemberSpec invocable_member = null;
3909 // Be careful, cannot return until error reporter is restored
3911 best_candidate = null;
3912 best_candidate_rate = int.MaxValue;
3914 var type_members = members;
3918 for (int i = 0; i < type_members.Count; ++i) {
3919 var member = type_members[i];
3922 // Methods in a base class are not candidates if any method in a derived
3923 // class is applicable
3925 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3928 if (!member.IsAccessible (current_type) && !error_mode)
3931 if (!(member is IParametersMember)) {
3933 // Will use it later to report ambiguity between best method and invocable member
3935 if (Invocation.IsMemberInvocable (member))
3936 invocable_member = member;
3942 // Check if candidate is applicable
3944 bool params_expanded_form = false;
3945 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3948 // How does it score compare to others
3950 if (candidate_rate < best_candidate_rate) {
3951 best_candidate_rate = candidate_rate;
3952 best_candidate = member;
3953 best_candidate_args = candidate_args;
3954 best_candidate_params = params_expanded_form;
3955 } else if (candidate_rate == 0) {
3957 // The member look is done per type for most operations but sometimes
3958 // it's not possible like for binary operators overload because they
3959 // are unioned between 2 sides
3961 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
3962 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
3966 // Is new candidate better
3967 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3968 best_candidate = member;
3969 best_candidate_args = candidate_args;
3970 best_candidate_params = params_expanded_form;
3972 // It's not better but any other found later could be but we are not sure yet
3973 if (ambiguous_candidates == null)
3974 ambiguous_candidates = new List<AmbiguousCandidate> ();
3976 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3980 // Restore expanded arguments
3981 if (candidate_args != args)
3982 candidate_args = args;
3984 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3986 if (prev_recorder != null)
3987 rc.Report.SetPrinter (prev_recorder);
3991 // We've found exact match
3993 if (best_candidate_rate == 0)
3997 // Try extension methods lookup when no ordinary method match was found and provider enables it
4000 var emg = base_provider.LookupExtensionMethod (rc);
4002 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4004 best_candidate_extension_group = emg;
4005 return (T) (MemberSpec) emg.BestCandidate;
4010 // Don't run expensive error reporting mode for probing
4017 lambda_conv_msgs = null;
4022 // No best member match found, report an error
4024 if (best_candidate_rate != 0 || error_mode) {
4025 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
4029 // TODO: HasDynamic is quite slow
4030 if (args_count != 0 && (restrictions & Restrictions.CovariantDelegate) == 0 && args.HasDynamic) {
4031 if (args [0].ArgType == Argument.AType.ExtensionType) {
4032 rc.Report.Error (1973, loc,
4033 "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",
4034 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError());
4037 BestCandidateIsDynamic = true;
4041 if (ambiguous_candidates != null) {
4043 // Now check that there are no ambiguities i.e the selected method
4044 // should be better than all the others
4046 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4047 var candidate = ambiguous_candidates [ix];
4049 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
4050 var ambiguous = candidate.Member;
4051 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4052 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4053 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4054 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4055 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4058 return (T) best_candidate;
4063 if (invocable_member != null) {
4064 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4065 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4066 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4067 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4071 // And now check if the arguments are all
4072 // compatible, perform conversions if
4073 // necessary etc. and return if everything is
4076 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
4079 if (best_candidate == null)
4083 // Check ObsoleteAttribute on the best method
4085 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4086 if (oa != null && !rc.IsObsolete)
4087 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4089 best_candidate.MemberDefinition.SetIsUsed ();
4091 args = best_candidate_args;
4092 return (T) best_candidate;
4095 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4097 return ResolveMember<MethodSpec> (rc, ref args);
4100 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4101 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4103 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4106 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4107 ec.Report.SymbolRelatedToPreviousError (method);
4108 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4109 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4110 TypeManager.CSharpSignature (method));
4113 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4114 TypeManager.CSharpSignature (method));
4115 } else if (IsDelegateInvoke) {
4116 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4117 DelegateType.GetSignatureForError ());
4119 ec.Report.SymbolRelatedToPreviousError (method);
4120 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4121 method.GetSignatureForError ());
4124 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4126 string index = (idx + 1).ToString ();
4127 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4128 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4129 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4130 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4131 index, Parameter.GetModifierSignature (a.Modifier));
4133 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4134 index, Parameter.GetModifierSignature (mod));
4136 string p1 = a.GetSignatureForError ();
4137 string p2 = TypeManager.CSharpName (paramType);
4140 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4141 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4142 ec.Report.SymbolRelatedToPreviousError (paramType);
4145 ec.Report.Error (1503, loc,
4146 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4151 // We have failed to find exact match so we return error info about the closest match
4153 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
4155 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4156 int arg_count = args == null ? 0 : args.Count;
4158 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4159 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4160 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4164 if (lambda_conv_msgs != null) {
4165 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4170 // For candidates which match on parameters count report more details about incorrect arguments
4172 var pm = best_candidate as IParametersMember;
4174 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4175 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4176 // Reject any inaccessible member
4177 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4178 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4179 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4183 var ms = best_candidate as MethodSpec;
4184 if (ms != null && ms.IsGeneric) {
4185 bool constr_ok = true;
4186 if (ms.TypeArguments != null)
4187 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4189 if (ta_count == 0) {
4190 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4194 rc.Report.Error (411, loc,
4195 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4196 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4203 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4209 // We failed to find any method with correct argument count, report best candidate
4211 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4214 if (best_candidate.Kind == MemberKind.Constructor) {
4215 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4216 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4217 } else if (IsDelegateInvoke) {
4218 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4219 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4220 DelegateType.GetSignatureForError (), arg_count.ToString ());
4222 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4223 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4224 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4225 name, arg_count.ToString ());
4229 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4231 var pm = member as IParametersMember;
4232 var pd = pm.Parameters;
4234 Parameter.Modifier p_mod = 0;
4236 int a_idx = 0, a_pos = 0;
4238 ArrayInitializer params_initializers = null;
4239 bool has_unsafe_arg = pm.MemberType.IsPointer;
4240 int arg_count = args == null ? 0 : args.Count;
4242 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4244 if (p_mod != Parameter.Modifier.PARAMS) {
4245 p_mod = pd.FixedParameters[a_idx].ModFlags;
4246 pt = pd.Types[a_idx];
4247 has_unsafe_arg |= pt.IsPointer;
4249 if (p_mod == Parameter.Modifier.PARAMS) {
4250 if (chose_params_expanded) {
4251 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4252 pt = TypeManager.GetElementType (pt);
4258 // Types have to be identical when ref or out modifer is used
4260 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4261 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4264 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4270 NamedArgument na = a as NamedArgument;
4272 int name_index = pd.GetParameterIndexByName (na.Name);
4273 if (name_index < 0 || name_index >= pd.Count) {
4274 if (IsDelegateInvoke) {
4275 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4276 ec.Report.Error (1746, na.Location,
4277 "The delegate `{0}' does not contain a parameter named `{1}'",
4278 DelegateType.GetSignatureForError (), na.Name);
4280 ec.Report.SymbolRelatedToPreviousError (member);
4281 ec.Report.Error (1739, na.Location,
4282 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4283 TypeManager.CSharpSignature (member), na.Name);
4285 } else if (args[name_index] != a) {
4286 if (IsDelegateInvoke)
4287 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4289 ec.Report.SymbolRelatedToPreviousError (member);
4291 ec.Report.Error (1744, na.Location,
4292 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4297 if (a.Expr.Type == InternalType.Dynamic)
4300 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4301 custom_errors.NoArgumentMatch (ec, member);
4305 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4310 // Convert params arguments to an array initializer
4312 if (params_initializers != null) {
4313 // we choose to use 'a.Expr' rather than 'conv' so that
4314 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4315 params_initializers.Add (a.Expr);
4316 args.RemoveAt (a_idx--);
4321 // Update the argument with the implicit conversion
4325 if (a_idx != arg_count) {
4326 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4331 // Fill not provided arguments required by params modifier
4333 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4335 args = new Arguments (1);
4337 pt = pd.Types[pd.Count - 1];
4338 pt = TypeManager.GetElementType (pt);
4339 has_unsafe_arg |= pt.IsPointer;
4340 params_initializers = new ArrayInitializer (0, loc);
4344 // Append an array argument with all params arguments
4346 if (params_initializers != null) {
4347 args.Add (new Argument (
4348 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4352 if (has_unsafe_arg && !ec.IsUnsafe) {
4353 Expression.UnsafeError (ec, loc);
4357 // We could infer inaccesible type arguments
4359 if (type_arguments == null && member.IsGeneric) {
4360 var ms = (MethodSpec) member;
4361 foreach (var ta in ms.TypeArguments) {
4362 if (!ta.IsAccessible (ec.CurrentType)) {
4363 ec.Report.SymbolRelatedToPreviousError (ta);
4364 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4374 public class ConstantExpr : MemberExpr
4378 public ConstantExpr (ConstSpec constant, Location loc)
4380 this.constant = constant;
4384 public override string Name {
4385 get { throw new NotImplementedException (); }
4388 public override bool IsInstance {
4389 get { return !IsStatic; }
4392 public override bool IsStatic {
4393 get { return true; }
4396 protected override TypeSpec DeclaringType {
4397 get { return constant.DeclaringType; }
4400 public override Expression CreateExpressionTree (ResolveContext ec)
4402 throw new NotSupportedException ("ET");
4405 protected override Expression DoResolve (ResolveContext rc)
4407 ResolveInstanceExpression (rc);
4408 DoBestMemberChecks (rc, constant);
4410 var c = constant.GetConstant (rc);
4412 // Creates reference expression to the constant value
4413 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4416 public override void Emit (EmitContext ec)
4418 throw new NotSupportedException ();
4421 public override string GetSignatureForError ()
4423 return constant.GetSignatureForError ();
4426 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4428 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4433 /// Fully resolved expression that evaluates to a Field
4435 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4436 protected FieldSpec spec;
4437 VariableInfo variable_info;
4439 LocalTemporary temp;
4442 protected FieldExpr (Location l)
4447 public FieldExpr (FieldSpec spec, Location loc)
4452 type = spec.MemberType;
4455 public FieldExpr (FieldBase fi, Location l)
4462 public override string Name {
4468 public bool IsHoisted {
4470 IVariableReference hv = InstanceExpression as IVariableReference;
4471 return hv != null && hv.IsHoisted;
4475 public override bool IsInstance {
4477 return !spec.IsStatic;
4481 public override bool IsStatic {
4483 return spec.IsStatic;
4487 public FieldSpec Spec {
4493 protected override TypeSpec DeclaringType {
4495 return spec.DeclaringType;
4499 public VariableInfo VariableInfo {
4501 return variable_info;
4507 public override string GetSignatureForError ()
4509 return TypeManager.GetFullNameSignature (spec);
4512 public bool IsMarshalByRefAccess ()
4514 // Checks possible ldflda of field access expression
4515 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4516 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4517 !(InstanceExpression is This);
4520 public void SetHasAddressTaken ()
4522 IVariableReference vr = InstanceExpression as IVariableReference;
4524 vr.SetHasAddressTaken ();
4527 public override Expression CreateExpressionTree (ResolveContext ec)
4529 Expression instance;
4530 if (InstanceExpression == null) {
4531 instance = new NullLiteral (loc);
4533 instance = InstanceExpression.CreateExpressionTree (ec);
4536 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4538 CreateTypeOfExpression ());
4540 return CreateExpressionFactoryCall (ec, "Field", args);
4543 public Expression CreateTypeOfExpression ()
4545 return new TypeOfField (spec, loc);
4548 protected override Expression DoResolve (ResolveContext ec)
4550 return DoResolve (ec, false, false);
4553 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4555 if (ResolveInstanceExpression (ec)) {
4556 // Resolve the field's instance expression while flow analysis is turned
4557 // off: when accessing a field "a.b", we must check whether the field
4558 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4560 if (lvalue_instance) {
4561 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4562 Expression right_side =
4563 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4565 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4568 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4569 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4573 if (InstanceExpression == null)
4576 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4577 InstanceExpression.CheckMarshalByRefAccess (ec);
4581 DoBestMemberChecks (ec, spec);
4583 var fb = spec as FixedFieldSpec;
4584 IVariableReference var = InstanceExpression as IVariableReference;
4586 if (lvalue_instance && var != null && var.VariableInfo != null) {
4587 var.VariableInfo.SetFieldAssigned (ec, Name);
4591 IFixedExpression fe = InstanceExpression as IFixedExpression;
4592 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4593 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4596 if (InstanceExpression.eclass != ExprClass.Variable) {
4597 ec.Report.SymbolRelatedToPreviousError (spec);
4598 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4599 TypeManager.GetFullNameSignature (spec));
4600 } else if (var != null && var.IsHoisted) {
4601 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4604 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4607 eclass = ExprClass.Variable;
4609 // If the instance expression is a local variable or parameter.
4610 if (var == null || var.VariableInfo == null)
4613 VariableInfo vi = var.VariableInfo;
4614 if (!vi.IsFieldAssigned (ec, Name, loc))
4617 variable_info = vi.GetSubStruct (Name);
4621 static readonly int [] codes = {
4622 191, // instance, write access
4623 192, // instance, out access
4624 198, // static, write access
4625 199, // static, out access
4626 1648, // member of value instance, write access
4627 1649, // member of value instance, out access
4628 1650, // member of value static, write access
4629 1651 // member of value static, out access
4632 static readonly string [] msgs = {
4633 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4634 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4635 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4636 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4637 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4638 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4639 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4640 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4643 // The return value is always null. Returning a value simplifies calling code.
4644 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4647 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4651 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4653 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4658 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4660 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4661 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4663 Expression e = DoResolve (ec, lvalue_instance, out_access);
4668 spec.MemberDefinition.SetIsAssigned ();
4670 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4671 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4672 ec.Report.Warning (420, 1, loc,
4673 "`{0}': A volatile field references will not be treated as volatile",
4674 spec.GetSignatureForError ());
4677 if (spec.IsReadOnly) {
4678 // InitOnly fields can only be assigned in constructors or initializers
4679 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4680 return Report_AssignToReadonly (ec, right_side);
4682 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4684 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4685 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4686 return Report_AssignToReadonly (ec, right_side);
4687 // static InitOnly fields cannot be assigned-to in an instance constructor
4688 if (IsStatic && !ec.IsStatic)
4689 return Report_AssignToReadonly (ec, right_side);
4690 // instance constructors can't modify InitOnly fields of other instances of the same type
4691 if (!IsStatic && !(InstanceExpression is This))
4692 return Report_AssignToReadonly (ec, right_side);
4696 if (right_side == EmptyExpression.OutAccess.Instance &&
4697 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4698 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4699 ec.Report.Warning (197, 1, loc,
4700 "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",
4701 GetSignatureForError ());
4704 eclass = ExprClass.Variable;
4708 public override int GetHashCode ()
4710 return spec.GetHashCode ();
4713 public bool IsFixed {
4716 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4718 IVariableReference variable = InstanceExpression as IVariableReference;
4719 if (variable != null)
4720 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4722 IFixedExpression fe = InstanceExpression as IFixedExpression;
4723 return fe != null && fe.IsFixed;
4727 public override bool Equals (object obj)
4729 FieldExpr fe = obj as FieldExpr;
4733 if (spec != fe.spec)
4736 if (InstanceExpression == null || fe.InstanceExpression == null)
4739 return InstanceExpression.Equals (fe.InstanceExpression);
4742 public void Emit (EmitContext ec, bool leave_copy)
4744 bool is_volatile = false;
4746 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4749 spec.MemberDefinition.SetIsUsed ();
4753 ec.Emit (OpCodes.Volatile);
4755 ec.Emit (OpCodes.Ldsfld, spec);
4758 EmitInstance (ec, false);
4760 // Optimization for build-in types
4761 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4762 ec.EmitLoadFromPtr (type);
4764 var ff = spec as FixedFieldSpec;
4766 ec.Emit (OpCodes.Ldflda, spec);
4767 ec.Emit (OpCodes.Ldflda, ff.Element);
4770 ec.Emit (OpCodes.Volatile);
4772 ec.Emit (OpCodes.Ldfld, spec);
4778 ec.Emit (OpCodes.Dup);
4780 temp = new LocalTemporary (this.Type);
4786 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4788 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
4790 EmitInstance (ec, prepared);
4794 ec.Emit (OpCodes.Dup);
4796 temp = new LocalTemporary (this.Type);
4801 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4802 ec.Emit (OpCodes.Volatile);
4804 spec.MemberDefinition.SetIsAssigned ();
4807 ec.Emit (OpCodes.Stsfld, spec);
4809 ec.Emit (OpCodes.Stfld, spec);
4818 public override void Emit (EmitContext ec)
4823 public override void EmitSideEffect (EmitContext ec)
4825 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4827 if (is_volatile) // || is_marshal_by_ref ())
4828 base.EmitSideEffect (ec);
4831 public void AddressOf (EmitContext ec, AddressOp mode)
4833 if ((mode & AddressOp.Store) != 0)
4834 spec.MemberDefinition.SetIsAssigned ();
4835 if ((mode & AddressOp.Load) != 0)
4836 spec.MemberDefinition.SetIsUsed ();
4839 // Handle initonly fields specially: make a copy and then
4840 // get the address of the copy.
4843 if (spec.IsReadOnly){
4845 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4858 local = ec.DeclareLocal (type, false);
4859 ec.Emit (OpCodes.Stloc, local);
4860 ec.Emit (OpCodes.Ldloca, local);
4866 ec.Emit (OpCodes.Ldsflda, spec);
4869 EmitInstance (ec, false);
4870 ec.Emit (OpCodes.Ldflda, spec);
4874 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4876 return MakeExpression (ctx);
4879 public override SLE.Expression MakeExpression (BuilderContext ctx)
4881 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4884 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4886 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4892 /// Expression that evaluates to a Property. The Assign class
4893 /// might set the `Value' expression if we are in an assignment.
4895 /// This is not an LValue because we need to re-write the expression, we
4896 /// can not take data from the stack and store it.
4898 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4900 public PropertyExpr (PropertySpec spec, Location l)
4903 best_candidate = spec;
4904 type = spec.MemberType;
4909 protected override TypeSpec DeclaringType {
4911 return best_candidate.DeclaringType;
4915 public override string Name {
4917 return best_candidate.Name;
4921 public override bool IsInstance {
4927 public override bool IsStatic {
4929 return best_candidate.IsStatic;
4933 public PropertySpec PropertyInfo {
4935 return best_candidate;
4941 public override Expression CreateExpressionTree (ResolveContext ec)
4944 if (IsSingleDimensionalArrayLength ()) {
4945 args = new Arguments (1);
4946 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4947 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4950 args = new Arguments (2);
4951 if (InstanceExpression == null)
4952 args.Add (new Argument (new NullLiteral (loc)));
4954 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4955 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4956 return CreateExpressionFactoryCall (ec, "Property", args);
4959 public Expression CreateSetterTypeOfExpression ()
4961 return new TypeOfMethod (Setter, loc);
4964 public override string GetSignatureForError ()
4966 return best_candidate.GetSignatureForError ();
4969 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4971 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4974 public override SLE.Expression MakeExpression (BuilderContext ctx)
4976 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4979 void Error_PropertyNotValid (ResolveContext ec)
4981 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4982 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4983 GetSignatureForError ());
4986 bool IsSingleDimensionalArrayLength ()
4988 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4991 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4992 return ac != null && ac.Rank == 1;
4995 public override void Emit (EmitContext ec, bool leave_copy)
4998 // Special case: length of single dimension array property is turned into ldlen
5000 if (IsSingleDimensionalArrayLength ()) {
5002 EmitInstance (ec, false);
5003 ec.Emit (OpCodes.Ldlen);
5004 ec.Emit (OpCodes.Conv_I4);
5008 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5011 ec.Emit (OpCodes.Dup);
5013 temp = new LocalTemporary (this.Type);
5019 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5023 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5024 args = new Arguments (0);
5029 ec.Emit (OpCodes.Dup);
5031 temp = new LocalTemporary (this.Type);
5036 args = new Arguments (1);
5040 temp = new LocalTemporary (this.Type);
5042 args.Add (new Argument (temp));
5044 args.Add (new Argument (source));
5048 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5056 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5058 eclass = ExprClass.PropertyAccess;
5060 if (best_candidate.IsNotRealProperty) {
5061 Error_PropertyNotValid (rc);
5064 if (ResolveInstanceExpression (rc)) {
5065 if (right_side != null && best_candidate.DeclaringType.IsStruct)
5066 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
5069 DoBestMemberChecks (rc, best_candidate);
5073 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5075 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5079 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5081 // getter and setter can be different for base calls
5082 MethodSpec getter, setter;
5083 protected T best_candidate;
5085 protected LocalTemporary temp;
5086 protected bool prepared;
5088 protected PropertyOrIndexerExpr (Location l)
5095 public MethodSpec Getter {
5104 public MethodSpec Setter {
5115 protected override Expression DoResolve (ResolveContext ec)
5117 if (eclass == ExprClass.Unresolved) {
5118 var expr = OverloadResolve (ec, null);
5122 if (InstanceExpression != null)
5123 InstanceExpression.CheckMarshalByRefAccess (ec);
5126 return expr.Resolve (ec);
5129 if (!ResolveGetter (ec))
5135 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5137 if (right_side == EmptyExpression.OutAccess.Instance) {
5138 // TODO: best_candidate can be null at this point
5139 INamedBlockVariable variable = null;
5140 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5141 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5142 best_candidate.Name);
5144 right_side.DoResolveLValue (ec, this);
5149 // if the property/indexer returns a value type, and we try to set a field in it
5150 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5151 Error_CannotModifyIntermediateExpressionValue (ec);
5154 if (eclass == ExprClass.Unresolved) {
5155 var expr = OverloadResolve (ec, right_side);
5160 return expr.ResolveLValue (ec, right_side);
5163 if (!ResolveSetter (ec))
5170 // Implements the IAssignMethod interface for assignments
5172 public abstract void Emit (EmitContext ec, bool leave_copy);
5173 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5175 public override void Emit (EmitContext ec)
5180 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5182 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5184 bool ResolveGetter (ResolveContext rc)
5186 if (!best_candidate.HasGet) {
5187 if (InstanceExpression != EmptyExpression.Null) {
5188 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5189 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5190 best_candidate.GetSignatureForError ());
5193 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5194 if (best_candidate.HasDifferentAccessibility) {
5195 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5196 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5197 TypeManager.CSharpSignature (best_candidate));
5199 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5200 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5204 if (best_candidate.HasDifferentAccessibility) {
5205 CheckProtectedMemberAccess (rc, best_candidate.Get);
5208 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5212 bool ResolveSetter (ResolveContext rc)
5214 if (!best_candidate.HasSet) {
5215 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5216 GetSignatureForError ());
5220 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5221 if (best_candidate.HasDifferentAccessibility) {
5222 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5223 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5224 GetSignatureForError ());
5226 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5227 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5231 if (best_candidate.HasDifferentAccessibility)
5232 CheckProtectedMemberAccess (rc, best_candidate.Set);
5234 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5240 /// Fully resolved expression that evaluates to an Event
5242 public class EventExpr : MemberExpr, IAssignMethod
5244 readonly EventSpec spec;
5247 public EventExpr (EventSpec spec, Location loc)
5255 protected override TypeSpec DeclaringType {
5257 return spec.DeclaringType;
5261 public override string Name {
5267 public override bool IsInstance {
5269 return !spec.IsStatic;
5273 public override bool IsStatic {
5275 return spec.IsStatic;
5279 public MethodSpec Operator {
5287 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5290 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5292 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5293 if (spec.BackingField != null &&
5294 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType))) {
5296 spec.MemberDefinition.SetIsUsed ();
5298 if (!ec.IsObsolete) {
5299 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5301 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5304 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5305 Error_AssignmentEventOnly (ec);
5307 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5309 InstanceExpression = null;
5311 return ml.ResolveMemberAccess (ec, left, original);
5314 Error_AssignmentEventOnly (ec);
5317 return base.ResolveMemberAccess (ec, left, original);
5320 public override Expression CreateExpressionTree (ResolveContext ec)
5322 throw new NotSupportedException ("ET");
5325 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5327 if (right_side == EmptyExpression.EventAddition) {
5328 op = spec.AccessorAdd;
5329 } else if (right_side == EmptyExpression.EventSubtraction) {
5330 op = spec.AccessorRemove;
5334 Error_AssignmentEventOnly (ec);
5338 op = CandidateToBaseOverride (ec, op);
5342 protected override Expression DoResolve (ResolveContext ec)
5344 eclass = ExprClass.EventAccess;
5345 type = spec.MemberType;
5347 ResolveInstanceExpression (ec);
5349 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5350 Error_CannotAssign (ec);
5353 DoBestMemberChecks (ec, spec);
5357 public override void Emit (EmitContext ec)
5359 throw new NotSupportedException ();
5360 //Error_CannotAssign ();
5363 #region IAssignMethod Members
5365 public void Emit (EmitContext ec, bool leave_copy)
5367 throw new NotImplementedException ();
5370 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5372 if (leave_copy || !prepare_for_load)
5373 throw new NotImplementedException ("EventExpr::EmitAssign");
5375 Arguments args = new Arguments (1);
5376 args.Add (new Argument (source));
5377 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5382 void Error_AssignmentEventOnly (ResolveContext ec)
5384 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5385 GetSignatureForError ());
5388 public void Error_CannotAssign (ResolveContext ec)
5390 ec.Report.Error (70, loc,
5391 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5392 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5395 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5397 name = name.Substring (0, name.LastIndexOf ('.'));
5398 base.Error_CannotCallAbstractBase (rc, name);
5401 public override string GetSignatureForError ()
5403 return TypeManager.CSharpSignature (spec);
5406 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5408 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5412 public class TemporaryVariableReference : VariableReference
5414 public class Declarator : Statement
5416 TemporaryVariableReference variable;
5418 public Declarator (TemporaryVariableReference variable)
5420 this.variable = variable;
5424 protected override void DoEmit (EmitContext ec)
5426 variable.li.CreateBuilder (ec);
5429 protected override void CloneTo (CloneContext clonectx, Statement target)
5437 public TemporaryVariableReference (LocalVariable li, Location loc)
5440 this.type = li.Type;
5444 public LocalVariable LocalInfo {
5450 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5452 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5453 return new TemporaryVariableReference (li, loc);
5456 public override Expression CreateExpressionTree (ResolveContext ec)
5458 throw new NotSupportedException ("ET");
5461 protected override Expression DoResolve (ResolveContext ec)
5463 eclass = ExprClass.Variable;
5466 // Don't capture temporary variables except when using
5467 // iterator redirection
5469 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5470 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5471 storey.CaptureLocalVariable (ec, li);
5477 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5479 return Resolve (ec);
5482 public override void Emit (EmitContext ec)
5484 li.CreateBuilder (ec);
5489 public void EmitAssign (EmitContext ec, Expression source)
5491 li.CreateBuilder (ec);
5493 EmitAssign (ec, source, false, false);
5496 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5498 return li.HoistedVariant;
5501 public override bool IsFixed {
5502 get { return true; }
5505 public override bool IsRef {
5506 get { return false; }
5509 public override string Name {
5510 get { throw new NotImplementedException (); }
5513 public override void SetHasAddressTaken ()
5515 throw new NotImplementedException ();
5518 protected override ILocalVariable Variable {
5522 public override VariableInfo VariableInfo {
5523 get { throw new NotImplementedException (); }
5528 /// Handles `var' contextual keyword; var becomes a keyword only
5529 /// if no type called var exists in a variable scope
5531 class VarExpr : SimpleName
5533 public VarExpr (Location loc)
5538 public bool InferType (ResolveContext ec, Expression right_side)
5541 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5543 type = right_side.Type;
5544 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5545 ec.Report.Error (815, loc,
5546 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5547 type.GetSignatureForError ());
5551 eclass = ExprClass.Variable;
5555 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5557 if (RootContext.Version < LanguageVersion.V_3)
5558 base.Error_TypeOrNamespaceNotFound (ec);
5560 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");