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 TypeSpec ResolveAsType (IMemberContext mc)
188 ResolveContext ec = new ResolveContext (mc);
189 Expression e = Resolve (ec);
191 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
196 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
198 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
201 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
203 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
206 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
208 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
209 name, TypeManager.CSharpName (type));
212 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
214 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
215 "expressions can be used as a statement");
218 public void Error_InvalidExpressionStatement (BlockContext ec)
220 Error_InvalidExpressionStatement (ec.Report, loc);
223 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
225 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
228 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
230 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
233 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
235 // The error was already reported as CS1660
236 if (type == InternalType.AnonymousMethod)
239 string from_type = type.GetSignatureForError ();
240 string to_type = target.GetSignatureForError ();
241 if (from_type == to_type) {
242 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
243 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
247 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
252 ec.Report.DisableReporting ();
253 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
254 ec.Report.EnableReporting ();
257 ec.Report.Error (266, loc,
258 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
261 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
266 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
268 // Better message for possible generic expressions
269 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
270 var report = context.Module.Compiler.Report;
271 report.SymbolRelatedToPreviousError (member);
272 if (member is TypeSpec)
273 member = ((TypeSpec) member).GetDefinition ();
275 member = ((MethodSpec) member).GetGenericMethodDefinition ();
277 string name = member.Kind == MemberKind.Method ? "method" : "type";
278 if (member.IsGeneric) {
279 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
280 name, member.GetSignatureForError (), member.Arity.ToString ());
282 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
283 name, member.GetSignatureForError ());
286 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
290 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
292 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
296 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
298 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
301 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
303 ec.Report.SymbolRelatedToPreviousError (type);
304 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
305 TypeManager.CSharpName (type), name);
308 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
310 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
313 protected void Error_VoidPointerOperation (ResolveContext rc)
315 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
318 public ResolveFlags ExprClassToResolveFlags {
322 case ExprClass.Namespace:
323 return ResolveFlags.Type;
325 case ExprClass.MethodGroup:
326 return ResolveFlags.MethodGroup;
328 case ExprClass.TypeParameter:
329 return ResolveFlags.TypeParameter;
331 case ExprClass.Value:
332 case ExprClass.Variable:
333 case ExprClass.PropertyAccess:
334 case ExprClass.EventAccess:
335 case ExprClass.IndexerAccess:
336 return ResolveFlags.VariableOrValue;
339 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
345 /// Resolves an expression and performs semantic analysis on it.
349 /// Currently Resolve wraps DoResolve to perform sanity
350 /// checking and assertion checking on what we expect from Resolve.
352 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
354 if (eclass != ExprClass.Unresolved)
364 if ((flags & e.ExprClassToResolveFlags) == 0) {
365 e.Error_UnexpectedKind (ec, flags, loc);
370 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
373 } catch (Exception ex) {
374 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
377 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
378 return EmptyExpression.Null; // TODO: Add location
383 /// Resolves an expression and performs semantic analysis on it.
385 public Expression Resolve (ResolveContext rc)
387 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
391 /// Resolves an expression for LValue assignment
395 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
396 /// checking and assertion checking on what we expect from Resolve
398 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
400 int errors = ec.Report.Errors;
401 bool out_access = right_side == EmptyExpression.OutAccess;
403 Expression e = DoResolveLValue (ec, right_side);
405 if (e != null && out_access && !(e is IMemoryLocation)) {
406 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
407 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
409 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
410 // e.GetType () + " " + e.GetSignatureForError ());
415 if (errors == ec.Report.Errors) {
417 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
419 Error_ValueAssignment (ec, loc);
424 if (e.eclass == ExprClass.Unresolved)
425 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
427 if ((e.type == null) && !(e is GenericTypeExpr))
428 throw new Exception ("Expression " + e + " did not set its type after Resolve");
433 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
435 rc.Module.Compiler.Report.Error (182, loc,
436 "An attribute argument must be a constant expression, typeof expression or array creation expression");
440 /// Emits the code for the expression
444 /// The Emit method is invoked to generate the code
445 /// for the expression.
447 public abstract void Emit (EmitContext ec);
450 // Emit code to branch to @target if this expression is equivalent to @on_true.
451 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
452 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
453 // including the use of conditional branches. Note also that a branch MUST be emitted
454 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
457 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
460 // Emit this expression for its side effects, not for its value.
461 // The default implementation is to emit the value, and then throw it away.
462 // Subclasses can provide more efficient implementations, but those MUST be equivalent
463 public virtual void EmitSideEffect (EmitContext ec)
466 ec.Emit (OpCodes.Pop);
470 /// Protected constructor. Only derivate types should
471 /// be able to be created
474 protected Expression ()
479 /// Returns a fully formed expression after a MemberLookup
482 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
484 if (spec is EventSpec)
485 return new EventExpr ((EventSpec) spec, loc);
486 if (spec is ConstSpec)
487 return new ConstantExpr ((ConstSpec) spec, loc);
488 if (spec is FieldSpec)
489 return new FieldExpr ((FieldSpec) spec, loc);
490 if (spec is PropertySpec)
491 return new PropertyExpr ((PropertySpec) spec, loc);
492 if (spec is TypeSpec)
493 return new TypeExpression (((TypeSpec) spec), loc);
498 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
500 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
502 rc.Report.SymbolRelatedToPreviousError (type);
504 // Report meaningful error for struct as they always have default ctor in C# context
505 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
507 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
508 type.GetSignatureForError ());
514 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
515 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
519 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
520 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
527 public enum MemberLookupRestrictions
536 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
537 // `qualifier_type' or null to lookup members in the current class.
539 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
541 var members = MemberCache.FindMembers (queried_type, name, false);
545 MemberSpec non_method = null;
546 MemberSpec ambig_non_method = null;
548 for (int i = 0; i < members.Count; ++i) {
549 var member = members[i];
551 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
552 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
555 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
559 if (!member.IsAccessible (rc))
563 // With runtime binder we can have a situation where queried type is inaccessible
564 // because it came via dynamic object, the check about inconsisted accessibility
565 // had no effect as the type was unknown during compilation
568 // private class N { }
570 // public dynamic Foo ()
576 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
580 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
581 if (member is MethodSpec)
582 return new MethodGroupExpr (members, queried_type, loc);
584 if (!Invocation.IsMemberInvocable (member))
588 if (non_method == null || member is MethodSpec) {
590 } else if (!errorMode) {
591 ambig_non_method = member;
595 if (non_method != null) {
596 if (ambig_non_method != null && rc != null) {
597 var report = rc.Module.Compiler.Report;
598 report.SymbolRelatedToPreviousError (non_method);
599 report.SymbolRelatedToPreviousError (ambig_non_method);
600 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
601 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
604 if (non_method is MethodSpec)
605 return new MethodGroupExpr (members, queried_type, loc);
607 return ExprClassFromMemberInfo (non_method, loc);
610 if (members[0].DeclaringType.BaseType == null)
613 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
615 } while (members != null);
620 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
622 throw new NotImplementedException ();
625 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
627 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
631 /// Returns an expression that can be used to invoke operator true
632 /// on the expression if it exists.
634 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
636 return GetOperatorTrueOrFalse (ec, e, true, loc);
640 /// Returns an expression that can be used to invoke operator false
641 /// on the expression if it exists.
643 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
645 return GetOperatorTrueOrFalse (ec, e, false, loc);
648 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
650 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
651 var methods = MemberCache.GetUserOperator (e.type, op, false);
655 Arguments arguments = new Arguments (1);
656 arguments.Add (new Argument (e));
658 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
659 var oper = res.ResolveOperator (ec, ref arguments);
664 return new UserOperatorCall (oper, arguments, null, loc);
667 public virtual string ExprClassName
671 case ExprClass.Unresolved:
673 case ExprClass.Value:
675 case ExprClass.Variable:
677 case ExprClass.Namespace:
681 case ExprClass.MethodGroup:
682 return "method group";
683 case ExprClass.PropertyAccess:
684 return "property access";
685 case ExprClass.EventAccess:
686 return "event access";
687 case ExprClass.IndexerAccess:
688 return "indexer access";
689 case ExprClass.Nothing:
691 case ExprClass.TypeParameter:
692 return "type parameter";
694 throw new Exception ("Should not happen");
699 /// Reports that we were expecting `expr' to be of class `expected'
701 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
703 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
706 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
710 name = mc.GetSignatureForError ();
712 name = GetSignatureForError ();
714 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
715 name, was, expected);
718 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
720 string [] valid = new string [4];
723 if ((flags & ResolveFlags.VariableOrValue) != 0) {
724 valid [count++] = "variable";
725 valid [count++] = "value";
728 if ((flags & ResolveFlags.Type) != 0)
729 valid [count++] = "type";
731 if ((flags & ResolveFlags.MethodGroup) != 0)
732 valid [count++] = "method group";
735 valid [count++] = "unknown";
737 StringBuilder sb = new StringBuilder (valid [0]);
738 for (int i = 1; i < count - 1; i++) {
740 sb.Append (valid [i]);
743 sb.Append ("' or `");
744 sb.Append (valid [count - 1]);
747 ec.Report.Error (119, loc,
748 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
751 public static void UnsafeError (ResolveContext ec, Location loc)
753 UnsafeError (ec.Report, loc);
756 public static void UnsafeError (Report Report, Location loc)
758 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
761 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
763 ec.Report.SymbolRelatedToPreviousError (type);
764 if (ec.CurrentInitializerVariable != null) {
765 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
766 TypeManager.CSharpName (type), GetSignatureForError ());
768 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
769 GetSignatureForError ());
774 // Converts `source' to an int, uint, long or ulong.
776 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
778 var btypes = ec.BuiltinTypes;
780 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
781 Arguments args = new Arguments (1);
782 args.Add (new Argument (source));
783 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
786 Expression converted;
788 using (ec.Set (ResolveContext.Options.CheckedScope)) {
789 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
790 if (converted == null)
791 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
792 if (converted == null)
793 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
794 if (converted == null)
795 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
797 if (converted == null) {
798 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
804 // Only positive constants are allowed at compile time
806 Constant c = converted as Constant;
807 if (c != null && c.IsNegative)
808 Error_NegativeArrayIndex (ec, source.loc);
810 // No conversion needed to array index
811 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
814 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
818 // Derived classes implement this method by cloning the fields that
819 // could become altered during the Resolve stage
821 // Only expressions that are created for the parser need to implement
824 protected virtual void CloneTo (CloneContext clonectx, Expression target)
826 throw new NotImplementedException (
828 "CloneTo not implemented for expression {0}", this.GetType ()));
832 // Clones an expression created by the parser.
834 // We only support expressions created by the parser so far, not
835 // expressions that have been resolved (many more classes would need
836 // to implement CloneTo).
838 // This infrastructure is here merely for Lambda expressions which
839 // compile the same code using different type values for the same
840 // arguments to find the correct overload
842 public virtual Expression Clone (CloneContext clonectx)
844 Expression cloned = (Expression) MemberwiseClone ();
845 CloneTo (clonectx, cloned);
851 // Implementation of expression to expression tree conversion
853 public abstract Expression CreateExpressionTree (ResolveContext ec);
855 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
857 return CreateExpressionFactoryCall (ec, name, null, args, loc);
860 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
862 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
865 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
867 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
870 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
872 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
876 return new TypeExpression (t, loc);
880 // Implemented by all expressions which support conversion from
881 // compiler expression to invokable runtime expression. Used by
882 // dynamic C# binder.
884 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
886 throw new NotImplementedException ("MakeExpression for " + GetType ());
891 /// This is just a base class for expressions that can
892 /// appear on statements (invocations, object creation,
893 /// assignments, post/pre increment and decrement). The idea
894 /// being that they would support an extra Emition interface that
895 /// does not leave a result on the stack.
897 public abstract class ExpressionStatement : Expression {
899 public ExpressionStatement ResolveStatement (BlockContext ec)
901 Expression e = Resolve (ec);
905 ExpressionStatement es = e as ExpressionStatement;
907 Error_InvalidExpressionStatement (ec);
913 /// Requests the expression to be emitted in a `statement'
914 /// context. This means that no new value is left on the
915 /// stack after invoking this method (constrasted with
916 /// Emit that will always leave a value on the stack).
918 public abstract void EmitStatement (EmitContext ec);
920 public override void EmitSideEffect (EmitContext ec)
927 /// This kind of cast is used to encapsulate the child
928 /// whose type is child.Type into an expression that is
929 /// reported to return "return_type". This is used to encapsulate
930 /// expressions which have compatible types, but need to be dealt
931 /// at higher levels with.
933 /// For example, a "byte" expression could be encapsulated in one
934 /// of these as an "unsigned int". The type for the expression
935 /// would be "unsigned int".
938 public abstract class TypeCast : Expression
940 protected readonly Expression child;
942 protected TypeCast (Expression child, TypeSpec return_type)
944 eclass = child.eclass;
945 loc = child.Location;
950 public Expression Child {
956 public override Expression CreateExpressionTree (ResolveContext ec)
958 Arguments args = new Arguments (2);
959 args.Add (new Argument (child.CreateExpressionTree (ec)));
960 args.Add (new Argument (new TypeOf (type, loc)));
962 if (type.IsPointer || child.Type.IsPointer)
963 Error_PointerInsideExpressionTree (ec);
965 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
968 protected override Expression DoResolve (ResolveContext ec)
970 // This should never be invoked, we are born in fully
971 // initialized state.
976 public override void Emit (EmitContext ec)
981 public override SLE.Expression MakeExpression (BuilderContext ctx)
984 return base.MakeExpression (ctx);
986 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
987 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
988 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
992 protected override void CloneTo (CloneContext clonectx, Expression t)
997 public override bool IsNull {
998 get { return child.IsNull; }
1002 public class EmptyCast : TypeCast {
1003 EmptyCast (Expression child, TypeSpec target_type)
1004 : base (child, target_type)
1008 public static Expression Create (Expression child, TypeSpec type)
1010 Constant c = child as Constant;
1012 return new EmptyConstantCast (c, type);
1014 EmptyCast e = child as EmptyCast;
1016 return new EmptyCast (e.child, type);
1018 return new EmptyCast (child, type);
1021 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1023 child.EmitBranchable (ec, label, on_true);
1026 public override void EmitSideEffect (EmitContext ec)
1028 child.EmitSideEffect (ec);
1033 // Used for predefined type user operator (no obsolete check, etc.)
1035 public class OperatorCast : TypeCast
1037 readonly MethodSpec conversion_operator;
1039 public OperatorCast (Expression expr, TypeSpec target_type)
1040 : this (expr, target_type, target_type, false)
1044 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1045 : this (expr, target_type, target_type, find_explicit)
1049 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1050 : base (expr, returnType)
1052 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1053 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1056 foreach (MethodSpec oper in mi) {
1057 if (oper.ReturnType != returnType)
1060 if (oper.Parameters.Types[0] == expr.Type) {
1061 conversion_operator = oper;
1067 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1068 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1071 public override void Emit (EmitContext ec)
1074 ec.Emit (OpCodes.Call, conversion_operator);
1079 // Constant specialization of EmptyCast.
1080 // We need to special case this since an empty cast of
1081 // a constant is still a constant.
1083 public class EmptyConstantCast : Constant
1085 public readonly Constant child;
1087 public EmptyConstantCast (Constant child, TypeSpec type)
1088 : base (child.Location)
1091 throw new ArgumentNullException ("child");
1094 this.eclass = child.eclass;
1098 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1100 if (child.Type == target_type)
1103 // FIXME: check that 'type' can be converted to 'target_type' first
1104 return child.ConvertExplicitly (in_checked_context, target_type);
1107 public override Expression CreateExpressionTree (ResolveContext ec)
1109 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1110 child.CreateExpressionTree (ec),
1111 new TypeOf (type, loc));
1114 Error_PointerInsideExpressionTree (ec);
1116 return CreateExpressionFactoryCall (ec, "Convert", args);
1119 public override bool IsDefaultValue {
1120 get { return child.IsDefaultValue; }
1123 public override bool IsNegative {
1124 get { return child.IsNegative; }
1127 public override bool IsNull {
1128 get { return child.IsNull; }
1131 public override bool IsOneInteger {
1132 get { return child.IsOneInteger; }
1135 public override bool IsZeroInteger {
1136 get { return child.IsZeroInteger; }
1139 public override void Emit (EmitContext ec)
1144 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1146 child.EmitBranchable (ec, label, on_true);
1148 // Only to make verifier happy
1149 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1150 ec.Emit (OpCodes.Unbox_Any, type);
1153 public override void EmitSideEffect (EmitContext ec)
1155 child.EmitSideEffect (ec);
1158 public override object GetValue ()
1160 return child.GetValue ();
1163 public override string GetValueAsLiteral ()
1165 return child.GetValueAsLiteral ();
1168 public override long GetValueAsLong ()
1170 return child.GetValueAsLong ();
1173 public override Constant ConvertImplicitly (TypeSpec target_type)
1175 if (type == target_type)
1178 // FIXME: Do we need to check user conversions?
1179 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1182 return child.ConvertImplicitly (target_type);
1187 /// This class is used to wrap literals which belong inside Enums
1189 public class EnumConstant : Constant
1191 public Constant Child;
1193 public EnumConstant (Constant child, TypeSpec enum_type)
1194 : base (child.Location)
1198 this.eclass = ExprClass.Value;
1199 this.type = enum_type;
1202 protected EnumConstant (Location loc)
1207 public override void Emit (EmitContext ec)
1212 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1214 Child.EncodeAttributeValue (rc, enc, Child.Type);
1217 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1219 Child.EmitBranchable (ec, label, on_true);
1222 public override void EmitSideEffect (EmitContext ec)
1224 Child.EmitSideEffect (ec);
1227 public override string GetSignatureForError()
1229 return TypeManager.CSharpName (Type);
1232 public override object GetValue ()
1234 return Child.GetValue ();
1238 public override object GetTypedValue ()
1241 // The method can be used in dynamic context only (on closed types)
1243 // System.Enum.ToObject cannot be called on dynamic types
1244 // EnumBuilder has to be used, but we cannot use EnumBuilder
1245 // because it does not properly support generics
1247 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1251 public override string GetValueAsLiteral ()
1253 return Child.GetValueAsLiteral ();
1256 public override long GetValueAsLong ()
1258 return Child.GetValueAsLong ();
1261 public EnumConstant Increment()
1263 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1266 public override bool IsDefaultValue {
1268 return Child.IsDefaultValue;
1272 public override bool IsZeroInteger {
1273 get { return Child.IsZeroInteger; }
1276 public override bool IsNegative {
1278 return Child.IsNegative;
1282 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1284 if (Child.Type == target_type)
1287 return Child.ConvertExplicitly (in_checked_context, target_type);
1290 public override Constant ConvertImplicitly (TypeSpec type)
1292 if (this.type == type) {
1296 if (!Convert.ImplicitStandardConversionExists (this, type)){
1300 return Child.ConvertImplicitly (type);
1305 /// This kind of cast is used to encapsulate Value Types in objects.
1307 /// The effect of it is to box the value type emitted by the previous
1310 public class BoxedCast : TypeCast {
1312 public BoxedCast (Expression expr, TypeSpec target_type)
1313 : base (expr, target_type)
1315 eclass = ExprClass.Value;
1318 protected override Expression DoResolve (ResolveContext ec)
1320 // This should never be invoked, we are born in fully
1321 // initialized state.
1326 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1328 // Only boxing to object type is supported
1329 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1330 base.EncodeAttributeValue (rc, enc, targetType);
1334 enc.Encode (child.Type);
1335 child.EncodeAttributeValue (rc, enc, child.Type);
1338 public override void Emit (EmitContext ec)
1342 ec.Emit (OpCodes.Box, child.Type);
1345 public override void EmitSideEffect (EmitContext ec)
1347 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1348 // so, we need to emit the box+pop instructions in most cases
1349 if (child.Type.IsStruct &&
1350 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1351 child.EmitSideEffect (ec);
1353 base.EmitSideEffect (ec);
1357 public class UnboxCast : TypeCast {
1358 public UnboxCast (Expression expr, TypeSpec return_type)
1359 : base (expr, return_type)
1363 protected override Expression DoResolve (ResolveContext ec)
1365 // This should never be invoked, we are born in fully
1366 // initialized state.
1371 public override void Emit (EmitContext ec)
1375 ec.Emit (OpCodes.Unbox_Any, type);
1380 /// This is used to perform explicit numeric conversions.
1382 /// Explicit numeric conversions might trigger exceptions in a checked
1383 /// context, so they should generate the conv.ovf opcodes instead of
1386 public class ConvCast : TypeCast {
1387 public enum Mode : byte {
1388 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1390 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1391 U2_I1, U2_U1, U2_I2, U2_CH,
1392 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1393 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1394 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1395 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1396 CH_I1, CH_U1, CH_I2,
1397 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1398 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1404 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1405 : base (child, return_type)
1410 protected override Expression DoResolve (ResolveContext ec)
1412 // This should never be invoked, we are born in fully
1413 // initialized state.
1418 public override string ToString ()
1420 return String.Format ("ConvCast ({0}, {1})", mode, child);
1423 public override void Emit (EmitContext ec)
1427 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1429 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1430 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1431 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1432 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1433 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1435 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1436 case Mode.U1_CH: /* nothing */ break;
1438 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1439 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1440 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1441 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1442 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1443 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1445 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1446 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1447 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1448 case Mode.U2_CH: /* nothing */ break;
1450 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1451 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1452 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1453 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1454 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1455 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1456 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1458 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1459 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1460 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1461 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1462 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1463 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1465 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1466 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1467 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1468 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1469 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1470 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1471 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1472 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1473 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1475 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1476 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1477 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1478 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1479 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1480 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1481 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1482 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1483 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1485 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1486 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1487 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1489 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1490 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1491 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1492 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1493 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1494 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1495 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1496 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1497 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1499 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1500 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1501 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1502 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1503 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1504 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1505 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1506 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1507 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1508 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1510 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1514 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1515 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1516 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1517 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1518 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1520 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1521 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1523 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1524 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1525 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1526 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1527 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1528 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1530 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1531 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1532 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1533 case Mode.U2_CH: /* nothing */ break;
1535 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1536 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1537 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1538 case Mode.I4_U4: /* nothing */ break;
1539 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1540 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1541 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1543 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1544 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1545 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1546 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1547 case Mode.U4_I4: /* nothing */ break;
1548 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1550 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1551 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1552 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1553 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1554 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1555 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1556 case Mode.I8_U8: /* nothing */ break;
1557 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1558 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1560 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1561 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1562 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1563 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1564 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1565 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1566 case Mode.U8_I8: /* nothing */ break;
1567 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1568 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1570 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1571 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1572 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1574 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1575 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1576 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1577 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1578 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1579 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1580 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1581 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1582 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1584 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1585 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1586 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1587 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1588 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1589 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1590 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1591 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1592 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1593 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1595 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1601 class OpcodeCast : TypeCast
1605 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1606 : base (child, return_type)
1611 protected override Expression DoResolve (ResolveContext ec)
1613 // This should never be invoked, we are born in fully
1614 // initialized state.
1619 public override void Emit (EmitContext ec)
1625 public TypeSpec UnderlyingType {
1626 get { return child.Type; }
1631 // Opcode casts expression with 2 opcodes but only
1632 // single expression tree node
1634 class OpcodeCastDuplex : OpcodeCast
1636 readonly OpCode second;
1638 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1639 : base (child, returnType, first)
1641 this.second = second;
1644 public override void Emit (EmitContext ec)
1652 /// This kind of cast is used to encapsulate a child and cast it
1653 /// to the class requested
1655 public sealed class ClassCast : TypeCast {
1656 readonly bool forced;
1658 public ClassCast (Expression child, TypeSpec return_type)
1659 : base (child, return_type)
1663 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1664 : base (child, return_type)
1666 this.forced = forced;
1669 public override void Emit (EmitContext ec)
1673 bool gen = TypeManager.IsGenericParameter (child.Type);
1675 ec.Emit (OpCodes.Box, child.Type);
1677 if (type.IsGenericParameter) {
1678 ec.Emit (OpCodes.Unbox_Any, type);
1685 ec.Emit (OpCodes.Castclass, type);
1690 // Created during resolving pahse when an expression is wrapped or constantified
1691 // and original expression can be used later (e.g. for expression trees)
1693 public class ReducedExpression : Expression
1695 sealed class ReducedConstantExpression : EmptyConstantCast
1697 readonly Expression orig_expr;
1699 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1700 : base (expr, expr.Type)
1702 this.orig_expr = orig_expr;
1705 public override Constant ConvertImplicitly (TypeSpec target_type)
1707 Constant c = base.ConvertImplicitly (target_type);
1709 c = new ReducedConstantExpression (c, orig_expr);
1714 public override Expression CreateExpressionTree (ResolveContext ec)
1716 return orig_expr.CreateExpressionTree (ec);
1719 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1721 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1723 c = new ReducedConstantExpression (c, orig_expr);
1728 sealed class ReducedExpressionStatement : ExpressionStatement
1730 readonly Expression orig_expr;
1731 readonly ExpressionStatement stm;
1733 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1735 this.orig_expr = orig;
1737 this.eclass = stm.eclass;
1738 this.type = stm.Type;
1740 this.loc = orig.Location;
1743 public override Expression CreateExpressionTree (ResolveContext ec)
1745 return orig_expr.CreateExpressionTree (ec);
1748 protected override Expression DoResolve (ResolveContext ec)
1753 public override void Emit (EmitContext ec)
1758 public override void EmitStatement (EmitContext ec)
1760 stm.EmitStatement (ec);
1764 readonly Expression expr, orig_expr;
1766 private ReducedExpression (Expression expr, Expression orig_expr)
1769 this.eclass = expr.eclass;
1770 this.type = expr.Type;
1771 this.orig_expr = orig_expr;
1772 this.loc = orig_expr.Location;
1777 public Expression OriginalExpression {
1786 // Creates fully resolved expression switcher
1788 public static Constant Create (Constant expr, Expression original_expr)
1790 if (expr.eclass == ExprClass.Unresolved)
1791 throw new ArgumentException ("Unresolved expression");
1793 return new ReducedConstantExpression (expr, original_expr);
1796 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1798 return new ReducedExpressionStatement (s, orig);
1801 public static Expression Create (Expression expr, Expression original_expr)
1803 return Create (expr, original_expr, true);
1807 // Creates unresolved reduce expression. The original expression has to be
1808 // already resolved. Created expression is constant based based on `expr'
1809 // value unless canBeConstant is used
1811 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1813 if (canBeConstant) {
1814 Constant c = expr as Constant;
1816 return Create (c, original_expr);
1819 ExpressionStatement s = expr as ExpressionStatement;
1821 return Create (s, original_expr);
1823 if (expr.eclass == ExprClass.Unresolved)
1824 throw new ArgumentException ("Unresolved expression");
1826 return new ReducedExpression (expr, original_expr);
1829 public override Expression CreateExpressionTree (ResolveContext ec)
1831 return orig_expr.CreateExpressionTree (ec);
1834 protected override Expression DoResolve (ResolveContext ec)
1839 public override void Emit (EmitContext ec)
1844 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1846 expr.EmitBranchable (ec, target, on_true);
1849 public override SLE.Expression MakeExpression (BuilderContext ctx)
1851 return orig_expr.MakeExpression (ctx);
1856 // Standard composite pattern
1858 public abstract class CompositeExpression : Expression
1860 protected Expression expr;
1862 protected CompositeExpression (Expression expr)
1865 this.loc = expr.Location;
1868 public override Expression CreateExpressionTree (ResolveContext ec)
1870 return expr.CreateExpressionTree (ec);
1873 public Expression Child {
1874 get { return expr; }
1877 protected override Expression DoResolve (ResolveContext ec)
1879 expr = expr.Resolve (ec);
1882 eclass = expr.eclass;
1888 public override void Emit (EmitContext ec)
1893 public override bool IsNull {
1894 get { return expr.IsNull; }
1899 // Base of expressions used only to narrow resolve flow
1901 public abstract class ShimExpression : Expression
1903 protected Expression expr;
1905 protected ShimExpression (Expression expr)
1910 protected override void CloneTo (CloneContext clonectx, Expression t)
1915 ShimExpression target = (ShimExpression) t;
1916 target.expr = expr.Clone (clonectx);
1919 public override Expression CreateExpressionTree (ResolveContext ec)
1921 throw new NotSupportedException ("ET");
1924 public override void Emit (EmitContext ec)
1926 throw new InternalErrorException ("Missing Resolve call");
1929 public Expression Expr {
1930 get { return expr; }
1935 // Unresolved type name expressions
1937 public abstract class ATypeNameExpression : FullNamedExpression
1940 protected TypeArguments targs;
1942 protected ATypeNameExpression (string name, Location l)
1948 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
1955 protected ATypeNameExpression (string name, int arity, Location l)
1956 : this (name, new UnboundTypeArguments (arity), l)
1962 protected int Arity {
1964 return targs == null ? 0 : targs.Count;
1968 public bool HasTypeArguments {
1970 return targs != null && !targs.IsEmpty;
1974 public string Name {
1983 public TypeArguments TypeArguments {
1991 public override bool Equals (object obj)
1993 ATypeNameExpression atne = obj as ATypeNameExpression;
1994 return atne != null && atne.Name == Name &&
1995 (targs == null || targs.Equals (atne.targs));
1998 public override int GetHashCode ()
2000 return Name.GetHashCode ();
2003 // TODO: Move it to MemberCore
2004 public static string GetMemberType (MemberCore mc)
2010 if (mc is FieldBase)
2012 if (mc is MethodCore)
2014 if (mc is EnumMember)
2022 public override string GetSignatureForError ()
2024 if (targs != null) {
2025 return Name + "<" + targs.GetSignatureForError () + ">";
2031 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2035 /// SimpleName expressions are formed of a single word and only happen at the beginning
2036 /// of a dotted-name.
2038 public class SimpleName : ATypeNameExpression
2040 public SimpleName (string name, Location l)
2045 public SimpleName (string name, TypeArguments args, Location l)
2046 : base (name, args, l)
2050 public SimpleName (string name, int arity, Location l)
2051 : base (name, arity, l)
2055 public SimpleName GetMethodGroup ()
2057 return new SimpleName (Name, targs, loc);
2060 protected override Expression DoResolve (ResolveContext ec)
2062 return SimpleNameResolve (ec, null, false);
2065 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2067 return SimpleNameResolve (ec, right_side, false);
2070 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2072 if (ctx.CurrentType != null) {
2073 if (ctx.CurrentMemberDefinition != null) {
2074 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2076 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2083 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2084 if (retval != null) {
2085 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2086 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2090 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2091 if (retval != null) {
2092 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2096 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2099 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2101 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2104 if (fne.Type != null && Arity > 0) {
2105 if (HasTypeArguments) {
2106 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2107 if (ct.ResolveAsType (ec) == null)
2113 return new GenericOpenTypeExpr (fne.Type, loc);
2117 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2119 if (!(fne is Namespace))
2123 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2124 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2125 ec.Module.Compiler.Report.Error (1980, Location,
2126 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2127 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2130 fne = new DynamicTypeExpr (loc);
2131 fne.ResolveAsType (ec);
2137 Error_TypeOrNamespaceNotFound (ec);
2141 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2143 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2146 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2148 int lookup_arity = Arity;
2149 bool errorMode = false;
2151 Block current_block = rc.CurrentBlock;
2152 INamedBlockVariable variable = null;
2153 bool variable_found = false;
2157 // Stage 1: binding to local variables or parameters
2159 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2161 if (current_block != null && lookup_arity == 0) {
2162 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2163 if (!variable.IsDeclared) {
2164 // We found local name in accessible block but it's not
2165 // initialized yet, maybe the user wanted to bind to something else
2167 variable_found = true;
2169 e = variable.CreateReferenceExpression (rc, loc);
2172 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2181 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2183 TypeSpec member_type = rc.CurrentType;
2184 for (; member_type != null; member_type = member_type.DeclaringType) {
2185 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2189 var me = e as MemberExpr;
2191 // The name matches a type, defer to ResolveAsTypeStep
2199 if (variable != null) {
2200 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2201 rc.Report.Error (844, loc,
2202 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2203 Name, me.GetSignatureForError ());
2207 } else if (me is MethodGroupExpr) {
2208 // Leave it to overload resolution to report correct error
2210 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2211 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2214 // LAMESPEC: again, ignores InvocableOnly
2215 if (variable != null) {
2216 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2217 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2221 // MemberLookup does not check accessors availability, this is actually needed for properties only
2223 var pe = me as PropertyExpr;
2226 // Break as there is no other overload available anyway
2227 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2228 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2231 pe.Getter = pe.PropertyInfo.Get;
2233 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2236 pe.Setter = pe.PropertyInfo.Set;
2241 // TODO: It's used by EventExpr -> FieldExpr transformation only
2242 // TODO: Should go to MemberAccess
2243 me = me.ResolveMemberAccess (rc, null, null);
2247 me.SetTypeArguments (rc, targs);
2254 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2256 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2257 if (IsPossibleTypeOrNamespace (rc)) {
2258 if (variable != null) {
2259 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2260 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2263 return ResolveAsTypeOrNamespace (rc);
2268 if (variable_found) {
2269 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2272 TypeParameter[] tparams = rc.CurrentTypeParameters;
2273 if (tparams != null) {
2274 foreach (var ctp in tparams) {
2275 if (ctp.Name == Name) {
2276 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2282 var ct = rc.CurrentType;
2284 if (ct.MemberDefinition.TypeParametersCount > 0) {
2285 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2286 if (ctp.Name == Name) {
2287 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2293 ct = ct.DeclaringType;
2294 } while (ct != null);
2297 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2298 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2300 rc.Report.SymbolRelatedToPreviousError (e.Type);
2301 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2306 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2308 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2310 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2314 return ErrorExpression.Instance;
2317 if (rc.Module.Evaluator != null) {
2318 var fi = rc.Module.Evaluator.LookupField (Name);
2320 return new FieldExpr (fi.Item1, loc);
2324 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2329 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2331 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2336 if (right_side != null) {
2337 if (e is TypeExpr) {
2338 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2342 e = e.ResolveLValue (ec, right_side);
2347 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2353 /// Represents a namespace or a type. The name of the class was inspired by
2354 /// section 10.8.1 (Fully Qualified Names).
2356 public abstract class FullNamedExpression : Expression
2358 protected override void CloneTo (CloneContext clonectx, Expression target)
2360 // Do nothing, most unresolved type expressions cannot be
2361 // resolved to different type
2364 public override Expression CreateExpressionTree (ResolveContext ec)
2366 throw new NotSupportedException ("ET");
2369 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2372 // This is used to resolve the expression as a type, a null
2373 // value will be returned if the expression is not a type
2376 public override TypeSpec ResolveAsType (IMemberContext mc)
2378 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2383 TypeExpr te = fne as TypeExpr;
2385 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2393 var dep = type.GetMissingDependencies ();
2395 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2399 // Obsolete checks cannot be done when resolving base context as they
2400 // require type dependencies to be set but we are in process of resolving them
2402 if (!(mc is TypeContainer.BaseContext)) {
2403 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2404 if (obsolete_attr != null && !mc.IsObsolete) {
2405 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2413 public override void Emit (EmitContext ec)
2415 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2416 GetSignatureForError ());
2421 /// Expression that evaluates to a type
2423 public abstract class TypeExpr : FullNamedExpression
2425 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2431 protected sealed override Expression DoResolve (ResolveContext ec)
2437 public override bool Equals (object obj)
2439 TypeExpr tobj = obj as TypeExpr;
2443 return Type == tobj.Type;
2446 public override int GetHashCode ()
2448 return Type.GetHashCode ();
2453 /// Fully resolved Expression that already evaluated to a type
2455 public class TypeExpression : TypeExpr
2457 public TypeExpression (TypeSpec t, Location l)
2460 eclass = ExprClass.Type;
2464 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2471 /// This class denotes an expression which evaluates to a member
2472 /// of a struct or a class.
2474 public abstract class MemberExpr : Expression
2477 // An instance expression associated with this member, if it's a
2478 // non-static member
2480 public Expression InstanceExpression;
2483 /// The name of this member.
2485 public abstract string Name {
2490 // When base.member is used
2492 public bool IsBase {
2493 get { return InstanceExpression is BaseThis; }
2497 /// Whether this is an instance member.
2499 public abstract bool IsInstance {
2504 /// Whether this is a static member.
2506 public abstract bool IsStatic {
2511 protected abstract TypeSpec DeclaringType {
2516 // Converts best base candidate for virtual method starting from QueriedBaseType
2518 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2521 // Only when base.member is used and method is virtual
2527 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2528 // means for base.member access we have to find the closest match after we found best candidate
2530 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2532 // The method could already be what we are looking for
2534 TypeSpec[] targs = null;
2535 if (method.DeclaringType != InstanceExpression.Type) {
2536 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2537 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2538 if (base_override.IsGeneric)
2539 targs = method.TypeArguments;
2541 method = base_override;
2545 // TODO: For now we do it for any hoisted call even if it's needed for
2546 // hoisted stories only but that requires a new expression wrapper
2547 if (rc.CurrentAnonymousMethod != null) {
2548 if (targs == null && method.IsGeneric) {
2549 targs = method.TypeArguments;
2550 method = method.GetGenericMethodDefinition ();
2553 if (method.Parameters.HasArglist)
2554 throw new NotImplementedException ("__arglist base call proxy");
2556 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2558 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2559 // get/set member expressions second call would fail to proxy because left expression
2560 // would be of 'this' and not 'base'
2561 if (rc.CurrentType.IsStruct)
2562 InstanceExpression = new This (loc).Resolve (rc);
2566 method = method.MakeGenericMethod (rc, targs);
2570 // Only base will allow this invocation to happen.
2572 if (method.IsAbstract) {
2573 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2579 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2581 if (InstanceExpression == null)
2584 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2585 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2589 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2591 var ct = rc.CurrentType;
2592 if (ct == qualifier)
2595 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2598 qualifier = qualifier.GetDefinition ();
2599 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2600 rc.Report.SymbolRelatedToPreviousError (member);
2601 rc.Report.Error (1540, loc,
2602 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2603 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2607 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2610 type = type.GetDefinition ();
2612 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2615 type = type.DeclaringType;
2616 } while (type != null);
2621 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2623 if (InstanceExpression != null) {
2624 InstanceExpression = InstanceExpression.Resolve (rc);
2625 CheckProtectedMemberAccess (rc, member);
2628 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2629 UnsafeError (rc, loc);
2632 var dep = member.GetMissingDependencies ();
2634 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2637 if (!rc.IsObsolete) {
2638 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2640 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2643 if (!(member is FieldSpec))
2644 member.MemberDefinition.SetIsUsed ();
2647 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2649 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2653 // Implements identicial simple name and type-name
2655 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2658 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2661 // 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
2662 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2664 if (left is MemberExpr || left is VariableReference) {
2665 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2666 if (identical_type != null && identical_type.Type == left.Type)
2667 return identical_type;
2673 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2676 if (InstanceExpression != null) {
2677 if (InstanceExpression is TypeExpr) {
2678 var t = InstanceExpression.Type;
2680 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2681 if (oa != null && !rc.IsObsolete) {
2682 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2685 t = t.DeclaringType;
2686 } while (t != null);
2688 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2689 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2690 rc.Report.Error (176, loc,
2691 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2692 GetSignatureForError ());
2696 InstanceExpression = null;
2702 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2703 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2704 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2705 rc.Report.Error (236, loc,
2706 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2707 GetSignatureForError ());
2709 rc.Report.Error (120, loc,
2710 "An object reference is required to access non-static member `{0}'",
2711 GetSignatureForError ());
2716 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2717 rc.Report.Error (38, loc,
2718 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2719 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2722 InstanceExpression = new This (loc);
2723 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2724 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2725 InstanceExpression = InstanceExpression.Resolve (rc);
2728 InstanceExpression = InstanceExpression.Resolve (rc);
2734 var me = InstanceExpression as MemberExpr;
2736 me.ResolveInstanceExpression (rc, rhs);
2738 var fe = me as FieldExpr;
2739 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2740 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2741 rc.Report.Warning (1690, 1, loc,
2742 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2743 me.GetSignatureForError ());
2750 // Run member-access postponed check once we know that
2751 // the expression is not field expression which is the only
2752 // expression which can use uninitialized this
2754 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2755 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2759 // Additional checks for l-value member access
2763 // TODO: It should be recursive but that would break csc compatibility
2765 if (InstanceExpression is UnboxCast) {
2766 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2773 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2775 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2776 ec.Report.Warning (1720, 1, left.Location,
2777 "Expression will always cause a `{0}'", "System.NullReferenceException");
2780 InstanceExpression = left;
2784 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2786 TypeSpec instance_type = InstanceExpression.Type;
2787 if (TypeSpec.IsValueType (instance_type)) {
2788 if (InstanceExpression is IMemoryLocation) {
2789 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2791 LocalTemporary t = new LocalTemporary (instance_type);
2792 InstanceExpression.Emit (ec);
2794 t.AddressOf (ec, AddressOp.Store);
2797 InstanceExpression.Emit (ec);
2799 // Only to make verifier happy
2800 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2801 ec.Emit (OpCodes.Box, instance_type);
2804 if (prepare_for_load)
2805 ec.Emit (OpCodes.Dup);
2808 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2812 // Represents a group of extension method candidates for whole namespace
2814 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2816 NamespaceContainer namespace_entry;
2817 public readonly Expression ExtensionExpression;
2819 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
2820 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2822 this.namespace_entry = n;
2823 this.ExtensionExpression = extensionExpr;
2826 public override bool IsStatic {
2827 get { return true; }
2830 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2832 if (namespace_entry == null)
2836 // For extension methodgroup we are not looking for base members but parent
2837 // namespace extension methods
2839 int arity = type_arguments == null ? 0 : type_arguments.Count;
2840 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2844 return found.Cast<MemberSpec> ().ToList ();
2847 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2849 // We are already here
2853 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2855 if (arguments == null)
2856 arguments = new Arguments (1);
2858 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2859 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2861 // Store resolved argument and restore original arguments
2863 // Clean-up modified arguments for error reporting
2864 arguments.RemoveAt (0);
2868 var me = ExtensionExpression as MemberExpr;
2870 me.ResolveInstanceExpression (ec, null);
2872 InstanceExpression = null;
2876 #region IErrorHandler Members
2878 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2883 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2885 rc.Report.SymbolRelatedToPreviousError (best);
2886 rc.Report.Error (1928, loc,
2887 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2888 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2891 rc.Report.Error (1929, loc,
2892 "Extension method instance type `{0}' cannot be converted to `{1}'",
2893 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2899 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2904 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2913 /// MethodGroupExpr represents a group of method candidates which
2914 /// can be resolved to the best method overload
2916 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2918 protected IList<MemberSpec> Methods;
2919 MethodSpec best_candidate;
2920 TypeSpec best_candidate_return;
2921 protected TypeArguments type_arguments;
2923 SimpleName simple_name;
2924 protected TypeSpec queried_type;
2926 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2930 this.type = InternalType.MethodGroup;
2932 eclass = ExprClass.MethodGroup;
2933 queried_type = type;
2936 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2937 : this (new MemberSpec[] { m }, type, loc)
2943 public MethodSpec BestCandidate {
2945 return best_candidate;
2949 public TypeSpec BestCandidateReturnType {
2951 return best_candidate_return;
2955 public IList<MemberSpec> Candidates {
2961 protected override TypeSpec DeclaringType {
2963 return queried_type;
2967 public override bool IsInstance {
2969 if (best_candidate != null)
2970 return !best_candidate.IsStatic;
2976 public override bool IsStatic {
2978 if (best_candidate != null)
2979 return best_candidate.IsStatic;
2985 public override string Name {
2987 if (best_candidate != null)
2988 return best_candidate.Name;
2991 return Methods.First ().Name;
2998 // When best candidate is already know this factory can be used
2999 // to avoid expensive overload resolution to be called
3001 // NOTE: InstanceExpression has to be set manually
3003 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3005 return new MethodGroupExpr (best, queriedType, loc) {
3006 best_candidate = best,
3007 best_candidate_return = best.ReturnType
3011 public override string GetSignatureForError ()
3013 if (best_candidate != null)
3014 return best_candidate.GetSignatureForError ();
3016 return Methods.First ().GetSignatureForError ();
3019 public override Expression CreateExpressionTree (ResolveContext ec)
3021 if (best_candidate == null) {
3022 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3026 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3027 ec.Report.Error (765, loc,
3028 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3030 return new TypeOfMethod (best_candidate, loc);
3033 protected override Expression DoResolve (ResolveContext ec)
3035 this.eclass = ExprClass.MethodGroup;
3037 if (InstanceExpression != null) {
3038 InstanceExpression = InstanceExpression.Resolve (ec);
3039 if (InstanceExpression == null)
3046 public override void Emit (EmitContext ec)
3048 throw new NotSupportedException ();
3051 public void EmitCall (EmitContext ec, Arguments arguments)
3053 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3056 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3058 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3059 Name, TypeManager.CSharpName (target));
3062 public static bool IsExtensionMethodArgument (Expression expr)
3065 // LAMESPEC: No details about which expressions are not allowed
3067 return !(expr is TypeExpr) && !(expr is BaseThis);
3071 /// Find the Applicable Function Members (7.4.2.1)
3073 /// me: Method Group expression with the members to select.
3074 /// it might contain constructors or methods (or anything
3075 /// that maps to a method).
3077 /// Arguments: ArrayList containing resolved Argument objects.
3079 /// loc: The location if we want an error to be reported, or a Null
3080 /// location for "probing" purposes.
3082 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3083 /// that is the best match of me on Arguments.
3086 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3088 // TODO: causes issues with probing mode, remove explicit Kind check
3089 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3092 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3093 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3094 r.BaseMembersProvider = this;
3097 if (cerrors != null)
3098 r.CustomErrors = cerrors;
3100 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3101 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3102 if (best_candidate == null)
3103 return r.BestCandidateIsDynamic ? this : null;
3105 // Overload resolver had to create a new method group, all checks bellow have already been executed
3106 if (r.BestCandidateNewMethodGroup != null)
3107 return r.BestCandidateNewMethodGroup;
3109 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3110 if (InstanceExpression != null) {
3111 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3112 InstanceExpression = null;
3114 if (best_candidate.IsStatic && simple_name != null) {
3115 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3118 InstanceExpression.Resolve (ec);
3122 ResolveInstanceExpression (ec, null);
3123 if (InstanceExpression != null)
3124 CheckProtectedMemberAccess (ec, best_candidate);
3127 var base_override = CandidateToBaseOverride (ec, best_candidate);
3128 if (base_override == best_candidate) {
3129 best_candidate_return = r.BestCandidateReturnType;
3131 best_candidate = base_override;
3132 best_candidate_return = best_candidate.ReturnType;
3138 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3140 simple_name = original;
3141 return base.ResolveMemberAccess (ec, left, original);
3144 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3146 type_arguments = ta;
3149 #region IBaseMembersProvider Members
3151 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3153 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3156 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3158 if (queried_type == member.DeclaringType)
3161 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3162 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3166 // Extension methods lookup after ordinary methods candidates failed to apply
3168 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3170 if (InstanceExpression == null)
3173 InstanceExpression = InstanceExpression.Resolve (rc);
3174 if (!IsExtensionMethodArgument (InstanceExpression))
3177 int arity = type_arguments == null ? 0 : type_arguments.Count;
3178 NamespaceContainer methods_scope = null;
3179 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3180 if (methods == null)
3183 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3184 emg.SetTypeArguments (rc, type_arguments);
3191 public struct OverloadResolver
3194 public enum Restrictions
3198 ProbingOnly = 1 << 1,
3199 CovariantDelegate = 1 << 2,
3200 NoBaseMembers = 1 << 3,
3201 BaseMembersIncluded = 1 << 4
3204 public interface IBaseMembersProvider
3206 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3207 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3208 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3211 public interface IErrorHandler
3213 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3214 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3215 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3216 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3219 sealed class NoBaseMembers : IBaseMembersProvider
3221 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3223 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3228 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3233 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3239 struct AmbiguousCandidate
3241 public readonly MemberSpec Member;
3242 public readonly bool Expanded;
3243 public readonly AParametersCollection Parameters;
3245 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3248 Parameters = parameters;
3249 Expanded = expanded;
3254 IList<MemberSpec> members;
3255 TypeArguments type_arguments;
3256 IBaseMembersProvider base_provider;
3257 IErrorHandler custom_errors;
3258 Restrictions restrictions;
3259 MethodGroupExpr best_candidate_extension_group;
3260 TypeSpec best_candidate_return_type;
3262 SessionReportPrinter lambda_conv_msgs;
3263 ReportPrinter prev_recorder;
3265 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3266 : this (members, null, restrictions, loc)
3270 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3273 if (members == null || members.Count == 0)
3274 throw new ArgumentException ("empty members set");
3276 this.members = members;
3278 type_arguments = targs;
3279 this.restrictions = restrictions;
3280 if (IsDelegateInvoke)
3281 this.restrictions |= Restrictions.NoBaseMembers;
3283 base_provider = NoBaseMembers.Instance;
3288 public IBaseMembersProvider BaseMembersProvider {
3290 return base_provider;
3293 base_provider = value;
3297 public bool BestCandidateIsDynamic { get; set; }
3300 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3302 public MethodGroupExpr BestCandidateNewMethodGroup {
3304 return best_candidate_extension_group;
3309 // Return type can be different between best candidate and closest override
3311 public TypeSpec BestCandidateReturnType {
3313 return best_candidate_return_type;
3317 public IErrorHandler CustomErrors {
3319 return custom_errors;
3322 custom_errors = value;
3326 TypeSpec DelegateType {
3328 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3329 throw new InternalErrorException ("Not running in delegate mode", loc);
3331 return members [0].DeclaringType;
3335 bool IsProbingOnly {
3337 return (restrictions & Restrictions.ProbingOnly) != 0;
3341 bool IsDelegateInvoke {
3343 return (restrictions & Restrictions.DelegateInvoke) != 0;
3350 // 7.4.3.3 Better conversion from expression
3351 // Returns : 1 if a->p is better,
3352 // 2 if a->q is better,
3353 // 0 if neither is better
3355 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3357 TypeSpec argument_type = a.Type;
3360 // If argument is an anonymous function
3362 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3364 // p and q are delegate types or expression tree types
3366 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3367 if (q.MemberDefinition != p.MemberDefinition) {
3372 // Uwrap delegate from Expression<T>
3374 q = TypeManager.GetTypeArguments (q)[0];
3375 p = TypeManager.GetTypeArguments (p)[0];
3378 var p_m = Delegate.GetInvokeMethod (p);
3379 var q_m = Delegate.GetInvokeMethod (q);
3382 // With identical parameter lists
3384 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3391 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3393 if (p.Kind == MemberKind.Void) {
3394 return q.Kind != MemberKind.Void ? 2 : 0;
3398 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3400 if (q.Kind == MemberKind.Void) {
3401 return p.Kind != MemberKind.Void ? 1: 0;
3404 if (argument_type == p)
3407 if (argument_type == q)
3411 return BetterTypeConversion (ec, p, q);
3415 // 7.4.3.4 Better conversion from type
3417 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3419 if (p == null || q == null)
3420 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3422 switch (p.BuiltinType) {
3423 case BuiltinTypeSpec.Type.Int:
3424 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3427 case BuiltinTypeSpec.Type.Long:
3428 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3431 case BuiltinTypeSpec.Type.SByte:
3432 switch (q.BuiltinType) {
3433 case BuiltinTypeSpec.Type.Byte:
3434 case BuiltinTypeSpec.Type.UShort:
3435 case BuiltinTypeSpec.Type.UInt:
3436 case BuiltinTypeSpec.Type.ULong:
3440 case BuiltinTypeSpec.Type.Short:
3441 switch (q.BuiltinType) {
3442 case BuiltinTypeSpec.Type.UShort:
3443 case BuiltinTypeSpec.Type.UInt:
3444 case BuiltinTypeSpec.Type.ULong:
3448 case BuiltinTypeSpec.Type.Dynamic:
3449 // Dynamic is never better
3453 switch (q.BuiltinType) {
3454 case BuiltinTypeSpec.Type.Int:
3455 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3458 case BuiltinTypeSpec.Type.Long:
3459 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3462 case BuiltinTypeSpec.Type.SByte:
3463 switch (p.BuiltinType) {
3464 case BuiltinTypeSpec.Type.Byte:
3465 case BuiltinTypeSpec.Type.UShort:
3466 case BuiltinTypeSpec.Type.UInt:
3467 case BuiltinTypeSpec.Type.ULong:
3471 case BuiltinTypeSpec.Type.Short:
3472 switch (p.BuiltinType) {
3473 case BuiltinTypeSpec.Type.UShort:
3474 case BuiltinTypeSpec.Type.UInt:
3475 case BuiltinTypeSpec.Type.ULong:
3479 case BuiltinTypeSpec.Type.Dynamic:
3480 // Dynamic is never better
3484 // FIXME: handle lifted operators
3486 // TODO: this is expensive
3487 Expression p_tmp = new EmptyExpression (p);
3488 Expression q_tmp = new EmptyExpression (q);
3490 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3491 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3493 if (p_to_q && !q_to_p)
3496 if (q_to_p && !p_to_q)
3503 /// Determines "Better function" between candidate
3504 /// and the current best match
3507 /// Returns a boolean indicating :
3508 /// false if candidate ain't better
3509 /// true if candidate is better than the current best match
3511 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3512 MemberSpec best, AParametersCollection bparam, bool best_params)
3514 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3515 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3517 bool better_at_least_one = false;
3519 int args_count = args == null ? 0 : args.Count;
3523 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3526 // Default arguments are ignored for better decision
3527 if (a.IsDefaultArgument)
3531 // When comparing named argument the parameter type index has to be looked up
3532 // in original parameter set (override version for virtual members)
3534 NamedArgument na = a as NamedArgument;
3536 int idx = cparam.GetParameterIndexByName (na.Name);
3537 ct = candidate_pd.Types[idx];
3538 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3539 ct = TypeManager.GetElementType (ct);
3541 idx = bparam.GetParameterIndexByName (na.Name);
3542 bt = best_pd.Types[idx];
3543 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3544 bt = TypeManager.GetElementType (bt);
3546 ct = candidate_pd.Types[c_idx];
3547 bt = best_pd.Types[b_idx];
3549 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3550 ct = TypeManager.GetElementType (ct);
3554 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3555 bt = TypeManager.GetElementType (bt);
3560 if (TypeSpecComparer.IsEqual (ct, bt))
3564 int result = BetterExpressionConversion (ec, a, ct, bt);
3566 // for each argument, the conversion to 'ct' should be no worse than
3567 // the conversion to 'bt'.
3571 // for at least one argument, the conversion to 'ct' should be better than
3572 // the conversion to 'bt'.
3574 better_at_least_one = true;
3577 if (better_at_least_one)
3581 // This handles the case
3583 // Add (float f1, float f2, float f3);
3584 // Add (params decimal [] foo);
3586 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3587 // first candidate would've chosen as better.
3589 if (!same && !a.IsDefaultArgument)
3593 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3597 // This handles the following cases:
3599 // Foo (int i) is better than Foo (int i, long l = 0)
3600 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3602 // Prefer non-optional version
3604 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3606 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3607 if (candidate_pd.Count >= best_pd.Count)
3610 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3617 // One is a non-generic method and second is a generic method, then non-generic is better
3619 if (best.IsGeneric != candidate.IsGeneric)
3620 return best.IsGeneric;
3623 // This handles the following cases:
3625 // Trim () is better than Trim (params char[] chars)
3626 // Concat (string s1, string s2, string s3) is better than
3627 // Concat (string s1, params string [] srest)
3628 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3630 // Prefer non-expanded version
3632 if (candidate_params != best_params)
3635 int candidate_param_count = candidate_pd.Count;
3636 int best_param_count = best_pd.Count;
3638 if (candidate_param_count != best_param_count)
3639 // can only happen if (candidate_params && best_params)
3640 return candidate_param_count > best_param_count && best_pd.HasParams;
3643 // Both methods have the same number of parameters, and the parameters have equal types
3644 // Pick the "more specific" signature using rules over original (non-inflated) types
3646 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3647 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3649 bool specific_at_least_once = false;
3650 for (j = 0; j < args_count; ++j) {
3651 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3653 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3654 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3656 ct = candidate_def_pd.Types[j];
3657 bt = best_def_pd.Types[j];
3662 TypeSpec specific = MoreSpecific (ct, bt);
3666 specific_at_least_once = true;
3669 if (specific_at_least_once)
3675 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3677 rc.Report.Error (1729, loc,
3678 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3679 type.GetSignatureForError (), argCount.ToString ());
3683 // Determines if the candidate method is applicable to the given set of arguments
3684 // There could be two different set of parameters for same candidate where one
3685 // is the closest override for default values and named arguments checks and second
3686 // one being the virtual base for the parameter types and modifiers.
3688 // A return value rates candidate method compatibility,
3689 // 0 = the best, int.MaxValue = the worst
3691 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)
3693 // Parameters of most-derived type used mainly for named and optional parameters
3694 var pd = pm.Parameters;
3696 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3697 // params modifier instead of most-derived type
3698 var cpd = ((IParametersMember) candidate).Parameters;
3699 int param_count = pd.Count;
3700 int optional_count = 0;
3702 Arguments orig_args = arguments;
3704 if (arg_count != param_count) {
3705 for (int i = 0; i < pd.Count; ++i) {
3706 if (pd.FixedParameters[i].HasDefaultValue) {
3707 optional_count = pd.Count - i;
3712 if (optional_count != 0) {
3713 // Readjust expected number when params used
3714 if (cpd.HasParams) {
3716 if (arg_count < param_count)
3718 } else if (arg_count > param_count) {
3719 int args_gap = System.Math.Abs (arg_count - param_count);
3720 return int.MaxValue - 10000 + args_gap;
3722 } else if (arg_count != param_count) {
3723 int args_gap = System.Math.Abs (arg_count - param_count);
3725 return int.MaxValue - 10000 + args_gap;
3726 if (arg_count < param_count - 1)
3727 return int.MaxValue - 10000 + args_gap;
3730 // Resize to fit optional arguments
3731 if (optional_count != 0) {
3732 if (arguments == null) {
3733 arguments = new Arguments (optional_count);
3735 // Have to create a new container, so the next run can do same
3736 var resized = new Arguments (param_count);
3737 resized.AddRange (arguments);
3738 arguments = resized;
3741 for (int i = arg_count; i < param_count; ++i)
3742 arguments.Add (null);
3746 if (arg_count > 0) {
3748 // Shuffle named arguments to the right positions if there are any
3750 if (arguments[arg_count - 1] is NamedArgument) {
3751 arg_count = arguments.Count;
3753 for (int i = 0; i < arg_count; ++i) {
3754 bool arg_moved = false;
3756 NamedArgument na = arguments[i] as NamedArgument;
3760 int index = pd.GetParameterIndexByName (na.Name);
3762 // Named parameter not found
3766 // already reordered
3771 if (index >= param_count) {
3772 // When using parameters which should not be available to the user
3773 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3776 arguments.Add (null);
3780 temp = arguments[index];
3782 // The slot has been taken by positional argument
3783 if (temp != null && !(temp is NamedArgument))
3788 arguments = arguments.MarkOrderedArgument (na);
3792 arguments[index] = arguments[i];
3793 arguments[i] = temp;
3800 arg_count = arguments.Count;
3802 } else if (arguments != null) {
3803 arg_count = arguments.Count;
3807 // 1. Handle generic method using type arguments when specified or type inference
3810 var ms = candidate as MethodSpec;
3811 if (ms != null && ms.IsGeneric) {
3812 // Setup constraint checker for probing only
3813 ConstraintChecker cc = new ConstraintChecker (null);
3815 if (type_arguments != null) {
3816 var g_args_count = ms.Arity;
3817 if (g_args_count != type_arguments.Count)
3818 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3820 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3822 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3823 // for now it simplifies things. I should probably add a callback to ResolveContext
3824 if (lambda_conv_msgs == null) {
3825 lambda_conv_msgs = new SessionReportPrinter ();
3826 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3829 var ti = new TypeInference (arguments);
3830 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3831 lambda_conv_msgs.EndSession ();
3834 return ti.InferenceScore - 20000;
3836 if (i_args.Length != 0) {
3837 ms = ms.MakeGenericMethod (ec, i_args);
3840 cc.IgnoreInferredDynamic = true;
3844 // Type arguments constraints have to match for the method to be applicable
3846 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3848 return int.MaxValue - 25000;
3852 // We have a generic return type and at same time the method is override which
3853 // means we have to also inflate override return type in case the candidate is
3854 // best candidate and override return type is different to base return type.
3856 // virtual Foo<T, object> with override Foo<T, dynamic>
3858 if (candidate != pm) {
3859 MethodSpec override_ms = (MethodSpec) pm;
3860 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3861 returnType = inflator.Inflate (returnType);
3863 returnType = ms.ReturnType;
3867 ptypes = ms.Parameters.Types;
3869 if (type_arguments != null)
3870 return int.MaxValue - 15000;
3876 // 2. Each argument has to be implicitly convertible to method parameter
3878 Parameter.Modifier p_mod = 0;
3881 for (int i = 0; i < arg_count; i++) {
3882 Argument a = arguments[i];
3884 if (!pd.FixedParameters[i].HasDefaultValue) {
3885 arguments = orig_args;
3886 return arg_count * 2 + 2;
3890 // Get the default value expression, we can use the same expression
3891 // if the type matches
3893 Expression e = pd.FixedParameters[i].DefaultValue;
3894 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3896 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3898 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3899 e = new MemberAccess (new MemberAccess (new MemberAccess (
3900 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3902 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3908 arguments[i] = new Argument (e, Argument.AType.Default);
3912 if (p_mod != Parameter.Modifier.PARAMS) {
3913 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3915 } else if (!params_expanded_form) {
3916 params_expanded_form = true;
3917 pt = ((ElementTypeSpec) pt).Element;
3923 if (!params_expanded_form) {
3924 if (a.ArgType == Argument.AType.ExtensionType) {
3926 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3929 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3930 Convert.ImplicitReferenceConversionExists (at, pt) ||
3931 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
3936 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3939 dynamicArgument = true;
3944 // It can be applicable in expanded form (when not doing exact match like for delegates)
3946 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3947 if (!params_expanded_form)
3948 pt = ((ElementTypeSpec) pt).Element;
3951 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3954 params_expanded_form = true;
3955 } else if (score < 0) {
3956 params_expanded_form = true;
3957 dynamicArgument = true;
3962 if (params_expanded_form)
3964 return (arg_count - i) * 2 + score;
3969 // When params parameter has no argument it will be provided later if the method is the best candidate
3971 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3972 params_expanded_form = true;
3975 // Restore original arguments for dynamic binder to keep the intention of original source code
3977 if (dynamicArgument)
3978 arguments = orig_args;
3984 // Tests argument compatibility with the parameter
3985 // The possible return values are
3987 // 1 - modifier mismatch
3988 // 2 - type mismatch
3989 // -1 - dynamic binding required
3991 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3994 // Types have to be identical when ref or out modifer
3995 // is used and argument is not of dynamic type
3997 if ((argument.Modifier | param_mod) != 0) {
3998 if (argument.Type != parameter) {
4000 // Do full equality check after quick path
4002 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4004 // Using dynamic for ref/out parameter can still succeed at runtime
4006 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4013 if (argument.Modifier != param_mod) {
4015 // Using dynamic for ref/out parameter can still succeed at runtime
4017 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4024 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4028 // Deploy custom error reporting for lambda methods. When probing lambda methods
4029 // keep all errors reported in separate set and once we are done and no best
4030 // candidate was found, this set is used to report more details about what was wrong
4033 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4034 if (lambda_conv_msgs == null) {
4035 lambda_conv_msgs = new SessionReportPrinter ();
4036 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4041 // Use implicit conversion in all modes to return same candidates when the expression
4042 // is used as argument or delegate conversion
4044 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4045 if (lambda_conv_msgs != null) {
4046 lambda_conv_msgs.EndSession ();
4056 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4058 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4060 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4063 var ac_p = p as ArrayContainer;
4065 var ac_q = ((ArrayContainer) q);
4066 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4067 if (specific == ac_p.Element)
4069 if (specific == ac_q.Element)
4071 } else if (TypeManager.IsGenericType (p)) {
4072 var pargs = TypeManager.GetTypeArguments (p);
4073 var qargs = TypeManager.GetTypeArguments (q);
4075 bool p_specific_at_least_once = false;
4076 bool q_specific_at_least_once = false;
4078 for (int i = 0; i < pargs.Length; i++) {
4079 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4080 if (specific == pargs[i])
4081 p_specific_at_least_once = true;
4082 if (specific == qargs[i])
4083 q_specific_at_least_once = true;
4086 if (p_specific_at_least_once && !q_specific_at_least_once)
4088 if (!p_specific_at_least_once && q_specific_at_least_once)
4096 // Find the best method from candidate list
4098 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4100 List<AmbiguousCandidate> ambiguous_candidates = null;
4102 MemberSpec best_candidate;
4103 Arguments best_candidate_args = null;
4104 bool best_candidate_params = false;
4105 bool best_candidate_dynamic = false;
4106 int best_candidate_rate;
4107 IParametersMember best_parameter_member = null;
4109 int args_count = args != null ? args.Count : 0;
4111 Arguments candidate_args = args;
4112 bool error_mode = false;
4113 MemberSpec invocable_member = null;
4115 // Be careful, cannot return until error reporter is restored
4117 best_candidate = null;
4118 best_candidate_rate = int.MaxValue;
4120 var type_members = members;
4124 for (int i = 0; i < type_members.Count; ++i) {
4125 var member = type_members[i];
4128 // Methods in a base class are not candidates if any method in a derived
4129 // class is applicable
4131 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4135 if (!member.IsAccessible (rc))
4138 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4142 IParametersMember pm = member as IParametersMember;
4145 // Will use it later to report ambiguity between best method and invocable member
4147 if (Invocation.IsMemberInvocable (member))
4148 invocable_member = member;
4154 // Overload resolution is looking for base member but using parameter names
4155 // and default values from the closest member. That means to do expensive lookup
4156 // for the closest override for virtual or abstract members
4158 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4159 var override_params = base_provider.GetOverrideMemberParameters (member);
4160 if (override_params != null)
4161 pm = override_params;
4165 // Check if the member candidate is applicable
4167 bool params_expanded_form = false;
4168 bool dynamic_argument = false;
4169 TypeSpec rt = pm.MemberType;
4170 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4173 // How does it score compare to others
4175 if (candidate_rate < best_candidate_rate) {
4176 best_candidate_rate = candidate_rate;
4177 best_candidate = member;
4178 best_candidate_args = candidate_args;
4179 best_candidate_params = params_expanded_form;
4180 best_candidate_dynamic = dynamic_argument;
4181 best_parameter_member = pm;
4182 best_candidate_return_type = rt;
4183 } else if (candidate_rate == 0) {
4185 // The member look is done per type for most operations but sometimes
4186 // it's not possible like for binary operators overload because they
4187 // are unioned between 2 sides
4189 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4190 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4195 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4197 // We pack all interface members into top level type which makes the overload resolution
4198 // more complicated for interfaces. We compensate it by removing methods with same
4199 // signature when building the cache hence this path should not really be hit often
4202 // interface IA { void Foo (int arg); }
4203 // interface IB : IA { void Foo (params int[] args); }
4205 // IB::Foo is the best overload when calling IB.Foo (1)
4208 if (ambiguous_candidates != null) {
4209 foreach (var amb_cand in ambiguous_candidates) {
4210 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4219 ambiguous_candidates = null;
4222 // Is the new candidate better
4223 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4227 best_candidate = member;
4228 best_candidate_args = candidate_args;
4229 best_candidate_params = params_expanded_form;
4230 best_candidate_dynamic = dynamic_argument;
4231 best_parameter_member = pm;
4232 best_candidate_return_type = rt;
4234 // It's not better but any other found later could be but we are not sure yet
4235 if (ambiguous_candidates == null)
4236 ambiguous_candidates = new List<AmbiguousCandidate> ();
4238 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4242 // Restore expanded arguments
4243 if (candidate_args != args)
4244 candidate_args = args;
4246 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4248 if (prev_recorder != null)
4249 rc.Report.SetPrinter (prev_recorder);
4253 // We've found exact match
4255 if (best_candidate_rate == 0)
4259 // Try extension methods lookup when no ordinary method match was found and provider enables it
4262 var emg = base_provider.LookupExtensionMethod (rc);
4264 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4266 best_candidate_extension_group = emg;
4267 return (T) (MemberSpec) emg.BestCandidate;
4272 // Don't run expensive error reporting mode for probing
4279 lambda_conv_msgs = null;
4284 // No best member match found, report an error
4286 if (best_candidate_rate != 0 || error_mode) {
4287 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4291 if (best_candidate_dynamic) {
4292 if (args[0].ArgType == Argument.AType.ExtensionType) {
4293 rc.Report.Error (1973, loc,
4294 "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",
4295 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4298 BestCandidateIsDynamic = true;
4303 // These flags indicates we are running delegate probing conversion. No need to
4304 // do more expensive checks
4306 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4307 return (T) best_candidate;
4309 if (ambiguous_candidates != null) {
4311 // Now check that there are no ambiguities i.e the selected method
4312 // should be better than all the others
4314 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4315 var candidate = ambiguous_candidates [ix];
4317 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4318 var ambiguous = candidate.Member;
4319 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4320 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4321 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4322 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4323 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4326 return (T) best_candidate;
4331 if (invocable_member != null) {
4332 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4333 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4334 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4335 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4339 // And now check if the arguments are all
4340 // compatible, perform conversions if
4341 // necessary etc. and return if everything is
4344 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4347 if (best_candidate == null)
4351 // Check ObsoleteAttribute on the best method
4353 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4354 if (oa != null && !rc.IsObsolete)
4355 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4357 var dep = best_candidate.GetMissingDependencies ();
4359 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4362 best_candidate.MemberDefinition.SetIsUsed ();
4364 args = best_candidate_args;
4365 return (T) best_candidate;
4368 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4370 return ResolveMember<MethodSpec> (rc, ref args);
4373 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4374 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4376 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4379 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4380 ec.Report.SymbolRelatedToPreviousError (method);
4381 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4382 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4383 TypeManager.CSharpSignature (method));
4386 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4387 TypeManager.CSharpSignature (method));
4388 } else if (IsDelegateInvoke) {
4389 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4390 DelegateType.GetSignatureForError ());
4392 ec.Report.SymbolRelatedToPreviousError (method);
4393 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4394 method.GetSignatureForError ());
4397 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4399 string index = (idx + 1).ToString ();
4400 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4401 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4402 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4403 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4404 index, Parameter.GetModifierSignature (a.Modifier));
4406 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4407 index, Parameter.GetModifierSignature (mod));
4408 } else if (a.Expr != ErrorExpression.Instance) {
4409 string p1 = a.GetSignatureForError ();
4410 string p2 = TypeManager.CSharpName (paramType);
4413 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4414 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4417 ec.Report.Error (1503, loc,
4418 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4423 // We have failed to find exact match so we return error info about the closest match
4425 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4427 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4428 int arg_count = args == null ? 0 : args.Count;
4430 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4431 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4432 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4436 if (lambda_conv_msgs != null) {
4437 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4442 // For candidates which match on parameters count report more details about incorrect arguments
4445 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4446 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4447 // Reject any inaccessible member
4448 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4449 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4450 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4454 var ms = best_candidate as MethodSpec;
4455 if (ms != null && ms.IsGeneric) {
4456 bool constr_ok = true;
4457 if (ms.TypeArguments != null)
4458 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4460 if (ta_count == 0) {
4461 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4465 rc.Report.Error (411, loc,
4466 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4467 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4474 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4480 // We failed to find any method with correct argument count, report best candidate
4482 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4485 if (best_candidate.Kind == MemberKind.Constructor) {
4486 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4487 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4488 } else if (IsDelegateInvoke) {
4489 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4490 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4491 DelegateType.GetSignatureForError (), arg_count.ToString ());
4493 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4494 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4495 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4496 name, arg_count.ToString ());
4500 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4502 var pd = pm.Parameters;
4503 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4505 Parameter.Modifier p_mod = 0;
4507 int a_idx = 0, a_pos = 0;
4509 ArrayInitializer params_initializers = null;
4510 bool has_unsafe_arg = pm.MemberType.IsPointer;
4511 int arg_count = args == null ? 0 : args.Count;
4513 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4515 if (p_mod != Parameter.Modifier.PARAMS) {
4516 p_mod = pd.FixedParameters[a_idx].ModFlags;
4518 has_unsafe_arg |= pt.IsPointer;
4520 if (p_mod == Parameter.Modifier.PARAMS) {
4521 if (chose_params_expanded) {
4522 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4523 pt = TypeManager.GetElementType (pt);
4529 // Types have to be identical when ref or out modifer is used
4531 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4532 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4535 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4541 NamedArgument na = a as NamedArgument;
4543 int name_index = pd.GetParameterIndexByName (na.Name);
4544 if (name_index < 0 || name_index >= pd.Count) {
4545 if (IsDelegateInvoke) {
4546 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4547 ec.Report.Error (1746, na.Location,
4548 "The delegate `{0}' does not contain a parameter named `{1}'",
4549 DelegateType.GetSignatureForError (), na.Name);
4551 ec.Report.SymbolRelatedToPreviousError (member);
4552 ec.Report.Error (1739, na.Location,
4553 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4554 TypeManager.CSharpSignature (member), na.Name);
4556 } else if (args[name_index] != a) {
4557 if (IsDelegateInvoke)
4558 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4560 ec.Report.SymbolRelatedToPreviousError (member);
4562 ec.Report.Error (1744, na.Location,
4563 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4568 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4571 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4572 custom_errors.NoArgumentMatch (ec, member);
4576 Expression conv = null;
4577 if (a.ArgType == Argument.AType.ExtensionType) {
4578 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4581 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4583 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4586 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4593 // Convert params arguments to an array initializer
4595 if (params_initializers != null) {
4596 // we choose to use 'a.Expr' rather than 'conv' so that
4597 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4598 params_initializers.Add (a.Expr);
4599 args.RemoveAt (a_idx--);
4604 // Update the argument with the implicit conversion
4608 if (a_idx != arg_count) {
4609 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4614 // Fill not provided arguments required by params modifier
4616 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4618 args = new Arguments (1);
4620 pt = ptypes[pd.Count - 1];
4621 pt = TypeManager.GetElementType (pt);
4622 has_unsafe_arg |= pt.IsPointer;
4623 params_initializers = new ArrayInitializer (0, loc);
4627 // Append an array argument with all params arguments
4629 if (params_initializers != null) {
4630 args.Add (new Argument (
4631 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4635 if (has_unsafe_arg && !ec.IsUnsafe) {
4636 Expression.UnsafeError (ec, loc);
4640 // We could infer inaccesible type arguments
4642 if (type_arguments == null && member.IsGeneric) {
4643 var ms = (MethodSpec) member;
4644 foreach (var ta in ms.TypeArguments) {
4645 if (!ta.IsAccessible (ec)) {
4646 ec.Report.SymbolRelatedToPreviousError (ta);
4647 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4657 public class ConstantExpr : MemberExpr
4659 readonly ConstSpec constant;
4661 public ConstantExpr (ConstSpec constant, Location loc)
4663 this.constant = constant;
4667 public override string Name {
4668 get { throw new NotImplementedException (); }
4671 public override bool IsInstance {
4672 get { return !IsStatic; }
4675 public override bool IsStatic {
4676 get { return true; }
4679 protected override TypeSpec DeclaringType {
4680 get { return constant.DeclaringType; }
4683 public override Expression CreateExpressionTree (ResolveContext ec)
4685 throw new NotSupportedException ("ET");
4688 protected override Expression DoResolve (ResolveContext rc)
4690 ResolveInstanceExpression (rc, null);
4691 DoBestMemberChecks (rc, constant);
4693 var c = constant.GetConstant (rc);
4695 // Creates reference expression to the constant value
4696 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4699 public override void Emit (EmitContext ec)
4701 throw new NotSupportedException ();
4704 public override string GetSignatureForError ()
4706 return constant.GetSignatureForError ();
4709 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4711 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4716 /// Fully resolved expression that evaluates to a Field
4718 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4719 protected FieldSpec spec;
4720 VariableInfo variable_info;
4722 LocalTemporary temp;
4725 protected FieldExpr (Location l)
4730 public FieldExpr (FieldSpec spec, Location loc)
4735 type = spec.MemberType;
4738 public FieldExpr (FieldBase fi, Location l)
4745 public override string Name {
4751 public bool IsHoisted {
4753 IVariableReference hv = InstanceExpression as IVariableReference;
4754 return hv != null && hv.IsHoisted;
4758 public override bool IsInstance {
4760 return !spec.IsStatic;
4764 public override bool IsStatic {
4766 return spec.IsStatic;
4770 public FieldSpec Spec {
4776 protected override TypeSpec DeclaringType {
4778 return spec.DeclaringType;
4782 public VariableInfo VariableInfo {
4784 return variable_info;
4790 public override string GetSignatureForError ()
4792 return TypeManager.GetFullNameSignature (spec);
4795 public bool IsMarshalByRefAccess (ResolveContext rc)
4797 // Checks possible ldflda of field access expression
4798 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
4799 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
4800 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
4803 public void SetHasAddressTaken ()
4805 IVariableReference vr = InstanceExpression as IVariableReference;
4807 vr.SetHasAddressTaken ();
4810 public override Expression CreateExpressionTree (ResolveContext ec)
4812 Expression instance;
4813 if (InstanceExpression == null) {
4814 instance = new NullLiteral (loc);
4816 instance = InstanceExpression.CreateExpressionTree (ec);
4819 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4821 CreateTypeOfExpression ());
4823 return CreateExpressionFactoryCall (ec, "Field", args);
4826 public Expression CreateTypeOfExpression ()
4828 return new TypeOfField (spec, loc);
4831 protected override Expression DoResolve (ResolveContext ec)
4833 return DoResolve (ec, null);
4836 Expression DoResolve (ResolveContext ec, Expression rhs)
4838 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4841 if (ResolveInstanceExpression (ec, rhs)) {
4842 // Resolve the field's instance expression while flow analysis is turned
4843 // off: when accessing a field "a.b", we must check whether the field
4844 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4846 if (lvalue_instance) {
4847 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4848 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
4850 Expression right_side =
4851 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4853 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4856 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4857 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4861 if (InstanceExpression == null)
4865 DoBestMemberChecks (ec, spec);
4868 var fb = spec as FixedFieldSpec;
4869 IVariableReference var = InstanceExpression as IVariableReference;
4871 if (lvalue_instance && var != null && var.VariableInfo != null) {
4872 var.VariableInfo.SetFieldAssigned (ec, Name);
4876 IFixedExpression fe = InstanceExpression as IFixedExpression;
4877 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4878 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4881 if (InstanceExpression.eclass != ExprClass.Variable) {
4882 ec.Report.SymbolRelatedToPreviousError (spec);
4883 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4884 TypeManager.GetFullNameSignature (spec));
4885 } else if (var != null && var.IsHoisted) {
4886 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4889 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4892 eclass = ExprClass.Variable;
4894 // If the instance expression is a local variable or parameter.
4895 if (var == null || var.VariableInfo == null)
4898 VariableInfo vi = var.VariableInfo;
4899 if (!vi.IsFieldAssigned (ec, Name, loc))
4902 variable_info = vi.GetSubStruct (Name);
4906 static readonly int [] codes = {
4907 191, // instance, write access
4908 192, // instance, out access
4909 198, // static, write access
4910 199, // static, out access
4911 1648, // member of value instance, write access
4912 1649, // member of value instance, out access
4913 1650, // member of value static, write access
4914 1651 // member of value static, out access
4917 static readonly string [] msgs = {
4918 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4919 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4920 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4921 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4922 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4923 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4924 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4925 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4928 // The return value is always null. Returning a value simplifies calling code.
4929 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4932 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4936 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4938 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4943 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4945 Expression e = DoResolve (ec, right_side);
4950 spec.MemberDefinition.SetIsAssigned ();
4952 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
4953 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4954 ec.Report.Warning (420, 1, loc,
4955 "`{0}': A volatile field references will not be treated as volatile",
4956 spec.GetSignatureForError ());
4959 if (spec.IsReadOnly) {
4960 // InitOnly fields can only be assigned in constructors or initializers
4961 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4962 return Report_AssignToReadonly (ec, right_side);
4964 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4966 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4967 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4968 return Report_AssignToReadonly (ec, right_side);
4969 // static InitOnly fields cannot be assigned-to in an instance constructor
4970 if (IsStatic && !ec.IsStatic)
4971 return Report_AssignToReadonly (ec, right_side);
4972 // instance constructors can't modify InitOnly fields of other instances of the same type
4973 if (!IsStatic && !(InstanceExpression is This))
4974 return Report_AssignToReadonly (ec, right_side);
4978 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
4979 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4980 ec.Report.Warning (197, 1, loc,
4981 "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",
4982 GetSignatureForError ());
4985 eclass = ExprClass.Variable;
4989 public override int GetHashCode ()
4991 return spec.GetHashCode ();
4994 public bool IsFixed {
4997 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4999 IVariableReference variable = InstanceExpression as IVariableReference;
5000 if (variable != null)
5001 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5003 IFixedExpression fe = InstanceExpression as IFixedExpression;
5004 return fe != null && fe.IsFixed;
5008 public override bool Equals (object obj)
5010 FieldExpr fe = obj as FieldExpr;
5014 if (spec != fe.spec)
5017 if (InstanceExpression == null || fe.InstanceExpression == null)
5020 return InstanceExpression.Equals (fe.InstanceExpression);
5023 public void Emit (EmitContext ec, bool leave_copy)
5025 bool is_volatile = false;
5027 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5030 spec.MemberDefinition.SetIsUsed ();
5034 ec.Emit (OpCodes.Volatile);
5036 ec.Emit (OpCodes.Ldsfld, spec);
5039 EmitInstance (ec, false);
5041 // Optimization for build-in types
5042 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5043 ec.EmitLoadFromPtr (type);
5045 var ff = spec as FixedFieldSpec;
5047 ec.Emit (OpCodes.Ldflda, spec);
5048 ec.Emit (OpCodes.Ldflda, ff.Element);
5051 ec.Emit (OpCodes.Volatile);
5053 ec.Emit (OpCodes.Ldfld, spec);
5059 ec.Emit (OpCodes.Dup);
5061 temp = new LocalTemporary (this.Type);
5067 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5069 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5071 EmitInstance (ec, prepared);
5075 ec.Emit (OpCodes.Dup);
5077 temp = new LocalTemporary (this.Type);
5082 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5083 ec.Emit (OpCodes.Volatile);
5085 spec.MemberDefinition.SetIsAssigned ();
5088 ec.Emit (OpCodes.Stsfld, spec);
5090 ec.Emit (OpCodes.Stfld, spec);
5099 public override void Emit (EmitContext ec)
5104 public override void EmitSideEffect (EmitContext ec)
5106 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5108 if (is_volatile) // || is_marshal_by_ref ())
5109 base.EmitSideEffect (ec);
5112 public void AddressOf (EmitContext ec, AddressOp mode)
5114 if ((mode & AddressOp.Store) != 0)
5115 spec.MemberDefinition.SetIsAssigned ();
5116 if ((mode & AddressOp.Load) != 0)
5117 spec.MemberDefinition.SetIsUsed ();
5120 // Handle initonly fields specially: make a copy and then
5121 // get the address of the copy.
5124 if (spec.IsReadOnly){
5126 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5139 local = ec.DeclareLocal (type, false);
5140 ec.Emit (OpCodes.Stloc, local);
5141 ec.Emit (OpCodes.Ldloca, local);
5147 ec.Emit (OpCodes.Ldsflda, spec);
5150 EmitInstance (ec, false);
5151 ec.Emit (OpCodes.Ldflda, spec);
5155 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5157 return MakeExpression (ctx);
5160 public override SLE.Expression MakeExpression (BuilderContext ctx)
5163 return base.MakeExpression (ctx);
5165 return SLE.Expression.Field (
5166 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5167 spec.GetMetaInfo ());
5171 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5173 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5179 /// Expression that evaluates to a Property. The Assign class
5180 /// might set the `Value' expression if we are in an assignment.
5182 /// This is not an LValue because we need to re-write the expression, we
5183 /// can not take data from the stack and store it.
5185 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5187 public PropertyExpr (PropertySpec spec, Location l)
5190 best_candidate = spec;
5191 type = spec.MemberType;
5196 protected override TypeSpec DeclaringType {
5198 return best_candidate.DeclaringType;
5202 public override string Name {
5204 return best_candidate.Name;
5208 public override bool IsInstance {
5214 public override bool IsStatic {
5216 return best_candidate.IsStatic;
5220 public PropertySpec PropertyInfo {
5222 return best_candidate;
5228 public override Expression CreateExpressionTree (ResolveContext ec)
5231 if (IsSingleDimensionalArrayLength ()) {
5232 args = new Arguments (1);
5233 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5234 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5237 args = new Arguments (2);
5238 if (InstanceExpression == null)
5239 args.Add (new Argument (new NullLiteral (loc)));
5241 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5242 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5243 return CreateExpressionFactoryCall (ec, "Property", args);
5246 public Expression CreateSetterTypeOfExpression ()
5248 return new TypeOfMethod (Setter, loc);
5251 public override string GetSignatureForError ()
5253 return best_candidate.GetSignatureForError ();
5256 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5259 return base.MakeExpression (ctx);
5261 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5265 public override SLE.Expression MakeExpression (BuilderContext ctx)
5268 return base.MakeExpression (ctx);
5270 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5274 void Error_PropertyNotValid (ResolveContext ec)
5276 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5277 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5278 GetSignatureForError ());
5281 bool IsSingleDimensionalArrayLength ()
5283 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5286 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5287 return ac != null && ac.Rank == 1;
5290 public override void Emit (EmitContext ec, bool leave_copy)
5293 // Special case: length of single dimension array property is turned into ldlen
5295 if (IsSingleDimensionalArrayLength ()) {
5297 EmitInstance (ec, false);
5298 ec.Emit (OpCodes.Ldlen);
5299 ec.Emit (OpCodes.Conv_I4);
5303 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5306 ec.Emit (OpCodes.Dup);
5308 temp = new LocalTemporary (this.Type);
5314 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5318 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5319 args = new Arguments (0);
5324 ec.Emit (OpCodes.Dup);
5326 temp = new LocalTemporary (this.Type);
5331 args = new Arguments (1);
5335 temp = new LocalTemporary (this.Type);
5337 args.Add (new Argument (temp));
5339 args.Add (new Argument (source));
5343 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5351 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5353 eclass = ExprClass.PropertyAccess;
5355 if (best_candidate.IsNotRealProperty) {
5356 Error_PropertyNotValid (rc);
5359 ResolveInstanceExpression (rc, right_side);
5361 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5362 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5363 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5365 type = p.MemberType;
5369 DoBestMemberChecks (rc, best_candidate);
5373 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5375 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5379 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5381 // getter and setter can be different for base calls
5382 MethodSpec getter, setter;
5383 protected T best_candidate;
5385 protected LocalTemporary temp;
5386 protected bool prepared;
5388 protected PropertyOrIndexerExpr (Location l)
5395 public MethodSpec Getter {
5404 public MethodSpec Setter {
5415 protected override Expression DoResolve (ResolveContext ec)
5417 if (eclass == ExprClass.Unresolved) {
5418 var expr = OverloadResolve (ec, null);
5423 return expr.Resolve (ec);
5426 if (!ResolveGetter (ec))
5432 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5434 if (right_side == EmptyExpression.OutAccess) {
5435 // TODO: best_candidate can be null at this point
5436 INamedBlockVariable variable = null;
5437 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5438 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5439 best_candidate.Name);
5441 right_side.DoResolveLValue (ec, this);
5446 // if the property/indexer returns a value type, and we try to set a field in it
5447 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5448 Error_CannotModifyIntermediateExpressionValue (ec);
5451 if (eclass == ExprClass.Unresolved) {
5452 var expr = OverloadResolve (ec, right_side);
5457 return expr.ResolveLValue (ec, right_side);
5460 if (!ResolveSetter (ec))
5467 // Implements the IAssignMethod interface for assignments
5469 public abstract void Emit (EmitContext ec, bool leave_copy);
5470 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5472 public override void Emit (EmitContext ec)
5477 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5479 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5481 bool ResolveGetter (ResolveContext rc)
5483 if (!best_candidate.HasGet) {
5484 if (InstanceExpression != EmptyExpression.Null) {
5485 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5486 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5487 best_candidate.GetSignatureForError ());
5490 } else if (!best_candidate.Get.IsAccessible (rc)) {
5491 if (best_candidate.HasDifferentAccessibility) {
5492 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5493 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5494 TypeManager.CSharpSignature (best_candidate));
5496 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5497 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5501 if (best_candidate.HasDifferentAccessibility) {
5502 CheckProtectedMemberAccess (rc, best_candidate.Get);
5505 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5509 bool ResolveSetter (ResolveContext rc)
5511 if (!best_candidate.HasSet) {
5512 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5513 GetSignatureForError ());
5517 if (!best_candidate.Set.IsAccessible (rc)) {
5518 if (best_candidate.HasDifferentAccessibility) {
5519 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5520 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5521 GetSignatureForError ());
5523 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5524 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5528 if (best_candidate.HasDifferentAccessibility)
5529 CheckProtectedMemberAccess (rc, best_candidate.Set);
5531 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5537 /// Fully resolved expression that evaluates to an Event
5539 public class EventExpr : MemberExpr, IAssignMethod
5541 readonly EventSpec spec;
5544 public EventExpr (EventSpec spec, Location loc)
5552 protected override TypeSpec DeclaringType {
5554 return spec.DeclaringType;
5558 public override string Name {
5564 public override bool IsInstance {
5566 return !spec.IsStatic;
5570 public override bool IsStatic {
5572 return spec.IsStatic;
5576 public MethodSpec Operator {
5584 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5587 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5589 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5590 if (spec.BackingField != null &&
5591 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5593 spec.MemberDefinition.SetIsUsed ();
5595 if (!ec.IsObsolete) {
5596 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5598 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5601 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5602 Error_AssignmentEventOnly (ec);
5604 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5606 InstanceExpression = null;
5608 return ml.ResolveMemberAccess (ec, left, original);
5612 return base.ResolveMemberAccess (ec, left, original);
5615 public override Expression CreateExpressionTree (ResolveContext ec)
5617 throw new NotSupportedException ("ET");
5620 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5622 if (right_side == EmptyExpression.EventAddition) {
5623 op = spec.AccessorAdd;
5624 } else if (right_side == EmptyExpression.EventSubtraction) {
5625 op = spec.AccessorRemove;
5629 Error_AssignmentEventOnly (ec);
5633 op = CandidateToBaseOverride (ec, op);
5637 protected override Expression DoResolve (ResolveContext ec)
5639 eclass = ExprClass.EventAccess;
5640 type = spec.MemberType;
5642 ResolveInstanceExpression (ec, null);
5644 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5645 Error_AssignmentEventOnly (ec);
5648 DoBestMemberChecks (ec, spec);
5652 public override void Emit (EmitContext ec)
5654 throw new NotSupportedException ();
5655 //Error_CannotAssign ();
5658 #region IAssignMethod Members
5660 public void Emit (EmitContext ec, bool leave_copy)
5662 throw new NotImplementedException ();
5665 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5667 if (leave_copy || !prepare_for_load)
5668 throw new NotImplementedException ("EventExpr::EmitAssign");
5670 Arguments args = new Arguments (1);
5671 args.Add (new Argument (source));
5672 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5677 void Error_AssignmentEventOnly (ResolveContext ec)
5679 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5680 ec.Report.Error (79, loc,
5681 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5682 GetSignatureForError ());
5684 ec.Report.Error (70, loc,
5685 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5686 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5690 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5692 name = name.Substring (0, name.LastIndexOf ('.'));
5693 base.Error_CannotCallAbstractBase (rc, name);
5696 public override string GetSignatureForError ()
5698 return TypeManager.CSharpSignature (spec);
5701 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5703 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
5707 public class TemporaryVariableReference : VariableReference
5709 public class Declarator : Statement
5711 TemporaryVariableReference variable;
5713 public Declarator (TemporaryVariableReference variable)
5715 this.variable = variable;
5719 protected override void DoEmit (EmitContext ec)
5721 variable.li.CreateBuilder (ec);
5724 protected override void CloneTo (CloneContext clonectx, Statement target)
5732 public TemporaryVariableReference (LocalVariable li, Location loc)
5735 this.type = li.Type;
5739 public override bool IsLockedByStatement {
5747 public LocalVariable LocalInfo {
5753 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5755 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5756 return new TemporaryVariableReference (li, loc);
5759 public override Expression CreateExpressionTree (ResolveContext ec)
5761 throw new NotSupportedException ("ET");
5764 protected override Expression DoResolve (ResolveContext ec)
5766 eclass = ExprClass.Variable;
5769 // Don't capture temporary variables except when using
5770 // iterator redirection
5772 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5773 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5774 storey.CaptureLocalVariable (ec, li);
5780 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5782 return Resolve (ec);
5785 public override void Emit (EmitContext ec)
5787 li.CreateBuilder (ec);
5792 public void EmitAssign (EmitContext ec, Expression source)
5794 li.CreateBuilder (ec);
5796 EmitAssign (ec, source, false, false);
5799 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5801 return li.HoistedVariant;
5804 public override bool IsFixed {
5805 get { return true; }
5808 public override bool IsRef {
5809 get { return false; }
5812 public override string Name {
5813 get { throw new NotImplementedException (); }
5816 public override void SetHasAddressTaken ()
5818 throw new NotImplementedException ();
5821 protected override ILocalVariable Variable {
5825 public override VariableInfo VariableInfo {
5826 get { throw new NotImplementedException (); }
5831 /// Handles `var' contextual keyword; var becomes a keyword only
5832 /// if no type called var exists in a variable scope
5834 class VarExpr : SimpleName
5836 public VarExpr (Location loc)
5841 public bool InferType (ResolveContext ec, Expression right_side)
5844 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5846 type = right_side.Type;
5847 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5848 ec.Report.Error (815, loc,
5849 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5850 type.GetSignatureForError ());
5854 eclass = ExprClass.Variable;
5858 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5860 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5861 base.Error_TypeOrNamespaceNotFound (ec);
5863 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");