2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
16 using SLE = System.Linq.Expressions;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// The ExprClass class contains the is used to pass the
31 /// classification of an expression (value, variable, namespace,
32 /// type, method group, property access, event access, indexer access,
35 public enum ExprClass : byte {
51 /// This is used to tell Resolve in which types of expressions we're
55 public enum ResolveFlags {
56 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
59 // Returns a type expression.
62 // Returns a method group.
65 TypeParameter = 1 << 3,
67 // Mask of all the expression class flags.
68 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 // An expressions resolved as a direct variable reference
102 public interface IVariableReference : IFixedExpression
104 bool IsHoisted { get; }
106 VariableInfo VariableInfo { get; }
108 void SetHasAddressTaken ();
112 // Implemented by an expression which could be or is always
115 public interface IFixedExpression
117 bool IsFixed { get; }
121 /// Base class for expressions
123 public abstract class Expression {
124 public ExprClass eclass;
125 protected TypeSpec type;
126 protected Location loc;
128 public TypeSpec Type {
130 set { type = value; }
133 public Location Location {
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.type.IsAccessible (ec.CurrentType)) {
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, Constructor.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)
608 if (!member.IsAccessible (currentType))
612 // With runtime binder we can have a situation where queried type is inaccessible
613 // because it came via dynamic object, the check about inconsisted accessibility
614 // had no effect as the type was unknown during compilation
617 // private class N { }
619 // public dynamic Foo ()
625 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (currentType))
629 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
630 if (member is MethodSpec)
631 return new MethodGroupExpr (members, queried_type, loc);
633 if (!Invocation.IsMemberInvocable (member))
637 if (non_method == null || member is MethodSpec) {
639 } else if (currentType != null) {
640 ambig_non_method = member;
644 if (non_method != null) {
645 if (ambig_non_method != null && rc != null) {
646 rc.Report.SymbolRelatedToPreviousError (non_method);
647 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
648 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
649 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
652 if (non_method is MethodSpec)
653 return new MethodGroupExpr (members, queried_type, loc);
655 return ExprClassFromMemberInfo (non_method, loc);
658 if (members[0].DeclaringType.BaseType == null)
661 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
663 } while (members != null);
668 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
670 throw new NotImplementedException ();
673 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
675 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
679 /// Returns an expression that can be used to invoke operator true
680 /// on the expression if it exists.
682 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
684 return GetOperatorTrueOrFalse (ec, e, true, loc);
688 /// Returns an expression that can be used to invoke operator false
689 /// on the expression if it exists.
691 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
693 return GetOperatorTrueOrFalse (ec, e, false, loc);
696 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
698 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
699 var methods = MemberCache.GetUserOperator (e.type, op, false);
703 Arguments arguments = new Arguments (1);
704 arguments.Add (new Argument (e));
706 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
707 var oper = res.ResolveOperator (ec, ref arguments);
712 return new UserOperatorCall (oper, arguments, null, loc);
715 public virtual string ExprClassName
719 case ExprClass.Unresolved:
721 case ExprClass.Value:
723 case ExprClass.Variable:
725 case ExprClass.Namespace:
729 case ExprClass.MethodGroup:
730 return "method group";
731 case ExprClass.PropertyAccess:
732 return "property access";
733 case ExprClass.EventAccess:
734 return "event access";
735 case ExprClass.IndexerAccess:
736 return "indexer access";
737 case ExprClass.Nothing:
739 case ExprClass.TypeParameter:
740 return "type parameter";
742 throw new Exception ("Should not happen");
747 /// Reports that we were expecting `expr' to be of class `expected'
749 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
751 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
754 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
758 name = mc.GetSignatureForError ();
760 name = GetSignatureForError ();
762 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
763 name, was, expected);
766 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
768 string [] valid = new string [4];
771 if ((flags & ResolveFlags.VariableOrValue) != 0) {
772 valid [count++] = "variable";
773 valid [count++] = "value";
776 if ((flags & ResolveFlags.Type) != 0)
777 valid [count++] = "type";
779 if ((flags & ResolveFlags.MethodGroup) != 0)
780 valid [count++] = "method group";
783 valid [count++] = "unknown";
785 StringBuilder sb = new StringBuilder (valid [0]);
786 for (int i = 1; i < count - 1; i++) {
788 sb.Append (valid [i]);
791 sb.Append ("' or `");
792 sb.Append (valid [count - 1]);
795 ec.Report.Error (119, loc,
796 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
799 public static void UnsafeError (ResolveContext ec, Location loc)
801 UnsafeError (ec.Report, loc);
804 public static void UnsafeError (Report Report, Location loc)
806 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
811 // Returns the size of type `t' if known, otherwise, 0
813 public static int GetTypeSize (TypeSpec t)
815 if (t == TypeManager.int32_type ||
816 t == TypeManager.uint32_type ||
817 t == TypeManager.float_type)
819 else if (t == TypeManager.int64_type ||
820 t == TypeManager.uint64_type ||
821 t == TypeManager.double_type)
823 else if (t == TypeManager.byte_type ||
824 t == TypeManager.sbyte_type ||
825 t == TypeManager.bool_type)
827 else if (t == TypeManager.short_type ||
828 t == TypeManager.char_type ||
829 t == TypeManager.ushort_type)
831 else if (t == TypeManager.decimal_type)
837 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
839 ec.Report.SymbolRelatedToPreviousError (type);
840 if (ec.CurrentInitializerVariable != null) {
841 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
842 TypeManager.CSharpName (type), GetSignatureForError ());
844 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
845 GetSignatureForError ());
850 // Converts `source' to an int, uint, long or ulong.
852 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
854 if (source.type == InternalType.Dynamic) {
855 Arguments args = new Arguments (1);
856 args.Add (new Argument (source));
857 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
860 Expression converted;
862 using (ec.Set (ResolveContext.Options.CheckedScope)) {
863 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
864 if (converted == null)
865 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
866 if (converted == null)
867 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
868 if (converted == null)
869 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
871 if (converted == null) {
872 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
878 // Only positive constants are allowed at compile time
880 Constant c = converted as Constant;
881 if (c != null && c.IsNegative)
882 Error_NegativeArrayIndex (ec, source.loc);
884 // No conversion needed to array index
885 if (converted.Type == TypeManager.int32_type)
888 return new ArrayIndexCast (converted).Resolve (ec);
892 // Derived classes implement this method by cloning the fields that
893 // could become altered during the Resolve stage
895 // Only expressions that are created for the parser need to implement
898 protected virtual void CloneTo (CloneContext clonectx, Expression target)
900 throw new NotImplementedException (
902 "CloneTo not implemented for expression {0}", this.GetType ()));
906 // Clones an expression created by the parser.
908 // We only support expressions created by the parser so far, not
909 // expressions that have been resolved (many more classes would need
910 // to implement CloneTo).
912 // This infrastructure is here merely for Lambda expressions which
913 // compile the same code using different type values for the same
914 // arguments to find the correct overload
916 public virtual Expression Clone (CloneContext clonectx)
918 Expression cloned = (Expression) MemberwiseClone ();
919 CloneTo (clonectx, cloned);
925 // Implementation of expression to expression tree conversion
927 public abstract Expression CreateExpressionTree (ResolveContext ec);
929 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
931 return CreateExpressionFactoryCall (ec, name, null, args, loc);
934 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
936 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
939 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
941 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
944 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
946 var t = ec.Module.PredefinedTypes.Expression.Resolve (loc);
950 return new TypeExpression (t, loc);
954 // Implemented by all expressions which support conversion from
955 // compiler expression to invokable runtime expression. Used by
956 // dynamic C# binder.
958 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
960 throw new NotImplementedException ("MakeExpression for " + GetType ());
965 /// This is just a base class for expressions that can
966 /// appear on statements (invocations, object creation,
967 /// assignments, post/pre increment and decrement). The idea
968 /// being that they would support an extra Emition interface that
969 /// does not leave a result on the stack.
971 public abstract class ExpressionStatement : Expression {
973 public ExpressionStatement ResolveStatement (BlockContext ec)
975 Expression e = Resolve (ec);
979 ExpressionStatement es = e as ExpressionStatement;
981 Error_InvalidExpressionStatement (ec);
987 /// Requests the expression to be emitted in a `statement'
988 /// context. This means that no new value is left on the
989 /// stack after invoking this method (constrasted with
990 /// Emit that will always leave a value on the stack).
992 public abstract void EmitStatement (EmitContext ec);
994 public override void EmitSideEffect (EmitContext ec)
1001 /// This kind of cast is used to encapsulate the child
1002 /// whose type is child.Type into an expression that is
1003 /// reported to return "return_type". This is used to encapsulate
1004 /// expressions which have compatible types, but need to be dealt
1005 /// at higher levels with.
1007 /// For example, a "byte" expression could be encapsulated in one
1008 /// of these as an "unsigned int". The type for the expression
1009 /// would be "unsigned int".
1012 public abstract class TypeCast : Expression
1014 protected readonly Expression child;
1016 protected TypeCast (Expression child, TypeSpec return_type)
1018 eclass = child.eclass;
1019 loc = child.Location;
1024 public Expression Child {
1030 public override Expression CreateExpressionTree (ResolveContext ec)
1032 Arguments args = new Arguments (2);
1033 args.Add (new Argument (child.CreateExpressionTree (ec)));
1034 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1036 if (type.IsPointer || child.Type.IsPointer)
1037 Error_PointerInsideExpressionTree (ec);
1039 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1042 protected override Expression DoResolve (ResolveContext ec)
1044 // This should never be invoked, we are born in fully
1045 // initialized state.
1050 public override void Emit (EmitContext ec)
1055 public override SLE.Expression MakeExpression (BuilderContext ctx)
1058 return base.MakeExpression (ctx);
1060 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1061 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1062 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1066 protected override void CloneTo (CloneContext clonectx, Expression t)
1071 public override bool IsNull {
1072 get { return child.IsNull; }
1076 public class EmptyCast : TypeCast {
1077 EmptyCast (Expression child, TypeSpec target_type)
1078 : base (child, target_type)
1082 public static Expression Create (Expression child, TypeSpec type)
1084 Constant c = child as Constant;
1086 return new EmptyConstantCast (c, type);
1088 EmptyCast e = child as EmptyCast;
1090 return new EmptyCast (e.child, type);
1092 return new EmptyCast (child, type);
1095 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1097 child.EmitBranchable (ec, label, on_true);
1100 public override void EmitSideEffect (EmitContext ec)
1102 child.EmitSideEffect (ec);
1107 // Used for predefined class library user casts (no obsolete check, etc.)
1109 public class OperatorCast : TypeCast {
1110 MethodSpec conversion_operator;
1112 public OperatorCast (Expression child, TypeSpec target_type)
1113 : this (child, target_type, false)
1117 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1118 : base (child, target_type)
1120 conversion_operator = GetConversionOperator (find_explicit);
1121 if (conversion_operator == null)
1122 throw new InternalErrorException ("Outer conversion routine is out of sync");
1125 // Returns the implicit operator that converts from
1126 // 'child.Type' to our target type (type)
1127 MethodSpec GetConversionOperator (bool find_explicit)
1129 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1131 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1133 mi = MemberCache.GetUserOperator (type, op, true);
1136 foreach (MethodSpec oper in mi) {
1137 if (oper.ReturnType != type)
1140 if (oper.Parameters.Types [0] == child.Type)
1147 public override void Emit (EmitContext ec)
1150 ec.Emit (OpCodes.Call, conversion_operator);
1155 /// This is a numeric cast to a Decimal
1157 public class CastToDecimal : OperatorCast {
1158 public CastToDecimal (Expression child)
1159 : this (child, false)
1163 public CastToDecimal (Expression child, bool find_explicit)
1164 : base (child, TypeManager.decimal_type, find_explicit)
1170 /// This is an explicit numeric cast from a Decimal
1172 public class CastFromDecimal : TypeCast
1174 static Dictionary<TypeSpec, MethodSpec> operators;
1176 public CastFromDecimal (Expression child, TypeSpec return_type)
1177 : base (child, return_type)
1179 if (child.Type != TypeManager.decimal_type)
1180 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1183 // Returns the explicit operator that converts from an
1184 // express of type System.Decimal to 'type'.
1185 public Expression Resolve ()
1187 if (operators == null) {
1188 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1190 operators = new Dictionary<TypeSpec, MethodSpec> ();
1191 foreach (MethodSpec oper in all_oper) {
1192 AParametersCollection pd = oper.Parameters;
1193 if (pd.Types [0] == TypeManager.decimal_type)
1194 operators.Add (oper.ReturnType, oper);
1198 return operators.ContainsKey (type) ? this : null;
1201 public override void Emit (EmitContext ec)
1205 ec.Emit (OpCodes.Call, operators [type]);
1208 public static void Reset ()
1216 // Constant specialization of EmptyCast.
1217 // We need to special case this since an empty cast of
1218 // a constant is still a constant.
1220 public class EmptyConstantCast : Constant
1222 public Constant child;
1224 public EmptyConstantCast (Constant child, TypeSpec type)
1225 : base (child.Location)
1228 throw new ArgumentNullException ("child");
1231 this.eclass = child.eclass;
1235 public override string AsString ()
1237 return child.AsString ();
1240 public override object GetValue ()
1242 return child.GetValue ();
1245 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1247 if (child.Type == target_type)
1250 // FIXME: check that 'type' can be converted to 'target_type' first
1251 return child.ConvertExplicitly (in_checked_context, target_type);
1254 public override Expression CreateExpressionTree (ResolveContext ec)
1256 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1257 child.CreateExpressionTree (ec),
1258 new TypeOf (new TypeExpression (type, loc), loc));
1261 Error_PointerInsideExpressionTree (ec);
1263 return CreateExpressionFactoryCall (ec, "Convert", args);
1266 public override bool IsDefaultValue {
1267 get { return child.IsDefaultValue; }
1270 public override bool IsNegative {
1271 get { return child.IsNegative; }
1274 public override bool IsNull {
1275 get { return child.IsNull; }
1278 public override bool IsOneInteger {
1279 get { return child.IsOneInteger; }
1282 public override bool IsZeroInteger {
1283 get { return child.IsZeroInteger; }
1286 protected override Expression DoResolve (ResolveContext rc)
1291 public override void Emit (EmitContext ec)
1296 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1298 child.EmitBranchable (ec, label, on_true);
1300 // Only to make verifier happy
1301 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1302 ec.Emit (OpCodes.Unbox_Any, type);
1305 public override void EmitSideEffect (EmitContext ec)
1307 child.EmitSideEffect (ec);
1310 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1312 // FIXME: Do we need to check user conversions?
1313 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1315 return child.ConvertImplicitly (rc, target_type);
1320 /// This class is used to wrap literals which belong inside Enums
1322 public class EnumConstant : Constant
1324 public Constant Child;
1326 public EnumConstant (Constant child, TypeSpec enum_type)
1327 : base (child.Location)
1330 this.type = enum_type;
1333 protected EnumConstant (Location loc)
1338 protected override Expression DoResolve (ResolveContext rc)
1340 Child = Child.Resolve (rc);
1341 this.eclass = ExprClass.Value;
1345 public override void Emit (EmitContext ec)
1350 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1352 Child.EncodeAttributeValue (rc, enc, Child.Type);
1355 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1357 Child.EmitBranchable (ec, label, on_true);
1360 public override void EmitSideEffect (EmitContext ec)
1362 Child.EmitSideEffect (ec);
1365 public override string GetSignatureForError()
1367 return TypeManager.CSharpName (Type);
1370 public override object GetValue ()
1372 return Child.GetValue ();
1376 public override object GetTypedValue ()
1379 // The method can be used in dynamic context only (on closed types)
1381 // System.Enum.ToObject cannot be called on dynamic types
1382 // EnumBuilder has to be used, but we cannot use EnumBuilder
1383 // because it does not properly support generics
1385 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1389 public override string AsString ()
1391 return Child.AsString ();
1394 public EnumConstant Increment()
1396 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1399 public override bool IsDefaultValue {
1401 return Child.IsDefaultValue;
1405 public override bool IsZeroInteger {
1406 get { return Child.IsZeroInteger; }
1409 public override bool IsNegative {
1411 return Child.IsNegative;
1415 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1417 if (Child.Type == target_type)
1420 return Child.ConvertExplicitly (in_checked_context, target_type);
1423 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1425 if (this.type == type) {
1429 if (!Convert.ImplicitStandardConversionExists (this, type)){
1433 return Child.ConvertImplicitly (rc, type);
1438 /// This kind of cast is used to encapsulate Value Types in objects.
1440 /// The effect of it is to box the value type emitted by the previous
1443 public class BoxedCast : TypeCast {
1445 public BoxedCast (Expression expr, TypeSpec target_type)
1446 : base (expr, target_type)
1448 eclass = ExprClass.Value;
1451 protected override Expression DoResolve (ResolveContext ec)
1453 // This should never be invoked, we are born in fully
1454 // initialized state.
1459 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1461 enc.Encode (child.Type);
1462 child.EncodeAttributeValue (rc, enc, child.Type);
1465 public override void Emit (EmitContext ec)
1469 ec.Emit (OpCodes.Box, child.Type);
1472 public override void EmitSideEffect (EmitContext ec)
1474 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1475 // so, we need to emit the box+pop instructions in most cases
1476 if (TypeManager.IsStruct (child.Type) &&
1477 (type == TypeManager.object_type || type == TypeManager.value_type))
1478 child.EmitSideEffect (ec);
1480 base.EmitSideEffect (ec);
1484 public class UnboxCast : TypeCast {
1485 public UnboxCast (Expression expr, TypeSpec return_type)
1486 : base (expr, return_type)
1490 protected override Expression DoResolve (ResolveContext ec)
1492 // This should never be invoked, we are born in fully
1493 // initialized state.
1498 public override void Emit (EmitContext ec)
1502 ec.Emit (OpCodes.Unbox_Any, type);
1507 /// This is used to perform explicit numeric conversions.
1509 /// Explicit numeric conversions might trigger exceptions in a checked
1510 /// context, so they should generate the conv.ovf opcodes instead of
1513 public class ConvCast : TypeCast {
1514 public enum Mode : byte {
1515 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1517 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1518 U2_I1, U2_U1, U2_I2, U2_CH,
1519 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1520 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1521 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1522 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1523 CH_I1, CH_U1, CH_I2,
1524 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1525 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1531 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1532 : base (child, return_type)
1537 protected override Expression DoResolve (ResolveContext ec)
1539 // This should never be invoked, we are born in fully
1540 // initialized state.
1545 public override string ToString ()
1547 return String.Format ("ConvCast ({0}, {1})", mode, child);
1550 public override void Emit (EmitContext ec)
1554 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1556 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1557 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1558 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1559 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1560 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1562 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1563 case Mode.U1_CH: /* nothing */ break;
1565 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1566 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1567 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1568 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1569 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1570 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1572 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1573 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1574 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1575 case Mode.U2_CH: /* nothing */ break;
1577 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1578 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1579 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1580 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1581 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1582 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1583 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1585 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1586 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1587 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1588 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1589 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1590 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1592 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1593 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1594 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1595 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1596 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1597 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1598 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1599 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1600 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1602 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1603 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1604 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1605 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1606 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1607 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1608 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1609 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1610 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1612 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1613 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1614 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1616 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1617 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1618 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1619 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1620 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1621 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1622 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1623 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1624 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1626 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1627 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1628 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1629 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1631 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1632 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1633 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1634 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1635 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1637 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1641 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1642 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1643 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1644 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1645 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1647 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1648 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1650 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1651 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1652 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1653 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1654 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1655 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1657 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1659 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1660 case Mode.U2_CH: /* nothing */ break;
1662 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1663 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1664 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1665 case Mode.I4_U4: /* nothing */ break;
1666 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1667 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1668 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1670 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1671 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1672 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1673 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.U4_I4: /* nothing */ break;
1675 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1677 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1678 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1679 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1680 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1681 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1682 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1683 case Mode.I8_U8: /* nothing */ break;
1684 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1685 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1687 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1688 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1689 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1690 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1692 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1693 case Mode.U8_I8: /* nothing */ break;
1694 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1695 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1697 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1698 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1699 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1702 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1703 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1704 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1705 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1706 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1707 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1708 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1709 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1711 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1712 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1713 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1714 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1716 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1717 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1718 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1719 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1720 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1722 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1728 class OpcodeCast : TypeCast
1732 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1733 : base (child, return_type)
1738 protected override Expression DoResolve (ResolveContext ec)
1740 // This should never be invoked, we are born in fully
1741 // initialized state.
1746 public override void Emit (EmitContext ec)
1752 public TypeSpec UnderlyingType {
1753 get { return child.Type; }
1758 // Opcode casts expression with 2 opcodes but only
1759 // single expression tree node
1761 class OpcodeCastDuplex : OpcodeCast
1763 readonly OpCode second;
1765 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1766 : base (child, returnType, first)
1768 this.second = second;
1771 public override void Emit (EmitContext ec)
1779 /// This kind of cast is used to encapsulate a child and cast it
1780 /// to the class requested
1782 public sealed class ClassCast : TypeCast {
1783 readonly bool forced;
1785 public ClassCast (Expression child, TypeSpec return_type)
1786 : base (child, return_type)
1790 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1791 : base (child, return_type)
1793 this.forced = forced;
1796 public override void Emit (EmitContext ec)
1800 bool gen = TypeManager.IsGenericParameter (child.Type);
1802 ec.Emit (OpCodes.Box, child.Type);
1804 if (type.IsGenericParameter) {
1805 ec.Emit (OpCodes.Unbox_Any, type);
1812 ec.Emit (OpCodes.Castclass, type);
1817 // Created during resolving pahse when an expression is wrapped or constantified
1818 // and original expression can be used later (e.g. for expression trees)
1820 public class ReducedExpression : Expression
1822 sealed class ReducedConstantExpression : EmptyConstantCast
1824 readonly Expression orig_expr;
1826 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1827 : base (expr, expr.Type)
1829 this.orig_expr = orig_expr;
1832 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1834 Constant c = base.ConvertImplicitly (rc, target_type);
1836 c = new ReducedConstantExpression (c, orig_expr);
1841 public override Expression CreateExpressionTree (ResolveContext ec)
1843 return orig_expr.CreateExpressionTree (ec);
1846 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1848 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1850 c = new ReducedConstantExpression (c, orig_expr);
1855 sealed class ReducedExpressionStatement : ExpressionStatement
1857 readonly Expression orig_expr;
1858 readonly ExpressionStatement stm;
1860 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1862 this.orig_expr = orig;
1864 this.loc = orig.Location;
1867 public override Expression CreateExpressionTree (ResolveContext ec)
1869 return orig_expr.CreateExpressionTree (ec);
1872 protected override Expression DoResolve (ResolveContext ec)
1874 eclass = stm.eclass;
1879 public override void Emit (EmitContext ec)
1884 public override void EmitStatement (EmitContext ec)
1886 stm.EmitStatement (ec);
1890 readonly Expression expr, orig_expr;
1892 private ReducedExpression (Expression expr, Expression orig_expr)
1895 this.eclass = expr.eclass;
1896 this.type = expr.Type;
1897 this.orig_expr = orig_expr;
1898 this.loc = orig_expr.Location;
1903 public Expression OriginalExpression {
1912 // Creates fully resolved expression switcher
1914 public static Constant Create (Constant expr, Expression original_expr)
1916 if (expr.eclass == ExprClass.Unresolved)
1917 throw new ArgumentException ("Unresolved expression");
1919 return new ReducedConstantExpression (expr, original_expr);
1922 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1924 return new ReducedExpressionStatement (s, orig);
1928 // Creates unresolved reduce expression. The original expression has to be
1931 public static Expression Create (Expression expr, Expression original_expr)
1933 Constant c = expr as Constant;
1935 return Create (c, original_expr);
1937 ExpressionStatement s = expr as ExpressionStatement;
1939 return Create (s, original_expr);
1941 if (expr.eclass == ExprClass.Unresolved)
1942 throw new ArgumentException ("Unresolved expression");
1944 return new ReducedExpression (expr, original_expr);
1947 public override Expression CreateExpressionTree (ResolveContext ec)
1949 return orig_expr.CreateExpressionTree (ec);
1952 protected override Expression DoResolve (ResolveContext ec)
1957 public override void Emit (EmitContext ec)
1962 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1964 expr.EmitBranchable (ec, target, on_true);
1967 public override SLE.Expression MakeExpression (BuilderContext ctx)
1969 return orig_expr.MakeExpression (ctx);
1974 // Standard composite pattern
1976 public abstract class CompositeExpression : Expression
1980 protected CompositeExpression (Expression expr)
1983 this.loc = expr.Location;
1986 public override Expression CreateExpressionTree (ResolveContext ec)
1988 return expr.CreateExpressionTree (ec);
1991 public Expression Child {
1992 get { return expr; }
1995 protected override Expression DoResolve (ResolveContext ec)
1997 expr = expr.Resolve (ec);
2000 eclass = expr.eclass;
2006 public override void Emit (EmitContext ec)
2011 public override bool IsNull {
2012 get { return expr.IsNull; }
2017 // Base of expressions used only to narrow resolve flow
2019 public abstract class ShimExpression : Expression
2021 protected Expression expr;
2023 protected ShimExpression (Expression expr)
2028 protected override void CloneTo (CloneContext clonectx, Expression t)
2033 ShimExpression target = (ShimExpression) t;
2034 target.expr = expr.Clone (clonectx);
2037 public override Expression CreateExpressionTree (ResolveContext ec)
2039 throw new NotSupportedException ("ET");
2042 public override void Emit (EmitContext ec)
2044 throw new InternalErrorException ("Missing Resolve call");
2047 public Expression Expr {
2048 get { return expr; }
2053 // Unresolved type name expressions
2055 public abstract class ATypeNameExpression : FullNamedExpression
2058 protected TypeArguments targs;
2060 protected ATypeNameExpression (string name, Location l)
2066 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2073 protected ATypeNameExpression (string name, int arity, Location l)
2074 : this (name, new UnboundTypeArguments (arity), l)
2080 protected int Arity {
2082 return targs == null ? 0 : targs.Count;
2086 public bool HasTypeArguments {
2088 return targs != null && !targs.IsEmpty;
2092 public string Name {
2101 public TypeArguments TypeArguments {
2109 public override bool Equals (object obj)
2111 ATypeNameExpression atne = obj as ATypeNameExpression;
2112 return atne != null && atne.Name == Name &&
2113 (targs == null || targs.Equals (atne.targs));
2116 public override int GetHashCode ()
2118 return Name.GetHashCode ();
2121 // TODO: Move it to MemberCore
2122 public static string GetMemberType (MemberCore mc)
2128 if (mc is FieldBase)
2130 if (mc is MethodCore)
2132 if (mc is EnumMember)
2140 public override string GetSignatureForError ()
2142 if (targs != null) {
2143 return Name + "<" + targs.GetSignatureForError () + ">";
2149 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2153 /// SimpleName expressions are formed of a single word and only happen at the beginning
2154 /// of a dotted-name.
2156 public class SimpleName : ATypeNameExpression
2158 public SimpleName (string name, Location l)
2163 public SimpleName (string name, TypeArguments args, Location l)
2164 : base (name, args, l)
2168 public SimpleName (string name, int arity, Location l)
2169 : base (name, arity, l)
2173 public SimpleName GetMethodGroup ()
2175 return new SimpleName (Name, targs, loc);
2178 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2180 if (ec.CurrentType != null) {
2181 if (ec.CurrentMemberDefinition != null) {
2182 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2184 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2190 // TODO MemberCache: Implement
2192 string ns = ec.CurrentType.Namespace;
2193 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2194 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2195 var type = a.GetType (fullname);
2197 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2198 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2203 if (ec.CurrentTypeDefinition != null) {
2204 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2206 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2213 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2214 if (retval != null) {
2215 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2217 var te = retval as TypeExpr;
2218 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2219 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2221 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2226 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2229 protected override Expression DoResolve (ResolveContext ec)
2231 return SimpleNameResolve (ec, null, false);
2234 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2236 return SimpleNameResolve (ec, right_side, false);
2239 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2241 int errors = ec.Compiler.Report.Errors;
2242 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2245 if (fne.Type != null && Arity > 0) {
2246 if (HasTypeArguments) {
2247 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2248 return ct.ResolveAsTypeStep (ec, false);
2251 return new GenericOpenTypeExpr (fne.Type, loc);
2255 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2257 if (!(fne is Namespace))
2261 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2262 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2263 ec.Compiler.Report.Error (1980, Location,
2264 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2265 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2268 return new DynamicTypeExpr (loc);
2274 if (silent || errors != ec.Compiler.Report.Errors)
2277 Error_TypeOrNamespaceNotFound (ec);
2281 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2283 int lookup_arity = Arity;
2284 bool errorMode = false;
2286 Block current_block = rc.CurrentBlock;
2287 INamedBlockVariable variable = null;
2288 bool variable_found = false;
2292 // Stage 1: binding to local variables or parameters
2294 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2296 if (current_block != null && lookup_arity == 0) {
2297 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2298 if (!variable.IsDeclared) {
2299 // We found local name in accessible block but it's not
2300 // initialized yet, maybe the user wanted to bind to something else
2302 variable_found = true;
2304 e = variable.CreateReferenceExpression (rc, loc);
2307 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2316 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2318 TypeSpec member_type = rc.CurrentType;
2319 TypeSpec current_type = member_type;
2320 for (; member_type != null; member_type = member_type.DeclaringType) {
2321 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2325 var me = e as MemberExpr;
2327 // The name matches a type, defer to ResolveAsTypeStep
2335 if (variable != null) {
2336 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2337 rc.Report.Error (844, loc,
2338 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2339 Name, me.GetSignatureForError ());
2343 } else if (me is MethodGroupExpr) {
2344 // Leave it to overload resolution to report correct error
2346 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2347 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2350 // LAMESPEC: again, ignores InvocableOnly
2351 if (variable != null) {
2352 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2353 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2357 // MemberLookup does not check accessors availability, this is actually needed for properties only
2359 var pe = me as PropertyExpr;
2362 // Break as there is no other overload available anyway
2363 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2364 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2367 pe.Getter = pe.PropertyInfo.Get;
2369 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2372 pe.Setter = pe.PropertyInfo.Set;
2377 // TODO: It's used by EventExpr -> FieldExpr transformation only
2378 // TODO: Should go to MemberAccess
2379 me = me.ResolveMemberAccess (rc, null, null);
2383 me.SetTypeArguments (rc, targs);
2390 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2392 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2393 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2395 if (variable != null) {
2396 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2397 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2405 if (variable_found) {
2406 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2408 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2414 if (RootContext.EvalMode) {
2415 var fi = Evaluator.LookupField (Name);
2417 return new FieldExpr (fi.Item1, loc);
2421 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2426 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2428 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2433 if (right_side != null) {
2434 if (e is TypeExpr) {
2435 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2439 e = e.ResolveLValue (ec, right_side);
2444 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2450 /// Represents a namespace or a type. The name of the class was inspired by
2451 /// section 10.8.1 (Fully Qualified Names).
2453 public abstract class FullNamedExpression : Expression
2455 protected override void CloneTo (CloneContext clonectx, Expression target)
2457 // Do nothing, most unresolved type expressions cannot be
2458 // resolved to different type
2461 public override Expression CreateExpressionTree (ResolveContext ec)
2463 throw new NotSupportedException ("ET");
2466 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2471 public override void Emit (EmitContext ec)
2473 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2474 GetSignatureForError ());
2479 /// Expression that evaluates to a type
2481 public abstract class TypeExpr : FullNamedExpression {
2482 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2484 TypeExpr t = DoResolveAsTypeStep (ec);
2488 eclass = ExprClass.Type;
2492 protected override Expression DoResolve (ResolveContext ec)
2494 return ResolveAsTypeTerminal (ec, false);
2497 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2499 public override bool Equals (object obj)
2501 TypeExpr tobj = obj as TypeExpr;
2505 return Type == tobj.Type;
2508 public override int GetHashCode ()
2510 return Type.GetHashCode ();
2515 /// Fully resolved Expression that already evaluated to a type
2517 public class TypeExpression : TypeExpr {
2518 public TypeExpression (TypeSpec t, Location l)
2521 eclass = ExprClass.Type;
2525 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2530 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2537 /// This class denotes an expression which evaluates to a member
2538 /// of a struct or a class.
2540 public abstract class MemberExpr : Expression
2543 // An instance expression associated with this member, if it's a
2544 // non-static member
2546 public Expression InstanceExpression;
2549 /// The name of this member.
2551 public abstract string Name {
2556 // When base.member is used
2558 public bool IsBase {
2559 get { return InstanceExpression is BaseThis; }
2563 /// Whether this is an instance member.
2565 public abstract bool IsInstance {
2570 /// Whether this is a static member.
2572 public abstract bool IsStatic {
2577 protected abstract TypeSpec DeclaringType {
2582 // Converts best base candidate for virtual method starting from QueriedBaseType
2584 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2587 // Only when base.member is used and method is virtual
2593 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2594 // means for base.member access we have to find the closest match after we found best candidate
2596 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2598 // The method could already be what we are looking for
2600 TypeSpec[] targs = null;
2601 if (method.DeclaringType != InstanceExpression.Type) {
2602 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2603 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2604 if (base_override.IsGeneric)
2605 targs = method.TypeArguments;
2607 method = base_override;
2611 // TODO: For now we do it for any hoisted call even if it's needed for
2612 // hoisted stories only but that requires a new expression wrapper
2613 if (rc.CurrentAnonymousMethod != null) {
2614 if (targs == null && method.IsGeneric) {
2615 targs = method.TypeArguments;
2616 method = method.GetGenericMethodDefinition ();
2619 if (method.Parameters.HasArglist)
2620 throw new NotImplementedException ("__arglist base call proxy");
2622 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2624 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2625 // get/set member expressions second call would fail to proxy because left expression
2626 // would be of 'this' and not 'base'
2627 if (rc.CurrentType.IsStruct)
2628 InstanceExpression = new This (loc).Resolve (rc);
2632 method = method.MakeGenericMethod (targs);
2636 // Only base will allow this invocation to happen.
2638 if (method.IsAbstract) {
2639 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2645 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2647 if (InstanceExpression == null)
2650 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2651 var ct = rc.CurrentType;
2652 var expr_type = InstanceExpression.Type;
2653 if (ct != expr_type) {
2654 expr_type = expr_type.GetDefinition ();
2655 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2656 rc.Report.SymbolRelatedToPreviousError (member);
2657 rc.Report.Error (1540, loc,
2658 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2659 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2665 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2668 type = type.GetDefinition ();
2670 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2673 type = type.DeclaringType;
2674 } while (type != null);
2679 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2681 if (InstanceExpression != null) {
2682 InstanceExpression = InstanceExpression.Resolve (rc);
2683 CheckProtectedMemberAccess (rc, member);
2686 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2687 UnsafeError (rc, loc);
2690 if (!rc.IsObsolete) {
2691 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2693 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2696 if (!(member is FieldSpec))
2697 member.MemberDefinition.SetIsUsed ();
2700 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2702 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2706 // Implements identicial simple name and type-name
2708 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2711 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2714 // 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
2715 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2717 if (left is MemberExpr || left is VariableReference) {
2718 rc.Report.DisableReporting ();
2719 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2720 rc.Report.EnableReporting ();
2721 if (identical_type != null && identical_type.Type == left.Type)
2722 return identical_type;
2728 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2731 if (InstanceExpression != null) {
2732 if (InstanceExpression is TypeExpr) {
2733 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2734 if (oa != null && !rc.IsObsolete) {
2735 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2738 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2739 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2740 rc.Report.Error (176, loc,
2741 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2742 GetSignatureForError ());
2746 InstanceExpression = null;
2752 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2753 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2754 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2755 rc.Report.Error (236, loc,
2756 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2757 GetSignatureForError ());
2759 rc.Report.Error (120, loc,
2760 "An object reference is required to access non-static member `{0}'",
2761 GetSignatureForError ());
2766 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2767 rc.Report.Error (38, loc,
2768 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2769 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2772 InstanceExpression = new This (loc);
2773 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2774 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2775 InstanceExpression = InstanceExpression.Resolve (rc);
2778 InstanceExpression = InstanceExpression.Resolve (rc);
2784 var me = InstanceExpression as MemberExpr;
2786 me.ResolveInstanceExpression (rc, rhs);
2788 var fe = me as FieldExpr;
2789 if (fe != null && fe.IsMarshalByRefAccess ()) {
2790 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2791 rc.Report.Warning (1690, 1, loc,
2792 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2793 me.GetSignatureForError ());
2800 // Run member-access postponed check once we know that
2801 // the expression is not field expression which is the only
2802 // expression which can use uninitialized this
2804 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2805 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2809 // Additional checks for l-value member access
2813 // TODO: It should be recursive but that would break csc compatibility
2815 if (InstanceExpression is UnboxCast) {
2816 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2823 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2825 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2826 ec.Report.Warning (1720, 1, left.Location,
2827 "Expression will always cause a `{0}'", "System.NullReferenceException");
2830 InstanceExpression = left;
2834 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2836 TypeSpec instance_type = InstanceExpression.Type;
2837 if (TypeManager.IsValueType (instance_type)) {
2838 if (InstanceExpression is IMemoryLocation) {
2839 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2841 LocalTemporary t = new LocalTemporary (instance_type);
2842 InstanceExpression.Emit (ec);
2844 t.AddressOf (ec, AddressOp.Store);
2847 InstanceExpression.Emit (ec);
2849 // Only to make verifier happy
2850 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2851 ec.Emit (OpCodes.Box, instance_type);
2854 if (prepare_for_load)
2855 ec.Emit (OpCodes.Dup);
2858 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2862 // Represents a group of extension method candidates for whole namespace
2864 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2866 NamespaceEntry namespace_entry;
2867 public readonly Expression ExtensionExpression;
2869 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2870 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2872 this.namespace_entry = n;
2873 this.ExtensionExpression = extensionExpr;
2876 public override bool IsStatic {
2877 get { return true; }
2880 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2882 if (namespace_entry == null)
2886 // For extension methodgroup we are not looking for base members but parent
2887 // namespace extension methods
2889 int arity = type_arguments == null ? 0 : type_arguments.Count;
2890 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2894 return found.Cast<MemberSpec> ().ToList ();
2897 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2899 // We are already here
2903 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2905 if (arguments == null)
2906 arguments = new Arguments (1);
2908 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2909 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2911 // Store resolved argument and restore original arguments
2913 // Clean-up modified arguments for error reporting
2914 arguments.RemoveAt (0);
2918 var me = ExtensionExpression as MemberExpr;
2920 me.ResolveInstanceExpression (ec, null);
2922 InstanceExpression = null;
2926 #region IErrorHandler Members
2928 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2933 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2935 rc.Report.SymbolRelatedToPreviousError (best);
2936 rc.Report.Error (1928, loc,
2937 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2938 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2941 rc.Report.Error (1929, loc,
2942 "Extension method instance type `{0}' cannot be converted to `{1}'",
2943 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2949 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2954 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2963 /// MethodGroupExpr represents a group of method candidates which
2964 /// can be resolved to the best method overload
2966 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2968 protected IList<MemberSpec> Methods;
2969 MethodSpec best_candidate;
2970 TypeSpec best_candidate_return;
2971 protected TypeArguments type_arguments;
2973 SimpleName simple_name;
2974 protected TypeSpec queried_type;
2976 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2980 this.type = InternalType.MethodGroup;
2982 eclass = ExprClass.MethodGroup;
2983 queried_type = type;
2986 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2987 : this (new MemberSpec[] { m }, type, loc)
2993 public MethodSpec BestCandidate {
2995 return best_candidate;
2999 public TypeSpec BestCandidateReturnType {
3001 return best_candidate_return;
3005 protected override TypeSpec DeclaringType {
3007 return queried_type;
3011 public override bool IsInstance {
3013 if (best_candidate != null)
3014 return !best_candidate.IsStatic;
3020 public override bool IsStatic {
3022 if (best_candidate != null)
3023 return best_candidate.IsStatic;
3029 public override string Name {
3031 if (best_candidate != null)
3032 return best_candidate.Name;
3035 return Methods.First ().Name;
3042 // When best candidate is already know this factory can be used
3043 // to avoid expensive overload resolution to be called
3045 // NOTE: InstanceExpression has to be set manually
3047 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3049 return new MethodGroupExpr (best, queriedType, loc) {
3050 best_candidate = best,
3051 best_candidate_return = best.ReturnType
3055 public override string GetSignatureForError ()
3057 if (best_candidate != null)
3058 return best_candidate.GetSignatureForError ();
3060 return Methods.First ().GetSignatureForError ();
3063 public override Expression CreateExpressionTree (ResolveContext ec)
3065 if (best_candidate == null) {
3066 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3070 if (best_candidate.IsConditionallyExcluded (loc))
3071 ec.Report.Error (765, loc,
3072 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3074 return new TypeOfMethod (best_candidate, loc);
3077 protected override Expression DoResolve (ResolveContext ec)
3079 this.eclass = ExprClass.MethodGroup;
3081 if (InstanceExpression != null) {
3082 InstanceExpression = InstanceExpression.Resolve (ec);
3083 if (InstanceExpression == null)
3090 public override void Emit (EmitContext ec)
3092 throw new NotSupportedException ();
3095 public void EmitCall (EmitContext ec, Arguments arguments)
3097 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3100 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3102 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3103 Name, TypeManager.CSharpName (target));
3106 public static bool IsExtensionMethodArgument (Expression expr)
3109 // LAMESPEC: No details about which expressions are not allowed
3111 return !(expr is TypeExpr) && !(expr is BaseThis);
3115 /// Find the Applicable Function Members (7.4.2.1)
3117 /// me: Method Group expression with the members to select.
3118 /// it might contain constructors or methods (or anything
3119 /// that maps to a method).
3121 /// Arguments: ArrayList containing resolved Argument objects.
3123 /// loc: The location if we want an error to be reported, or a Null
3124 /// location for "probing" purposes.
3126 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3127 /// that is the best match of me on Arguments.
3130 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3132 // TODO: causes issues with probing mode, remove explicit Kind check
3133 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3136 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3137 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3138 r.BaseMembersProvider = this;
3141 if (cerrors != null)
3142 r.CustomErrors = cerrors;
3144 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3145 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3146 if (best_candidate == null)
3147 return r.BestCandidateIsDynamic ? this : null;
3149 // Overload resolver had to create a new method group, all checks bellow have already been executed
3150 if (r.BestCandidateNewMethodGroup != null)
3151 return r.BestCandidateNewMethodGroup;
3153 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3154 if (InstanceExpression != null) {
3155 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3156 InstanceExpression = null;
3158 if (best_candidate.IsStatic && simple_name != null) {
3159 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3162 InstanceExpression.Resolve (ec);
3166 ResolveInstanceExpression (ec, null);
3167 if (InstanceExpression != null)
3168 CheckProtectedMemberAccess (ec, best_candidate);
3171 var base_override = CandidateToBaseOverride (ec, best_candidate);
3172 if (base_override == best_candidate) {
3173 best_candidate_return = r.BestCandidateReturnType;
3175 best_candidate = base_override;
3176 best_candidate_return = best_candidate.ReturnType;
3182 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3184 simple_name = original;
3185 return base.ResolveMemberAccess (ec, left, original);
3188 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3190 type_arguments = ta;
3193 #region IBaseMembersProvider Members
3195 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3197 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3200 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3202 if (queried_type == member.DeclaringType)
3205 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3206 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3210 // Extension methods lookup after ordinary methods candidates failed to apply
3212 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3214 if (InstanceExpression == null)
3217 InstanceExpression = InstanceExpression.Resolve (rc);
3218 if (!IsExtensionMethodArgument (InstanceExpression))
3221 int arity = type_arguments == null ? 0 : type_arguments.Count;
3222 NamespaceEntry methods_scope = null;
3223 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3224 if (methods == null)
3227 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3228 emg.SetTypeArguments (rc, type_arguments);
3235 public struct OverloadResolver
3238 public enum Restrictions
3242 ProbingOnly = 1 << 1,
3243 CovariantDelegate = 1 << 2,
3244 NoBaseMembers = 1 << 3,
3245 BaseMembersIncluded = 1 << 4
3248 public interface IBaseMembersProvider
3250 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3251 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3252 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3255 public interface IErrorHandler
3257 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3258 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3259 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3260 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3263 sealed class NoBaseMembers : IBaseMembersProvider
3265 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3267 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3272 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3277 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3283 struct AmbiguousCandidate
3285 public readonly MemberSpec Member;
3286 public readonly bool Expanded;
3287 public readonly AParametersCollection Parameters;
3289 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3292 Parameters = parameters;
3293 Expanded = expanded;
3298 IList<MemberSpec> members;
3299 TypeArguments type_arguments;
3300 IBaseMembersProvider base_provider;
3301 IErrorHandler custom_errors;
3302 Restrictions restrictions;
3303 MethodGroupExpr best_candidate_extension_group;
3304 TypeSpec best_candidate_return_type;
3306 SessionReportPrinter lambda_conv_msgs;
3307 ReportPrinter prev_recorder;
3309 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3310 : this (members, null, restrictions, loc)
3314 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3317 if (members == null || members.Count == 0)
3318 throw new ArgumentException ("empty members set");
3320 this.members = members;
3322 type_arguments = targs;
3323 this.restrictions = restrictions;
3324 if (IsDelegateInvoke)
3325 this.restrictions |= Restrictions.NoBaseMembers;
3327 base_provider = NoBaseMembers.Instance;
3332 public IBaseMembersProvider BaseMembersProvider {
3334 return base_provider;
3337 base_provider = value;
3341 public bool BestCandidateIsDynamic { get; set; }
3344 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3346 public MethodGroupExpr BestCandidateNewMethodGroup {
3348 return best_candidate_extension_group;
3353 // Return type can be different between best candidate and closest override
3355 public TypeSpec BestCandidateReturnType {
3357 return best_candidate_return_type;
3361 public IErrorHandler CustomErrors {
3363 return custom_errors;
3366 custom_errors = value;
3370 TypeSpec DelegateType {
3372 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3373 throw new InternalErrorException ("Not running in delegate mode", loc);
3375 return members [0].DeclaringType;
3379 bool IsProbingOnly {
3381 return (restrictions & Restrictions.ProbingOnly) != 0;
3385 bool IsDelegateInvoke {
3387 return (restrictions & Restrictions.DelegateInvoke) != 0;
3394 // 7.4.3.3 Better conversion from expression
3395 // Returns : 1 if a->p is better,
3396 // 2 if a->q is better,
3397 // 0 if neither is better
3399 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3401 TypeSpec argument_type = a.Type;
3402 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3404 // Uwrap delegate from Expression<T>
3406 if (p.GetDefinition () == TypeManager.expression_type) {
3407 p = TypeManager.GetTypeArguments (p)[0];
3409 if (q.GetDefinition () == TypeManager.expression_type) {
3410 q = TypeManager.GetTypeArguments (q)[0];
3413 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3414 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3415 if (p == TypeManager.void_type && q != TypeManager.void_type)
3417 if (q == TypeManager.void_type && p != TypeManager.void_type)
3420 if (argument_type == p)
3423 if (argument_type == q)
3427 return BetterTypeConversion (ec, p, q);
3431 // 7.4.3.4 Better conversion from type
3433 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3435 if (p == null || q == null)
3436 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3438 if (p == TypeManager.int32_type) {
3439 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3441 } else if (p == TypeManager.int64_type) {
3442 if (q == TypeManager.uint64_type)
3444 } else if (p == TypeManager.sbyte_type) {
3445 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3446 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3448 } else if (p == TypeManager.short_type) {
3449 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3450 q == TypeManager.uint64_type)
3452 } else if (p == InternalType.Dynamic) {
3453 // Dynamic is never better
3457 if (q == TypeManager.int32_type) {
3458 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3460 } if (q == TypeManager.int64_type) {
3461 if (p == TypeManager.uint64_type)
3463 } else if (q == TypeManager.sbyte_type) {
3464 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3465 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3467 } if (q == TypeManager.short_type) {
3468 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3469 p == TypeManager.uint64_type)
3471 } else if (q == InternalType.Dynamic) {
3472 // Dynamic is never better
3476 // FIXME: handle lifted operators
3478 // TODO: this is expensive
3479 Expression p_tmp = new EmptyExpression (p);
3480 Expression q_tmp = new EmptyExpression (q);
3482 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3483 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3485 if (p_to_q && !q_to_p)
3488 if (q_to_p && !p_to_q)
3495 /// Determines "Better function" between candidate
3496 /// and the current best match
3499 /// Returns a boolean indicating :
3500 /// false if candidate ain't better
3501 /// true if candidate is better than the current best match
3503 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3504 MemberSpec best, AParametersCollection bparam, bool best_params)
3506 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3507 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3509 bool better_at_least_one = false;
3511 int args_count = args == null ? 0 : args.Count;
3515 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3518 // Default arguments are ignored for better decision
3519 if (a.IsDefaultArgument)
3523 // When comparing named argument the parameter type index has to be looked up
3524 // in original parameter set (override version for virtual members)
3526 NamedArgument na = a as NamedArgument;
3528 int idx = cparam.GetParameterIndexByName (na.Name);
3529 ct = candidate_pd.Types[idx];
3530 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3531 ct = TypeManager.GetElementType (ct);
3533 idx = bparam.GetParameterIndexByName (na.Name);
3534 bt = best_pd.Types[idx];
3535 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3536 bt = TypeManager.GetElementType (bt);
3538 ct = candidate_pd.Types[c_idx];
3539 bt = best_pd.Types[b_idx];
3541 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3542 ct = TypeManager.GetElementType (ct);
3546 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3547 bt = TypeManager.GetElementType (bt);
3552 if (TypeSpecComparer.IsEqual (ct, bt))
3556 int result = BetterExpressionConversion (ec, a, ct, bt);
3558 // for each argument, the conversion to 'ct' should be no worse than
3559 // the conversion to 'bt'.
3563 // for at least one argument, the conversion to 'ct' should be better than
3564 // the conversion to 'bt'.
3566 better_at_least_one = true;
3569 if (better_at_least_one)
3573 // This handles the case
3575 // Add (float f1, float f2, float f3);
3576 // Add (params decimal [] foo);
3578 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3579 // first candidate would've chosen as better.
3581 if (!same && !a.IsDefaultArgument)
3585 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3589 // This handles the following cases:
3591 // Foo (int i) is better than Foo (int i, long l = 0)
3592 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3594 // Prefer non-optional version
3596 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3598 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3599 if (candidate_pd.Count >= best_pd.Count)
3602 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3609 // One is a non-generic method and second is a generic method, then non-generic is better
3611 if (best.IsGeneric != candidate.IsGeneric)
3612 return best.IsGeneric;
3615 // This handles the following cases:
3617 // Trim () is better than Trim (params char[] chars)
3618 // Concat (string s1, string s2, string s3) is better than
3619 // Concat (string s1, params string [] srest)
3620 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3622 // Prefer non-expanded version
3624 if (candidate_params != best_params)
3627 int candidate_param_count = candidate_pd.Count;
3628 int best_param_count = best_pd.Count;
3630 if (candidate_param_count != best_param_count)
3631 // can only happen if (candidate_params && best_params)
3632 return candidate_param_count > best_param_count && best_pd.HasParams;
3635 // Both methods have the same number of parameters, and the parameters have equal types
3636 // Pick the "more specific" signature using rules over original (non-inflated) types
3638 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3639 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3641 bool specific_at_least_once = false;
3642 for (j = 0; j < candidate_param_count; ++j) {
3643 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3645 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3646 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3648 ct = candidate_def_pd.Types[j];
3649 bt = best_def_pd.Types[j];
3654 TypeSpec specific = MoreSpecific (ct, bt);
3658 specific_at_least_once = true;
3661 if (specific_at_least_once)
3667 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3669 rc.Report.Error (1729, loc,
3670 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3671 type.GetSignatureForError (), argCount.ToString ());
3675 // Determines if the candidate method is applicable to the given set of arguments
3676 // There could be two different set of parameters for same candidate where one
3677 // is the closest override for default values and named arguments checks and second
3678 // one being the virtual base for the parameter types and modifiers.
3680 // A return value rates candidate method compatibility,
3681 // 0 = the best, int.MaxValue = the worst
3683 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
3685 var pd = pm.Parameters;
3686 int param_count = pd.Count;
3687 int optional_count = 0;
3689 Arguments orig_args = arguments;
3691 if (arg_count != param_count) {
3692 for (int i = 0; i < pd.Count; ++i) {
3693 if (pd.FixedParameters[i].HasDefaultValue) {
3694 optional_count = pd.Count - i;
3699 int args_gap = System.Math.Abs (arg_count - param_count);
3700 if (optional_count != 0) {
3701 if (args_gap > optional_count)
3702 return int.MaxValue - 10000 + args_gap - optional_count;
3704 // Readjust expected number when params used
3707 if (arg_count < param_count)
3709 } else if (arg_count > param_count) {
3710 return int.MaxValue - 10000 + args_gap;
3712 } else if (arg_count != param_count) {
3714 return int.MaxValue - 10000 + args_gap;
3715 if (arg_count < param_count - 1)
3716 return int.MaxValue - 10000 + args_gap;
3719 // Resize to fit optional arguments
3720 if (optional_count != 0) {
3721 if (arguments == null) {
3722 arguments = new Arguments (optional_count);
3724 // Have to create a new container, so the next run can do same
3725 var resized = new Arguments (param_count);
3726 resized.AddRange (arguments);
3727 arguments = resized;
3730 for (int i = arg_count; i < param_count; ++i)
3731 arguments.Add (null);
3735 if (arg_count > 0) {
3737 // Shuffle named arguments to the right positions if there are any
3739 if (arguments[arg_count - 1] is NamedArgument) {
3740 arg_count = arguments.Count;
3742 for (int i = 0; i < arg_count; ++i) {
3743 bool arg_moved = false;
3745 NamedArgument na = arguments[i] as NamedArgument;
3749 int index = pd.GetParameterIndexByName (na.Name);
3751 // Named parameter not found
3755 // already reordered
3760 if (index >= param_count) {
3761 // When using parameters which should not be available to the user
3762 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3765 arguments.Add (null);
3769 temp = arguments[index];
3771 // The slot has been taken by positional argument
3772 if (temp != null && !(temp is NamedArgument))
3777 arguments = arguments.MarkOrderedArgument (na);
3781 arguments[index] = arguments[i];
3782 arguments[i] = temp;
3789 arg_count = arguments.Count;
3791 } else if (arguments != null) {
3792 arg_count = arguments.Count;
3796 // 1. Handle generic method using type arguments when specified or type inference
3798 var ms = candidate as MethodSpec;
3799 if (ms != null && ms.IsGeneric) {
3800 // Setup constraint checker for probing only
3801 ConstraintChecker cc = new ConstraintChecker (null);
3803 if (type_arguments != null) {
3804 var g_args_count = ms.Arity;
3805 if (g_args_count != type_arguments.Count)
3806 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3808 ms = ms.MakeGenericMethod (type_arguments.Arguments);
3810 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3811 // for now it simplifies things. I should probably add a callback to ResolveContext
3812 if (lambda_conv_msgs == null) {
3813 lambda_conv_msgs = new SessionReportPrinter ();
3814 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3817 var ti = new TypeInference (arguments);
3818 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3819 lambda_conv_msgs.EndSession ();
3822 return ti.InferenceScore - 20000;
3824 if (i_args.Length != 0) {
3825 ms = ms.MakeGenericMethod (i_args);
3828 cc.IgnoreInferredDynamic = true;
3832 // Type arguments constraints have to match for the method to be applicable
3834 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3836 return int.MaxValue - 25000;
3840 // We have a generic return type and at same time the method is override which
3841 // means we have to also inflate override return type in case the candidate is
3842 // best candidate and override return type is different to base return type.
3844 // virtual Foo<T, object> with override Foo<T, dynamic>
3846 if (candidate != pm) {
3847 MethodSpec override_ms = (MethodSpec) pm;
3848 var inflator = new TypeParameterInflator (ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3849 returnType = inflator.Inflate (returnType);
3851 returnType = ms.ReturnType;
3857 if (type_arguments != null)
3858 return int.MaxValue - 15000;
3862 // 2. Each argument has to be implicitly convertible to method parameter
3864 Parameter.Modifier p_mod = 0;
3866 TypeSpec[] ptypes = ((IParametersMember) candidate).Parameters.Types;
3868 for (int i = 0; i < arg_count; i++) {
3869 Argument a = arguments[i];
3871 if (!pd.FixedParameters[i].HasDefaultValue) {
3872 arguments = orig_args;
3873 return arg_count * 2 + 2;
3877 // Get the default value expression, we can use the same expression
3878 // if the type matches
3880 Expression e = pd.FixedParameters[i].DefaultValue;
3881 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3883 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3885 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3886 e = new MemberAccess (new MemberAccess (new MemberAccess (
3887 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3889 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3895 arguments[i] = new Argument (e, Argument.AType.Default);
3899 if (p_mod != Parameter.Modifier.PARAMS) {
3900 p_mod = pd.FixedParameters[i].ModFlags;
3902 } else if (!params_expanded_form) {
3903 params_expanded_form = true;
3904 pt = ((ElementTypeSpec) pt).Element;
3910 if (!params_expanded_form) {
3911 if (a.ArgType == Argument.AType.ExtensionType) {
3913 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3916 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3917 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3918 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3923 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3926 dynamicArgument = true;
3931 // It can be applicable in expanded form (when not doing exact match like for delegates)
3933 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3934 if (!params_expanded_form)
3935 pt = ((ElementTypeSpec) pt).Element;
3938 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3941 params_expanded_form = true;
3942 } else if (score < 0) {
3943 params_expanded_form = true;
3944 dynamicArgument = true;
3949 if (params_expanded_form)
3951 return (arg_count - i) * 2 + score;
3956 // When params parameter has no argument it will be provided later if the method is the best candidate
3958 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3959 params_expanded_form = true;
3962 // Restore original arguments for dynamic binder to keep the intention of original source code
3964 if (dynamicArgument)
3965 arguments = orig_args;
3971 // Tests argument compatibility with the parameter
3972 // The possible return values are
3974 // 1 - modifier mismatch
3975 // 2 - type mismatch
3976 // -1 - dynamic binding required
3978 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3981 // Types have to be identical when ref or out modifer
3982 // is used and argument is not of dynamic type
3984 if ((argument.Modifier | param_mod) != 0) {
3985 if (argument.Type != parameter) {
3987 // Do full equality check after quick path
3989 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
3991 // Using dynamic for ref/out parameter can still succeed at runtime
3993 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4000 if (argument.Modifier != param_mod) {
4002 // Using dynamic for ref/out parameter can still succeed at runtime
4004 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4011 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4015 // Deploy custom error reporting for lambda methods. When probing lambda methods
4016 // keep all errors reported in separate set and once we are done and no best
4017 // candidate found, this set is used to report more details about what was wrong
4020 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4021 if (lambda_conv_msgs == null) {
4022 lambda_conv_msgs = new SessionReportPrinter ();
4023 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4027 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4028 if (lambda_conv_msgs != null) {
4029 lambda_conv_msgs.EndSession ();
4039 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4041 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4043 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4046 var ac_p = p as ArrayContainer;
4048 var ac_q = ((ArrayContainer) q);
4049 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4050 if (specific == ac_p.Element)
4052 if (specific == ac_q.Element)
4054 } else if (TypeManager.IsGenericType (p)) {
4055 var pargs = TypeManager.GetTypeArguments (p);
4056 var qargs = TypeManager.GetTypeArguments (q);
4058 bool p_specific_at_least_once = false;
4059 bool q_specific_at_least_once = false;
4061 for (int i = 0; i < pargs.Length; i++) {
4062 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4063 if (specific == pargs[i])
4064 p_specific_at_least_once = true;
4065 if (specific == qargs[i])
4066 q_specific_at_least_once = true;
4069 if (p_specific_at_least_once && !q_specific_at_least_once)
4071 if (!p_specific_at_least_once && q_specific_at_least_once)
4079 // Find the best method from candidate list
4081 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4083 List<AmbiguousCandidate> ambiguous_candidates = null;
4085 MemberSpec best_candidate;
4086 Arguments best_candidate_args = null;
4087 bool best_candidate_params = false;
4088 bool best_candidate_dynamic = false;
4089 int best_candidate_rate;
4090 IParametersMember best_parameter_member = null;
4092 int args_count = args != null ? args.Count : 0;
4094 Arguments candidate_args = args;
4095 bool error_mode = false;
4096 var current_type = rc.CurrentType;
4097 MemberSpec invocable_member = null;
4099 // Be careful, cannot return until error reporter is restored
4101 best_candidate = null;
4102 best_candidate_rate = int.MaxValue;
4104 var type_members = members;
4108 for (int i = 0; i < type_members.Count; ++i) {
4109 var member = type_members[i];
4112 // Methods in a base class are not candidates if any method in a derived
4113 // class is applicable
4115 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4119 if (!member.IsAccessible (current_type))
4122 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4126 IParametersMember pm = member as IParametersMember;
4129 // Will use it later to report ambiguity between best method and invocable member
4131 if (Invocation.IsMemberInvocable (member))
4132 invocable_member = member;
4138 // Overload resolution is looking for base member but using parameter names
4139 // and default values from the closest member. That means to do expensive lookup
4140 // for the closest override for virtual or abstract members
4142 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4143 var override_params = base_provider.GetOverrideMemberParameters (member);
4144 if (override_params != null)
4145 pm = override_params;
4149 // Check if the member candidate is applicable
4151 bool params_expanded_form = false;
4152 bool dynamic_argument = false;
4153 TypeSpec rt = pm.MemberType;
4154 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4157 // How does it score compare to others
4159 if (candidate_rate < best_candidate_rate) {
4160 best_candidate_rate = candidate_rate;
4161 best_candidate = member;
4162 best_candidate_args = candidate_args;
4163 best_candidate_params = params_expanded_form;
4164 best_candidate_dynamic = dynamic_argument;
4165 best_parameter_member = pm;
4166 best_candidate_return_type = rt;
4167 } else if (candidate_rate == 0) {
4169 // The member look is done per type for most operations but sometimes
4170 // it's not possible like for binary operators overload because they
4171 // are unioned between 2 sides
4173 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4174 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4179 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4181 // We pack all interface members into top level type which makes the overload resolution
4182 // more complicated for interfaces. We accomodate for this by removing methods with same
4183 // signature when building the cache hence this path should not really be hit often
4186 // interface IA { void Foo (int arg); }
4187 // interface IB : IA { void Foo (params int[] args); }
4189 // IB::Foo is the best overload when calling IB.Foo (1)
4192 if (ambiguous_candidates != null) {
4193 foreach (var amb_cand in ambiguous_candidates) {
4194 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4203 ambiguous_candidates = null;
4206 // Is the new candidate better
4207 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4211 best_candidate = member;
4212 best_candidate_args = candidate_args;
4213 best_candidate_params = params_expanded_form;
4214 best_candidate_dynamic = dynamic_argument;
4215 best_parameter_member = pm;
4216 best_candidate_return_type = rt;
4218 // It's not better but any other found later could be but we are not sure yet
4219 if (ambiguous_candidates == null)
4220 ambiguous_candidates = new List<AmbiguousCandidate> ();
4222 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4226 // Restore expanded arguments
4227 if (candidate_args != args)
4228 candidate_args = args;
4230 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4232 if (prev_recorder != null)
4233 rc.Report.SetPrinter (prev_recorder);
4237 // We've found exact match
4239 if (best_candidate_rate == 0)
4243 // Try extension methods lookup when no ordinary method match was found and provider enables it
4246 var emg = base_provider.LookupExtensionMethod (rc);
4248 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4250 best_candidate_extension_group = emg;
4251 return (T) (MemberSpec) emg.BestCandidate;
4256 // Don't run expensive error reporting mode for probing
4263 lambda_conv_msgs = null;
4268 // No best member match found, report an error
4270 if (best_candidate_rate != 0 || error_mode) {
4271 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4275 if (best_candidate_dynamic) {
4276 if (args[0].ArgType == Argument.AType.ExtensionType) {
4277 rc.Report.Error (1973, loc,
4278 "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",
4279 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4282 BestCandidateIsDynamic = true;
4286 if (ambiguous_candidates != null) {
4288 // Now check that there are no ambiguities i.e the selected method
4289 // should be better than all the others
4291 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4292 var candidate = ambiguous_candidates [ix];
4294 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4295 var ambiguous = candidate.Member;
4296 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4297 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4298 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4299 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4300 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4303 return (T) best_candidate;
4308 if (invocable_member != null) {
4309 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4310 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4311 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4312 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4316 // And now check if the arguments are all
4317 // compatible, perform conversions if
4318 // necessary etc. and return if everything is
4321 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4324 if (best_candidate == null)
4328 // Check ObsoleteAttribute on the best method
4330 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4331 if (oa != null && !rc.IsObsolete)
4332 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4334 best_candidate.MemberDefinition.SetIsUsed ();
4336 args = best_candidate_args;
4337 return (T) best_candidate;
4340 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4342 return ResolveMember<MethodSpec> (rc, ref args);
4345 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4346 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4348 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4351 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4352 ec.Report.SymbolRelatedToPreviousError (method);
4353 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4354 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4355 TypeManager.CSharpSignature (method));
4358 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4359 TypeManager.CSharpSignature (method));
4360 } else if (IsDelegateInvoke) {
4361 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4362 DelegateType.GetSignatureForError ());
4364 ec.Report.SymbolRelatedToPreviousError (method);
4365 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4366 method.GetSignatureForError ());
4369 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4371 string index = (idx + 1).ToString ();
4372 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4373 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4374 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4375 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4376 index, Parameter.GetModifierSignature (a.Modifier));
4378 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4379 index, Parameter.GetModifierSignature (mod));
4381 string p1 = a.GetSignatureForError ();
4382 string p2 = TypeManager.CSharpName (paramType);
4385 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4386 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4387 ec.Report.SymbolRelatedToPreviousError (paramType);
4390 ec.Report.Error (1503, loc,
4391 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4396 // We have failed to find exact match so we return error info about the closest match
4398 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4400 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4401 int arg_count = args == null ? 0 : args.Count;
4403 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4404 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4405 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4409 if (lambda_conv_msgs != null) {
4410 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4415 // For candidates which match on parameters count report more details about incorrect arguments
4418 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4419 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4420 // Reject any inaccessible member
4421 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4422 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4423 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4427 var ms = best_candidate as MethodSpec;
4428 if (ms != null && ms.IsGeneric) {
4429 bool constr_ok = true;
4430 if (ms.TypeArguments != null)
4431 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4433 if (ta_count == 0) {
4434 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4438 rc.Report.Error (411, loc,
4439 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4440 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4447 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4453 // We failed to find any method with correct argument count, report best candidate
4455 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4458 if (best_candidate.Kind == MemberKind.Constructor) {
4459 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4460 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4461 } else if (IsDelegateInvoke) {
4462 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4463 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4464 DelegateType.GetSignatureForError (), arg_count.ToString ());
4466 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4467 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4468 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4469 name, arg_count.ToString ());
4473 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4475 var pd = pm.Parameters;
4476 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4478 Parameter.Modifier p_mod = 0;
4480 int a_idx = 0, a_pos = 0;
4482 ArrayInitializer params_initializers = null;
4483 bool has_unsafe_arg = pm.MemberType.IsPointer;
4484 int arg_count = args == null ? 0 : args.Count;
4486 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4488 if (p_mod != Parameter.Modifier.PARAMS) {
4489 p_mod = pd.FixedParameters[a_idx].ModFlags;
4491 has_unsafe_arg |= pt.IsPointer;
4493 if (p_mod == Parameter.Modifier.PARAMS) {
4494 if (chose_params_expanded) {
4495 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4496 pt = TypeManager.GetElementType (pt);
4502 // Types have to be identical when ref or out modifer is used
4504 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4505 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4508 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4514 NamedArgument na = a as NamedArgument;
4516 int name_index = pd.GetParameterIndexByName (na.Name);
4517 if (name_index < 0 || name_index >= pd.Count) {
4518 if (IsDelegateInvoke) {
4519 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4520 ec.Report.Error (1746, na.Location,
4521 "The delegate `{0}' does not contain a parameter named `{1}'",
4522 DelegateType.GetSignatureForError (), na.Name);
4524 ec.Report.SymbolRelatedToPreviousError (member);
4525 ec.Report.Error (1739, na.Location,
4526 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4527 TypeManager.CSharpSignature (member), na.Name);
4529 } else if (args[name_index] != a) {
4530 if (IsDelegateInvoke)
4531 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4533 ec.Report.SymbolRelatedToPreviousError (member);
4535 ec.Report.Error (1744, na.Location,
4536 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4541 if (a.Expr.Type == InternalType.Dynamic)
4544 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4545 custom_errors.NoArgumentMatch (ec, member);
4549 Expression conv = null;
4550 if (a.ArgType == Argument.AType.ExtensionType) {
4551 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4554 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4556 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4559 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4566 // Convert params arguments to an array initializer
4568 if (params_initializers != null) {
4569 // we choose to use 'a.Expr' rather than 'conv' so that
4570 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4571 params_initializers.Add (a.Expr);
4572 args.RemoveAt (a_idx--);
4577 // Update the argument with the implicit conversion
4581 if (a_idx != arg_count) {
4582 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4587 // Fill not provided arguments required by params modifier
4589 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4591 args = new Arguments (1);
4593 pt = ptypes[pd.Count - 1];
4594 pt = TypeManager.GetElementType (pt);
4595 has_unsafe_arg |= pt.IsPointer;
4596 params_initializers = new ArrayInitializer (0, loc);
4600 // Append an array argument with all params arguments
4602 if (params_initializers != null) {
4603 args.Add (new Argument (
4604 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4608 if (has_unsafe_arg && !ec.IsUnsafe) {
4609 Expression.UnsafeError (ec, loc);
4613 // We could infer inaccesible type arguments
4615 if (type_arguments == null && member.IsGeneric) {
4616 var ms = (MethodSpec) member;
4617 foreach (var ta in ms.TypeArguments) {
4618 if (!ta.IsAccessible (ec.CurrentType)) {
4619 ec.Report.SymbolRelatedToPreviousError (ta);
4620 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4630 public class ConstantExpr : MemberExpr
4634 public ConstantExpr (ConstSpec constant, Location loc)
4636 this.constant = constant;
4640 public override string Name {
4641 get { throw new NotImplementedException (); }
4644 public override bool IsInstance {
4645 get { return !IsStatic; }
4648 public override bool IsStatic {
4649 get { return true; }
4652 protected override TypeSpec DeclaringType {
4653 get { return constant.DeclaringType; }
4656 public override Expression CreateExpressionTree (ResolveContext ec)
4658 throw new NotSupportedException ("ET");
4661 protected override Expression DoResolve (ResolveContext rc)
4663 ResolveInstanceExpression (rc, null);
4664 DoBestMemberChecks (rc, constant);
4666 var c = constant.GetConstant (rc);
4668 // Creates reference expression to the constant value
4669 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4672 public override void Emit (EmitContext ec)
4674 throw new NotSupportedException ();
4677 public override string GetSignatureForError ()
4679 return constant.GetSignatureForError ();
4682 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4684 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4689 /// Fully resolved expression that evaluates to a Field
4691 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4692 protected FieldSpec spec;
4693 VariableInfo variable_info;
4695 LocalTemporary temp;
4698 protected FieldExpr (Location l)
4703 public FieldExpr (FieldSpec spec, Location loc)
4708 type = spec.MemberType;
4711 public FieldExpr (FieldBase fi, Location l)
4718 public override string Name {
4724 public bool IsHoisted {
4726 IVariableReference hv = InstanceExpression as IVariableReference;
4727 return hv != null && hv.IsHoisted;
4731 public override bool IsInstance {
4733 return !spec.IsStatic;
4737 public override bool IsStatic {
4739 return spec.IsStatic;
4743 public FieldSpec Spec {
4749 protected override TypeSpec DeclaringType {
4751 return spec.DeclaringType;
4755 public VariableInfo VariableInfo {
4757 return variable_info;
4763 public override string GetSignatureForError ()
4765 return TypeManager.GetFullNameSignature (spec);
4768 public bool IsMarshalByRefAccess ()
4770 // Checks possible ldflda of field access expression
4771 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4772 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4773 !(InstanceExpression is This);
4776 public void SetHasAddressTaken ()
4778 IVariableReference vr = InstanceExpression as IVariableReference;
4780 vr.SetHasAddressTaken ();
4783 public override Expression CreateExpressionTree (ResolveContext ec)
4785 Expression instance;
4786 if (InstanceExpression == null) {
4787 instance = new NullLiteral (loc);
4789 instance = InstanceExpression.CreateExpressionTree (ec);
4792 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4794 CreateTypeOfExpression ());
4796 return CreateExpressionFactoryCall (ec, "Field", args);
4799 public Expression CreateTypeOfExpression ()
4801 return new TypeOfField (spec, loc);
4804 protected override Expression DoResolve (ResolveContext ec)
4806 return DoResolve (ec, null);
4809 Expression DoResolve (ResolveContext ec, Expression rhs)
4811 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4813 if (ResolveInstanceExpression (ec, rhs)) {
4814 // Resolve the field's instance expression while flow analysis is turned
4815 // off: when accessing a field "a.b", we must check whether the field
4816 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4818 if (lvalue_instance) {
4819 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4820 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4822 Expression right_side =
4823 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4825 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4828 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4829 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4833 if (InstanceExpression == null)
4837 DoBestMemberChecks (ec, spec);
4839 var fb = spec as FixedFieldSpec;
4840 IVariableReference var = InstanceExpression as IVariableReference;
4842 if (lvalue_instance && var != null && var.VariableInfo != null) {
4843 var.VariableInfo.SetFieldAssigned (ec, Name);
4847 IFixedExpression fe = InstanceExpression as IFixedExpression;
4848 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4849 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4852 if (InstanceExpression.eclass != ExprClass.Variable) {
4853 ec.Report.SymbolRelatedToPreviousError (spec);
4854 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4855 TypeManager.GetFullNameSignature (spec));
4856 } else if (var != null && var.IsHoisted) {
4857 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4860 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4863 eclass = ExprClass.Variable;
4865 // If the instance expression is a local variable or parameter.
4866 if (var == null || var.VariableInfo == null)
4869 VariableInfo vi = var.VariableInfo;
4870 if (!vi.IsFieldAssigned (ec, Name, loc))
4873 variable_info = vi.GetSubStruct (Name);
4877 static readonly int [] codes = {
4878 191, // instance, write access
4879 192, // instance, out access
4880 198, // static, write access
4881 199, // static, out access
4882 1648, // member of value instance, write access
4883 1649, // member of value instance, out access
4884 1650, // member of value static, write access
4885 1651 // member of value static, out access
4888 static readonly string [] msgs = {
4889 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4890 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4891 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4892 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4893 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4894 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4895 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4896 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4899 // The return value is always null. Returning a value simplifies calling code.
4900 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4903 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4907 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4909 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4914 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4916 Expression e = DoResolve (ec, right_side);
4921 spec.MemberDefinition.SetIsAssigned ();
4923 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4924 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4925 ec.Report.Warning (420, 1, loc,
4926 "`{0}': A volatile field references will not be treated as volatile",
4927 spec.GetSignatureForError ());
4930 if (spec.IsReadOnly) {
4931 // InitOnly fields can only be assigned in constructors or initializers
4932 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4933 return Report_AssignToReadonly (ec, right_side);
4935 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4937 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4938 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4939 return Report_AssignToReadonly (ec, right_side);
4940 // static InitOnly fields cannot be assigned-to in an instance constructor
4941 if (IsStatic && !ec.IsStatic)
4942 return Report_AssignToReadonly (ec, right_side);
4943 // instance constructors can't modify InitOnly fields of other instances of the same type
4944 if (!IsStatic && !(InstanceExpression is This))
4945 return Report_AssignToReadonly (ec, right_side);
4949 if (right_side == EmptyExpression.OutAccess.Instance &&
4950 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4951 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4952 ec.Report.Warning (197, 1, loc,
4953 "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",
4954 GetSignatureForError ());
4957 eclass = ExprClass.Variable;
4961 public override int GetHashCode ()
4963 return spec.GetHashCode ();
4966 public bool IsFixed {
4969 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4971 IVariableReference variable = InstanceExpression as IVariableReference;
4972 if (variable != null)
4973 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4975 IFixedExpression fe = InstanceExpression as IFixedExpression;
4976 return fe != null && fe.IsFixed;
4980 public override bool Equals (object obj)
4982 FieldExpr fe = obj as FieldExpr;
4986 if (spec != fe.spec)
4989 if (InstanceExpression == null || fe.InstanceExpression == null)
4992 return InstanceExpression.Equals (fe.InstanceExpression);
4995 public void Emit (EmitContext ec, bool leave_copy)
4997 bool is_volatile = false;
4999 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5002 spec.MemberDefinition.SetIsUsed ();
5006 ec.Emit (OpCodes.Volatile);
5008 ec.Emit (OpCodes.Ldsfld, spec);
5011 EmitInstance (ec, false);
5013 // Optimization for build-in types
5014 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
5015 ec.EmitLoadFromPtr (type);
5017 var ff = spec as FixedFieldSpec;
5019 ec.Emit (OpCodes.Ldflda, spec);
5020 ec.Emit (OpCodes.Ldflda, ff.Element);
5023 ec.Emit (OpCodes.Volatile);
5025 ec.Emit (OpCodes.Ldfld, spec);
5031 ec.Emit (OpCodes.Dup);
5033 temp = new LocalTemporary (this.Type);
5039 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5041 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5043 EmitInstance (ec, prepared);
5047 ec.Emit (OpCodes.Dup);
5049 temp = new LocalTemporary (this.Type);
5054 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5055 ec.Emit (OpCodes.Volatile);
5057 spec.MemberDefinition.SetIsAssigned ();
5060 ec.Emit (OpCodes.Stsfld, spec);
5062 ec.Emit (OpCodes.Stfld, spec);
5071 public override void Emit (EmitContext ec)
5076 public override void EmitSideEffect (EmitContext ec)
5078 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5080 if (is_volatile) // || is_marshal_by_ref ())
5081 base.EmitSideEffect (ec);
5084 public void AddressOf (EmitContext ec, AddressOp mode)
5086 if ((mode & AddressOp.Store) != 0)
5087 spec.MemberDefinition.SetIsAssigned ();
5088 if ((mode & AddressOp.Load) != 0)
5089 spec.MemberDefinition.SetIsUsed ();
5092 // Handle initonly fields specially: make a copy and then
5093 // get the address of the copy.
5096 if (spec.IsReadOnly){
5098 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5111 local = ec.DeclareLocal (type, false);
5112 ec.Emit (OpCodes.Stloc, local);
5113 ec.Emit (OpCodes.Ldloca, local);
5119 ec.Emit (OpCodes.Ldsflda, spec);
5122 EmitInstance (ec, false);
5123 ec.Emit (OpCodes.Ldflda, spec);
5127 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5129 return MakeExpression (ctx);
5132 public override SLE.Expression MakeExpression (BuilderContext ctx)
5135 return base.MakeExpression (ctx);
5137 return SLE.Expression.Field (
5138 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5139 spec.GetMetaInfo ());
5143 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5145 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5151 /// Expression that evaluates to a Property. The Assign class
5152 /// might set the `Value' expression if we are in an assignment.
5154 /// This is not an LValue because we need to re-write the expression, we
5155 /// can not take data from the stack and store it.
5157 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5159 public PropertyExpr (PropertySpec spec, Location l)
5162 best_candidate = spec;
5163 type = spec.MemberType;
5168 protected override TypeSpec DeclaringType {
5170 return best_candidate.DeclaringType;
5174 public override string Name {
5176 return best_candidate.Name;
5180 public override bool IsInstance {
5186 public override bool IsStatic {
5188 return best_candidate.IsStatic;
5192 public PropertySpec PropertyInfo {
5194 return best_candidate;
5200 public override Expression CreateExpressionTree (ResolveContext ec)
5203 if (IsSingleDimensionalArrayLength ()) {
5204 args = new Arguments (1);
5205 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5206 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5209 args = new Arguments (2);
5210 if (InstanceExpression == null)
5211 args.Add (new Argument (new NullLiteral (loc)));
5213 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5214 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5215 return CreateExpressionFactoryCall (ec, "Property", args);
5218 public Expression CreateSetterTypeOfExpression ()
5220 return new TypeOfMethod (Setter, loc);
5223 public override string GetSignatureForError ()
5225 return best_candidate.GetSignatureForError ();
5228 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5231 return base.MakeExpression (ctx);
5233 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5237 public override SLE.Expression MakeExpression (BuilderContext ctx)
5240 return base.MakeExpression (ctx);
5242 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5246 void Error_PropertyNotValid (ResolveContext ec)
5248 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5249 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5250 GetSignatureForError ());
5253 bool IsSingleDimensionalArrayLength ()
5255 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5258 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5259 return ac != null && ac.Rank == 1;
5262 public override void Emit (EmitContext ec, bool leave_copy)
5265 // Special case: length of single dimension array property is turned into ldlen
5267 if (IsSingleDimensionalArrayLength ()) {
5269 EmitInstance (ec, false);
5270 ec.Emit (OpCodes.Ldlen);
5271 ec.Emit (OpCodes.Conv_I4);
5275 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5278 ec.Emit (OpCodes.Dup);
5280 temp = new LocalTemporary (this.Type);
5286 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5290 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5291 args = new Arguments (0);
5296 ec.Emit (OpCodes.Dup);
5298 temp = new LocalTemporary (this.Type);
5303 args = new Arguments (1);
5307 temp = new LocalTemporary (this.Type);
5309 args.Add (new Argument (temp));
5311 args.Add (new Argument (source));
5315 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5323 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5325 eclass = ExprClass.PropertyAccess;
5327 if (best_candidate.IsNotRealProperty) {
5328 Error_PropertyNotValid (rc);
5331 ResolveInstanceExpression (rc, right_side);
5333 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5334 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5335 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5337 type = p.MemberType;
5341 DoBestMemberChecks (rc, best_candidate);
5345 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5347 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5351 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5353 // getter and setter can be different for base calls
5354 MethodSpec getter, setter;
5355 protected T best_candidate;
5357 protected LocalTemporary temp;
5358 protected bool prepared;
5360 protected PropertyOrIndexerExpr (Location l)
5367 public MethodSpec Getter {
5376 public MethodSpec Setter {
5387 protected override Expression DoResolve (ResolveContext ec)
5389 if (eclass == ExprClass.Unresolved) {
5390 var expr = OverloadResolve (ec, null);
5395 return expr.Resolve (ec);
5398 if (!ResolveGetter (ec))
5404 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5406 if (right_side == EmptyExpression.OutAccess.Instance) {
5407 // TODO: best_candidate can be null at this point
5408 INamedBlockVariable variable = null;
5409 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5410 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5411 best_candidate.Name);
5413 right_side.DoResolveLValue (ec, this);
5418 // if the property/indexer returns a value type, and we try to set a field in it
5419 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5420 Error_CannotModifyIntermediateExpressionValue (ec);
5423 if (eclass == ExprClass.Unresolved) {
5424 var expr = OverloadResolve (ec, right_side);
5429 return expr.ResolveLValue (ec, right_side);
5432 if (!ResolveSetter (ec))
5439 // Implements the IAssignMethod interface for assignments
5441 public abstract void Emit (EmitContext ec, bool leave_copy);
5442 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5444 public override void Emit (EmitContext ec)
5449 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5451 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5453 bool ResolveGetter (ResolveContext rc)
5455 if (!best_candidate.HasGet) {
5456 if (InstanceExpression != EmptyExpression.Null) {
5457 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5458 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5459 best_candidate.GetSignatureForError ());
5462 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5463 if (best_candidate.HasDifferentAccessibility) {
5464 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5465 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5466 TypeManager.CSharpSignature (best_candidate));
5468 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5469 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5473 if (best_candidate.HasDifferentAccessibility) {
5474 CheckProtectedMemberAccess (rc, best_candidate.Get);
5477 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5481 bool ResolveSetter (ResolveContext rc)
5483 if (!best_candidate.HasSet) {
5484 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5485 GetSignatureForError ());
5489 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5490 if (best_candidate.HasDifferentAccessibility) {
5491 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5492 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5493 GetSignatureForError ());
5495 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5496 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5500 if (best_candidate.HasDifferentAccessibility)
5501 CheckProtectedMemberAccess (rc, best_candidate.Set);
5503 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5509 /// Fully resolved expression that evaluates to an Event
5511 public class EventExpr : MemberExpr, IAssignMethod
5513 readonly EventSpec spec;
5516 public EventExpr (EventSpec spec, Location loc)
5524 protected override TypeSpec DeclaringType {
5526 return spec.DeclaringType;
5530 public override string Name {
5536 public override bool IsInstance {
5538 return !spec.IsStatic;
5542 public override bool IsStatic {
5544 return spec.IsStatic;
5548 public MethodSpec Operator {
5556 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5559 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5561 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5562 if (spec.BackingField != null &&
5563 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType))) {
5565 spec.MemberDefinition.SetIsUsed ();
5567 if (!ec.IsObsolete) {
5568 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5570 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5573 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5574 Error_AssignmentEventOnly (ec);
5576 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5578 InstanceExpression = null;
5580 return ml.ResolveMemberAccess (ec, left, original);
5584 return base.ResolveMemberAccess (ec, left, original);
5587 public override Expression CreateExpressionTree (ResolveContext ec)
5589 throw new NotSupportedException ("ET");
5592 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5594 if (right_side == EmptyExpression.EventAddition) {
5595 op = spec.AccessorAdd;
5596 } else if (right_side == EmptyExpression.EventSubtraction) {
5597 op = spec.AccessorRemove;
5601 Error_AssignmentEventOnly (ec);
5605 op = CandidateToBaseOverride (ec, op);
5609 protected override Expression DoResolve (ResolveContext ec)
5611 eclass = ExprClass.EventAccess;
5612 type = spec.MemberType;
5614 ResolveInstanceExpression (ec, null);
5616 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5617 Error_AssignmentEventOnly (ec);
5620 DoBestMemberChecks (ec, spec);
5624 public override void Emit (EmitContext ec)
5626 throw new NotSupportedException ();
5627 //Error_CannotAssign ();
5630 #region IAssignMethod Members
5632 public void Emit (EmitContext ec, bool leave_copy)
5634 throw new NotImplementedException ();
5637 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5639 if (leave_copy || !prepare_for_load)
5640 throw new NotImplementedException ("EventExpr::EmitAssign");
5642 Arguments args = new Arguments (1);
5643 args.Add (new Argument (source));
5644 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5649 void Error_AssignmentEventOnly (ResolveContext ec)
5651 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType)) {
5652 ec.Report.Error (79, loc,
5653 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5654 GetSignatureForError ());
5656 ec.Report.Error (70, loc,
5657 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5658 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5662 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5664 name = name.Substring (0, name.LastIndexOf ('.'));
5665 base.Error_CannotCallAbstractBase (rc, name);
5668 public override string GetSignatureForError ()
5670 return TypeManager.CSharpSignature (spec);
5673 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5675 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5679 public class TemporaryVariableReference : VariableReference
5681 public class Declarator : Statement
5683 TemporaryVariableReference variable;
5685 public Declarator (TemporaryVariableReference variable)
5687 this.variable = variable;
5691 protected override void DoEmit (EmitContext ec)
5693 variable.li.CreateBuilder (ec);
5696 protected override void CloneTo (CloneContext clonectx, Statement target)
5704 public TemporaryVariableReference (LocalVariable li, Location loc)
5707 this.type = li.Type;
5711 public override bool IsLockedByStatement {
5719 public LocalVariable LocalInfo {
5725 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5727 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5728 return new TemporaryVariableReference (li, loc);
5731 public override Expression CreateExpressionTree (ResolveContext ec)
5733 throw new NotSupportedException ("ET");
5736 protected override Expression DoResolve (ResolveContext ec)
5738 eclass = ExprClass.Variable;
5741 // Don't capture temporary variables except when using
5742 // iterator redirection
5744 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5745 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5746 storey.CaptureLocalVariable (ec, li);
5752 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5754 return Resolve (ec);
5757 public override void Emit (EmitContext ec)
5759 li.CreateBuilder (ec);
5764 public void EmitAssign (EmitContext ec, Expression source)
5766 li.CreateBuilder (ec);
5768 EmitAssign (ec, source, false, false);
5771 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5773 return li.HoistedVariant;
5776 public override bool IsFixed {
5777 get { return true; }
5780 public override bool IsRef {
5781 get { return false; }
5784 public override string Name {
5785 get { throw new NotImplementedException (); }
5788 public override void SetHasAddressTaken ()
5790 throw new NotImplementedException ();
5793 protected override ILocalVariable Variable {
5797 public override VariableInfo VariableInfo {
5798 get { throw new NotImplementedException (); }
5803 /// Handles `var' contextual keyword; var becomes a keyword only
5804 /// if no type called var exists in a variable scope
5806 class VarExpr : SimpleName
5808 public VarExpr (Location loc)
5813 public bool InferType (ResolveContext ec, Expression right_side)
5816 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5818 type = right_side.Type;
5819 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5820 ec.Report.Error (815, loc,
5821 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5822 type.GetSignatureForError ());
5826 eclass = ExprClass.Variable;
5830 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5832 if (RootContext.Version < LanguageVersion.V_3)
5833 base.Error_TypeOrNamespaceNotFound (ec);
5835 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");