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 || non_method.IsNotCSharpCompatible) {
590 } else if (!errorMode && !member.IsNotCSharpCompatible) {
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 rc)
1870 return expr.CreateExpressionTree (rc);
1873 public Expression Child {
1874 get { return expr; }
1877 protected override Expression DoResolve (ResolveContext rc)
1879 expr = expr.Resolve (rc);
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 public Expression Expr {
1916 protected override void CloneTo (CloneContext clonectx, Expression t)
1921 ShimExpression target = (ShimExpression) t;
1922 target.expr = expr.Clone (clonectx);
1925 public override Expression CreateExpressionTree (ResolveContext ec)
1927 throw new NotSupportedException ("ET");
1930 public override void Emit (EmitContext ec)
1932 throw new InternalErrorException ("Missing Resolve call");
1938 // Unresolved type name expressions
1940 public abstract class ATypeNameExpression : FullNamedExpression
1943 protected TypeArguments targs;
1945 protected ATypeNameExpression (string name, Location l)
1951 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
1958 protected ATypeNameExpression (string name, int arity, Location l)
1959 : this (name, new UnboundTypeArguments (arity), l)
1965 protected int Arity {
1967 return targs == null ? 0 : targs.Count;
1971 public bool HasTypeArguments {
1973 return targs != null && !targs.IsEmpty;
1977 public string Name {
1986 public TypeArguments TypeArguments {
1994 public override bool Equals (object obj)
1996 ATypeNameExpression atne = obj as ATypeNameExpression;
1997 return atne != null && atne.Name == Name &&
1998 (targs == null || targs.Equals (atne.targs));
2001 public override int GetHashCode ()
2003 return Name.GetHashCode ();
2006 // TODO: Move it to MemberCore
2007 public static string GetMemberType (MemberCore mc)
2013 if (mc is FieldBase)
2015 if (mc is MethodCore)
2017 if (mc is EnumMember)
2025 public override string GetSignatureForError ()
2027 if (targs != null) {
2028 return Name + "<" + targs.GetSignatureForError () + ">";
2034 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2038 /// SimpleName expressions are formed of a single word and only happen at the beginning
2039 /// of a dotted-name.
2041 public class SimpleName : ATypeNameExpression
2043 public SimpleName (string name, Location l)
2048 public SimpleName (string name, TypeArguments args, Location l)
2049 : base (name, args, l)
2053 public SimpleName (string name, int arity, Location l)
2054 : base (name, arity, l)
2058 public SimpleName GetMethodGroup ()
2060 return new SimpleName (Name, targs, loc);
2063 protected override Expression DoResolve (ResolveContext ec)
2065 return SimpleNameResolve (ec, null, false);
2068 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2070 return SimpleNameResolve (ec, right_side, false);
2073 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2075 if (ctx.CurrentType != null) {
2076 if (ctx.CurrentMemberDefinition != null) {
2077 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2079 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2086 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2087 if (retval != null) {
2088 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2089 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2093 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2094 if (retval != null) {
2095 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2099 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2102 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2104 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2107 if (fne.Type != null && Arity > 0) {
2108 if (HasTypeArguments) {
2109 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2110 if (ct.ResolveAsType (ec) == null)
2116 return new GenericOpenTypeExpr (fne.Type, loc);
2120 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2122 if (!(fne is Namespace))
2126 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2127 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2128 ec.Module.Compiler.Report.Error (1980, Location,
2129 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2130 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2133 fne = new DynamicTypeExpr (loc);
2134 fne.ResolveAsType (ec);
2140 Error_TypeOrNamespaceNotFound (ec);
2144 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2146 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2149 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2151 int lookup_arity = Arity;
2152 bool errorMode = false;
2154 Block current_block = rc.CurrentBlock;
2155 INamedBlockVariable variable = null;
2156 bool variable_found = false;
2160 // Stage 1: binding to local variables or parameters
2162 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2164 if (current_block != null && lookup_arity == 0) {
2165 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2166 if (!variable.IsDeclared) {
2167 // We found local name in accessible block but it's not
2168 // initialized yet, maybe the user wanted to bind to something else
2170 variable_found = true;
2172 e = variable.CreateReferenceExpression (rc, loc);
2175 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2184 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2186 TypeSpec member_type = rc.CurrentType;
2187 for (; member_type != null; member_type = member_type.DeclaringType) {
2188 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2192 var me = e as MemberExpr;
2194 // The name matches a type, defer to ResolveAsTypeStep
2202 if (variable != null) {
2203 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2204 rc.Report.Error (844, loc,
2205 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2206 Name, me.GetSignatureForError ());
2210 } else if (me is MethodGroupExpr) {
2211 // Leave it to overload resolution to report correct error
2213 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2214 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2217 // LAMESPEC: again, ignores InvocableOnly
2218 if (variable != null) {
2219 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2220 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2224 // MemberLookup does not check accessors availability, this is actually needed for properties only
2226 var pe = me as PropertyExpr;
2229 // Break as there is no other overload available anyway
2230 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2231 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2234 pe.Getter = pe.PropertyInfo.Get;
2236 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2239 pe.Setter = pe.PropertyInfo.Set;
2244 // TODO: It's used by EventExpr -> FieldExpr transformation only
2245 // TODO: Should go to MemberAccess
2246 me = me.ResolveMemberAccess (rc, null, null);
2250 me.SetTypeArguments (rc, targs);
2257 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2259 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2260 if (IsPossibleTypeOrNamespace (rc)) {
2261 if (variable != null) {
2262 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2263 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2266 return ResolveAsTypeOrNamespace (rc);
2271 if (variable_found) {
2272 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2275 TypeParameter[] tparams = rc.CurrentTypeParameters;
2276 if (tparams != null) {
2277 foreach (var ctp in tparams) {
2278 if (ctp.Name == Name) {
2279 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2285 var ct = rc.CurrentType;
2287 if (ct.MemberDefinition.TypeParametersCount > 0) {
2288 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2289 if (ctp.Name == Name) {
2290 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2296 ct = ct.DeclaringType;
2297 } while (ct != null);
2300 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2301 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2303 rc.Report.SymbolRelatedToPreviousError (e.Type);
2304 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2309 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2311 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2312 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2317 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2320 return ErrorExpression.Instance;
2323 if (rc.Module.Evaluator != null) {
2324 var fi = rc.Module.Evaluator.LookupField (Name);
2326 return new FieldExpr (fi.Item1, loc);
2334 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2336 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2341 if (right_side != null) {
2342 if (e is TypeExpr) {
2343 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2347 e = e.ResolveLValue (ec, right_side);
2352 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2358 /// Represents a namespace or a type. The name of the class was inspired by
2359 /// section 10.8.1 (Fully Qualified Names).
2361 public abstract class FullNamedExpression : Expression
2363 protected override void CloneTo (CloneContext clonectx, Expression target)
2365 // Do nothing, most unresolved type expressions cannot be
2366 // resolved to different type
2369 public override Expression CreateExpressionTree (ResolveContext ec)
2371 throw new NotSupportedException ("ET");
2374 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2377 // This is used to resolve the expression as a type, a null
2378 // value will be returned if the expression is not a type
2381 public override TypeSpec ResolveAsType (IMemberContext mc)
2383 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2388 TypeExpr te = fne as TypeExpr;
2390 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2398 var dep = type.GetMissingDependencies ();
2400 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2404 // Obsolete checks cannot be done when resolving base context as they
2405 // require type dependencies to be set but we are in process of resolving them
2407 if (!(mc is TypeContainer.BaseContext)) {
2408 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2409 if (obsolete_attr != null && !mc.IsObsolete) {
2410 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2418 public override void Emit (EmitContext ec)
2420 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2421 GetSignatureForError ());
2426 /// Expression that evaluates to a type
2428 public abstract class TypeExpr : FullNamedExpression
2430 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2436 protected sealed override Expression DoResolve (ResolveContext ec)
2442 public override bool Equals (object obj)
2444 TypeExpr tobj = obj as TypeExpr;
2448 return Type == tobj.Type;
2451 public override int GetHashCode ()
2453 return Type.GetHashCode ();
2458 /// Fully resolved Expression that already evaluated to a type
2460 public class TypeExpression : TypeExpr
2462 public TypeExpression (TypeSpec t, Location l)
2465 eclass = ExprClass.Type;
2469 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2476 /// This class denotes an expression which evaluates to a member
2477 /// of a struct or a class.
2479 public abstract class MemberExpr : Expression
2482 // An instance expression associated with this member, if it's a
2483 // non-static member
2485 public Expression InstanceExpression;
2488 /// The name of this member.
2490 public abstract string Name {
2495 // When base.member is used
2497 public bool IsBase {
2498 get { return InstanceExpression is BaseThis; }
2502 /// Whether this is an instance member.
2504 public abstract bool IsInstance {
2509 /// Whether this is a static member.
2511 public abstract bool IsStatic {
2515 protected abstract TypeSpec DeclaringType {
2520 // Converts best base candidate for virtual method starting from QueriedBaseType
2522 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2525 // Only when base.member is used and method is virtual
2531 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2532 // means for base.member access we have to find the closest match after we found best candidate
2534 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2536 // The method could already be what we are looking for
2538 TypeSpec[] targs = null;
2539 if (method.DeclaringType != InstanceExpression.Type) {
2540 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2541 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2542 if (base_override.IsGeneric)
2543 targs = method.TypeArguments;
2545 method = base_override;
2549 // TODO: For now we do it for any hoisted call even if it's needed for
2550 // hoisted stories only but that requires a new expression wrapper
2551 if (rc.CurrentAnonymousMethod != null) {
2552 if (targs == null && method.IsGeneric) {
2553 targs = method.TypeArguments;
2554 method = method.GetGenericMethodDefinition ();
2557 if (method.Parameters.HasArglist)
2558 throw new NotImplementedException ("__arglist base call proxy");
2560 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2562 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2563 // get/set member expressions second call would fail to proxy because left expression
2564 // would be of 'this' and not 'base'
2565 if (rc.CurrentType.IsStruct)
2566 InstanceExpression = new This (loc).Resolve (rc);
2570 method = method.MakeGenericMethod (rc, targs);
2574 // Only base will allow this invocation to happen.
2576 if (method.IsAbstract) {
2577 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2583 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2585 if (InstanceExpression == null)
2588 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2589 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2593 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2595 var ct = rc.CurrentType;
2596 if (ct == qualifier)
2599 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2602 qualifier = qualifier.GetDefinition ();
2603 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2604 rc.Report.SymbolRelatedToPreviousError (member);
2605 rc.Report.Error (1540, loc,
2606 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2607 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2611 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2614 type = type.GetDefinition ();
2616 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2619 type = type.DeclaringType;
2620 } while (type != null);
2625 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2627 if (InstanceExpression != null) {
2628 InstanceExpression = InstanceExpression.Resolve (rc);
2629 CheckProtectedMemberAccess (rc, member);
2632 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2633 UnsafeError (rc, loc);
2636 var dep = member.GetMissingDependencies ();
2638 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2641 if (!rc.IsObsolete) {
2642 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2644 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2647 if (!(member is FieldSpec))
2648 member.MemberDefinition.SetIsUsed ();
2651 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2653 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2657 // Implements identicial simple name and type-name
2659 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2662 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2665 // 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
2666 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2668 if (left is MemberExpr || left is VariableReference) {
2669 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2670 if (identical_type != null && identical_type.Type == left.Type)
2671 return identical_type;
2677 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2680 if (InstanceExpression != null) {
2681 if (InstanceExpression is TypeExpr) {
2682 var t = InstanceExpression.Type;
2684 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2685 if (oa != null && !rc.IsObsolete) {
2686 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2689 t = t.DeclaringType;
2690 } while (t != null);
2692 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2693 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2694 rc.Report.Error (176, loc,
2695 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2696 GetSignatureForError ());
2700 InstanceExpression = null;
2706 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2707 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2708 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2709 rc.Report.Error (236, loc,
2710 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2711 GetSignatureForError ());
2713 rc.Report.Error (120, loc,
2714 "An object reference is required to access non-static member `{0}'",
2715 GetSignatureForError ());
2720 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2721 rc.Report.Error (38, loc,
2722 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2723 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2726 InstanceExpression = new This (loc);
2727 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2728 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2729 InstanceExpression = InstanceExpression.Resolve (rc);
2732 InstanceExpression = InstanceExpression.Resolve (rc);
2738 var me = InstanceExpression as MemberExpr;
2740 me.ResolveInstanceExpression (rc, rhs);
2742 var fe = me as FieldExpr;
2743 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2744 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2745 rc.Report.Warning (1690, 1, loc,
2746 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2747 me.GetSignatureForError ());
2754 // Run member-access postponed check once we know that
2755 // the expression is not field expression which is the only
2756 // expression which can use uninitialized this
2758 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2759 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2763 // Additional checks for l-value member access
2767 // TODO: It should be recursive but that would break csc compatibility
2769 if (InstanceExpression is UnboxCast) {
2770 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2777 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2779 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2780 ec.Report.Warning (1720, 1, left.Location,
2781 "Expression will always cause a `{0}'", "System.NullReferenceException");
2784 InstanceExpression = left;
2788 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2790 TypeSpec instance_type = InstanceExpression.Type;
2791 if (TypeSpec.IsValueType (instance_type)) {
2792 if (InstanceExpression is IMemoryLocation) {
2793 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2795 LocalTemporary t = new LocalTemporary (instance_type);
2796 InstanceExpression.Emit (ec);
2798 t.AddressOf (ec, AddressOp.Store);
2801 InstanceExpression.Emit (ec);
2803 // Only to make verifier happy
2804 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2805 ec.Emit (OpCodes.Box, instance_type);
2808 if (prepare_for_load)
2809 ec.Emit (OpCodes.Dup);
2812 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2816 // Represents a group of extension method candidates for whole namespace
2818 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2820 NamespaceContainer namespace_entry;
2821 public readonly Expression ExtensionExpression;
2823 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
2824 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2826 this.namespace_entry = n;
2827 this.ExtensionExpression = extensionExpr;
2830 public override bool IsStatic {
2831 get { return true; }
2834 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2836 if (namespace_entry == null)
2840 // For extension methodgroup we are not looking for base members but parent
2841 // namespace extension methods
2843 int arity = type_arguments == null ? 0 : type_arguments.Count;
2844 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2848 return found.Cast<MemberSpec> ().ToList ();
2851 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2853 // We are already here
2857 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2859 if (arguments == null)
2860 arguments = new Arguments (1);
2862 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2863 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2865 // Store resolved argument and restore original arguments
2867 // Clean-up modified arguments for error reporting
2868 arguments.RemoveAt (0);
2872 var me = ExtensionExpression as MemberExpr;
2874 me.ResolveInstanceExpression (ec, null);
2876 InstanceExpression = null;
2880 #region IErrorHandler Members
2882 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2887 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2889 rc.Report.SymbolRelatedToPreviousError (best);
2890 rc.Report.Error (1928, loc,
2891 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2892 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2895 rc.Report.Error (1929, loc,
2896 "Extension method instance type `{0}' cannot be converted to `{1}'",
2897 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2903 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2908 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2917 /// MethodGroupExpr represents a group of method candidates which
2918 /// can be resolved to the best method overload
2920 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2922 protected IList<MemberSpec> Methods;
2923 MethodSpec best_candidate;
2924 TypeSpec best_candidate_return;
2925 protected TypeArguments type_arguments;
2927 SimpleName simple_name;
2928 protected TypeSpec queried_type;
2930 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2934 this.type = InternalType.MethodGroup;
2936 eclass = ExprClass.MethodGroup;
2937 queried_type = type;
2940 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2941 : this (new MemberSpec[] { m }, type, loc)
2947 public MethodSpec BestCandidate {
2949 return best_candidate;
2953 public TypeSpec BestCandidateReturnType {
2955 return best_candidate_return;
2959 public IList<MemberSpec> Candidates {
2965 protected override TypeSpec DeclaringType {
2967 return queried_type;
2971 public override bool IsInstance {
2973 if (best_candidate != null)
2974 return !best_candidate.IsStatic;
2980 public override bool IsStatic {
2982 if (best_candidate != null)
2983 return best_candidate.IsStatic;
2989 public override string Name {
2991 if (best_candidate != null)
2992 return best_candidate.Name;
2995 return Methods.First ().Name;
3002 // When best candidate is already know this factory can be used
3003 // to avoid expensive overload resolution to be called
3005 // NOTE: InstanceExpression has to be set manually
3007 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3009 return new MethodGroupExpr (best, queriedType, loc) {
3010 best_candidate = best,
3011 best_candidate_return = best.ReturnType
3015 public override string GetSignatureForError ()
3017 if (best_candidate != null)
3018 return best_candidate.GetSignatureForError ();
3020 return Methods.First ().GetSignatureForError ();
3023 public override Expression CreateExpressionTree (ResolveContext ec)
3025 if (best_candidate == null) {
3026 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3030 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3031 ec.Report.Error (765, loc,
3032 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3034 return new TypeOfMethod (best_candidate, loc);
3037 protected override Expression DoResolve (ResolveContext ec)
3039 this.eclass = ExprClass.MethodGroup;
3041 if (InstanceExpression != null) {
3042 InstanceExpression = InstanceExpression.Resolve (ec);
3043 if (InstanceExpression == null)
3050 public override void Emit (EmitContext ec)
3052 throw new NotSupportedException ();
3055 public void EmitCall (EmitContext ec, Arguments arguments)
3057 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3060 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3062 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3063 Name, TypeManager.CSharpName (target));
3066 public static bool IsExtensionMethodArgument (Expression expr)
3069 // LAMESPEC: No details about which expressions are not allowed
3071 return !(expr is TypeExpr) && !(expr is BaseThis);
3075 /// Find the Applicable Function Members (7.4.2.1)
3077 /// me: Method Group expression with the members to select.
3078 /// it might contain constructors or methods (or anything
3079 /// that maps to a method).
3081 /// Arguments: ArrayList containing resolved Argument objects.
3083 /// loc: The location if we want an error to be reported, or a Null
3084 /// location for "probing" purposes.
3086 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3087 /// that is the best match of me on Arguments.
3090 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3092 // TODO: causes issues with probing mode, remove explicit Kind check
3093 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3096 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3097 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3098 r.BaseMembersProvider = this;
3101 if (cerrors != null)
3102 r.CustomErrors = cerrors;
3104 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3105 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3106 if (best_candidate == null)
3107 return r.BestCandidateIsDynamic ? this : null;
3109 // Overload resolver had to create a new method group, all checks bellow have already been executed
3110 if (r.BestCandidateNewMethodGroup != null)
3111 return r.BestCandidateNewMethodGroup;
3113 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3114 if (InstanceExpression != null) {
3115 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3116 InstanceExpression = null;
3118 if (best_candidate.IsStatic && simple_name != null) {
3119 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3122 InstanceExpression.Resolve (ec);
3126 ResolveInstanceExpression (ec, null);
3127 if (InstanceExpression != null)
3128 CheckProtectedMemberAccess (ec, best_candidate);
3131 var base_override = CandidateToBaseOverride (ec, best_candidate);
3132 if (base_override == best_candidate) {
3133 best_candidate_return = r.BestCandidateReturnType;
3135 best_candidate = base_override;
3136 best_candidate_return = best_candidate.ReturnType;
3142 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3144 simple_name = original;
3145 return base.ResolveMemberAccess (ec, left, original);
3148 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3150 type_arguments = ta;
3153 #region IBaseMembersProvider Members
3155 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3157 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3160 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3162 if (queried_type == member.DeclaringType)
3165 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3166 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3170 // Extension methods lookup after ordinary methods candidates failed to apply
3172 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3174 if (InstanceExpression == null)
3177 InstanceExpression = InstanceExpression.Resolve (rc);
3178 if (!IsExtensionMethodArgument (InstanceExpression))
3181 int arity = type_arguments == null ? 0 : type_arguments.Count;
3182 NamespaceContainer methods_scope = null;
3183 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3184 if (methods == null)
3187 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3188 emg.SetTypeArguments (rc, type_arguments);
3195 public struct OverloadResolver
3198 public enum Restrictions
3202 ProbingOnly = 1 << 1,
3203 CovariantDelegate = 1 << 2,
3204 NoBaseMembers = 1 << 3,
3205 BaseMembersIncluded = 1 << 4
3208 public interface IBaseMembersProvider
3210 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3211 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3212 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3215 public interface IErrorHandler
3217 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3218 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3219 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3220 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3223 sealed class NoBaseMembers : IBaseMembersProvider
3225 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3227 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3232 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3237 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3243 struct AmbiguousCandidate
3245 public readonly MemberSpec Member;
3246 public readonly bool Expanded;
3247 public readonly AParametersCollection Parameters;
3249 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3252 Parameters = parameters;
3253 Expanded = expanded;
3258 IList<MemberSpec> members;
3259 TypeArguments type_arguments;
3260 IBaseMembersProvider base_provider;
3261 IErrorHandler custom_errors;
3262 Restrictions restrictions;
3263 MethodGroupExpr best_candidate_extension_group;
3264 TypeSpec best_candidate_return_type;
3266 SessionReportPrinter lambda_conv_msgs;
3267 ReportPrinter prev_recorder;
3269 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3270 : this (members, null, restrictions, loc)
3274 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3277 if (members == null || members.Count == 0)
3278 throw new ArgumentException ("empty members set");
3280 this.members = members;
3282 type_arguments = targs;
3283 this.restrictions = restrictions;
3284 if (IsDelegateInvoke)
3285 this.restrictions |= Restrictions.NoBaseMembers;
3287 base_provider = NoBaseMembers.Instance;
3292 public IBaseMembersProvider BaseMembersProvider {
3294 return base_provider;
3297 base_provider = value;
3301 public bool BestCandidateIsDynamic { get; set; }
3304 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3306 public MethodGroupExpr BestCandidateNewMethodGroup {
3308 return best_candidate_extension_group;
3313 // Return type can be different between best candidate and closest override
3315 public TypeSpec BestCandidateReturnType {
3317 return best_candidate_return_type;
3321 public IErrorHandler CustomErrors {
3323 return custom_errors;
3326 custom_errors = value;
3330 TypeSpec DelegateType {
3332 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3333 throw new InternalErrorException ("Not running in delegate mode", loc);
3335 return members [0].DeclaringType;
3339 bool IsProbingOnly {
3341 return (restrictions & Restrictions.ProbingOnly) != 0;
3345 bool IsDelegateInvoke {
3347 return (restrictions & Restrictions.DelegateInvoke) != 0;
3354 // 7.4.3.3 Better conversion from expression
3355 // Returns : 1 if a->p is better,
3356 // 2 if a->q is better,
3357 // 0 if neither is better
3359 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3361 TypeSpec argument_type = a.Type;
3364 // If argument is an anonymous function
3366 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3368 // p and q are delegate types or expression tree types
3370 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3371 if (q.MemberDefinition != p.MemberDefinition) {
3376 // Uwrap delegate from Expression<T>
3378 q = TypeManager.GetTypeArguments (q)[0];
3379 p = TypeManager.GetTypeArguments (p)[0];
3382 var p_m = Delegate.GetInvokeMethod (p);
3383 var q_m = Delegate.GetInvokeMethod (q);
3386 // With identical parameter lists
3388 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3395 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3397 if (p.Kind == MemberKind.Void) {
3398 return q.Kind != MemberKind.Void ? 2 : 0;
3402 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3404 if (q.Kind == MemberKind.Void) {
3405 return p.Kind != MemberKind.Void ? 1: 0;
3409 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3410 // better conversion is performed between underlying types Y1 and Y2
3412 if (p.IsGenericTask || q.IsGenericTask) {
3413 if (p.IsGenericTask != q.IsGenericTask) {
3417 var async_am = a.Expr as AnonymousMethodExpression;
3418 if (async_am == null || !async_am.IsAsync)
3421 q = q.TypeArguments[0];
3422 p = p.TypeArguments[0];
3426 // The parameters are identicial and return type is not void, use better type conversion
3427 // on return type to determine better one
3430 if (argument_type == p)
3433 if (argument_type == q)
3437 return BetterTypeConversion (ec, p, q);
3441 // 7.4.3.4 Better conversion from type
3443 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3445 if (p == null || q == null)
3446 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3448 switch (p.BuiltinType) {
3449 case BuiltinTypeSpec.Type.Int:
3450 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3453 case BuiltinTypeSpec.Type.Long:
3454 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3457 case BuiltinTypeSpec.Type.SByte:
3458 switch (q.BuiltinType) {
3459 case BuiltinTypeSpec.Type.Byte:
3460 case BuiltinTypeSpec.Type.UShort:
3461 case BuiltinTypeSpec.Type.UInt:
3462 case BuiltinTypeSpec.Type.ULong:
3466 case BuiltinTypeSpec.Type.Short:
3467 switch (q.BuiltinType) {
3468 case BuiltinTypeSpec.Type.UShort:
3469 case BuiltinTypeSpec.Type.UInt:
3470 case BuiltinTypeSpec.Type.ULong:
3474 case BuiltinTypeSpec.Type.Dynamic:
3475 // Dynamic is never better
3479 switch (q.BuiltinType) {
3480 case BuiltinTypeSpec.Type.Int:
3481 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3484 case BuiltinTypeSpec.Type.Long:
3485 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3488 case BuiltinTypeSpec.Type.SByte:
3489 switch (p.BuiltinType) {
3490 case BuiltinTypeSpec.Type.Byte:
3491 case BuiltinTypeSpec.Type.UShort:
3492 case BuiltinTypeSpec.Type.UInt:
3493 case BuiltinTypeSpec.Type.ULong:
3497 case BuiltinTypeSpec.Type.Short:
3498 switch (p.BuiltinType) {
3499 case BuiltinTypeSpec.Type.UShort:
3500 case BuiltinTypeSpec.Type.UInt:
3501 case BuiltinTypeSpec.Type.ULong:
3505 case BuiltinTypeSpec.Type.Dynamic:
3506 // Dynamic is never better
3510 // FIXME: handle lifted operators
3512 // TODO: this is expensive
3513 Expression p_tmp = new EmptyExpression (p);
3514 Expression q_tmp = new EmptyExpression (q);
3516 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3517 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3519 if (p_to_q && !q_to_p)
3522 if (q_to_p && !p_to_q)
3529 /// Determines "Better function" between candidate
3530 /// and the current best match
3533 /// Returns a boolean indicating :
3534 /// false if candidate ain't better
3535 /// true if candidate is better than the current best match
3537 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3538 MemberSpec best, AParametersCollection bparam, bool best_params)
3540 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3541 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3543 bool better_at_least_one = false;
3545 int args_count = args == null ? 0 : args.Count;
3549 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3552 // Default arguments are ignored for better decision
3553 if (a.IsDefaultArgument)
3557 // When comparing named argument the parameter type index has to be looked up
3558 // in original parameter set (override version for virtual members)
3560 NamedArgument na = a as NamedArgument;
3562 int idx = cparam.GetParameterIndexByName (na.Name);
3563 ct = candidate_pd.Types[idx];
3564 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3565 ct = TypeManager.GetElementType (ct);
3567 idx = bparam.GetParameterIndexByName (na.Name);
3568 bt = best_pd.Types[idx];
3569 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3570 bt = TypeManager.GetElementType (bt);
3572 ct = candidate_pd.Types[c_idx];
3573 bt = best_pd.Types[b_idx];
3575 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3576 ct = TypeManager.GetElementType (ct);
3580 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3581 bt = TypeManager.GetElementType (bt);
3586 if (TypeSpecComparer.IsEqual (ct, bt))
3590 int result = BetterExpressionConversion (ec, a, ct, bt);
3592 // for each argument, the conversion to 'ct' should be no worse than
3593 // the conversion to 'bt'.
3597 // for at least one argument, the conversion to 'ct' should be better than
3598 // the conversion to 'bt'.
3600 better_at_least_one = true;
3603 if (better_at_least_one)
3607 // This handles the case
3609 // Add (float f1, float f2, float f3);
3610 // Add (params decimal [] foo);
3612 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3613 // first candidate would've chosen as better.
3615 if (!same && !a.IsDefaultArgument)
3619 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3623 // This handles the following cases:
3625 // Foo (int i) is better than Foo (int i, long l = 0)
3626 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3628 // Prefer non-optional version
3630 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3632 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3633 if (candidate_pd.Count >= best_pd.Count)
3636 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3643 // One is a non-generic method and second is a generic method, then non-generic is better
3645 if (best.IsGeneric != candidate.IsGeneric)
3646 return best.IsGeneric;
3649 // This handles the following cases:
3651 // Trim () is better than Trim (params char[] chars)
3652 // Concat (string s1, string s2, string s3) is better than
3653 // Concat (string s1, params string [] srest)
3654 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3656 // Prefer non-expanded version
3658 if (candidate_params != best_params)
3661 int candidate_param_count = candidate_pd.Count;
3662 int best_param_count = best_pd.Count;
3664 if (candidate_param_count != best_param_count)
3665 // can only happen if (candidate_params && best_params)
3666 return candidate_param_count > best_param_count && best_pd.HasParams;
3669 // Both methods have the same number of parameters, and the parameters have equal types
3670 // Pick the "more specific" signature using rules over original (non-inflated) types
3672 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3673 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3675 bool specific_at_least_once = false;
3676 for (j = 0; j < args_count; ++j) {
3677 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3679 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3680 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3682 ct = candidate_def_pd.Types[j];
3683 bt = best_def_pd.Types[j];
3688 TypeSpec specific = MoreSpecific (ct, bt);
3692 specific_at_least_once = true;
3695 if (specific_at_least_once)
3701 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3703 rc.Report.Error (1729, loc,
3704 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3705 type.GetSignatureForError (), argCount.ToString ());
3709 // Determines if the candidate method is applicable to the given set of arguments
3710 // There could be two different set of parameters for same candidate where one
3711 // is the closest override for default values and named arguments checks and second
3712 // one being the virtual base for the parameter types and modifiers.
3714 // A return value rates candidate method compatibility,
3715 // 0 = the best, int.MaxValue = the worst
3717 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)
3719 // Parameters of most-derived type used mainly for named and optional parameters
3720 var pd = pm.Parameters;
3722 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3723 // params modifier instead of most-derived type
3724 var cpd = ((IParametersMember) candidate).Parameters;
3725 int param_count = pd.Count;
3726 int optional_count = 0;
3728 Arguments orig_args = arguments;
3730 if (arg_count != param_count) {
3731 for (int i = 0; i < pd.Count; ++i) {
3732 if (pd.FixedParameters[i].HasDefaultValue) {
3733 optional_count = pd.Count - i;
3738 if (optional_count != 0) {
3739 // Readjust expected number when params used
3740 if (cpd.HasParams) {
3742 if (arg_count < param_count)
3744 } else if (arg_count > param_count) {
3745 int args_gap = System.Math.Abs (arg_count - param_count);
3746 return int.MaxValue - 10000 + args_gap;
3748 } else if (arg_count != param_count) {
3749 int args_gap = System.Math.Abs (arg_count - param_count);
3751 return int.MaxValue - 10000 + args_gap;
3752 if (arg_count < param_count - 1)
3753 return int.MaxValue - 10000 + args_gap;
3756 // Resize to fit optional arguments
3757 if (optional_count != 0) {
3758 if (arguments == null) {
3759 arguments = new Arguments (optional_count);
3761 // Have to create a new container, so the next run can do same
3762 var resized = new Arguments (param_count);
3763 resized.AddRange (arguments);
3764 arguments = resized;
3767 for (int i = arg_count; i < param_count; ++i)
3768 arguments.Add (null);
3772 if (arg_count > 0) {
3774 // Shuffle named arguments to the right positions if there are any
3776 if (arguments[arg_count - 1] is NamedArgument) {
3777 arg_count = arguments.Count;
3779 for (int i = 0; i < arg_count; ++i) {
3780 bool arg_moved = false;
3782 NamedArgument na = arguments[i] as NamedArgument;
3786 int index = pd.GetParameterIndexByName (na.Name);
3788 // Named parameter not found
3792 // already reordered
3797 if (index >= param_count) {
3798 // When using parameters which should not be available to the user
3799 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3802 arguments.Add (null);
3806 temp = arguments[index];
3808 // The slot has been taken by positional argument
3809 if (temp != null && !(temp is NamedArgument))
3814 arguments = arguments.MarkOrderedArgument (na);
3818 arguments[index] = arguments[i];
3819 arguments[i] = temp;
3826 arg_count = arguments.Count;
3828 } else if (arguments != null) {
3829 arg_count = arguments.Count;
3833 // 1. Handle generic method using type arguments when specified or type inference
3836 var ms = candidate as MethodSpec;
3837 if (ms != null && ms.IsGeneric) {
3838 // Setup constraint checker for probing only
3839 ConstraintChecker cc = new ConstraintChecker (null);
3841 if (type_arguments != null) {
3842 var g_args_count = ms.Arity;
3843 if (g_args_count != type_arguments.Count)
3844 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3846 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3848 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3849 // for now it simplifies things. I should probably add a callback to ResolveContext
3850 if (lambda_conv_msgs == null) {
3851 lambda_conv_msgs = new SessionReportPrinter ();
3852 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3855 var ti = new TypeInference (arguments);
3856 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3857 lambda_conv_msgs.EndSession ();
3860 return ti.InferenceScore - 20000;
3862 if (i_args.Length != 0) {
3863 ms = ms.MakeGenericMethod (ec, i_args);
3866 cc.IgnoreInferredDynamic = true;
3870 // Type arguments constraints have to match for the method to be applicable
3872 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3874 return int.MaxValue - 25000;
3878 // We have a generic return type and at same time the method is override which
3879 // means we have to also inflate override return type in case the candidate is
3880 // best candidate and override return type is different to base return type.
3882 // virtual Foo<T, object> with override Foo<T, dynamic>
3884 if (candidate != pm) {
3885 MethodSpec override_ms = (MethodSpec) pm;
3886 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3887 returnType = inflator.Inflate (returnType);
3889 returnType = ms.ReturnType;
3893 ptypes = ms.Parameters.Types;
3895 if (type_arguments != null)
3896 return int.MaxValue - 15000;
3902 // 2. Each argument has to be implicitly convertible to method parameter
3904 Parameter.Modifier p_mod = 0;
3907 for (int i = 0; i < arg_count; i++) {
3908 Argument a = arguments[i];
3910 if (!pd.FixedParameters[i].HasDefaultValue) {
3911 arguments = orig_args;
3912 return arg_count * 2 + 2;
3916 // Get the default value expression, we can use the same expression
3917 // if the type matches
3919 Expression e = pd.FixedParameters[i].DefaultValue;
3920 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3922 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3924 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3925 e = new MemberAccess (new MemberAccess (new MemberAccess (
3926 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3928 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3934 arguments[i] = new Argument (e, Argument.AType.Default);
3938 if (p_mod != Parameter.Modifier.PARAMS) {
3939 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3941 } else if (!params_expanded_form) {
3942 params_expanded_form = true;
3943 pt = ((ElementTypeSpec) pt).Element;
3949 if (!params_expanded_form) {
3950 if (a.ArgType == Argument.AType.ExtensionType) {
3952 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3955 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3956 Convert.ImplicitReferenceConversionExists (at, pt) ||
3957 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
3962 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3965 dynamicArgument = true;
3970 // It can be applicable in expanded form (when not doing exact match like for delegates)
3972 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3973 if (!params_expanded_form)
3974 pt = ((ElementTypeSpec) pt).Element;
3977 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3980 params_expanded_form = true;
3981 } else if (score < 0) {
3982 params_expanded_form = true;
3983 dynamicArgument = true;
3988 if (params_expanded_form)
3990 return (arg_count - i) * 2 + score;
3995 // When params parameter has no argument it will be provided later if the method is the best candidate
3997 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3998 params_expanded_form = true;
4001 // Restore original arguments for dynamic binder to keep the intention of original source code
4003 if (dynamicArgument)
4004 arguments = orig_args;
4010 // Tests argument compatibility with the parameter
4011 // The possible return values are
4013 // 1 - modifier mismatch
4014 // 2 - type mismatch
4015 // -1 - dynamic binding required
4017 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4020 // Types have to be identical when ref or out modifer
4021 // is used and argument is not of dynamic type
4023 if ((argument.Modifier | param_mod) != 0) {
4024 if (argument.Type != parameter) {
4026 // Do full equality check after quick path
4028 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4030 // Using dynamic for ref/out parameter can still succeed at runtime
4032 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4039 if (argument.Modifier != param_mod) {
4041 // Using dynamic for ref/out parameter can still succeed at runtime
4043 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4050 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4054 // Deploy custom error reporting for lambda methods. When probing lambda methods
4055 // keep all errors reported in separate set and once we are done and no best
4056 // candidate was found, this set is used to report more details about what was wrong
4059 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4060 if (lambda_conv_msgs == null) {
4061 lambda_conv_msgs = new SessionReportPrinter ();
4062 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4067 // Use implicit conversion in all modes to return same candidates when the expression
4068 // is used as argument or delegate conversion
4070 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4071 if (lambda_conv_msgs != null) {
4072 lambda_conv_msgs.EndSession ();
4082 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4084 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4086 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4089 var ac_p = p as ArrayContainer;
4091 var ac_q = ((ArrayContainer) q);
4092 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4093 if (specific == ac_p.Element)
4095 if (specific == ac_q.Element)
4097 } else if (TypeManager.IsGenericType (p)) {
4098 var pargs = TypeManager.GetTypeArguments (p);
4099 var qargs = TypeManager.GetTypeArguments (q);
4101 bool p_specific_at_least_once = false;
4102 bool q_specific_at_least_once = false;
4104 for (int i = 0; i < pargs.Length; i++) {
4105 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4106 if (specific == pargs[i])
4107 p_specific_at_least_once = true;
4108 if (specific == qargs[i])
4109 q_specific_at_least_once = true;
4112 if (p_specific_at_least_once && !q_specific_at_least_once)
4114 if (!p_specific_at_least_once && q_specific_at_least_once)
4122 // Find the best method from candidate list
4124 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4126 List<AmbiguousCandidate> ambiguous_candidates = null;
4128 MemberSpec best_candidate;
4129 Arguments best_candidate_args = null;
4130 bool best_candidate_params = false;
4131 bool best_candidate_dynamic = false;
4132 int best_candidate_rate;
4133 IParametersMember best_parameter_member = null;
4135 int args_count = args != null ? args.Count : 0;
4137 Arguments candidate_args = args;
4138 bool error_mode = false;
4139 MemberSpec invocable_member = null;
4141 // Be careful, cannot return until error reporter is restored
4143 best_candidate = null;
4144 best_candidate_rate = int.MaxValue;
4146 var type_members = members;
4150 for (int i = 0; i < type_members.Count; ++i) {
4151 var member = type_members[i];
4154 // Methods in a base class are not candidates if any method in a derived
4155 // class is applicable
4157 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4161 if (!member.IsAccessible (rc))
4164 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4168 IParametersMember pm = member as IParametersMember;
4171 // Will use it later to report ambiguity between best method and invocable member
4173 if (Invocation.IsMemberInvocable (member))
4174 invocable_member = member;
4180 // Overload resolution is looking for base member but using parameter names
4181 // and default values from the closest member. That means to do expensive lookup
4182 // for the closest override for virtual or abstract members
4184 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4185 var override_params = base_provider.GetOverrideMemberParameters (member);
4186 if (override_params != null)
4187 pm = override_params;
4191 // Check if the member candidate is applicable
4193 bool params_expanded_form = false;
4194 bool dynamic_argument = false;
4195 TypeSpec rt = pm.MemberType;
4196 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4199 // How does it score compare to others
4201 if (candidate_rate < best_candidate_rate) {
4202 best_candidate_rate = candidate_rate;
4203 best_candidate = member;
4204 best_candidate_args = candidate_args;
4205 best_candidate_params = params_expanded_form;
4206 best_candidate_dynamic = dynamic_argument;
4207 best_parameter_member = pm;
4208 best_candidate_return_type = rt;
4209 } else if (candidate_rate == 0) {
4211 // The member look is done per type for most operations but sometimes
4212 // it's not possible like for binary operators overload because they
4213 // are unioned between 2 sides
4215 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4216 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4221 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4223 // We pack all interface members into top level type which makes the overload resolution
4224 // more complicated for interfaces. We compensate it by removing methods with same
4225 // signature when building the cache hence this path should not really be hit often
4228 // interface IA { void Foo (int arg); }
4229 // interface IB : IA { void Foo (params int[] args); }
4231 // IB::Foo is the best overload when calling IB.Foo (1)
4234 if (ambiguous_candidates != null) {
4235 foreach (var amb_cand in ambiguous_candidates) {
4236 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4245 ambiguous_candidates = null;
4248 // Is the new candidate better
4249 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4253 best_candidate = member;
4254 best_candidate_args = candidate_args;
4255 best_candidate_params = params_expanded_form;
4256 best_candidate_dynamic = dynamic_argument;
4257 best_parameter_member = pm;
4258 best_candidate_return_type = rt;
4260 // It's not better but any other found later could be but we are not sure yet
4261 if (ambiguous_candidates == null)
4262 ambiguous_candidates = new List<AmbiguousCandidate> ();
4264 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4268 // Restore expanded arguments
4269 if (candidate_args != args)
4270 candidate_args = args;
4272 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4274 if (prev_recorder != null)
4275 rc.Report.SetPrinter (prev_recorder);
4279 // We've found exact match
4281 if (best_candidate_rate == 0)
4285 // Try extension methods lookup when no ordinary method match was found and provider enables it
4288 var emg = base_provider.LookupExtensionMethod (rc);
4290 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4292 best_candidate_extension_group = emg;
4293 return (T) (MemberSpec) emg.BestCandidate;
4298 // Don't run expensive error reporting mode for probing
4305 lambda_conv_msgs = null;
4310 // No best member match found, report an error
4312 if (best_candidate_rate != 0 || error_mode) {
4313 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4317 if (best_candidate_dynamic) {
4318 if (args[0].ArgType == Argument.AType.ExtensionType) {
4319 rc.Report.Error (1973, loc,
4320 "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",
4321 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4324 BestCandidateIsDynamic = true;
4329 // These flags indicates we are running delegate probing conversion. No need to
4330 // do more expensive checks
4332 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4333 return (T) best_candidate;
4335 if (ambiguous_candidates != null) {
4337 // Now check that there are no ambiguities i.e the selected method
4338 // should be better than all the others
4340 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4341 var candidate = ambiguous_candidates [ix];
4343 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4344 var ambiguous = candidate.Member;
4345 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4346 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4347 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4348 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4349 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4352 return (T) best_candidate;
4357 if (invocable_member != null) {
4358 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4359 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4360 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4361 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4365 // And now check if the arguments are all
4366 // compatible, perform conversions if
4367 // necessary etc. and return if everything is
4370 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4373 if (best_candidate == null)
4377 // Check ObsoleteAttribute on the best method
4379 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4380 if (oa != null && !rc.IsObsolete)
4381 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4383 var dep = best_candidate.GetMissingDependencies ();
4385 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4388 best_candidate.MemberDefinition.SetIsUsed ();
4390 args = best_candidate_args;
4391 return (T) best_candidate;
4394 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4396 return ResolveMember<MethodSpec> (rc, ref args);
4399 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4400 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4402 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4405 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4406 ec.Report.SymbolRelatedToPreviousError (method);
4407 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4408 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4409 TypeManager.CSharpSignature (method));
4412 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4413 TypeManager.CSharpSignature (method));
4414 } else if (IsDelegateInvoke) {
4415 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4416 DelegateType.GetSignatureForError ());
4418 ec.Report.SymbolRelatedToPreviousError (method);
4419 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4420 method.GetSignatureForError ());
4423 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4425 string index = (idx + 1).ToString ();
4426 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4427 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4428 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4429 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4430 index, Parameter.GetModifierSignature (a.Modifier));
4432 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4433 index, Parameter.GetModifierSignature (mod));
4434 } else if (a.Expr != ErrorExpression.Instance) {
4435 string p1 = a.GetSignatureForError ();
4436 string p2 = TypeManager.CSharpName (paramType);
4439 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4440 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4443 ec.Report.Error (1503, loc,
4444 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4449 // We have failed to find exact match so we return error info about the closest match
4451 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4453 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4454 int arg_count = args == null ? 0 : args.Count;
4456 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4457 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4458 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4462 if (lambda_conv_msgs != null) {
4463 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4468 // For candidates which match on parameters count report more details about incorrect arguments
4471 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4472 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4473 // Reject any inaccessible member
4474 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4475 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4476 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4480 var ms = best_candidate as MethodSpec;
4481 if (ms != null && ms.IsGeneric) {
4482 bool constr_ok = true;
4483 if (ms.TypeArguments != null)
4484 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4486 if (ta_count == 0) {
4487 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4491 rc.Report.Error (411, loc,
4492 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4493 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4500 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4506 // We failed to find any method with correct argument count, report best candidate
4508 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4511 if (best_candidate.Kind == MemberKind.Constructor) {
4512 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4513 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4514 } else if (IsDelegateInvoke) {
4515 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4516 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4517 DelegateType.GetSignatureForError (), arg_count.ToString ());
4519 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4520 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4521 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4522 name, arg_count.ToString ());
4526 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4528 var pd = pm.Parameters;
4529 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4531 Parameter.Modifier p_mod = 0;
4533 int a_idx = 0, a_pos = 0;
4535 ArrayInitializer params_initializers = null;
4536 bool has_unsafe_arg = pm.MemberType.IsPointer;
4537 int arg_count = args == null ? 0 : args.Count;
4539 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4541 if (p_mod != Parameter.Modifier.PARAMS) {
4542 p_mod = pd.FixedParameters[a_idx].ModFlags;
4544 has_unsafe_arg |= pt.IsPointer;
4546 if (p_mod == Parameter.Modifier.PARAMS) {
4547 if (chose_params_expanded) {
4548 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4549 pt = TypeManager.GetElementType (pt);
4555 // Types have to be identical when ref or out modifer is used
4557 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4558 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4561 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4567 NamedArgument na = a as NamedArgument;
4569 int name_index = pd.GetParameterIndexByName (na.Name);
4570 if (name_index < 0 || name_index >= pd.Count) {
4571 if (IsDelegateInvoke) {
4572 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4573 ec.Report.Error (1746, na.Location,
4574 "The delegate `{0}' does not contain a parameter named `{1}'",
4575 DelegateType.GetSignatureForError (), na.Name);
4577 ec.Report.SymbolRelatedToPreviousError (member);
4578 ec.Report.Error (1739, na.Location,
4579 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4580 TypeManager.CSharpSignature (member), na.Name);
4582 } else if (args[name_index] != a) {
4583 if (IsDelegateInvoke)
4584 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4586 ec.Report.SymbolRelatedToPreviousError (member);
4588 ec.Report.Error (1744, na.Location,
4589 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4594 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4597 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4598 custom_errors.NoArgumentMatch (ec, member);
4602 Expression conv = null;
4603 if (a.ArgType == Argument.AType.ExtensionType) {
4604 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4607 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4609 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4612 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4619 // Convert params arguments to an array initializer
4621 if (params_initializers != null) {
4622 // we choose to use 'a.Expr' rather than 'conv' so that
4623 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4624 params_initializers.Add (a.Expr);
4625 args.RemoveAt (a_idx--);
4630 // Update the argument with the implicit conversion
4634 if (a_idx != arg_count) {
4635 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4640 // Fill not provided arguments required by params modifier
4642 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4644 args = new Arguments (1);
4646 pt = ptypes[pd.Count - 1];
4647 pt = TypeManager.GetElementType (pt);
4648 has_unsafe_arg |= pt.IsPointer;
4649 params_initializers = new ArrayInitializer (0, loc);
4653 // Append an array argument with all params arguments
4655 if (params_initializers != null) {
4656 args.Add (new Argument (
4657 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4661 if (has_unsafe_arg && !ec.IsUnsafe) {
4662 Expression.UnsafeError (ec, loc);
4666 // We could infer inaccesible type arguments
4668 if (type_arguments == null && member.IsGeneric) {
4669 var ms = (MethodSpec) member;
4670 foreach (var ta in ms.TypeArguments) {
4671 if (!ta.IsAccessible (ec)) {
4672 ec.Report.SymbolRelatedToPreviousError (ta);
4673 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4683 public class ConstantExpr : MemberExpr
4685 readonly ConstSpec constant;
4687 public ConstantExpr (ConstSpec constant, Location loc)
4689 this.constant = constant;
4693 public override string Name {
4694 get { throw new NotImplementedException (); }
4697 public override bool IsInstance {
4698 get { return !IsStatic; }
4701 public override bool IsStatic {
4702 get { return true; }
4705 protected override TypeSpec DeclaringType {
4706 get { return constant.DeclaringType; }
4709 public override Expression CreateExpressionTree (ResolveContext ec)
4711 throw new NotSupportedException ("ET");
4714 protected override Expression DoResolve (ResolveContext rc)
4716 ResolveInstanceExpression (rc, null);
4717 DoBestMemberChecks (rc, constant);
4719 var c = constant.GetConstant (rc);
4721 // Creates reference expression to the constant value
4722 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4725 public override void Emit (EmitContext ec)
4727 throw new NotSupportedException ();
4730 public override string GetSignatureForError ()
4732 return constant.GetSignatureForError ();
4735 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4737 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4742 /// Fully resolved expression that evaluates to a Field
4744 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4745 protected FieldSpec spec;
4746 VariableInfo variable_info;
4748 LocalTemporary temp;
4751 protected FieldExpr (Location l)
4756 public FieldExpr (FieldSpec spec, Location loc)
4761 type = spec.MemberType;
4764 public FieldExpr (FieldBase fi, Location l)
4771 public override string Name {
4777 public bool IsHoisted {
4779 IVariableReference hv = InstanceExpression as IVariableReference;
4780 return hv != null && hv.IsHoisted;
4784 public override bool IsInstance {
4786 return !spec.IsStatic;
4790 public override bool IsStatic {
4792 return spec.IsStatic;
4796 public FieldSpec Spec {
4802 protected override TypeSpec DeclaringType {
4804 return spec.DeclaringType;
4808 public VariableInfo VariableInfo {
4810 return variable_info;
4816 public override string GetSignatureForError ()
4818 return TypeManager.GetFullNameSignature (spec);
4821 public bool IsMarshalByRefAccess (ResolveContext rc)
4823 // Checks possible ldflda of field access expression
4824 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
4825 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
4826 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
4829 public void SetHasAddressTaken ()
4831 IVariableReference vr = InstanceExpression as IVariableReference;
4833 vr.SetHasAddressTaken ();
4836 public override Expression CreateExpressionTree (ResolveContext ec)
4838 Expression instance;
4839 if (InstanceExpression == null) {
4840 instance = new NullLiteral (loc);
4842 instance = InstanceExpression.CreateExpressionTree (ec);
4845 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4847 CreateTypeOfExpression ());
4849 return CreateExpressionFactoryCall (ec, "Field", args);
4852 public Expression CreateTypeOfExpression ()
4854 return new TypeOfField (spec, loc);
4857 protected override Expression DoResolve (ResolveContext ec)
4859 return DoResolve (ec, null);
4862 Expression DoResolve (ResolveContext ec, Expression rhs)
4864 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4867 if (ResolveInstanceExpression (ec, rhs)) {
4868 // Resolve the field's instance expression while flow analysis is turned
4869 // off: when accessing a field "a.b", we must check whether the field
4870 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4872 if (lvalue_instance) {
4873 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4874 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
4876 Expression right_side =
4877 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4879 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4882 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4883 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4887 if (InstanceExpression == null)
4891 DoBestMemberChecks (ec, spec);
4894 var fb = spec as FixedFieldSpec;
4895 IVariableReference var = InstanceExpression as IVariableReference;
4897 if (lvalue_instance && var != null && var.VariableInfo != null) {
4898 var.VariableInfo.SetFieldAssigned (ec, Name);
4902 IFixedExpression fe = InstanceExpression as IFixedExpression;
4903 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4904 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4907 if (InstanceExpression.eclass != ExprClass.Variable) {
4908 ec.Report.SymbolRelatedToPreviousError (spec);
4909 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4910 TypeManager.GetFullNameSignature (spec));
4911 } else if (var != null && var.IsHoisted) {
4912 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4915 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4918 eclass = ExprClass.Variable;
4920 // If the instance expression is a local variable or parameter.
4921 if (var == null || var.VariableInfo == null)
4924 VariableInfo vi = var.VariableInfo;
4925 if (!vi.IsFieldAssigned (ec, Name, loc))
4928 variable_info = vi.GetSubStruct (Name);
4932 static readonly int [] codes = {
4933 191, // instance, write access
4934 192, // instance, out access
4935 198, // static, write access
4936 199, // static, out access
4937 1648, // member of value instance, write access
4938 1649, // member of value instance, out access
4939 1650, // member of value static, write access
4940 1651 // member of value static, out access
4943 static readonly string [] msgs = {
4944 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4945 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4946 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4947 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4948 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4949 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4950 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4951 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4954 // The return value is always null. Returning a value simplifies calling code.
4955 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4958 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4962 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4964 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4969 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4971 Expression e = DoResolve (ec, right_side);
4976 spec.MemberDefinition.SetIsAssigned ();
4978 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
4979 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4980 ec.Report.Warning (420, 1, loc,
4981 "`{0}': A volatile field references will not be treated as volatile",
4982 spec.GetSignatureForError ());
4985 if (spec.IsReadOnly) {
4986 // InitOnly fields can only be assigned in constructors or initializers
4987 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4988 return Report_AssignToReadonly (ec, right_side);
4990 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4992 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4993 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4994 return Report_AssignToReadonly (ec, right_side);
4995 // static InitOnly fields cannot be assigned-to in an instance constructor
4996 if (IsStatic && !ec.IsStatic)
4997 return Report_AssignToReadonly (ec, right_side);
4998 // instance constructors can't modify InitOnly fields of other instances of the same type
4999 if (!IsStatic && !(InstanceExpression is This))
5000 return Report_AssignToReadonly (ec, right_side);
5004 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5005 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5006 ec.Report.Warning (197, 1, loc,
5007 "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",
5008 GetSignatureForError ());
5011 eclass = ExprClass.Variable;
5015 public override int GetHashCode ()
5017 return spec.GetHashCode ();
5020 public bool IsFixed {
5023 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5025 IVariableReference variable = InstanceExpression as IVariableReference;
5026 if (variable != null)
5027 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5029 IFixedExpression fe = InstanceExpression as IFixedExpression;
5030 return fe != null && fe.IsFixed;
5034 public override bool Equals (object obj)
5036 FieldExpr fe = obj as FieldExpr;
5040 if (spec != fe.spec)
5043 if (InstanceExpression == null || fe.InstanceExpression == null)
5046 return InstanceExpression.Equals (fe.InstanceExpression);
5049 public void Emit (EmitContext ec, bool leave_copy)
5051 bool is_volatile = false;
5053 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5056 spec.MemberDefinition.SetIsUsed ();
5060 ec.Emit (OpCodes.Volatile);
5062 ec.Emit (OpCodes.Ldsfld, spec);
5065 EmitInstance (ec, false);
5067 // Optimization for build-in types
5068 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5069 ec.EmitLoadFromPtr (type);
5071 var ff = spec as FixedFieldSpec;
5073 ec.Emit (OpCodes.Ldflda, spec);
5074 ec.Emit (OpCodes.Ldflda, ff.Element);
5077 ec.Emit (OpCodes.Volatile);
5079 ec.Emit (OpCodes.Ldfld, spec);
5085 ec.Emit (OpCodes.Dup);
5087 temp = new LocalTemporary (this.Type);
5093 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5095 var await_expr = source as Await;
5096 if (await_expr != null) {
5098 // Await is not ordinary expression (it contains jump), hence the usual flow cannot be used
5099 // to emit instance load before expression
5101 await_expr.EmitAssign (ec, this);
5103 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5105 EmitInstance (ec, prepared);
5111 ec.Emit (OpCodes.Dup);
5113 temp = new LocalTemporary (this.Type);
5118 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5119 ec.Emit (OpCodes.Volatile);
5121 spec.MemberDefinition.SetIsAssigned ();
5124 ec.Emit (OpCodes.Stsfld, spec);
5126 ec.Emit (OpCodes.Stfld, spec);
5135 public override void Emit (EmitContext ec)
5140 public override void EmitSideEffect (EmitContext ec)
5142 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5144 if (is_volatile) // || is_marshal_by_ref ())
5145 base.EmitSideEffect (ec);
5148 public void AddressOf (EmitContext ec, AddressOp mode)
5150 if ((mode & AddressOp.Store) != 0)
5151 spec.MemberDefinition.SetIsAssigned ();
5152 if ((mode & AddressOp.Load) != 0)
5153 spec.MemberDefinition.SetIsUsed ();
5156 // Handle initonly fields specially: make a copy and then
5157 // get the address of the copy.
5160 if (spec.IsReadOnly){
5162 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5175 local = ec.DeclareLocal (type, false);
5176 ec.Emit (OpCodes.Stloc, local);
5177 ec.Emit (OpCodes.Ldloca, local);
5183 ec.Emit (OpCodes.Ldsflda, spec);
5186 EmitInstance (ec, false);
5187 ec.Emit (OpCodes.Ldflda, spec);
5191 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5193 return MakeExpression (ctx);
5196 public override SLE.Expression MakeExpression (BuilderContext ctx)
5199 return base.MakeExpression (ctx);
5201 return SLE.Expression.Field (
5202 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5203 spec.GetMetaInfo ());
5207 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5209 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5215 /// Expression that evaluates to a Property. The Assign class
5216 /// might set the `Value' expression if we are in an assignment.
5218 /// This is not an LValue because we need to re-write the expression, we
5219 /// can not take data from the stack and store it.
5221 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5223 public PropertyExpr (PropertySpec spec, Location l)
5226 best_candidate = spec;
5227 type = spec.MemberType;
5232 protected override TypeSpec DeclaringType {
5234 return best_candidate.DeclaringType;
5238 public override string Name {
5240 return best_candidate.Name;
5244 public override bool IsInstance {
5250 public override bool IsStatic {
5252 return best_candidate.IsStatic;
5256 public PropertySpec PropertyInfo {
5258 return best_candidate;
5264 public override Expression CreateExpressionTree (ResolveContext ec)
5267 if (IsSingleDimensionalArrayLength ()) {
5268 args = new Arguments (1);
5269 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5270 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5273 args = new Arguments (2);
5274 if (InstanceExpression == null)
5275 args.Add (new Argument (new NullLiteral (loc)));
5277 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5278 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5279 return CreateExpressionFactoryCall (ec, "Property", args);
5282 public Expression CreateSetterTypeOfExpression ()
5284 return new TypeOfMethod (Setter, loc);
5287 public override string GetSignatureForError ()
5289 return best_candidate.GetSignatureForError ();
5292 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5295 return base.MakeExpression (ctx);
5297 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5301 public override SLE.Expression MakeExpression (BuilderContext ctx)
5304 return base.MakeExpression (ctx);
5306 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5310 void Error_PropertyNotValid (ResolveContext ec)
5312 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5313 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5314 GetSignatureForError ());
5317 bool IsSingleDimensionalArrayLength ()
5319 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5322 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5323 return ac != null && ac.Rank == 1;
5326 public override void Emit (EmitContext ec, bool leave_copy)
5329 // Special case: length of single dimension array property is turned into ldlen
5331 if (IsSingleDimensionalArrayLength ()) {
5333 EmitInstance (ec, false);
5334 ec.Emit (OpCodes.Ldlen);
5335 ec.Emit (OpCodes.Conv_I4);
5339 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5342 ec.Emit (OpCodes.Dup);
5344 temp = new LocalTemporary (this.Type);
5350 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5354 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5355 args = new Arguments (0);
5360 ec.Emit (OpCodes.Dup);
5362 temp = new LocalTemporary (this.Type);
5367 args = new Arguments (1);
5371 temp = new LocalTemporary (this.Type);
5373 args.Add (new Argument (temp));
5375 args.Add (new Argument (source));
5379 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5387 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5389 eclass = ExprClass.PropertyAccess;
5391 if (best_candidate.IsNotCSharpCompatible) {
5392 Error_PropertyNotValid (rc);
5395 ResolveInstanceExpression (rc, right_side);
5397 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5398 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5399 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5401 type = p.MemberType;
5405 DoBestMemberChecks (rc, best_candidate);
5409 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5411 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5415 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5417 // getter and setter can be different for base calls
5418 MethodSpec getter, setter;
5419 protected T best_candidate;
5421 protected LocalTemporary temp;
5422 protected bool prepared;
5424 protected PropertyOrIndexerExpr (Location l)
5431 public MethodSpec Getter {
5440 public MethodSpec Setter {
5451 protected override Expression DoResolve (ResolveContext ec)
5453 if (eclass == ExprClass.Unresolved) {
5454 var expr = OverloadResolve (ec, null);
5459 return expr.Resolve (ec);
5462 if (!ResolveGetter (ec))
5468 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5470 if (right_side == EmptyExpression.OutAccess) {
5471 // TODO: best_candidate can be null at this point
5472 INamedBlockVariable variable = null;
5473 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5474 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5475 best_candidate.Name);
5477 right_side.DoResolveLValue (ec, this);
5482 // if the property/indexer returns a value type, and we try to set a field in it
5483 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5484 Error_CannotModifyIntermediateExpressionValue (ec);
5487 if (eclass == ExprClass.Unresolved) {
5488 var expr = OverloadResolve (ec, right_side);
5493 return expr.ResolveLValue (ec, right_side);
5496 if (!ResolveSetter (ec))
5503 // Implements the IAssignMethod interface for assignments
5505 public abstract void Emit (EmitContext ec, bool leave_copy);
5506 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5508 public override void Emit (EmitContext ec)
5513 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5515 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5517 bool ResolveGetter (ResolveContext rc)
5519 if (!best_candidate.HasGet) {
5520 if (InstanceExpression != EmptyExpression.Null) {
5521 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5522 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5523 best_candidate.GetSignatureForError ());
5526 } else if (!best_candidate.Get.IsAccessible (rc)) {
5527 if (best_candidate.HasDifferentAccessibility) {
5528 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5529 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5530 TypeManager.CSharpSignature (best_candidate));
5532 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5533 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5537 if (best_candidate.HasDifferentAccessibility) {
5538 CheckProtectedMemberAccess (rc, best_candidate.Get);
5541 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5545 bool ResolveSetter (ResolveContext rc)
5547 if (!best_candidate.HasSet) {
5548 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5549 GetSignatureForError ());
5553 if (!best_candidate.Set.IsAccessible (rc)) {
5554 if (best_candidate.HasDifferentAccessibility) {
5555 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5556 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5557 GetSignatureForError ());
5559 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5560 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5564 if (best_candidate.HasDifferentAccessibility)
5565 CheckProtectedMemberAccess (rc, best_candidate.Set);
5567 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5573 /// Fully resolved expression that evaluates to an Event
5575 public class EventExpr : MemberExpr, IAssignMethod
5577 readonly EventSpec spec;
5580 public EventExpr (EventSpec spec, Location loc)
5588 protected override TypeSpec DeclaringType {
5590 return spec.DeclaringType;
5594 public override string Name {
5600 public override bool IsInstance {
5602 return !spec.IsStatic;
5606 public override bool IsStatic {
5608 return spec.IsStatic;
5612 public MethodSpec Operator {
5620 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5623 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5625 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5626 if (spec.BackingField != null &&
5627 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5629 spec.MemberDefinition.SetIsUsed ();
5631 if (!ec.IsObsolete) {
5632 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5634 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5637 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5638 Error_AssignmentEventOnly (ec);
5640 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5642 InstanceExpression = null;
5644 return ml.ResolveMemberAccess (ec, left, original);
5648 return base.ResolveMemberAccess (ec, left, original);
5651 public override Expression CreateExpressionTree (ResolveContext ec)
5653 throw new NotSupportedException ("ET");
5656 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5658 if (right_side == EmptyExpression.EventAddition) {
5659 op = spec.AccessorAdd;
5660 } else if (right_side == EmptyExpression.EventSubtraction) {
5661 op = spec.AccessorRemove;
5665 Error_AssignmentEventOnly (ec);
5669 op = CandidateToBaseOverride (ec, op);
5673 protected override Expression DoResolve (ResolveContext ec)
5675 eclass = ExprClass.EventAccess;
5676 type = spec.MemberType;
5678 ResolveInstanceExpression (ec, null);
5680 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5681 Error_AssignmentEventOnly (ec);
5684 DoBestMemberChecks (ec, spec);
5688 public override void Emit (EmitContext ec)
5690 throw new NotSupportedException ();
5691 //Error_CannotAssign ();
5694 #region IAssignMethod Members
5696 public void Emit (EmitContext ec, bool leave_copy)
5698 throw new NotImplementedException ();
5701 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5703 if (leave_copy || !prepare_for_load)
5704 throw new NotImplementedException ("EventExpr::EmitAssign");
5706 Arguments args = new Arguments (1);
5707 args.Add (new Argument (source));
5708 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5713 void Error_AssignmentEventOnly (ResolveContext ec)
5715 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5716 ec.Report.Error (79, loc,
5717 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5718 GetSignatureForError ());
5720 ec.Report.Error (70, loc,
5721 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5722 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5726 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5728 name = name.Substring (0, name.LastIndexOf ('.'));
5729 base.Error_CannotCallAbstractBase (rc, name);
5732 public override string GetSignatureForError ()
5734 return TypeManager.CSharpSignature (spec);
5737 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5739 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
5743 public class TemporaryVariableReference : VariableReference
5745 public class Declarator : Statement
5747 TemporaryVariableReference variable;
5749 public Declarator (TemporaryVariableReference variable)
5751 this.variable = variable;
5755 protected override void DoEmit (EmitContext ec)
5757 variable.li.CreateBuilder (ec);
5760 protected override void CloneTo (CloneContext clonectx, Statement target)
5768 public TemporaryVariableReference (LocalVariable li, Location loc)
5771 this.type = li.Type;
5775 public override bool IsLockedByStatement {
5783 public LocalVariable LocalInfo {
5789 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5791 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5792 return new TemporaryVariableReference (li, loc);
5795 public override Expression CreateExpressionTree (ResolveContext ec)
5797 throw new NotSupportedException ("ET");
5800 protected override Expression DoResolve (ResolveContext ec)
5802 eclass = ExprClass.Variable;
5805 // Don't capture temporary variables except when using
5806 // iterator redirection
5808 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5809 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5810 storey.CaptureLocalVariable (ec, li);
5816 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5818 return Resolve (ec);
5821 public override void Emit (EmitContext ec)
5823 li.CreateBuilder (ec);
5828 public void EmitAssign (EmitContext ec, Expression source)
5830 li.CreateBuilder (ec);
5832 EmitAssign (ec, source, false, false);
5835 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5837 return li.HoistedVariant;
5840 public override bool IsFixed {
5841 get { return true; }
5844 public override bool IsRef {
5845 get { return false; }
5848 public override string Name {
5849 get { throw new NotImplementedException (); }
5852 public override void SetHasAddressTaken ()
5854 throw new NotImplementedException ();
5857 protected override ILocalVariable Variable {
5861 public override VariableInfo VariableInfo {
5862 get { throw new NotImplementedException (); }
5867 /// Handles `var' contextual keyword; var becomes a keyword only
5868 /// if no type called var exists in a variable scope
5870 class VarExpr : SimpleName
5872 public VarExpr (Location loc)
5877 public bool InferType (ResolveContext ec, Expression right_side)
5880 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5882 type = right_side.Type;
5883 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5884 ec.Report.Error (815, loc,
5885 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5886 type.GetSignatureForError ());
5890 eclass = ExprClass.Variable;
5894 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5896 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5897 base.Error_TypeOrNamespaceNotFound (ec);
5899 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");