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 public class OpcodeCast : TypeCast {
1728 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1729 : base (child, return_type)
1734 protected override Expression DoResolve (ResolveContext ec)
1736 // This should never be invoked, we are born in fully
1737 // initialized state.
1742 public override void Emit (EmitContext ec)
1748 public TypeSpec UnderlyingType {
1749 get { return child.Type; }
1754 /// This kind of cast is used to encapsulate a child and cast it
1755 /// to the class requested
1757 public sealed class ClassCast : TypeCast {
1758 readonly bool forced;
1760 public ClassCast (Expression child, TypeSpec return_type)
1761 : base (child, return_type)
1765 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1766 : base (child, return_type)
1768 this.forced = forced;
1771 public override void Emit (EmitContext ec)
1775 bool gen = TypeManager.IsGenericParameter (child.Type);
1777 ec.Emit (OpCodes.Box, child.Type);
1779 if (type.IsGenericParameter) {
1780 ec.Emit (OpCodes.Unbox_Any, type);
1787 ec.Emit (OpCodes.Castclass, type);
1792 // Created during resolving pahse when an expression is wrapped or constantified
1793 // and original expression can be used later (e.g. for expression trees)
1795 public class ReducedExpression : Expression
1797 sealed class ReducedConstantExpression : EmptyConstantCast
1799 readonly Expression orig_expr;
1801 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1802 : base (expr, expr.Type)
1804 this.orig_expr = orig_expr;
1807 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1809 Constant c = base.ConvertImplicitly (rc, target_type);
1811 c = new ReducedConstantExpression (c, orig_expr);
1816 public override Expression CreateExpressionTree (ResolveContext ec)
1818 return orig_expr.CreateExpressionTree (ec);
1821 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1823 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1825 c = new ReducedConstantExpression (c, orig_expr);
1830 sealed class ReducedExpressionStatement : ExpressionStatement
1832 readonly Expression orig_expr;
1833 readonly ExpressionStatement stm;
1835 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1837 this.orig_expr = orig;
1839 this.loc = orig.Location;
1842 public override Expression CreateExpressionTree (ResolveContext ec)
1844 return orig_expr.CreateExpressionTree (ec);
1847 protected override Expression DoResolve (ResolveContext ec)
1849 eclass = stm.eclass;
1854 public override void Emit (EmitContext ec)
1859 public override void EmitStatement (EmitContext ec)
1861 stm.EmitStatement (ec);
1865 readonly Expression expr, orig_expr;
1867 private ReducedExpression (Expression expr, Expression orig_expr)
1870 this.eclass = expr.eclass;
1871 this.type = expr.Type;
1872 this.orig_expr = orig_expr;
1873 this.loc = orig_expr.Location;
1878 public Expression OriginalExpression {
1887 // Creates fully resolved expression switcher
1889 public static Constant Create (Constant expr, Expression original_expr)
1891 if (expr.eclass == ExprClass.Unresolved)
1892 throw new ArgumentException ("Unresolved expression");
1894 return new ReducedConstantExpression (expr, original_expr);
1897 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1899 return new ReducedExpressionStatement (s, orig);
1903 // Creates unresolved reduce expression. The original expression has to be
1906 public static Expression Create (Expression expr, Expression original_expr)
1908 Constant c = expr as Constant;
1910 return Create (c, original_expr);
1912 ExpressionStatement s = expr as ExpressionStatement;
1914 return Create (s, original_expr);
1916 if (expr.eclass == ExprClass.Unresolved)
1917 throw new ArgumentException ("Unresolved expression");
1919 return new ReducedExpression (expr, original_expr);
1922 public override Expression CreateExpressionTree (ResolveContext ec)
1924 return orig_expr.CreateExpressionTree (ec);
1927 protected override Expression DoResolve (ResolveContext ec)
1932 public override void Emit (EmitContext ec)
1937 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1939 expr.EmitBranchable (ec, target, on_true);
1942 public override SLE.Expression MakeExpression (BuilderContext ctx)
1944 return orig_expr.MakeExpression (ctx);
1949 // Standard composite pattern
1951 public abstract class CompositeExpression : Expression
1955 protected CompositeExpression (Expression expr)
1958 this.loc = expr.Location;
1961 public override Expression CreateExpressionTree (ResolveContext ec)
1963 return expr.CreateExpressionTree (ec);
1966 public Expression Child {
1967 get { return expr; }
1970 protected override Expression DoResolve (ResolveContext ec)
1972 expr = expr.Resolve (ec);
1975 eclass = expr.eclass;
1981 public override void Emit (EmitContext ec)
1986 public override bool IsNull {
1987 get { return expr.IsNull; }
1992 // Base of expressions used only to narrow resolve flow
1994 public abstract class ShimExpression : Expression
1996 protected Expression expr;
1998 protected ShimExpression (Expression expr)
2003 protected override void CloneTo (CloneContext clonectx, Expression t)
2008 ShimExpression target = (ShimExpression) t;
2009 target.expr = expr.Clone (clonectx);
2012 public override Expression CreateExpressionTree (ResolveContext ec)
2014 throw new NotSupportedException ("ET");
2017 public override void Emit (EmitContext ec)
2019 throw new InternalErrorException ("Missing Resolve call");
2022 public Expression Expr {
2023 get { return expr; }
2028 // Unresolved type name expressions
2030 public abstract class ATypeNameExpression : FullNamedExpression
2033 protected TypeArguments targs;
2035 protected ATypeNameExpression (string name, Location l)
2041 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2048 protected ATypeNameExpression (string name, int arity, Location l)
2049 : this (name, new UnboundTypeArguments (arity), l)
2055 protected int Arity {
2057 return targs == null ? 0 : targs.Count;
2061 public bool HasTypeArguments {
2063 return targs != null && !targs.IsEmpty;
2067 public string Name {
2076 public TypeArguments TypeArguments {
2084 public override bool Equals (object obj)
2086 ATypeNameExpression atne = obj as ATypeNameExpression;
2087 return atne != null && atne.Name == Name &&
2088 (targs == null || targs.Equals (atne.targs));
2091 public override int GetHashCode ()
2093 return Name.GetHashCode ();
2096 // TODO: Move it to MemberCore
2097 public static string GetMemberType (MemberCore mc)
2103 if (mc is FieldBase)
2105 if (mc is MethodCore)
2107 if (mc is EnumMember)
2115 public override string GetSignatureForError ()
2117 if (targs != null) {
2118 return Name + "<" + targs.GetSignatureForError () + ">";
2124 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2128 /// SimpleName expressions are formed of a single word and only happen at the beginning
2129 /// of a dotted-name.
2131 public class SimpleName : ATypeNameExpression
2133 public SimpleName (string name, Location l)
2138 public SimpleName (string name, TypeArguments args, Location l)
2139 : base (name, args, l)
2143 public SimpleName (string name, int arity, Location l)
2144 : base (name, arity, l)
2148 public SimpleName GetMethodGroup ()
2150 return new SimpleName (Name, targs, loc);
2153 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2155 if (ec.CurrentType != null) {
2156 if (ec.CurrentMemberDefinition != null) {
2157 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2159 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2165 // TODO MemberCache: Implement
2167 string ns = ec.CurrentType.Namespace;
2168 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2169 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2170 var type = a.GetType (fullname);
2172 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2173 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2178 if (ec.CurrentTypeDefinition != null) {
2179 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2181 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2188 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2189 if (retval != null) {
2190 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2192 var te = retval as TypeExpr;
2193 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2194 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2196 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2201 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2204 protected override Expression DoResolve (ResolveContext ec)
2206 return SimpleNameResolve (ec, null, false);
2209 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2211 return SimpleNameResolve (ec, right_side, false);
2214 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2216 int errors = ec.Compiler.Report.Errors;
2217 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2220 if (fne.Type != null && Arity > 0) {
2221 if (HasTypeArguments) {
2222 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2223 return ct.ResolveAsTypeStep (ec, false);
2226 return new GenericOpenTypeExpr (fne.Type, loc);
2230 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2232 if (!(fne is Namespace))
2236 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2237 if (!ec.Compiler.PredefinedAttributes.Dynamic.IsDefined) {
2238 ec.Compiler.Report.Error (1980, Location,
2239 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2240 ec.Compiler.PredefinedAttributes.Dynamic.GetSignatureForError ());
2243 return new DynamicTypeExpr (loc);
2249 if (silent || errors != ec.Compiler.Report.Errors)
2252 Error_TypeOrNamespaceNotFound (ec);
2256 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2258 int lookup_arity = Arity;
2259 bool errorMode = false;
2261 Block current_block = rc.CurrentBlock;
2262 INamedBlockVariable variable = null;
2263 bool variable_found = false;
2267 // Stage 1: binding to local variables or parameters
2269 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2271 if (current_block != null && lookup_arity == 0) {
2272 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2273 if (!variable.IsDeclared) {
2274 // We found local name in accessible block but it's not
2275 // initialized yet, maybe the user wanted to bind to something else
2277 variable_found = true;
2279 e = variable.CreateReferenceExpression (rc, loc);
2282 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2291 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2293 TypeSpec member_type = rc.CurrentType;
2294 TypeSpec current_type = member_type;
2295 for (; member_type != null; member_type = member_type.DeclaringType) {
2296 var me = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc) as MemberExpr;
2301 if (variable != null) {
2302 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2303 rc.Report.Error (844, loc,
2304 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2305 Name, me.GetSignatureForError ());
2309 } else if (me is MethodGroupExpr) {
2310 // Leave it to overload resolution to report correct error
2312 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2313 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2316 if (variable != null && (restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2317 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2318 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2322 // MemberLookup does not check accessors availability, this is actually needed for properties only
2324 var pe = me as PropertyExpr;
2327 // Break as there is no other overload available anyway
2328 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2329 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2332 pe.Getter = pe.PropertyInfo.Get;
2334 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2337 pe.Setter = pe.PropertyInfo.Set;
2342 // TODO: It's used by EventExpr -> FieldExpr transformation only
2343 // TODO: Should go to MemberAccess
2344 me = me.ResolveMemberAccess (rc, null, null);
2348 me.SetTypeArguments (rc, targs);
2355 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2357 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2358 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2364 if (variable_found) {
2365 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2367 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2373 if (RootContext.EvalMode) {
2374 var fi = Evaluator.LookupField (Name);
2376 return new FieldExpr (fi.Item1, loc);
2380 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2385 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2387 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2392 if (right_side != null) {
2393 if (e is TypeExpr) {
2394 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2398 e = e.ResolveLValue (ec, right_side);
2403 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2409 /// Represents a namespace or a type. The name of the class was inspired by
2410 /// section 10.8.1 (Fully Qualified Names).
2412 public abstract class FullNamedExpression : Expression
2414 protected override void CloneTo (CloneContext clonectx, Expression target)
2416 // Do nothing, most unresolved type expressions cannot be
2417 // resolved to different type
2420 public override Expression CreateExpressionTree (ResolveContext ec)
2422 throw new NotSupportedException ("ET");
2425 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2430 public override void Emit (EmitContext ec)
2432 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2433 GetSignatureForError ());
2438 /// Expression that evaluates to a type
2440 public abstract class TypeExpr : FullNamedExpression {
2441 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2443 TypeExpr t = DoResolveAsTypeStep (ec);
2447 eclass = ExprClass.Type;
2451 protected override Expression DoResolve (ResolveContext ec)
2453 return ResolveAsTypeTerminal (ec, false);
2456 public virtual bool CheckAccessLevel (IMemberContext mc)
2458 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2460 c = mc.CurrentMemberDefinition.Parent;
2462 return c.CheckAccessLevel (Type);
2465 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2467 public override bool Equals (object obj)
2469 TypeExpr tobj = obj as TypeExpr;
2473 return Type == tobj.Type;
2476 public override int GetHashCode ()
2478 return Type.GetHashCode ();
2483 /// Fully resolved Expression that already evaluated to a type
2485 public class TypeExpression : TypeExpr {
2486 public TypeExpression (TypeSpec t, Location l)
2489 eclass = ExprClass.Type;
2493 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2498 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2505 /// This class denotes an expression which evaluates to a member
2506 /// of a struct or a class.
2508 public abstract class MemberExpr : Expression
2511 // An instance expression associated with this member, if it's a
2512 // non-static member
2514 public Expression InstanceExpression;
2517 /// The name of this member.
2519 public abstract string Name {
2524 // When base.member is used
2526 public bool IsBase {
2527 get { return InstanceExpression is BaseThis; }
2531 /// Whether this is an instance member.
2533 public abstract bool IsInstance {
2538 /// Whether this is a static member.
2540 public abstract bool IsStatic {
2545 protected abstract TypeSpec DeclaringType {
2550 // Converts best base candidate for virtual method starting from QueriedBaseType
2552 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2555 // Only when base.member is used and method is virtual
2561 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2562 // means for base.member access we have to find the closest match after we found best candidate
2564 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2566 // The method could already be what we are looking for
2568 TypeSpec[] targs = null;
2569 if (method.DeclaringType != InstanceExpression.Type) {
2570 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2571 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2572 if (base_override.IsGeneric)
2573 targs = method.TypeArguments;
2575 method = base_override;
2579 // TODO: For now we do it for any hoisted call even if it's needed for
2580 // hoisted stories only but that requires a new expression wrapper
2581 if (rc.CurrentAnonymousMethod != null) {
2582 if (targs == null && method.IsGeneric) {
2583 targs = method.TypeArguments;
2584 method = method.GetGenericMethodDefinition ();
2587 if (method.Parameters.HasArglist)
2588 throw new NotImplementedException ("__arglist base call proxy");
2590 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2592 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2593 // get/set member expressions second call would fail to proxy because left expression
2594 // would be of 'this' and not 'base'
2595 if (rc.CurrentType.IsStruct)
2596 InstanceExpression = rc.GetThis (loc);
2600 method = method.MakeGenericMethod (targs);
2604 // Only base will allow this invocation to happen.
2606 if (method.IsAbstract) {
2607 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2613 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2615 if (InstanceExpression == null)
2618 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2619 var ct = rc.CurrentType;
2620 var expr_type = InstanceExpression.Type;
2621 if (ct != expr_type) {
2622 expr_type = expr_type.GetDefinition ();
2623 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2624 rc.Report.SymbolRelatedToPreviousError (member);
2625 rc.Report.Error (1540, loc,
2626 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2627 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2633 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2636 type = type.GetDefinition ();
2638 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2641 type = type.DeclaringType;
2642 } while (type != null);
2647 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2649 if (InstanceExpression != null) {
2650 InstanceExpression = InstanceExpression.Resolve (rc);
2651 CheckProtectedMemberAccess (rc, member);
2654 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2655 UnsafeError (rc, loc);
2658 if (!rc.IsObsolete) {
2659 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2661 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2664 if (!(member is FieldSpec))
2665 member.MemberDefinition.SetIsUsed ();
2668 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2670 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2674 // Implements identicial simple name and type-name
2676 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2679 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2682 // 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
2683 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2685 if (left is MemberExpr || left is VariableReference) {
2686 rc.Report.DisableReporting ();
2687 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2688 rc.Report.EnableReporting ();
2689 if (identical_type != null && identical_type.Type == left.Type)
2690 return identical_type;
2696 public bool ResolveInstanceExpression (ResolveContext rc)
2699 if (InstanceExpression != null) {
2700 if (InstanceExpression is TypeExpr) {
2701 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2702 if (oa != null && !rc.IsObsolete) {
2703 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2706 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2707 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2708 rc.Report.Error (176, loc,
2709 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2710 GetSignatureForError ());
2714 InstanceExpression = null;
2720 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2721 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2722 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2723 rc.Report.Error (236, loc,
2724 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2725 GetSignatureForError ());
2727 rc.Report.Error (120, loc,
2728 "An object reference is required to access non-static member `{0}'",
2729 GetSignatureForError ());
2734 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2735 rc.Report.Error (38, loc,
2736 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2737 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2740 InstanceExpression = rc.GetThis (loc);
2744 var me = InstanceExpression as MemberExpr;
2746 me.ResolveInstanceExpression (rc);
2748 var fe = me as FieldExpr;
2749 if (fe != null && fe.IsMarshalByRefAccess ()) {
2750 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2751 rc.Report.Warning (1690, 1, loc,
2752 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2753 me.GetSignatureForError ());
2760 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2762 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2763 ec.Report.Warning (1720, 1, left.Location,
2764 "Expression will always cause a `{0}'", "System.NullReferenceException");
2767 InstanceExpression = left;
2771 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2773 TypeSpec instance_type = InstanceExpression.Type;
2774 if (TypeManager.IsValueType (instance_type)) {
2775 if (InstanceExpression is IMemoryLocation) {
2776 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2778 LocalTemporary t = new LocalTemporary (instance_type);
2779 InstanceExpression.Emit (ec);
2781 t.AddressOf (ec, AddressOp.Store);
2784 InstanceExpression.Emit (ec);
2786 // Only to make verifier happy
2787 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2788 ec.Emit (OpCodes.Box, instance_type);
2791 if (prepare_for_load)
2792 ec.Emit (OpCodes.Dup);
2795 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2799 // Represents a group of extension method candidates for whole namespace
2801 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2803 NamespaceEntry namespace_entry;
2804 public readonly Expression ExtensionExpression;
2806 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2807 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2809 this.namespace_entry = n;
2810 this.ExtensionExpression = extensionExpr;
2813 public override bool IsStatic {
2814 get { return true; }
2817 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2819 if (namespace_entry == null)
2823 // For extension methodgroup we are not looking for base members but parent
2824 // namespace extension methods
2826 int arity = type_arguments == null ? 0 : type_arguments.Count;
2827 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2831 return found.Cast<MemberSpec> ().ToList ();
2834 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2836 // We are already here
2840 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2842 if (arguments == null)
2843 arguments = new Arguments (1);
2845 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2846 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2848 // Store resolved argument and restore original arguments
2850 // Clean-up modified arguments for error reporting
2851 arguments.RemoveAt (0);
2855 var me = ExtensionExpression as MemberExpr;
2857 me.ResolveInstanceExpression (ec);
2859 InstanceExpression = null;
2863 #region IErrorHandler Members
2865 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2870 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2872 rc.Report.SymbolRelatedToPreviousError (best);
2873 rc.Report.Error (1928, loc,
2874 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2875 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2878 rc.Report.Error (1929, loc,
2879 "Extension method instance type `{0}' cannot be converted to `{1}'",
2880 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2886 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2891 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2900 /// MethodGroupExpr represents a group of method candidates which
2901 /// can be resolved to the best method overload
2903 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2905 protected IList<MemberSpec> Methods;
2906 MethodSpec best_candidate;
2907 protected TypeArguments type_arguments;
2909 SimpleName simple_name;
2910 protected TypeSpec queried_type;
2912 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2916 this.type = InternalType.MethodGroup;
2918 eclass = ExprClass.MethodGroup;
2919 queried_type = type;
2922 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2923 : this (new MemberSpec[] { m }, type, loc)
2929 public MethodSpec BestCandidate {
2931 return best_candidate;
2935 protected override TypeSpec DeclaringType {
2937 return queried_type;
2941 public override bool IsInstance {
2943 if (best_candidate != null)
2944 return !best_candidate.IsStatic;
2950 public override bool IsStatic {
2952 if (best_candidate != null)
2953 return best_candidate.IsStatic;
2959 public override string Name {
2961 if (best_candidate != null)
2962 return best_candidate.Name;
2965 return Methods.First ().Name;
2972 // When best candidate is already know this factory can be used
2973 // to avoid expensive overload resolution to be called
2975 // NOTE: InstanceExpression has to be set manually
2977 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2979 return new MethodGroupExpr (best, queriedType, loc) {
2980 best_candidate = best
2984 public override string GetSignatureForError ()
2986 if (best_candidate != null)
2987 return best_candidate.GetSignatureForError ();
2989 return Methods.First ().GetSignatureForError ();
2992 public override Expression CreateExpressionTree (ResolveContext ec)
2994 if (best_candidate == null) {
2995 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
2999 if (best_candidate.IsConditionallyExcluded (loc))
3000 ec.Report.Error (765, loc,
3001 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3003 return new TypeOfMethod (best_candidate, loc);
3006 protected override Expression DoResolve (ResolveContext ec)
3008 this.eclass = ExprClass.MethodGroup;
3010 if (InstanceExpression != null) {
3011 InstanceExpression = InstanceExpression.Resolve (ec);
3012 if (InstanceExpression == null)
3019 public override void Emit (EmitContext ec)
3021 throw new NotSupportedException ();
3024 public void EmitCall (EmitContext ec, Arguments arguments)
3026 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3029 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3031 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3032 Name, TypeManager.CSharpName (target));
3035 public static bool IsExtensionMethodArgument (Expression expr)
3038 // LAMESPEC: No details about which expressions are not allowed
3040 return !(expr is TypeExpr) && !(expr is BaseThis);
3044 /// Find the Applicable Function Members (7.4.2.1)
3046 /// me: Method Group expression with the members to select.
3047 /// it might contain constructors or methods (or anything
3048 /// that maps to a method).
3050 /// Arguments: ArrayList containing resolved Argument objects.
3052 /// loc: The location if we want an error to be reported, or a Null
3053 /// location for "probing" purposes.
3055 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3056 /// that is the best match of me on Arguments.
3059 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3061 // TODO: causes issues with probing mode, remove explicit Kind check
3062 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3065 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3066 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3067 r.BaseMembersProvider = this;
3070 if (cerrors != null)
3071 r.CustomErrors = cerrors;
3073 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3074 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3075 if (best_candidate == null)
3076 return r.BestCandidateIsDynamic ? this : null;
3078 // Overload resolver had to create a new method group, all checks bellow have already been executed
3079 if (r.BestCandidateNewMethodGroup != null)
3080 return r.BestCandidateNewMethodGroup;
3082 if (best_candidate.Kind == MemberKind.Method) {
3083 if (InstanceExpression != null) {
3084 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3085 InstanceExpression = null;
3087 if (best_candidate.IsStatic && simple_name != null) {
3088 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3091 InstanceExpression.Resolve (ec);
3095 ResolveInstanceExpression (ec);
3096 if (InstanceExpression != null)
3097 CheckProtectedMemberAccess (ec, best_candidate);
3100 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3104 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3106 simple_name = original;
3107 return base.ResolveMemberAccess (ec, left, original);
3110 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3112 type_arguments = ta;
3115 #region IBaseMembersProvider Members
3117 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3119 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3123 // Extension methods lookup after ordinary methods candidates failed to apply
3125 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3127 if (InstanceExpression == null)
3130 InstanceExpression = InstanceExpression.Resolve (rc);
3131 if (!IsExtensionMethodArgument (InstanceExpression))
3134 int arity = type_arguments == null ? 0 : type_arguments.Count;
3135 NamespaceEntry methods_scope = null;
3136 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3137 if (methods == null)
3140 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3141 emg.SetTypeArguments (rc, type_arguments);
3148 public struct OverloadResolver
3151 public enum Restrictions
3155 ProbingOnly = 1 << 1,
3156 CovariantDelegate = 1 << 2,
3157 NoBaseMembers = 1 << 3,
3158 BaseMembersIncluded = 1 << 4
3161 public interface IBaseMembersProvider
3163 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3164 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3167 public interface IErrorHandler
3169 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3170 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3171 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3172 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3175 sealed class NoBaseMembers : IBaseMembersProvider
3177 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3179 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3184 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3190 struct AmbiguousCandidate
3192 public readonly MemberSpec Member;
3193 public readonly bool Expanded;
3195 public AmbiguousCandidate (MemberSpec member, bool expanded)
3198 Expanded = expanded;
3203 IList<MemberSpec> members;
3204 TypeArguments type_arguments;
3205 IBaseMembersProvider base_provider;
3206 IErrorHandler custom_errors;
3207 Restrictions restrictions;
3208 MethodGroupExpr best_candidate_extension_group;
3210 SessionReportPrinter lambda_conv_msgs;
3211 ReportPrinter prev_recorder;
3213 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3214 : this (members, null, restrictions, loc)
3218 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3221 if (members == null || members.Count == 0)
3222 throw new ArgumentException ("empty members set");
3224 this.members = members;
3226 type_arguments = targs;
3227 this.restrictions = restrictions;
3228 if (IsDelegateInvoke)
3229 this.restrictions |= Restrictions.NoBaseMembers;
3231 base_provider = NoBaseMembers.Instance;
3236 public IBaseMembersProvider BaseMembersProvider {
3238 return base_provider;
3241 base_provider = value;
3245 public bool BestCandidateIsDynamic { get; set; }
3248 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3250 public MethodGroupExpr BestCandidateNewMethodGroup {
3252 return best_candidate_extension_group;
3256 public IErrorHandler CustomErrors {
3258 return custom_errors;
3261 custom_errors = value;
3265 TypeSpec DelegateType {
3267 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3268 throw new InternalErrorException ("Not running in delegate mode", loc);
3270 return members [0].DeclaringType;
3274 bool IsProbingOnly {
3276 return (restrictions & Restrictions.ProbingOnly) != 0;
3280 bool IsDelegateInvoke {
3282 return (restrictions & Restrictions.DelegateInvoke) != 0;
3289 // 7.4.3.3 Better conversion from expression
3290 // Returns : 1 if a->p is better,
3291 // 2 if a->q is better,
3292 // 0 if neither is better
3294 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3296 TypeSpec argument_type = a.Type;
3297 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3299 // Uwrap delegate from Expression<T>
3301 if (p.GetDefinition () == TypeManager.expression_type) {
3302 p = TypeManager.GetTypeArguments (p)[0];
3304 if (q.GetDefinition () == TypeManager.expression_type) {
3305 q = TypeManager.GetTypeArguments (q)[0];
3308 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3309 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3310 if (p == TypeManager.void_type && q != TypeManager.void_type)
3312 if (q == TypeManager.void_type && p != TypeManager.void_type)
3315 if (argument_type == p)
3318 if (argument_type == q)
3322 return BetterTypeConversion (ec, p, q);
3326 // 7.4.3.4 Better conversion from type
3328 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3330 if (p == null || q == null)
3331 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3333 if (p == TypeManager.int32_type) {
3334 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3336 } else if (p == TypeManager.int64_type) {
3337 if (q == TypeManager.uint64_type)
3339 } else if (p == TypeManager.sbyte_type) {
3340 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3341 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3343 } else if (p == TypeManager.short_type) {
3344 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3345 q == TypeManager.uint64_type)
3347 } else if (p == InternalType.Dynamic) {
3348 if (q == TypeManager.object_type)
3352 if (q == TypeManager.int32_type) {
3353 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3355 } if (q == TypeManager.int64_type) {
3356 if (p == TypeManager.uint64_type)
3358 } else if (q == TypeManager.sbyte_type) {
3359 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3360 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3362 } if (q == TypeManager.short_type) {
3363 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3364 p == TypeManager.uint64_type)
3366 } else if (q == InternalType.Dynamic) {
3367 if (p == TypeManager.object_type)
3371 // TODO: this is expensive
3372 Expression p_tmp = new EmptyExpression (p);
3373 Expression q_tmp = new EmptyExpression (q);
3375 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3376 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3378 if (p_to_q && !q_to_p)
3381 if (q_to_p && !p_to_q)
3388 /// Determines "Better function" between candidate
3389 /// and the current best match
3392 /// Returns a boolean indicating :
3393 /// false if candidate ain't better
3394 /// true if candidate is better than the current best match
3396 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3397 MemberSpec best, bool best_params)
3399 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3400 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3402 bool better_at_least_one = false;
3404 int args_count = args == null ? 0 : args.Count;
3406 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3407 Argument a = args[j];
3409 // Default arguments are ignored for better decision
3410 if (a.IsDefaultArgument)
3413 TypeSpec ct = candidate_pd.Types[c_idx];
3414 TypeSpec bt = best_pd.Types[b_idx];
3416 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3417 ct = TypeManager.GetElementType (ct);
3421 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3422 bt = TypeManager.GetElementType (bt);
3430 int result = BetterExpressionConversion (ec, a, ct, bt);
3432 // for each argument, the conversion to 'ct' should be no worse than
3433 // the conversion to 'bt'.
3437 // for at least one argument, the conversion to 'ct' should be better than
3438 // the conversion to 'bt'.
3440 better_at_least_one = true;
3443 if (better_at_least_one)
3447 // This handles the case
3449 // Add (float f1, float f2, float f3);
3450 // Add (params decimal [] foo);
3452 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3453 // first candidate would've chosen as better.
3459 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3463 // This handles the following cases:
3465 // Foo (int i) is better than Foo (int i, long l = 0)
3466 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3468 // Prefer non-optional version
3470 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3471 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3472 if (candidate_pd.Count >= best_pd.Count)
3475 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3482 // One is a non-generic method and second is a generic method, then non-generic is better
3484 if (best.IsGeneric != candidate.IsGeneric)
3485 return best.IsGeneric;
3488 // This handles the following cases:
3490 // Trim () is better than Trim (params char[] chars)
3491 // Concat (string s1, string s2, string s3) is better than
3492 // Concat (string s1, params string [] srest)
3493 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3495 // Prefer non-expanded version
3497 if (candidate_params != best_params)
3500 int candidate_param_count = candidate_pd.Count;
3501 int best_param_count = best_pd.Count;
3503 if (candidate_param_count != best_param_count)
3504 // can only happen if (candidate_params && best_params)
3505 return candidate_param_count > best_param_count && best_pd.HasParams;
3508 // Both methods have the same number of parameters, and the parameters have equal types
3509 // Pick the "more specific" signature using rules over original (non-inflated) types
3511 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3512 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3514 bool specific_at_least_once = false;
3515 for (j = 0; j < candidate_param_count; ++j) {
3516 var ct = candidate_def_pd.Types[j];
3517 var bt = best_def_pd.Types[j];
3520 TypeSpec specific = MoreSpecific (ct, bt);
3524 specific_at_least_once = true;
3527 if (specific_at_least_once)
3530 // FIXME: handle lifted operators
3536 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3538 rc.Report.Error (1729, loc,
3539 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3540 type.GetSignatureForError (), argCount.ToString ());
3544 /// Determines if the candidate method is applicable (section 14.4.2.1)
3545 /// to the given set of arguments
3546 /// A return value rates candidate method compatibility,
3547 /// 0 = the best, int.MaxValue = the worst
3549 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3551 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3552 int param_count = pd.Count;
3553 int optional_count = 0;
3556 if (arg_count != param_count) {
3557 for (int i = 0; i < pd.Count; ++i) {
3558 if (pd.FixedParameters[i].HasDefaultValue) {
3559 optional_count = pd.Count - i;
3564 int args_gap = System.Math.Abs (arg_count - param_count);
3565 if (optional_count != 0) {
3566 if (args_gap > optional_count)
3567 return int.MaxValue - 10000 + args_gap - optional_count;
3569 // Readjust expected number when params used
3572 if (arg_count < param_count)
3574 } else if (arg_count > param_count) {
3575 return int.MaxValue - 10000 + args_gap;
3577 } else if (arg_count != param_count) {
3579 return int.MaxValue - 10000 + args_gap;
3580 if (arg_count < param_count - 1)
3581 return int.MaxValue - 10000 + args_gap;
3584 // Resize to fit optional arguments
3585 if (optional_count != 0) {
3586 if (arguments == null) {
3587 arguments = new Arguments (optional_count);
3589 // Have to create a new container, so the next run can do same
3590 var resized = new Arguments (param_count);
3591 resized.AddRange (arguments);
3592 arguments = resized;
3595 for (int i = arg_count; i < param_count; ++i)
3596 arguments.Add (null);
3600 if (arg_count > 0) {
3602 // Shuffle named arguments to the right positions if there are any
3604 if (arguments[arg_count - 1] is NamedArgument) {
3605 arg_count = arguments.Count;
3607 for (int i = 0; i < arg_count; ++i) {
3608 bool arg_moved = false;
3610 NamedArgument na = arguments[i] as NamedArgument;
3614 int index = pd.GetParameterIndexByName (na.Name);
3616 // Named parameter not found or already reordered
3617 if (index == i || index < 0)
3621 if (index >= param_count) {
3622 // When using parameters which should not be available to the user
3623 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3626 arguments.Add (null);
3630 temp = arguments[index];
3632 // The slot has been taken by positional argument
3633 if (temp != null && !(temp is NamedArgument))
3638 arguments.MarkReorderedArgument (na);
3642 arguments[index] = arguments[i];
3643 arguments[i] = temp;
3650 arg_count = arguments.Count;
3652 } else if (arguments != null) {
3653 arg_count = arguments.Count;
3657 // 1. Handle generic method using type arguments when specified or type inference
3659 var ms = candidate as MethodSpec;
3660 if (ms != null && ms.IsGeneric) {
3661 // Setup constraint checker for probing only
3662 ConstraintChecker cc = new ConstraintChecker (null);
3664 if (type_arguments != null) {
3665 var g_args_count = ms.Arity;
3666 if (g_args_count != type_arguments.Count)
3667 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3669 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3672 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3673 // for now it simplifies things. I should probably add a callback to ResolveContext
3674 if (lambda_conv_msgs == null) {
3675 lambda_conv_msgs = new SessionReportPrinter ();
3676 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3679 var ti = new TypeInference (arguments);
3680 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3681 lambda_conv_msgs.EndSession ();
3684 return ti.InferenceScore - 20000;
3686 if (i_args.Length != 0) {
3687 candidate = ms = ms.MakeGenericMethod (i_args);
3691 cc.IgnoreInferredDynamic = true;
3695 // Type arguments constraints have to match for the method to be applicable
3697 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
3698 return int.MaxValue - 25000;
3701 if (type_arguments != null)
3702 return int.MaxValue - 15000;
3706 // 2. Each argument has to be implicitly convertible to method parameter
3708 Parameter.Modifier p_mod = 0;
3710 for (int i = 0; i < arg_count; i++) {
3711 Argument a = arguments[i];
3713 if (!pd.FixedParameters[i].HasDefaultValue)
3714 throw new InternalErrorException ();
3717 // Get the default value expression, we can use the same expression
3718 // if the type matches
3720 Expression e = pd.FixedParameters[i].DefaultValue;
3721 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3723 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3725 if (e == EmptyExpression.MissingValue && pd.Types[i] == TypeManager.object_type) {
3726 e = new MemberAccess (new MemberAccess (new MemberAccess (
3727 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3729 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc);
3735 arguments[i] = new Argument (e, Argument.AType.Default);
3739 if (p_mod != Parameter.Modifier.PARAMS) {
3740 p_mod = pd.FixedParameters[i].ModFlags;
3742 } else if (!params_expanded_form) {
3743 params_expanded_form = true;
3744 pt = ((ElementTypeSpec) pt).Element;
3750 if (!params_expanded_form)
3751 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3754 // It can be applicable in expanded form (when not doing exact match like for delegates)
3756 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3757 if (!params_expanded_form)
3758 pt = ((ElementTypeSpec) pt).Element;
3760 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3762 params_expanded_form = true;
3766 if (params_expanded_form)
3768 return (arg_count - i) * 2 + score;
3773 // When params parameter has notargument, will be provided later if the method is the best candidate
3775 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3776 params_expanded_form = true;
3781 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3784 // Types have to be identical when ref or out modifer
3785 // is used and argument is not of dynamic type
3787 if ((argument.Modifier | param_mod) != 0) {
3789 // Defer to dynamic binder
3791 if (argument.Type == InternalType.Dynamic)
3794 if (argument.Type != parameter) {
3796 // Do full equality check after quick path
3798 if (!TypeSpecComparer.IsEqual (argument.Type, parameter))
3803 // Deploy custom error reporting for lambda methods. When probing lambda methods
3804 // keep all errors reported in separate set and once we are done and no best
3805 // candidate found, this set is used to report more details about what was wrong
3808 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3809 if (lambda_conv_msgs == null) {
3810 lambda_conv_msgs = new SessionReportPrinter ();
3811 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3815 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3816 if (lambda_conv_msgs != null) {
3817 lambda_conv_msgs.EndSession ();
3824 if (argument.Modifier != param_mod)
3830 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3832 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3834 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3837 var ac_p = p as ArrayContainer;
3839 var ac_q = ((ArrayContainer) q);
3840 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3841 if (specific == ac_p.Element)
3843 if (specific == ac_q.Element)
3845 } else if (TypeManager.IsGenericType (p)) {
3846 var pargs = TypeManager.GetTypeArguments (p);
3847 var qargs = TypeManager.GetTypeArguments (q);
3849 bool p_specific_at_least_once = false;
3850 bool q_specific_at_least_once = false;
3852 for (int i = 0; i < pargs.Length; i++) {
3853 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3854 if (specific == pargs[i])
3855 p_specific_at_least_once = true;
3856 if (specific == qargs[i])
3857 q_specific_at_least_once = true;
3860 if (p_specific_at_least_once && !q_specific_at_least_once)
3862 if (!p_specific_at_least_once && q_specific_at_least_once)
3870 // Find the best method from candidate list
3872 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3874 List<AmbiguousCandidate> ambiguous_candidates = null;
3876 MemberSpec best_candidate;
3877 Arguments best_candidate_args = null;
3878 bool best_candidate_params = false;
3879 int best_candidate_rate;
3881 int args_count = args != null ? args.Count : 0;
3882 Arguments candidate_args = args;
3883 bool error_mode = false;
3884 var current_type = rc.CurrentType;
3885 MemberSpec invocable_member = null;
3887 // Be careful, cannot return until error reporter is restored
3889 best_candidate = null;
3890 best_candidate_rate = int.MaxValue;
3892 var type_members = members;
3896 for (int i = 0; i < type_members.Count; ++i) {
3897 var member = type_members[i];
3900 // Methods in a base class are not candidates if any method in a derived
3901 // class is applicable
3903 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3906 if (!member.IsAccessible (current_type) && !error_mode)
3909 if (!(member is IParametersMember)) {
3911 // Will use it later to report ambiguity between best method and invocable member
3913 if (Invocation.IsMemberInvocable (member))
3914 invocable_member = member;
3920 // Check if candidate is applicable
3922 bool params_expanded_form = false;
3923 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3926 // How does it score compare to others
3928 if (candidate_rate < best_candidate_rate) {
3929 best_candidate_rate = candidate_rate;
3930 best_candidate = member;
3931 best_candidate_args = candidate_args;
3932 best_candidate_params = params_expanded_form;
3933 } else if (candidate_rate == 0) {
3935 // The member look is done per type for most operations but sometimes
3936 // it's not possible like for binary operators overload because they
3937 // are unioned between 2 sides
3939 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
3940 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
3944 // Is new candidate better
3945 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3946 best_candidate = member;
3947 best_candidate_args = candidate_args;
3948 best_candidate_params = params_expanded_form;
3950 // It's not better but any other found later could be but we are not sure yet
3951 if (ambiguous_candidates == null)
3952 ambiguous_candidates = new List<AmbiguousCandidate> ();
3954 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3958 // Restore expanded arguments
3959 if (candidate_args != args)
3960 candidate_args = args;
3962 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3964 if (prev_recorder != null)
3965 rc.Report.SetPrinter (prev_recorder);
3969 // We've found exact match
3971 if (best_candidate_rate == 0)
3975 // Try extension methods lookup when no ordinary method match was found and provider enables it
3978 var emg = base_provider.LookupExtensionMethod (rc);
3980 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
3982 best_candidate_extension_group = emg;
3983 return (T) (MemberSpec) emg.BestCandidate;
3988 // Don't run expensive error reporting mode for probing
3995 lambda_conv_msgs = null;
4000 // No best member match found, report an error
4002 if (best_candidate_rate != 0 || error_mode) {
4003 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
4007 // TODO: HasDynamic is quite slow
4008 if (args_count != 0 && (restrictions & Restrictions.CovariantDelegate) == 0 && args.HasDynamic) {
4009 if (args [0].ArgType == Argument.AType.ExtensionType) {
4010 rc.Report.Error (1973, loc,
4011 "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",
4012 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError());
4015 BestCandidateIsDynamic = true;
4019 if (ambiguous_candidates != null) {
4021 // Now check that there are no ambiguities i.e the selected method
4022 // should be better than all the others
4024 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4025 var candidate = ambiguous_candidates [ix];
4027 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
4028 var ambiguous = candidate.Member;
4029 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4030 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4031 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4032 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4033 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4036 return (T) best_candidate;
4041 if (invocable_member != null) {
4042 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4043 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4044 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4045 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4049 // And now check if the arguments are all
4050 // compatible, perform conversions if
4051 // necessary etc. and return if everything is
4054 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
4057 if (best_candidate == null)
4061 // Check ObsoleteAttribute on the best method
4063 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4064 if (oa != null && !rc.IsObsolete)
4065 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4067 best_candidate.MemberDefinition.SetIsUsed ();
4069 args = best_candidate_args;
4070 return (T) best_candidate;
4073 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4075 return ResolveMember<MethodSpec> (rc, ref args);
4078 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4079 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4081 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4084 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4085 ec.Report.SymbolRelatedToPreviousError (method);
4086 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4087 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4088 TypeManager.CSharpSignature (method));
4091 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4092 TypeManager.CSharpSignature (method));
4093 } else if (IsDelegateInvoke) {
4094 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4095 DelegateType.GetSignatureForError ());
4097 ec.Report.SymbolRelatedToPreviousError (method);
4098 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4099 method.GetSignatureForError ());
4102 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4104 string index = (idx + 1).ToString ();
4105 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4106 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4107 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4108 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4109 index, Parameter.GetModifierSignature (a.Modifier));
4111 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4112 index, Parameter.GetModifierSignature (mod));
4114 string p1 = a.GetSignatureForError ();
4115 string p2 = TypeManager.CSharpName (paramType);
4118 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4119 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4120 ec.Report.SymbolRelatedToPreviousError (paramType);
4123 ec.Report.Error (1503, loc,
4124 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4129 // We have failed to find exact match so we return error info about the closest match
4131 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
4133 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4134 int arg_count = args == null ? 0 : args.Count;
4136 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4137 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4138 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4142 if (lambda_conv_msgs != null) {
4143 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4148 // For candidates which match on parameters count report more details about incorrect arguments
4150 var pm = best_candidate as IParametersMember;
4152 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4153 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4154 // Reject any inaccessible member
4155 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4156 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4157 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4161 var ms = best_candidate as MethodSpec;
4162 if (ms != null && ms.IsGeneric) {
4163 bool constr_ok = true;
4164 if (ms.TypeArguments != null)
4165 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4167 if (ta_count == 0) {
4168 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4172 rc.Report.Error (411, loc,
4173 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4174 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4181 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4187 // We failed to find any method with correct argument count, report best candidate
4189 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4192 if (best_candidate.Kind == MemberKind.Constructor) {
4193 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4194 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4195 } else if (IsDelegateInvoke) {
4196 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4197 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4198 DelegateType.GetSignatureForError (), arg_count.ToString ());
4200 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4201 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4202 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4203 name, arg_count.ToString ());
4207 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4209 var pm = member as IParametersMember;
4210 var pd = pm.Parameters;
4212 Parameter.Modifier p_mod = 0;
4214 int a_idx = 0, a_pos = 0;
4216 ArrayInitializer params_initializers = null;
4217 bool has_unsafe_arg = pm.MemberType.IsPointer;
4218 int arg_count = args == null ? 0 : args.Count;
4220 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4222 if (p_mod != Parameter.Modifier.PARAMS) {
4223 p_mod = pd.FixedParameters[a_idx].ModFlags;
4224 pt = pd.Types[a_idx];
4225 has_unsafe_arg |= pt.IsPointer;
4227 if (p_mod == Parameter.Modifier.PARAMS) {
4228 if (chose_params_expanded) {
4229 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4230 pt = TypeManager.GetElementType (pt);
4236 // Types have to be identical when ref or out modifer is used
4238 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4239 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4242 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4248 NamedArgument na = a as NamedArgument;
4250 int name_index = pd.GetParameterIndexByName (na.Name);
4251 if (name_index < 0 || name_index >= pd.Count) {
4252 if (IsDelegateInvoke) {
4253 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4254 ec.Report.Error (1746, na.Location,
4255 "The delegate `{0}' does not contain a parameter named `{1}'",
4256 DelegateType.GetSignatureForError (), na.Name);
4258 ec.Report.SymbolRelatedToPreviousError (member);
4259 ec.Report.Error (1739, na.Location,
4260 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4261 TypeManager.CSharpSignature (member), na.Name);
4263 } else if (args[name_index] != a) {
4264 if (IsDelegateInvoke)
4265 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4267 ec.Report.SymbolRelatedToPreviousError (member);
4269 ec.Report.Error (1744, na.Location,
4270 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4275 if (a.Expr.Type == InternalType.Dynamic)
4278 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4279 custom_errors.NoArgumentMatch (ec, member);
4283 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4288 // Convert params arguments to an array initializer
4290 if (params_initializers != null) {
4291 // we choose to use 'a.Expr' rather than 'conv' so that
4292 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4293 params_initializers.Add (a.Expr);
4294 args.RemoveAt (a_idx--);
4299 // Update the argument with the implicit conversion
4303 if (a_idx != arg_count) {
4304 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4309 // Fill not provided arguments required by params modifier
4311 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4313 args = new Arguments (1);
4315 pt = pd.Types[pd.Count - 1];
4316 pt = TypeManager.GetElementType (pt);
4317 has_unsafe_arg |= pt.IsPointer;
4318 params_initializers = new ArrayInitializer (0, loc);
4322 // Append an array argument with all params arguments
4324 if (params_initializers != null) {
4325 args.Add (new Argument (
4326 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4330 if (has_unsafe_arg && !ec.IsUnsafe) {
4331 Expression.UnsafeError (ec, loc);
4335 // We could infer inaccesible type arguments
4337 if (type_arguments == null && member.IsGeneric) {
4338 var ms = (MethodSpec) member;
4339 foreach (var ta in ms.TypeArguments) {
4340 if (!ta.IsAccessible (ec.CurrentType)) {
4341 ec.Report.SymbolRelatedToPreviousError (ta);
4342 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4352 public class ConstantExpr : MemberExpr
4356 public ConstantExpr (ConstSpec constant, Location loc)
4358 this.constant = constant;
4362 public override string Name {
4363 get { throw new NotImplementedException (); }
4366 public override bool IsInstance {
4367 get { return !IsStatic; }
4370 public override bool IsStatic {
4371 get { return true; }
4374 protected override TypeSpec DeclaringType {
4375 get { return constant.DeclaringType; }
4378 public override Expression CreateExpressionTree (ResolveContext ec)
4380 throw new NotSupportedException ("ET");
4383 protected override Expression DoResolve (ResolveContext rc)
4385 ResolveInstanceExpression (rc);
4386 DoBestMemberChecks (rc, constant);
4388 var c = constant.GetConstant (rc);
4390 // Creates reference expression to the constant value
4391 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4394 public override void Emit (EmitContext ec)
4396 throw new NotSupportedException ();
4399 public override string GetSignatureForError ()
4401 return constant.GetSignatureForError ();
4404 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4406 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4411 /// Fully resolved expression that evaluates to a Field
4413 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4414 protected FieldSpec spec;
4415 VariableInfo variable_info;
4417 LocalTemporary temp;
4420 protected FieldExpr (Location l)
4425 public FieldExpr (FieldSpec spec, Location loc)
4430 type = spec.MemberType;
4433 public FieldExpr (FieldBase fi, Location l)
4440 public override string Name {
4446 public bool IsHoisted {
4448 IVariableReference hv = InstanceExpression as IVariableReference;
4449 return hv != null && hv.IsHoisted;
4453 public override bool IsInstance {
4455 return !spec.IsStatic;
4459 public override bool IsStatic {
4461 return spec.IsStatic;
4465 public FieldSpec Spec {
4471 protected override TypeSpec DeclaringType {
4473 return spec.DeclaringType;
4477 public VariableInfo VariableInfo {
4479 return variable_info;
4485 public override string GetSignatureForError ()
4487 return TypeManager.GetFullNameSignature (spec);
4490 public bool IsMarshalByRefAccess ()
4492 // Checks possible ldflda of field access expression
4493 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4494 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4495 !(InstanceExpression is This);
4498 public void SetHasAddressTaken ()
4500 IVariableReference vr = InstanceExpression as IVariableReference;
4502 vr.SetHasAddressTaken ();
4505 public override Expression CreateExpressionTree (ResolveContext ec)
4507 Expression instance;
4508 if (InstanceExpression == null) {
4509 instance = new NullLiteral (loc);
4511 instance = InstanceExpression.CreateExpressionTree (ec);
4514 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4516 CreateTypeOfExpression ());
4518 return CreateExpressionFactoryCall (ec, "Field", args);
4521 public Expression CreateTypeOfExpression ()
4523 return new TypeOfField (spec, loc);
4526 protected override Expression DoResolve (ResolveContext ec)
4528 return DoResolve (ec, false, false);
4531 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4533 if (ResolveInstanceExpression (ec)) {
4534 // Resolve the field's instance expression while flow analysis is turned
4535 // off: when accessing a field "a.b", we must check whether the field
4536 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4538 if (lvalue_instance) {
4539 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4540 Expression right_side =
4541 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4543 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4546 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4547 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4551 if (InstanceExpression == null)
4554 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4555 InstanceExpression.CheckMarshalByRefAccess (ec);
4559 DoBestMemberChecks (ec, spec);
4561 var fb = spec as FixedFieldSpec;
4562 IVariableReference var = InstanceExpression as IVariableReference;
4564 if (lvalue_instance && var != null && var.VariableInfo != null) {
4565 var.VariableInfo.SetFieldAssigned (ec, Name);
4569 IFixedExpression fe = InstanceExpression as IFixedExpression;
4570 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4571 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4574 if (InstanceExpression.eclass != ExprClass.Variable) {
4575 ec.Report.SymbolRelatedToPreviousError (spec);
4576 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4577 TypeManager.GetFullNameSignature (spec));
4578 } else if (var != null && var.IsHoisted) {
4579 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4582 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4585 eclass = ExprClass.Variable;
4587 // If the instance expression is a local variable or parameter.
4588 if (var == null || var.VariableInfo == null)
4591 VariableInfo vi = var.VariableInfo;
4592 if (!vi.IsFieldAssigned (ec, Name, loc))
4595 variable_info = vi.GetSubStruct (Name);
4599 static readonly int [] codes = {
4600 191, // instance, write access
4601 192, // instance, out access
4602 198, // static, write access
4603 199, // static, out access
4604 1648, // member of value instance, write access
4605 1649, // member of value instance, out access
4606 1650, // member of value static, write access
4607 1651 // member of value static, out access
4610 static readonly string [] msgs = {
4611 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4612 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4613 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4614 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4615 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4616 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4617 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4618 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4621 // The return value is always null. Returning a value simplifies calling code.
4622 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4625 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4629 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4631 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4636 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4638 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4639 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4641 Expression e = DoResolve (ec, lvalue_instance, out_access);
4646 spec.MemberDefinition.SetIsAssigned ();
4648 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4649 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4650 ec.Report.Warning (420, 1, loc,
4651 "`{0}': A volatile field references will not be treated as volatile",
4652 spec.GetSignatureForError ());
4655 if (spec.IsReadOnly) {
4656 // InitOnly fields can only be assigned in constructors or initializers
4657 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4658 return Report_AssignToReadonly (ec, right_side);
4660 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4662 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4663 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4664 return Report_AssignToReadonly (ec, right_side);
4665 // static InitOnly fields cannot be assigned-to in an instance constructor
4666 if (IsStatic && !ec.IsStatic)
4667 return Report_AssignToReadonly (ec, right_side);
4668 // instance constructors can't modify InitOnly fields of other instances of the same type
4669 if (!IsStatic && !(InstanceExpression is This))
4670 return Report_AssignToReadonly (ec, right_side);
4674 if (right_side == EmptyExpression.OutAccess.Instance &&
4675 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4676 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4677 ec.Report.Warning (197, 1, loc,
4678 "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",
4679 GetSignatureForError ());
4682 eclass = ExprClass.Variable;
4686 public override int GetHashCode ()
4688 return spec.GetHashCode ();
4691 public bool IsFixed {
4694 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4696 IVariableReference variable = InstanceExpression as IVariableReference;
4697 if (variable != null)
4698 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4700 IFixedExpression fe = InstanceExpression as IFixedExpression;
4701 return fe != null && fe.IsFixed;
4705 public override bool Equals (object obj)
4707 FieldExpr fe = obj as FieldExpr;
4711 if (spec != fe.spec)
4714 if (InstanceExpression == null || fe.InstanceExpression == null)
4717 return InstanceExpression.Equals (fe.InstanceExpression);
4720 public void Emit (EmitContext ec, bool leave_copy)
4722 bool is_volatile = false;
4724 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4727 spec.MemberDefinition.SetIsUsed ();
4731 ec.Emit (OpCodes.Volatile);
4733 ec.Emit (OpCodes.Ldsfld, spec);
4736 EmitInstance (ec, false);
4738 // Optimization for build-in types
4739 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4740 ec.EmitLoadFromPtr (type);
4742 var ff = spec as FixedFieldSpec;
4744 ec.Emit (OpCodes.Ldflda, spec);
4745 ec.Emit (OpCodes.Ldflda, ff.Element);
4748 ec.Emit (OpCodes.Volatile);
4750 ec.Emit (OpCodes.Ldfld, spec);
4756 ec.Emit (OpCodes.Dup);
4758 temp = new LocalTemporary (this.Type);
4764 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4766 prepared = prepare_for_load;
4768 EmitInstance (ec, prepared);
4772 ec.Emit (OpCodes.Dup);
4774 temp = new LocalTemporary (this.Type);
4779 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4780 ec.Emit (OpCodes.Volatile);
4782 spec.MemberDefinition.SetIsAssigned ();
4785 ec.Emit (OpCodes.Stsfld, spec);
4787 ec.Emit (OpCodes.Stfld, spec);
4796 public override void Emit (EmitContext ec)
4801 public override void EmitSideEffect (EmitContext ec)
4803 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4805 if (is_volatile) // || is_marshal_by_ref ())
4806 base.EmitSideEffect (ec);
4809 public void AddressOf (EmitContext ec, AddressOp mode)
4811 if ((mode & AddressOp.Store) != 0)
4812 spec.MemberDefinition.SetIsAssigned ();
4813 if ((mode & AddressOp.Load) != 0)
4814 spec.MemberDefinition.SetIsUsed ();
4817 // Handle initonly fields specially: make a copy and then
4818 // get the address of the copy.
4821 if (spec.IsReadOnly){
4823 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4836 local = ec.DeclareLocal (type, false);
4837 ec.Emit (OpCodes.Stloc, local);
4838 ec.Emit (OpCodes.Ldloca, local);
4844 ec.Emit (OpCodes.Ldsflda, spec);
4847 EmitInstance (ec, false);
4848 ec.Emit (OpCodes.Ldflda, spec);
4852 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4854 return MakeExpression (ctx);
4857 public override SLE.Expression MakeExpression (BuilderContext ctx)
4859 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4862 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4864 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4870 /// Expression that evaluates to a Property. The Assign class
4871 /// might set the `Value' expression if we are in an assignment.
4873 /// This is not an LValue because we need to re-write the expression, we
4874 /// can not take data from the stack and store it.
4876 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4878 public PropertyExpr (PropertySpec spec, Location l)
4881 best_candidate = spec;
4882 type = spec.MemberType;
4887 protected override TypeSpec DeclaringType {
4889 return best_candidate.DeclaringType;
4893 public override string Name {
4895 return best_candidate.Name;
4899 public override bool IsInstance {
4905 public override bool IsStatic {
4907 return best_candidate.IsStatic;
4911 public PropertySpec PropertyInfo {
4913 return best_candidate;
4919 public override Expression CreateExpressionTree (ResolveContext ec)
4922 if (IsSingleDimensionalArrayLength ()) {
4923 args = new Arguments (1);
4924 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4925 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4928 args = new Arguments (2);
4929 if (InstanceExpression == null)
4930 args.Add (new Argument (new NullLiteral (loc)));
4932 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4933 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4934 return CreateExpressionFactoryCall (ec, "Property", args);
4937 public Expression CreateSetterTypeOfExpression ()
4939 return new TypeOfMethod (Setter, loc);
4942 public override string GetSignatureForError ()
4944 return best_candidate.GetSignatureForError ();
4947 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4949 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4952 public override SLE.Expression MakeExpression (BuilderContext ctx)
4954 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4957 void Error_PropertyNotValid (ResolveContext ec)
4959 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4960 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4961 GetSignatureForError ());
4964 bool IsSingleDimensionalArrayLength ()
4966 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4969 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4970 return ac != null && ac.Rank == 1;
4973 public override void Emit (EmitContext ec, bool leave_copy)
4976 // Special case: length of single dimension array property is turned into ldlen
4978 if (IsSingleDimensionalArrayLength ()) {
4980 EmitInstance (ec, false);
4981 ec.Emit (OpCodes.Ldlen);
4982 ec.Emit (OpCodes.Conv_I4);
4986 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
4989 ec.Emit (OpCodes.Dup);
4991 temp = new LocalTemporary (this.Type);
4997 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4999 Expression my_source = source;
5001 if (prepare_for_load) {
5006 ec.Emit (OpCodes.Dup);
5008 temp = new LocalTemporary (this.Type);
5012 } else if (leave_copy) {
5014 temp = new LocalTemporary (this.Type);
5019 Arguments args = new Arguments (1);
5020 args.Add (new Argument (my_source));
5022 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5030 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5032 eclass = ExprClass.PropertyAccess;
5034 if (best_candidate.IsNotRealProperty) {
5035 Error_PropertyNotValid (rc);
5038 if (ResolveInstanceExpression (rc)) {
5039 if (right_side != null && best_candidate.DeclaringType.IsStruct)
5040 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
5043 DoBestMemberChecks (rc, best_candidate);
5047 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5049 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5053 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5055 // getter and setter can be different for base calls
5056 MethodSpec getter, setter;
5057 protected T best_candidate;
5059 protected LocalTemporary temp;
5060 protected bool prepared;
5062 protected PropertyOrIndexerExpr (Location l)
5069 public MethodSpec Getter {
5078 public MethodSpec Setter {
5089 protected override Expression DoResolve (ResolveContext ec)
5091 if (eclass == ExprClass.Unresolved) {
5092 var expr = OverloadResolve (ec, null);
5096 if (InstanceExpression != null)
5097 InstanceExpression.CheckMarshalByRefAccess (ec);
5100 return expr.Resolve (ec);
5103 if (!ResolveGetter (ec))
5109 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5111 if (right_side == EmptyExpression.OutAccess.Instance) {
5112 // TODO: best_candidate can be null at this point
5113 INamedBlockVariable variable = null;
5114 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5115 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5116 best_candidate.Name);
5118 right_side.DoResolveLValue (ec, this);
5123 // if the property/indexer returns a value type, and we try to set a field in it
5124 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5125 Error_CannotModifyIntermediateExpressionValue (ec);
5128 if (eclass == ExprClass.Unresolved) {
5129 var expr = OverloadResolve (ec, right_side);
5134 return expr.ResolveLValue (ec, right_side);
5137 if (!ResolveSetter (ec))
5144 // Implements the IAssignMethod interface for assignments
5146 public abstract void Emit (EmitContext ec, bool leave_copy);
5147 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5149 public override void Emit (EmitContext ec)
5154 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5156 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5158 bool ResolveGetter (ResolveContext rc)
5160 if (!best_candidate.HasGet) {
5161 if (InstanceExpression != EmptyExpression.Null) {
5162 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5163 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5164 best_candidate.GetSignatureForError ());
5167 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5168 if (best_candidate.HasDifferentAccessibility) {
5169 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5170 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5171 TypeManager.CSharpSignature (best_candidate));
5173 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5174 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5178 if (best_candidate.HasDifferentAccessibility) {
5179 CheckProtectedMemberAccess (rc, best_candidate.Get);
5182 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5186 bool ResolveSetter (ResolveContext rc)
5188 if (!best_candidate.HasSet) {
5189 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5190 GetSignatureForError ());
5194 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5195 if (best_candidate.HasDifferentAccessibility) {
5196 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5197 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5198 GetSignatureForError ());
5200 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5201 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5205 if (best_candidate.HasDifferentAccessibility)
5206 CheckProtectedMemberAccess (rc, best_candidate.Set);
5208 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5214 /// Fully resolved expression that evaluates to an Event
5216 public class EventExpr : MemberExpr, IAssignMethod
5218 readonly EventSpec spec;
5221 public EventExpr (EventSpec spec, Location loc)
5229 protected override TypeSpec DeclaringType {
5231 return spec.DeclaringType;
5235 public override string Name {
5241 public override bool IsInstance {
5243 return !spec.IsStatic;
5247 public override bool IsStatic {
5249 return spec.IsStatic;
5253 public MethodSpec Operator {
5261 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5264 // If the event is local to this class, we transform ourselves into a FieldExpr
5267 if (spec.DeclaringType == ec.CurrentType ||
5268 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5270 if (spec.BackingField != null) {
5271 spec.MemberDefinition.SetIsUsed ();
5273 if (!ec.IsObsolete) {
5274 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5276 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5279 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5280 Error_AssignmentEventOnly (ec);
5282 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5284 InstanceExpression = null;
5286 return ml.ResolveMemberAccess (ec, left, original);
5290 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5291 Error_AssignmentEventOnly (ec);
5293 return base.ResolveMemberAccess (ec, left, original);
5296 public override Expression CreateExpressionTree (ResolveContext ec)
5298 throw new NotSupportedException ("ET");
5301 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5303 if (right_side == EmptyExpression.EventAddition) {
5304 op = spec.AccessorAdd;
5305 } else if (right_side == EmptyExpression.EventSubtraction) {
5306 op = spec.AccessorRemove;
5310 Error_AssignmentEventOnly (ec);
5314 op = CandidateToBaseOverride (ec, op);
5318 protected override Expression DoResolve (ResolveContext ec)
5320 eclass = ExprClass.EventAccess;
5321 type = spec.MemberType;
5323 ResolveInstanceExpression (ec);
5325 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5326 Error_CannotAssign (ec);
5329 DoBestMemberChecks (ec, spec);
5333 public override void Emit (EmitContext ec)
5335 throw new NotSupportedException ();
5336 //Error_CannotAssign ();
5339 #region IAssignMethod Members
5341 public void Emit (EmitContext ec, bool leave_copy)
5343 throw new NotImplementedException ();
5346 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5348 if (leave_copy || !prepare_for_load)
5349 throw new NotImplementedException ("EventExpr::EmitAssign");
5351 Arguments args = new Arguments (1);
5352 args.Add (new Argument (source));
5353 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5358 void Error_AssignmentEventOnly (ResolveContext ec)
5360 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5361 GetSignatureForError ());
5364 public void Error_CannotAssign (ResolveContext ec)
5366 ec.Report.Error (70, loc,
5367 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5368 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5371 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5373 name = name.Substring (0, name.LastIndexOf ('.'));
5374 base.Error_CannotCallAbstractBase (rc, name);
5377 public override string GetSignatureForError ()
5379 return TypeManager.CSharpSignature (spec);
5382 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5384 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5388 public class TemporaryVariableReference : VariableReference
5390 public class Declarator : Statement
5392 TemporaryVariableReference variable;
5394 public Declarator (TemporaryVariableReference variable)
5396 this.variable = variable;
5400 protected override void DoEmit (EmitContext ec)
5402 variable.li.CreateBuilder (ec);
5405 protected override void CloneTo (CloneContext clonectx, Statement target)
5413 public TemporaryVariableReference (LocalVariable li, Location loc)
5416 this.type = li.Type;
5420 public LocalVariable LocalInfo {
5426 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5428 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5429 return new TemporaryVariableReference (li, loc);
5432 public override Expression CreateExpressionTree (ResolveContext ec)
5434 throw new NotSupportedException ("ET");
5437 protected override Expression DoResolve (ResolveContext ec)
5439 eclass = ExprClass.Variable;
5442 // Don't capture temporary variables except when using
5443 // iterator redirection
5445 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5446 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5447 storey.CaptureLocalVariable (ec, li);
5453 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5455 return Resolve (ec);
5458 public override void Emit (EmitContext ec)
5460 li.CreateBuilder (ec);
5465 public void EmitAssign (EmitContext ec, Expression source)
5467 li.CreateBuilder (ec);
5469 EmitAssign (ec, source, false, false);
5472 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5474 return li.HoistedVariant;
5477 public override bool IsFixed {
5478 get { return true; }
5481 public override bool IsRef {
5482 get { return false; }
5485 public override string Name {
5486 get { throw new NotImplementedException (); }
5489 public override void SetHasAddressTaken ()
5491 throw new NotImplementedException ();
5494 protected override ILocalVariable Variable {
5498 public override VariableInfo VariableInfo {
5499 get { throw new NotImplementedException (); }
5504 /// Handles `var' contextual keyword; var becomes a keyword only
5505 /// if no type called var exists in a variable scope
5507 class VarExpr : SimpleName
5509 public VarExpr (Location loc)
5514 public bool InferType (ResolveContext ec, Expression right_side)
5517 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5519 type = right_side.Type;
5520 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5521 ec.Report.Error (815, loc,
5522 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5523 type.GetSignatureForError ());
5527 eclass = ExprClass.Variable;
5531 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5533 if (RootContext.Version < LanguageVersion.V_3)
5534 base.Error_TypeOrNamespaceNotFound (ec);
5536 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");