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 virtual bool IsSideEffectFree {
139 public Location Location {
143 public virtual bool IsNull {
150 /// Performs semantic analysis on the Expression
154 /// The Resolve method is invoked to perform the semantic analysis
157 /// The return value is an expression (it can be the
158 /// same expression in some cases) or a new
159 /// expression that better represents this node.
161 /// For example, optimizations of Unary (LiteralInt)
162 /// would return a new LiteralInt with a negated
165 /// If there is an error during semantic analysis,
166 /// then an error should be reported (using Report)
167 /// and a null value should be returned.
169 /// There are two side effects expected from calling
170 /// Resolve(): the the field variable "eclass" should
171 /// be set to any value of the enumeration
172 /// `ExprClass' and the type variable should be set
173 /// to a valid type (this is the type of the
176 protected abstract Expression DoResolve (ResolveContext rc);
178 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
184 // This is used if the expression should be resolved as a type or namespace name.
185 // the default implementation fails.
187 public virtual TypeSpec ResolveAsType (IMemberContext mc)
189 ResolveContext ec = new ResolveContext (mc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
197 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
199 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
202 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
204 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
207 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
209 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
210 name, TypeManager.CSharpName (type));
213 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
215 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
216 "expressions can be used as a statement");
219 public void Error_InvalidExpressionStatement (BlockContext ec)
221 Error_InvalidExpressionStatement (ec.Report, loc);
224 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
226 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
229 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
231 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
234 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
236 // The error was already reported as CS1660
237 if (type == InternalType.AnonymousMethod)
240 string from_type = type.GetSignatureForError ();
241 string to_type = target.GetSignatureForError ();
242 if (from_type == to_type) {
243 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
244 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
248 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
253 ec.Report.DisableReporting ();
254 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
255 ec.Report.EnableReporting ();
258 ec.Report.Error (266, loc,
259 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
262 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
267 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
269 // Better message for possible generic expressions
270 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
271 var report = context.Module.Compiler.Report;
272 report.SymbolRelatedToPreviousError (member);
273 if (member is TypeSpec)
274 member = ((TypeSpec) member).GetDefinition ();
276 member = ((MethodSpec) member).GetGenericMethodDefinition ();
278 string name = member.Kind == MemberKind.Method ? "method" : "type";
279 if (member.IsGeneric) {
280 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
281 name, member.GetSignatureForError (), member.Arity.ToString ());
283 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
284 name, member.GetSignatureForError ());
287 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
291 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
293 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
297 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
299 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
302 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
304 ec.Report.SymbolRelatedToPreviousError (type);
305 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
306 TypeManager.CSharpName (type), name);
309 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
311 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
314 protected void Error_VoidPointerOperation (ResolveContext rc)
316 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
319 public ResolveFlags ExprClassToResolveFlags {
323 case ExprClass.Namespace:
324 return ResolveFlags.Type;
326 case ExprClass.MethodGroup:
327 return ResolveFlags.MethodGroup;
329 case ExprClass.TypeParameter:
330 return ResolveFlags.TypeParameter;
332 case ExprClass.Value:
333 case ExprClass.Variable:
334 case ExprClass.PropertyAccess:
335 case ExprClass.EventAccess:
336 case ExprClass.IndexerAccess:
337 return ResolveFlags.VariableOrValue;
340 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
345 public virtual string GetSignatureForError ()
347 return type.GetDefinition ().GetSignatureForError ();
351 /// Resolves an expression and performs semantic analysis on it.
355 /// Currently Resolve wraps DoResolve to perform sanity
356 /// checking and assertion checking on what we expect from Resolve.
358 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
360 if (eclass != ExprClass.Unresolved)
370 if ((flags & e.ExprClassToResolveFlags) == 0) {
371 e.Error_UnexpectedKind (ec, flags, loc);
376 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
379 } catch (Exception ex) {
380 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
383 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
384 return EmptyExpression.Null; // TODO: Add location
389 /// Resolves an expression and performs semantic analysis on it.
391 public Expression Resolve (ResolveContext rc)
393 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
397 /// Resolves an expression for LValue assignment
401 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
402 /// checking and assertion checking on what we expect from Resolve
404 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
406 int errors = ec.Report.Errors;
407 bool out_access = right_side == EmptyExpression.OutAccess;
409 Expression e = DoResolveLValue (ec, right_side);
411 if (e != null && out_access && !(e is IMemoryLocation)) {
412 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
413 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
415 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
416 // e.GetType () + " " + e.GetSignatureForError ());
421 if (errors == ec.Report.Errors) {
423 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
425 Error_ValueAssignment (ec, loc);
430 if (e.eclass == ExprClass.Unresolved)
431 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
433 if ((e.type == null) && !(e is GenericTypeExpr))
434 throw new Exception ("Expression " + e + " did not set its type after Resolve");
439 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
441 rc.Module.Compiler.Report.Error (182, loc,
442 "An attribute argument must be a constant expression, typeof expression or array creation expression");
446 /// Emits the code for the expression
450 /// The Emit method is invoked to generate the code
451 /// for the expression.
453 public abstract void Emit (EmitContext ec);
456 // Emit code to branch to @target if this expression is equivalent to @on_true.
457 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
458 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
459 // including the use of conditional branches. Note also that a branch MUST be emitted
460 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
463 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
466 // Emit this expression for its side effects, not for its value.
467 // The default implementation is to emit the value, and then throw it away.
468 // Subclasses can provide more efficient implementations, but those MUST be equivalent
469 public virtual void EmitSideEffect (EmitContext ec)
472 ec.Emit (OpCodes.Pop);
476 /// Protected constructor. Only derivate types should
477 /// be able to be created
480 protected Expression ()
485 /// Returns a fully formed expression after a MemberLookup
488 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
490 if (spec is EventSpec)
491 return new EventExpr ((EventSpec) spec, loc);
492 if (spec is ConstSpec)
493 return new ConstantExpr ((ConstSpec) spec, loc);
494 if (spec is FieldSpec)
495 return new FieldExpr ((FieldSpec) spec, loc);
496 if (spec is PropertySpec)
497 return new PropertyExpr ((PropertySpec) spec, loc);
498 if (spec is TypeSpec)
499 return new TypeExpression (((TypeSpec) spec), loc);
504 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
506 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
508 rc.Report.SymbolRelatedToPreviousError (type);
510 // Report meaningful error for struct as they always have default ctor in C# context
511 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
513 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
514 type.GetSignatureForError ());
520 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
521 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
525 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
526 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
533 public enum MemberLookupRestrictions
542 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
543 // `qualifier_type' or null to lookup members in the current class.
545 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
547 var members = MemberCache.FindMembers (queried_type, name, false);
551 MemberSpec non_method = null;
552 MemberSpec ambig_non_method = null;
554 for (int i = 0; i < members.Count; ++i) {
555 var member = members[i];
557 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
558 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
561 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
565 if (!member.IsAccessible (rc))
569 // With runtime binder we can have a situation where queried type is inaccessible
570 // because it came via dynamic object, the check about inconsisted accessibility
571 // had no effect as the type was unknown during compilation
574 // private class N { }
576 // public dynamic Foo ()
582 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
586 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
587 if (member is MethodSpec)
588 return new MethodGroupExpr (members, queried_type, loc);
590 if (!Invocation.IsMemberInvocable (member))
594 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
596 } else if (!errorMode && !member.IsNotCSharpCompatible) {
597 ambig_non_method = member;
601 if (non_method != null) {
602 if (ambig_non_method != null && rc != null) {
603 var report = rc.Module.Compiler.Report;
604 report.SymbolRelatedToPreviousError (non_method);
605 report.SymbolRelatedToPreviousError (ambig_non_method);
606 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
607 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
610 if (non_method is MethodSpec)
611 return new MethodGroupExpr (members, queried_type, loc);
613 return ExprClassFromMemberInfo (non_method, loc);
616 if (members[0].DeclaringType.BaseType == null)
619 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
621 } while (members != null);
626 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
628 throw new NotImplementedException ();
631 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
633 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
637 /// Returns an expression that can be used to invoke operator true
638 /// on the expression if it exists.
640 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
642 return GetOperatorTrueOrFalse (ec, e, true, loc);
646 /// Returns an expression that can be used to invoke operator false
647 /// on the expression if it exists.
649 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
651 return GetOperatorTrueOrFalse (ec, e, false, loc);
654 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
656 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
657 var methods = MemberCache.GetUserOperator (e.type, op, false);
661 Arguments arguments = new Arguments (1);
662 arguments.Add (new Argument (e));
664 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
665 var oper = res.ResolveOperator (ec, ref arguments);
670 return new UserOperatorCall (oper, arguments, null, loc);
673 public virtual string ExprClassName
677 case ExprClass.Unresolved:
679 case ExprClass.Value:
681 case ExprClass.Variable:
683 case ExprClass.Namespace:
687 case ExprClass.MethodGroup:
688 return "method group";
689 case ExprClass.PropertyAccess:
690 return "property access";
691 case ExprClass.EventAccess:
692 return "event access";
693 case ExprClass.IndexerAccess:
694 return "indexer access";
695 case ExprClass.Nothing:
697 case ExprClass.TypeParameter:
698 return "type parameter";
700 throw new Exception ("Should not happen");
705 /// Reports that we were expecting `expr' to be of class `expected'
707 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
709 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
712 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
716 name = mc.GetSignatureForError ();
718 name = GetSignatureForError ();
720 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
721 name, was, expected);
724 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
726 string [] valid = new string [4];
729 if ((flags & ResolveFlags.VariableOrValue) != 0) {
730 valid [count++] = "variable";
731 valid [count++] = "value";
734 if ((flags & ResolveFlags.Type) != 0)
735 valid [count++] = "type";
737 if ((flags & ResolveFlags.MethodGroup) != 0)
738 valid [count++] = "method group";
741 valid [count++] = "unknown";
743 StringBuilder sb = new StringBuilder (valid [0]);
744 for (int i = 1; i < count - 1; i++) {
746 sb.Append (valid [i]);
749 sb.Append ("' or `");
750 sb.Append (valid [count - 1]);
753 ec.Report.Error (119, loc,
754 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
757 public static void UnsafeError (ResolveContext ec, Location loc)
759 UnsafeError (ec.Report, loc);
762 public static void UnsafeError (Report Report, Location loc)
764 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
767 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
769 ec.Report.SymbolRelatedToPreviousError (type);
770 if (ec.CurrentInitializerVariable != null) {
771 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
772 TypeManager.CSharpName (type), GetSignatureForError ());
774 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
775 GetSignatureForError ());
780 // Converts `source' to an int, uint, long or ulong.
782 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
784 var btypes = ec.BuiltinTypes;
786 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
787 Arguments args = new Arguments (1);
788 args.Add (new Argument (source));
789 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
792 Expression converted;
794 using (ec.Set (ResolveContext.Options.CheckedScope)) {
795 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
796 if (converted == null)
797 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
798 if (converted == null)
799 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
800 if (converted == null)
801 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
803 if (converted == null) {
804 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
810 // Only positive constants are allowed at compile time
812 Constant c = converted as Constant;
813 if (c != null && c.IsNegative)
814 Error_NegativeArrayIndex (ec, source.loc);
816 // No conversion needed to array index
817 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
820 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
824 // Derived classes implement this method by cloning the fields that
825 // could become altered during the Resolve stage
827 // Only expressions that are created for the parser need to implement
830 protected virtual void CloneTo (CloneContext clonectx, Expression target)
832 throw new NotImplementedException (
834 "CloneTo not implemented for expression {0}", this.GetType ()));
838 // Clones an expression created by the parser.
840 // We only support expressions created by the parser so far, not
841 // expressions that have been resolved (many more classes would need
842 // to implement CloneTo).
844 // This infrastructure is here merely for Lambda expressions which
845 // compile the same code using different type values for the same
846 // arguments to find the correct overload
848 public virtual Expression Clone (CloneContext clonectx)
850 Expression cloned = (Expression) MemberwiseClone ();
851 CloneTo (clonectx, cloned);
857 // Implementation of expression to expression tree conversion
859 public abstract Expression CreateExpressionTree (ResolveContext ec);
861 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
863 return CreateExpressionFactoryCall (ec, name, null, args, loc);
866 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
868 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
871 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
873 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
876 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
878 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
882 return new TypeExpression (t, loc);
886 // Implemented by all expressions which support conversion from
887 // compiler expression to invokable runtime expression. Used by
888 // dynamic C# binder.
890 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
892 throw new NotImplementedException ("MakeExpression for " + GetType ());
897 /// This is just a base class for expressions that can
898 /// appear on statements (invocations, object creation,
899 /// assignments, post/pre increment and decrement). The idea
900 /// being that they would support an extra Emition interface that
901 /// does not leave a result on the stack.
903 public abstract class ExpressionStatement : Expression {
905 public ExpressionStatement ResolveStatement (BlockContext ec)
907 Expression e = Resolve (ec);
911 ExpressionStatement es = e as ExpressionStatement;
913 Error_InvalidExpressionStatement (ec);
919 /// Requests the expression to be emitted in a `statement'
920 /// context. This means that no new value is left on the
921 /// stack after invoking this method (constrasted with
922 /// Emit that will always leave a value on the stack).
924 public abstract void EmitStatement (EmitContext ec);
926 public override void EmitSideEffect (EmitContext ec)
933 /// This kind of cast is used to encapsulate the child
934 /// whose type is child.Type into an expression that is
935 /// reported to return "return_type". This is used to encapsulate
936 /// expressions which have compatible types, but need to be dealt
937 /// at higher levels with.
939 /// For example, a "byte" expression could be encapsulated in one
940 /// of these as an "unsigned int". The type for the expression
941 /// would be "unsigned int".
944 public abstract class TypeCast : Expression
946 protected readonly Expression child;
948 protected TypeCast (Expression child, TypeSpec return_type)
950 eclass = child.eclass;
951 loc = child.Location;
956 public Expression Child {
962 public override Expression CreateExpressionTree (ResolveContext ec)
964 Arguments args = new Arguments (2);
965 args.Add (new Argument (child.CreateExpressionTree (ec)));
966 args.Add (new Argument (new TypeOf (type, loc)));
968 if (type.IsPointer || child.Type.IsPointer)
969 Error_PointerInsideExpressionTree (ec);
971 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
974 protected override Expression DoResolve (ResolveContext ec)
976 // This should never be invoked, we are born in fully
977 // initialized state.
982 public override void Emit (EmitContext ec)
987 public override SLE.Expression MakeExpression (BuilderContext ctx)
990 return base.MakeExpression (ctx);
992 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
993 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
994 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
998 protected override void CloneTo (CloneContext clonectx, Expression t)
1003 public override bool IsNull {
1004 get { return child.IsNull; }
1008 public class EmptyCast : TypeCast {
1009 EmptyCast (Expression child, TypeSpec target_type)
1010 : base (child, target_type)
1014 public static Expression Create (Expression child, TypeSpec type)
1016 Constant c = child as Constant;
1018 return new EmptyConstantCast (c, type);
1020 EmptyCast e = child as EmptyCast;
1022 return new EmptyCast (e.child, type);
1024 return new EmptyCast (child, type);
1027 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1029 child.EmitBranchable (ec, label, on_true);
1032 public override void EmitSideEffect (EmitContext ec)
1034 child.EmitSideEffect (ec);
1039 // Used for predefined type user operator (no obsolete check, etc.)
1041 public class OperatorCast : TypeCast
1043 readonly MethodSpec conversion_operator;
1045 public OperatorCast (Expression expr, TypeSpec target_type)
1046 : this (expr, target_type, target_type, false)
1050 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1051 : this (expr, target_type, target_type, find_explicit)
1055 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1056 : base (expr, returnType)
1058 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1059 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1062 foreach (MethodSpec oper in mi) {
1063 if (oper.ReturnType != returnType)
1066 if (oper.Parameters.Types[0] == expr.Type) {
1067 conversion_operator = oper;
1073 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1074 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1077 public override void Emit (EmitContext ec)
1080 ec.Emit (OpCodes.Call, conversion_operator);
1085 // Constant specialization of EmptyCast.
1086 // We need to special case this since an empty cast of
1087 // a constant is still a constant.
1089 public class EmptyConstantCast : Constant
1091 public readonly Constant child;
1093 public EmptyConstantCast (Constant child, TypeSpec type)
1094 : base (child.Location)
1097 throw new ArgumentNullException ("child");
1100 this.eclass = child.eclass;
1104 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1106 if (child.Type == target_type)
1109 // FIXME: check that 'type' can be converted to 'target_type' first
1110 return child.ConvertExplicitly (in_checked_context, target_type);
1113 public override Expression CreateExpressionTree (ResolveContext ec)
1115 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1116 child.CreateExpressionTree (ec),
1117 new TypeOf (type, loc));
1120 Error_PointerInsideExpressionTree (ec);
1122 return CreateExpressionFactoryCall (ec, "Convert", args);
1125 public override bool IsDefaultValue {
1126 get { return child.IsDefaultValue; }
1129 public override bool IsNegative {
1130 get { return child.IsNegative; }
1133 public override bool IsNull {
1134 get { return child.IsNull; }
1137 public override bool IsOneInteger {
1138 get { return child.IsOneInteger; }
1141 public override bool IsSideEffectFree {
1143 return child.IsSideEffectFree;
1147 public override bool IsZeroInteger {
1148 get { return child.IsZeroInteger; }
1151 public override void Emit (EmitContext ec)
1156 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1158 child.EmitBranchable (ec, label, on_true);
1160 // Only to make verifier happy
1161 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1162 ec.Emit (OpCodes.Unbox_Any, type);
1165 public override void EmitSideEffect (EmitContext ec)
1167 child.EmitSideEffect (ec);
1170 public override object GetValue ()
1172 return child.GetValue ();
1175 public override string GetValueAsLiteral ()
1177 return child.GetValueAsLiteral ();
1180 public override long GetValueAsLong ()
1182 return child.GetValueAsLong ();
1185 public override Constant ConvertImplicitly (TypeSpec target_type)
1187 if (type == target_type)
1190 // FIXME: Do we need to check user conversions?
1191 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1194 return child.ConvertImplicitly (target_type);
1199 /// This class is used to wrap literals which belong inside Enums
1201 public class EnumConstant : Constant
1203 public Constant Child;
1205 public EnumConstant (Constant child, TypeSpec enum_type)
1206 : base (child.Location)
1210 this.eclass = ExprClass.Value;
1211 this.type = enum_type;
1214 protected EnumConstant (Location loc)
1219 public override void Emit (EmitContext ec)
1224 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1226 Child.EncodeAttributeValue (rc, enc, Child.Type);
1229 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1231 Child.EmitBranchable (ec, label, on_true);
1234 public override void EmitSideEffect (EmitContext ec)
1236 Child.EmitSideEffect (ec);
1239 public override string GetSignatureForError()
1241 return TypeManager.CSharpName (Type);
1244 public override object GetValue ()
1246 return Child.GetValue ();
1250 public override object GetTypedValue ()
1253 // The method can be used in dynamic context only (on closed types)
1255 // System.Enum.ToObject cannot be called on dynamic types
1256 // EnumBuilder has to be used, but we cannot use EnumBuilder
1257 // because it does not properly support generics
1259 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1263 public override string GetValueAsLiteral ()
1265 return Child.GetValueAsLiteral ();
1268 public override long GetValueAsLong ()
1270 return Child.GetValueAsLong ();
1273 public EnumConstant Increment()
1275 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1278 public override bool IsDefaultValue {
1280 return Child.IsDefaultValue;
1284 public override bool IsSideEffectFree {
1286 return Child.IsSideEffectFree;
1290 public override bool IsZeroInteger {
1291 get { return Child.IsZeroInteger; }
1294 public override bool IsNegative {
1296 return Child.IsNegative;
1300 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1302 if (Child.Type == target_type)
1305 return Child.ConvertExplicitly (in_checked_context, target_type);
1308 public override Constant ConvertImplicitly (TypeSpec type)
1310 if (this.type == type) {
1314 if (!Convert.ImplicitStandardConversionExists (this, type)){
1318 return Child.ConvertImplicitly (type);
1323 /// This kind of cast is used to encapsulate Value Types in objects.
1325 /// The effect of it is to box the value type emitted by the previous
1328 public class BoxedCast : TypeCast {
1330 public BoxedCast (Expression expr, TypeSpec target_type)
1331 : base (expr, target_type)
1333 eclass = ExprClass.Value;
1336 protected override Expression DoResolve (ResolveContext ec)
1338 // This should never be invoked, we are born in fully
1339 // initialized state.
1344 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1346 // Only boxing to object type is supported
1347 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1348 base.EncodeAttributeValue (rc, enc, targetType);
1352 enc.Encode (child.Type);
1353 child.EncodeAttributeValue (rc, enc, child.Type);
1356 public override void Emit (EmitContext ec)
1360 ec.Emit (OpCodes.Box, child.Type);
1363 public override void EmitSideEffect (EmitContext ec)
1365 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1366 // so, we need to emit the box+pop instructions in most cases
1367 if (child.Type.IsStruct &&
1368 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1369 child.EmitSideEffect (ec);
1371 base.EmitSideEffect (ec);
1375 public class UnboxCast : TypeCast {
1376 public UnboxCast (Expression expr, TypeSpec return_type)
1377 : base (expr, return_type)
1381 protected override Expression DoResolve (ResolveContext ec)
1383 // This should never be invoked, we are born in fully
1384 // initialized state.
1389 public override void Emit (EmitContext ec)
1393 ec.Emit (OpCodes.Unbox_Any, type);
1398 /// This is used to perform explicit numeric conversions.
1400 /// Explicit numeric conversions might trigger exceptions in a checked
1401 /// context, so they should generate the conv.ovf opcodes instead of
1404 public class ConvCast : TypeCast {
1405 public enum Mode : byte {
1406 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1408 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1409 U2_I1, U2_U1, U2_I2, U2_CH,
1410 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1411 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1412 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1413 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1414 CH_I1, CH_U1, CH_I2,
1415 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1416 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1422 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1423 : base (child, return_type)
1428 protected override Expression DoResolve (ResolveContext ec)
1430 // This should never be invoked, we are born in fully
1431 // initialized state.
1436 public override string ToString ()
1438 return String.Format ("ConvCast ({0}, {1})", mode, child);
1441 public override void Emit (EmitContext ec)
1445 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1447 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1448 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1449 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1450 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1451 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1453 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1454 case Mode.U1_CH: /* nothing */ break;
1456 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1457 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1458 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1459 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1460 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1461 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1463 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1464 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1465 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1466 case Mode.U2_CH: /* nothing */ break;
1468 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1469 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1470 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1471 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1472 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1473 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1474 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1476 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1477 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1478 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1479 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1480 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1481 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1483 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1484 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1485 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1486 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1487 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1488 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1489 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1490 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1491 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1493 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1494 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1495 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1496 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1497 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1498 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1499 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1500 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1501 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1503 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1504 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1505 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1507 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1508 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1509 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1510 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1511 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1512 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1513 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1514 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1515 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1517 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1518 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1519 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1520 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1521 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1522 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1523 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1524 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1525 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1526 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1528 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1532 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1533 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1534 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1535 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1536 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1538 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1539 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1541 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1542 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1543 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1544 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1545 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1546 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1548 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1549 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1550 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1551 case Mode.U2_CH: /* nothing */ break;
1553 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1554 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1555 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1556 case Mode.I4_U4: /* nothing */ break;
1557 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1558 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1559 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1561 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1562 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1563 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1564 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1565 case Mode.U4_I4: /* nothing */ break;
1566 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1568 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1569 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1570 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1571 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1572 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1573 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1574 case Mode.I8_U8: /* nothing */ break;
1575 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1576 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1578 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1579 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1580 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1581 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1582 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1583 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1584 case Mode.U8_I8: /* nothing */ break;
1585 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1586 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1588 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1589 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1590 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1592 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1593 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1594 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1595 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1596 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1597 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1598 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1599 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1600 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1602 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1603 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1604 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1605 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1606 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1607 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1608 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1609 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1610 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1611 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1613 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1619 class OpcodeCast : TypeCast
1623 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1624 : base (child, return_type)
1629 protected override Expression DoResolve (ResolveContext ec)
1631 // This should never be invoked, we are born in fully
1632 // initialized state.
1637 public override void Emit (EmitContext ec)
1643 public TypeSpec UnderlyingType {
1644 get { return child.Type; }
1649 // Opcode casts expression with 2 opcodes but only
1650 // single expression tree node
1652 class OpcodeCastDuplex : OpcodeCast
1654 readonly OpCode second;
1656 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1657 : base (child, returnType, first)
1659 this.second = second;
1662 public override void Emit (EmitContext ec)
1670 /// This kind of cast is used to encapsulate a child and cast it
1671 /// to the class requested
1673 public sealed class ClassCast : TypeCast {
1674 readonly bool forced;
1676 public ClassCast (Expression child, TypeSpec return_type)
1677 : base (child, return_type)
1681 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1682 : base (child, return_type)
1684 this.forced = forced;
1687 public override void Emit (EmitContext ec)
1691 bool gen = TypeManager.IsGenericParameter (child.Type);
1693 ec.Emit (OpCodes.Box, child.Type);
1695 if (type.IsGenericParameter) {
1696 ec.Emit (OpCodes.Unbox_Any, type);
1703 ec.Emit (OpCodes.Castclass, type);
1708 // Created during resolving pahse when an expression is wrapped or constantified
1709 // and original expression can be used later (e.g. for expression trees)
1711 public class ReducedExpression : Expression
1713 sealed class ReducedConstantExpression : EmptyConstantCast
1715 readonly Expression orig_expr;
1717 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1718 : base (expr, expr.Type)
1720 this.orig_expr = orig_expr;
1723 public override Constant ConvertImplicitly (TypeSpec target_type)
1725 Constant c = base.ConvertImplicitly (target_type);
1727 c = new ReducedConstantExpression (c, orig_expr);
1732 public override Expression CreateExpressionTree (ResolveContext ec)
1734 return orig_expr.CreateExpressionTree (ec);
1737 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1739 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1741 c = new ReducedConstantExpression (c, orig_expr);
1746 sealed class ReducedExpressionStatement : ExpressionStatement
1748 readonly Expression orig_expr;
1749 readonly ExpressionStatement stm;
1751 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1753 this.orig_expr = orig;
1755 this.eclass = stm.eclass;
1756 this.type = stm.Type;
1758 this.loc = orig.Location;
1761 public override Expression CreateExpressionTree (ResolveContext ec)
1763 return orig_expr.CreateExpressionTree (ec);
1766 protected override Expression DoResolve (ResolveContext ec)
1771 public override void Emit (EmitContext ec)
1776 public override void EmitStatement (EmitContext ec)
1778 stm.EmitStatement (ec);
1782 readonly Expression expr, orig_expr;
1784 private ReducedExpression (Expression expr, Expression orig_expr)
1787 this.eclass = expr.eclass;
1788 this.type = expr.Type;
1789 this.orig_expr = orig_expr;
1790 this.loc = orig_expr.Location;
1795 public Expression OriginalExpression {
1804 // Creates fully resolved expression switcher
1806 public static Constant Create (Constant expr, Expression original_expr)
1808 if (expr.eclass == ExprClass.Unresolved)
1809 throw new ArgumentException ("Unresolved expression");
1811 return new ReducedConstantExpression (expr, original_expr);
1814 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1816 return new ReducedExpressionStatement (s, orig);
1819 public static Expression Create (Expression expr, Expression original_expr)
1821 return Create (expr, original_expr, true);
1825 // Creates unresolved reduce expression. The original expression has to be
1826 // already resolved. Created expression is constant based based on `expr'
1827 // value unless canBeConstant is used
1829 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1831 if (canBeConstant) {
1832 Constant c = expr as Constant;
1834 return Create (c, original_expr);
1837 ExpressionStatement s = expr as ExpressionStatement;
1839 return Create (s, original_expr);
1841 if (expr.eclass == ExprClass.Unresolved)
1842 throw new ArgumentException ("Unresolved expression");
1844 return new ReducedExpression (expr, original_expr);
1847 public override Expression CreateExpressionTree (ResolveContext ec)
1849 return orig_expr.CreateExpressionTree (ec);
1852 protected override Expression DoResolve (ResolveContext ec)
1857 public override void Emit (EmitContext ec)
1862 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1864 expr.EmitBranchable (ec, target, on_true);
1867 public override SLE.Expression MakeExpression (BuilderContext ctx)
1869 return orig_expr.MakeExpression (ctx);
1874 // Standard composite pattern
1876 public abstract class CompositeExpression : Expression
1878 protected Expression expr;
1880 protected CompositeExpression (Expression expr)
1883 this.loc = expr.Location;
1886 public override Expression CreateExpressionTree (ResolveContext rc)
1888 return expr.CreateExpressionTree (rc);
1891 public Expression Child {
1892 get { return expr; }
1895 protected override Expression DoResolve (ResolveContext rc)
1897 expr = expr.Resolve (rc);
1900 eclass = expr.eclass;
1906 public override void Emit (EmitContext ec)
1911 public override bool IsNull {
1912 get { return expr.IsNull; }
1917 // Base of expressions used only to narrow resolve flow
1919 public abstract class ShimExpression : Expression
1921 protected Expression expr;
1923 protected ShimExpression (Expression expr)
1928 public Expression Expr {
1934 protected override void CloneTo (CloneContext clonectx, Expression t)
1939 ShimExpression target = (ShimExpression) t;
1940 target.expr = expr.Clone (clonectx);
1943 public override Expression CreateExpressionTree (ResolveContext ec)
1945 throw new NotSupportedException ("ET");
1948 public override void Emit (EmitContext ec)
1950 throw new InternalErrorException ("Missing Resolve call");
1956 // Unresolved type name expressions
1958 public abstract class ATypeNameExpression : FullNamedExpression
1961 protected TypeArguments targs;
1963 protected ATypeNameExpression (string name, Location l)
1969 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
1976 protected ATypeNameExpression (string name, int arity, Location l)
1977 : this (name, new UnboundTypeArguments (arity), l)
1983 protected int Arity {
1985 return targs == null ? 0 : targs.Count;
1989 public bool HasTypeArguments {
1991 return targs != null && !targs.IsEmpty;
1995 public string Name {
2004 public TypeArguments TypeArguments {
2012 public override bool Equals (object obj)
2014 ATypeNameExpression atne = obj as ATypeNameExpression;
2015 return atne != null && atne.Name == Name &&
2016 (targs == null || targs.Equals (atne.targs));
2019 public override int GetHashCode ()
2021 return Name.GetHashCode ();
2024 // TODO: Move it to MemberCore
2025 public static string GetMemberType (MemberCore mc)
2031 if (mc is FieldBase)
2033 if (mc is MethodCore)
2035 if (mc is EnumMember)
2043 public override string GetSignatureForError ()
2045 if (targs != null) {
2046 return Name + "<" + targs.GetSignatureForError () + ">";
2052 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2056 /// SimpleName expressions are formed of a single word and only happen at the beginning
2057 /// of a dotted-name.
2059 public class SimpleName : ATypeNameExpression
2061 public SimpleName (string name, Location l)
2066 public SimpleName (string name, TypeArguments args, Location l)
2067 : base (name, args, l)
2071 public SimpleName (string name, int arity, Location l)
2072 : base (name, arity, l)
2076 public SimpleName GetMethodGroup ()
2078 return new SimpleName (Name, targs, loc);
2081 protected override Expression DoResolve (ResolveContext ec)
2083 return SimpleNameResolve (ec, null, false);
2086 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2088 return SimpleNameResolve (ec, right_side, false);
2091 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2093 if (ctx.CurrentType != null) {
2094 if (ctx.CurrentMemberDefinition != null) {
2095 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2097 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2104 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2105 if (retval != null) {
2106 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2107 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2111 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2112 if (retval != null) {
2113 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2117 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2120 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2122 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2125 if (fne.Type != null && Arity > 0) {
2126 if (HasTypeArguments) {
2127 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2128 if (ct.ResolveAsType (ec) == null)
2134 return new GenericOpenTypeExpr (fne.Type, loc);
2138 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2140 if (!(fne is Namespace))
2144 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2145 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2146 ec.Module.Compiler.Report.Error (1980, Location,
2147 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2148 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2151 fne = new DynamicTypeExpr (loc);
2152 fne.ResolveAsType (ec);
2158 Error_TypeOrNamespaceNotFound (ec);
2162 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2164 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2167 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2169 int lookup_arity = Arity;
2170 bool errorMode = false;
2172 Block current_block = rc.CurrentBlock;
2173 INamedBlockVariable variable = null;
2174 bool variable_found = false;
2178 // Stage 1: binding to local variables or parameters
2180 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2182 if (current_block != null && lookup_arity == 0) {
2183 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2184 if (!variable.IsDeclared) {
2185 // We found local name in accessible block but it's not
2186 // initialized yet, maybe the user wanted to bind to something else
2188 variable_found = true;
2190 e = variable.CreateReferenceExpression (rc, loc);
2193 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2202 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2204 TypeSpec member_type = rc.CurrentType;
2205 for (; member_type != null; member_type = member_type.DeclaringType) {
2206 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2210 var me = e as MemberExpr;
2212 // The name matches a type, defer to ResolveAsTypeStep
2220 if (variable != null) {
2221 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2222 rc.Report.Error (844, loc,
2223 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2224 Name, me.GetSignatureForError ());
2228 } else if (me is MethodGroupExpr) {
2229 // Leave it to overload resolution to report correct error
2231 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2232 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2235 // LAMESPEC: again, ignores InvocableOnly
2236 if (variable != null) {
2237 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2238 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2242 // MemberLookup does not check accessors availability, this is actually needed for properties only
2244 var pe = me as PropertyExpr;
2247 // Break as there is no other overload available anyway
2248 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2249 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2252 pe.Getter = pe.PropertyInfo.Get;
2254 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2257 pe.Setter = pe.PropertyInfo.Set;
2262 // TODO: It's used by EventExpr -> FieldExpr transformation only
2263 // TODO: Should go to MemberAccess
2264 me = me.ResolveMemberAccess (rc, null, null);
2268 me.SetTypeArguments (rc, targs);
2275 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2277 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2278 if (IsPossibleTypeOrNamespace (rc)) {
2279 if (variable != null) {
2280 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2281 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2284 return ResolveAsTypeOrNamespace (rc);
2289 if (variable_found) {
2290 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2293 TypeParameter[] tparams = rc.CurrentTypeParameters;
2294 if (tparams != null) {
2295 foreach (var ctp in tparams) {
2296 if (ctp.Name == Name) {
2297 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2303 var ct = rc.CurrentType;
2305 if (ct.MemberDefinition.TypeParametersCount > 0) {
2306 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2307 if (ctp.Name == Name) {
2308 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2314 ct = ct.DeclaringType;
2315 } while (ct != null);
2318 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2319 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2321 rc.Report.SymbolRelatedToPreviousError (e.Type);
2322 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2327 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2329 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2330 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2335 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2338 return ErrorExpression.Instance;
2341 if (rc.Module.Evaluator != null) {
2342 var fi = rc.Module.Evaluator.LookupField (Name);
2344 return new FieldExpr (fi.Item1, loc);
2352 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2354 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2359 if (right_side != null) {
2360 if (e is TypeExpr) {
2361 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2365 e = e.ResolveLValue (ec, right_side);
2370 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2376 /// Represents a namespace or a type. The name of the class was inspired by
2377 /// section 10.8.1 (Fully Qualified Names).
2379 public abstract class FullNamedExpression : Expression
2381 protected override void CloneTo (CloneContext clonectx, Expression target)
2383 // Do nothing, most unresolved type expressions cannot be
2384 // resolved to different type
2387 public override Expression CreateExpressionTree (ResolveContext ec)
2389 throw new NotSupportedException ("ET");
2392 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2395 // This is used to resolve the expression as a type, a null
2396 // value will be returned if the expression is not a type
2399 public override TypeSpec ResolveAsType (IMemberContext mc)
2401 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2406 TypeExpr te = fne as TypeExpr;
2408 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2416 var dep = type.GetMissingDependencies ();
2418 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2422 // Obsolete checks cannot be done when resolving base context as they
2423 // require type dependencies to be set but we are in process of resolving them
2425 if (!(mc is TypeContainer.BaseContext)) {
2426 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2427 if (obsolete_attr != null && !mc.IsObsolete) {
2428 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2436 public override void Emit (EmitContext ec)
2438 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2439 GetSignatureForError ());
2444 /// Expression that evaluates to a type
2446 public abstract class TypeExpr : FullNamedExpression
2448 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2454 protected sealed override Expression DoResolve (ResolveContext ec)
2460 public override bool Equals (object obj)
2462 TypeExpr tobj = obj as TypeExpr;
2466 return Type == tobj.Type;
2469 public override int GetHashCode ()
2471 return Type.GetHashCode ();
2476 /// Fully resolved Expression that already evaluated to a type
2478 public class TypeExpression : TypeExpr
2480 public TypeExpression (TypeSpec t, Location l)
2483 eclass = ExprClass.Type;
2487 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2494 /// This class denotes an expression which evaluates to a member
2495 /// of a struct or a class.
2497 public abstract class MemberExpr : Expression
2500 // An instance expression associated with this member, if it's a
2501 // non-static member
2503 public Expression InstanceExpression;
2506 /// The name of this member.
2508 public abstract string Name {
2513 // When base.member is used
2515 public bool IsBase {
2516 get { return InstanceExpression is BaseThis; }
2520 /// Whether this is an instance member.
2522 public abstract bool IsInstance {
2527 /// Whether this is a static member.
2529 public abstract bool IsStatic {
2533 protected abstract TypeSpec DeclaringType {
2538 // Converts best base candidate for virtual method starting from QueriedBaseType
2540 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2543 // Only when base.member is used and method is virtual
2549 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2550 // means for base.member access we have to find the closest match after we found best candidate
2552 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2554 // The method could already be what we are looking for
2556 TypeSpec[] targs = null;
2557 if (method.DeclaringType != InstanceExpression.Type) {
2558 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2559 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2560 if (base_override.IsGeneric)
2561 targs = method.TypeArguments;
2563 method = base_override;
2567 // TODO: For now we do it for any hoisted call even if it's needed for
2568 // hoisted stories only but that requires a new expression wrapper
2569 if (rc.CurrentAnonymousMethod != null) {
2570 if (targs == null && method.IsGeneric) {
2571 targs = method.TypeArguments;
2572 method = method.GetGenericMethodDefinition ();
2575 if (method.Parameters.HasArglist)
2576 throw new NotImplementedException ("__arglist base call proxy");
2578 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2580 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2581 // get/set member expressions second call would fail to proxy because left expression
2582 // would be of 'this' and not 'base'
2583 if (rc.CurrentType.IsStruct)
2584 InstanceExpression = new This (loc).Resolve (rc);
2588 method = method.MakeGenericMethod (rc, targs);
2592 // Only base will allow this invocation to happen.
2594 if (method.IsAbstract) {
2595 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2601 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2603 if (InstanceExpression == null)
2606 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2607 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2611 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2613 var ct = rc.CurrentType;
2614 if (ct == qualifier)
2617 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2620 qualifier = qualifier.GetDefinition ();
2621 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2622 rc.Report.SymbolRelatedToPreviousError (member);
2623 rc.Report.Error (1540, loc,
2624 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2625 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2629 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2632 type = type.GetDefinition ();
2634 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2637 type = type.DeclaringType;
2638 } while (type != null);
2643 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2645 if (InstanceExpression != null) {
2646 InstanceExpression = InstanceExpression.Resolve (rc);
2647 CheckProtectedMemberAccess (rc, member);
2650 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2651 UnsafeError (rc, loc);
2654 var dep = member.GetMissingDependencies ();
2656 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2659 if (!rc.IsObsolete) {
2660 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2662 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2665 if (!(member is FieldSpec))
2666 member.MemberDefinition.SetIsUsed ();
2669 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2671 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2675 // Implements identicial simple name and type-name
2677 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2680 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2683 // 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
2684 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2686 if (left is MemberExpr || left is VariableReference) {
2687 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2688 if (identical_type != null && identical_type.Type == left.Type)
2689 return identical_type;
2695 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2698 if (InstanceExpression != null) {
2699 if (InstanceExpression is TypeExpr) {
2700 var t = InstanceExpression.Type;
2702 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2703 if (oa != null && !rc.IsObsolete) {
2704 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2707 t = t.DeclaringType;
2708 } while (t != null);
2710 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2711 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2712 rc.Report.Error (176, loc,
2713 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2714 GetSignatureForError ());
2718 InstanceExpression = null;
2724 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2725 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2726 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2727 rc.Report.Error (236, loc,
2728 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2729 GetSignatureForError ());
2731 rc.Report.Error (120, loc,
2732 "An object reference is required to access non-static member `{0}'",
2733 GetSignatureForError ());
2738 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2739 rc.Report.Error (38, loc,
2740 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2741 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2744 InstanceExpression = new This (loc);
2745 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2746 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2747 InstanceExpression = InstanceExpression.Resolve (rc);
2750 InstanceExpression = InstanceExpression.Resolve (rc);
2756 var me = InstanceExpression as MemberExpr;
2758 me.ResolveInstanceExpression (rc, rhs);
2760 var fe = me as FieldExpr;
2761 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2762 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2763 rc.Report.Warning (1690, 1, loc,
2764 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2765 me.GetSignatureForError ());
2772 // Run member-access postponed check once we know that
2773 // the expression is not field expression which is the only
2774 // expression which can use uninitialized this
2776 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2777 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2781 // Additional checks for l-value member access
2785 // TODO: It should be recursive but that would break csc compatibility
2787 if (InstanceExpression is UnboxCast) {
2788 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2795 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2797 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2798 ec.Report.Warning (1720, 1, left.Location,
2799 "Expression will always cause a `{0}'", "System.NullReferenceException");
2802 InstanceExpression = left;
2806 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2808 TypeSpec instance_type = InstanceExpression.Type;
2809 if (TypeSpec.IsValueType (instance_type)) {
2810 if (InstanceExpression is IMemoryLocation) {
2811 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2813 LocalTemporary t = new LocalTemporary (instance_type);
2814 InstanceExpression.Emit (ec);
2816 t.AddressOf (ec, AddressOp.Store);
2819 InstanceExpression.Emit (ec);
2821 // Only to make verifier happy
2822 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2823 ec.Emit (OpCodes.Box, instance_type);
2826 if (prepare_for_load)
2827 ec.Emit (OpCodes.Dup);
2830 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2834 // Represents a group of extension method candidates for whole namespace
2836 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2838 NamespaceContainer namespace_entry;
2839 public readonly Expression ExtensionExpression;
2841 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
2842 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2844 this.namespace_entry = n;
2845 this.ExtensionExpression = extensionExpr;
2848 public override bool IsStatic {
2849 get { return true; }
2852 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2854 if (namespace_entry == null)
2858 // For extension methodgroup we are not looking for base members but parent
2859 // namespace extension methods
2861 int arity = type_arguments == null ? 0 : type_arguments.Count;
2862 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2866 return found.Cast<MemberSpec> ().ToList ();
2869 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2871 // We are already here
2875 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2877 if (arguments == null)
2878 arguments = new Arguments (1);
2880 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2881 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2883 // Store resolved argument and restore original arguments
2885 // Clean-up modified arguments for error reporting
2886 arguments.RemoveAt (0);
2890 var me = ExtensionExpression as MemberExpr;
2892 me.ResolveInstanceExpression (ec, null);
2894 InstanceExpression = null;
2898 #region IErrorHandler Members
2900 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2905 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2907 rc.Report.SymbolRelatedToPreviousError (best);
2908 rc.Report.Error (1928, loc,
2909 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2910 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2913 rc.Report.Error (1929, loc,
2914 "Extension method instance type `{0}' cannot be converted to `{1}'",
2915 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2921 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2926 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2935 /// MethodGroupExpr represents a group of method candidates which
2936 /// can be resolved to the best method overload
2938 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2940 protected IList<MemberSpec> Methods;
2941 MethodSpec best_candidate;
2942 TypeSpec best_candidate_return;
2943 protected TypeArguments type_arguments;
2945 SimpleName simple_name;
2946 protected TypeSpec queried_type;
2948 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2952 this.type = InternalType.MethodGroup;
2954 eclass = ExprClass.MethodGroup;
2955 queried_type = type;
2958 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2959 : this (new MemberSpec[] { m }, type, loc)
2965 public MethodSpec BestCandidate {
2967 return best_candidate;
2971 public TypeSpec BestCandidateReturnType {
2973 return best_candidate_return;
2977 public IList<MemberSpec> Candidates {
2983 protected override TypeSpec DeclaringType {
2985 return queried_type;
2989 public override bool IsInstance {
2991 if (best_candidate != null)
2992 return !best_candidate.IsStatic;
2998 public override bool IsStatic {
3000 if (best_candidate != null)
3001 return best_candidate.IsStatic;
3007 public override string Name {
3009 if (best_candidate != null)
3010 return best_candidate.Name;
3013 return Methods.First ().Name;
3020 // When best candidate is already know this factory can be used
3021 // to avoid expensive overload resolution to be called
3023 // NOTE: InstanceExpression has to be set manually
3025 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3027 return new MethodGroupExpr (best, queriedType, loc) {
3028 best_candidate = best,
3029 best_candidate_return = best.ReturnType
3033 public override string GetSignatureForError ()
3035 if (best_candidate != null)
3036 return best_candidate.GetSignatureForError ();
3038 return Methods.First ().GetSignatureForError ();
3041 public override Expression CreateExpressionTree (ResolveContext ec)
3043 if (best_candidate == null) {
3044 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3048 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3049 ec.Report.Error (765, loc,
3050 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3052 return new TypeOfMethod (best_candidate, loc);
3055 protected override Expression DoResolve (ResolveContext ec)
3057 this.eclass = ExprClass.MethodGroup;
3059 if (InstanceExpression != null) {
3060 InstanceExpression = InstanceExpression.Resolve (ec);
3061 if (InstanceExpression == null)
3068 public override void Emit (EmitContext ec)
3070 throw new NotSupportedException ();
3073 public void EmitCall (EmitContext ec, Arguments arguments)
3075 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3078 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3080 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3081 Name, TypeManager.CSharpName (target));
3084 public static bool IsExtensionMethodArgument (Expression expr)
3087 // LAMESPEC: No details about which expressions are not allowed
3089 return !(expr is TypeExpr) && !(expr is BaseThis);
3093 /// Find the Applicable Function Members (7.4.2.1)
3095 /// me: Method Group expression with the members to select.
3096 /// it might contain constructors or methods (or anything
3097 /// that maps to a method).
3099 /// Arguments: ArrayList containing resolved Argument objects.
3101 /// loc: The location if we want an error to be reported, or a Null
3102 /// location for "probing" purposes.
3104 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3105 /// that is the best match of me on Arguments.
3108 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3110 // TODO: causes issues with probing mode, remove explicit Kind check
3111 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3114 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3115 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3116 r.BaseMembersProvider = this;
3119 if (cerrors != null)
3120 r.CustomErrors = cerrors;
3122 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3123 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3124 if (best_candidate == null)
3125 return r.BestCandidateIsDynamic ? this : null;
3127 // Overload resolver had to create a new method group, all checks bellow have already been executed
3128 if (r.BestCandidateNewMethodGroup != null)
3129 return r.BestCandidateNewMethodGroup;
3131 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3132 if (InstanceExpression != null) {
3133 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3134 InstanceExpression = null;
3136 if (best_candidate.IsStatic && simple_name != null) {
3137 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3140 InstanceExpression.Resolve (ec);
3144 ResolveInstanceExpression (ec, null);
3145 if (InstanceExpression != null)
3146 CheckProtectedMemberAccess (ec, best_candidate);
3149 var base_override = CandidateToBaseOverride (ec, best_candidate);
3150 if (base_override == best_candidate) {
3151 best_candidate_return = r.BestCandidateReturnType;
3153 best_candidate = base_override;
3154 best_candidate_return = best_candidate.ReturnType;
3160 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3162 simple_name = original;
3163 return base.ResolveMemberAccess (ec, left, original);
3166 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3168 type_arguments = ta;
3171 #region IBaseMembersProvider Members
3173 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3175 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3178 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3180 if (queried_type == member.DeclaringType)
3183 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3184 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3188 // Extension methods lookup after ordinary methods candidates failed to apply
3190 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3192 if (InstanceExpression == null)
3195 InstanceExpression = InstanceExpression.Resolve (rc);
3196 if (!IsExtensionMethodArgument (InstanceExpression))
3199 int arity = type_arguments == null ? 0 : type_arguments.Count;
3200 NamespaceContainer methods_scope = null;
3201 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3202 if (methods == null)
3205 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3206 emg.SetTypeArguments (rc, type_arguments);
3213 public struct OverloadResolver
3216 public enum Restrictions
3220 ProbingOnly = 1 << 1,
3221 CovariantDelegate = 1 << 2,
3222 NoBaseMembers = 1 << 3,
3223 BaseMembersIncluded = 1 << 4
3226 public interface IBaseMembersProvider
3228 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3229 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3230 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3233 public interface IErrorHandler
3235 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3236 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3237 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3238 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3241 sealed class NoBaseMembers : IBaseMembersProvider
3243 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3245 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3250 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3255 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3261 struct AmbiguousCandidate
3263 public readonly MemberSpec Member;
3264 public readonly bool Expanded;
3265 public readonly AParametersCollection Parameters;
3267 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3270 Parameters = parameters;
3271 Expanded = expanded;
3276 IList<MemberSpec> members;
3277 TypeArguments type_arguments;
3278 IBaseMembersProvider base_provider;
3279 IErrorHandler custom_errors;
3280 Restrictions restrictions;
3281 MethodGroupExpr best_candidate_extension_group;
3282 TypeSpec best_candidate_return_type;
3284 SessionReportPrinter lambda_conv_msgs;
3285 ReportPrinter prev_recorder;
3287 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3288 : this (members, null, restrictions, loc)
3292 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3295 if (members == null || members.Count == 0)
3296 throw new ArgumentException ("empty members set");
3298 this.members = members;
3300 type_arguments = targs;
3301 this.restrictions = restrictions;
3302 if (IsDelegateInvoke)
3303 this.restrictions |= Restrictions.NoBaseMembers;
3305 base_provider = NoBaseMembers.Instance;
3310 public IBaseMembersProvider BaseMembersProvider {
3312 return base_provider;
3315 base_provider = value;
3319 public bool BestCandidateIsDynamic { get; set; }
3322 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3324 public MethodGroupExpr BestCandidateNewMethodGroup {
3326 return best_candidate_extension_group;
3331 // Return type can be different between best candidate and closest override
3333 public TypeSpec BestCandidateReturnType {
3335 return best_candidate_return_type;
3339 public IErrorHandler CustomErrors {
3341 return custom_errors;
3344 custom_errors = value;
3348 TypeSpec DelegateType {
3350 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3351 throw new InternalErrorException ("Not running in delegate mode", loc);
3353 return members [0].DeclaringType;
3357 bool IsProbingOnly {
3359 return (restrictions & Restrictions.ProbingOnly) != 0;
3363 bool IsDelegateInvoke {
3365 return (restrictions & Restrictions.DelegateInvoke) != 0;
3372 // 7.4.3.3 Better conversion from expression
3373 // Returns : 1 if a->p is better,
3374 // 2 if a->q is better,
3375 // 0 if neither is better
3377 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3379 TypeSpec argument_type = a.Type;
3382 // If argument is an anonymous function
3384 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3386 // p and q are delegate types or expression tree types
3388 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3389 if (q.MemberDefinition != p.MemberDefinition) {
3394 // Uwrap delegate from Expression<T>
3396 q = TypeManager.GetTypeArguments (q)[0];
3397 p = TypeManager.GetTypeArguments (p)[0];
3400 var p_m = Delegate.GetInvokeMethod (p);
3401 var q_m = Delegate.GetInvokeMethod (q);
3404 // With identical parameter lists
3406 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3413 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3415 if (p.Kind == MemberKind.Void) {
3416 return q.Kind != MemberKind.Void ? 2 : 0;
3420 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3422 if (q.Kind == MemberKind.Void) {
3423 return p.Kind != MemberKind.Void ? 1: 0;
3427 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3428 // better conversion is performed between underlying types Y1 and Y2
3430 if (p.IsGenericTask || q.IsGenericTask) {
3431 if (p.IsGenericTask != q.IsGenericTask) {
3435 var async_am = a.Expr as AnonymousMethodExpression;
3436 if (async_am == null || !async_am.IsAsync)
3439 q = q.TypeArguments[0];
3440 p = p.TypeArguments[0];
3444 // The parameters are identicial and return type is not void, use better type conversion
3445 // on return type to determine better one
3448 if (argument_type == p)
3451 if (argument_type == q)
3455 return BetterTypeConversion (ec, p, q);
3459 // 7.4.3.4 Better conversion from type
3461 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3463 if (p == null || q == null)
3464 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3466 switch (p.BuiltinType) {
3467 case BuiltinTypeSpec.Type.Int:
3468 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3471 case BuiltinTypeSpec.Type.Long:
3472 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3475 case BuiltinTypeSpec.Type.SByte:
3476 switch (q.BuiltinType) {
3477 case BuiltinTypeSpec.Type.Byte:
3478 case BuiltinTypeSpec.Type.UShort:
3479 case BuiltinTypeSpec.Type.UInt:
3480 case BuiltinTypeSpec.Type.ULong:
3484 case BuiltinTypeSpec.Type.Short:
3485 switch (q.BuiltinType) {
3486 case BuiltinTypeSpec.Type.UShort:
3487 case BuiltinTypeSpec.Type.UInt:
3488 case BuiltinTypeSpec.Type.ULong:
3492 case BuiltinTypeSpec.Type.Dynamic:
3493 // Dynamic is never better
3497 switch (q.BuiltinType) {
3498 case BuiltinTypeSpec.Type.Int:
3499 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3502 case BuiltinTypeSpec.Type.Long:
3503 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3506 case BuiltinTypeSpec.Type.SByte:
3507 switch (p.BuiltinType) {
3508 case BuiltinTypeSpec.Type.Byte:
3509 case BuiltinTypeSpec.Type.UShort:
3510 case BuiltinTypeSpec.Type.UInt:
3511 case BuiltinTypeSpec.Type.ULong:
3515 case BuiltinTypeSpec.Type.Short:
3516 switch (p.BuiltinType) {
3517 case BuiltinTypeSpec.Type.UShort:
3518 case BuiltinTypeSpec.Type.UInt:
3519 case BuiltinTypeSpec.Type.ULong:
3523 case BuiltinTypeSpec.Type.Dynamic:
3524 // Dynamic is never better
3528 // FIXME: handle lifted operators
3530 // TODO: this is expensive
3531 Expression p_tmp = new EmptyExpression (p);
3532 Expression q_tmp = new EmptyExpression (q);
3534 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3535 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3537 if (p_to_q && !q_to_p)
3540 if (q_to_p && !p_to_q)
3547 /// Determines "Better function" between candidate
3548 /// and the current best match
3551 /// Returns a boolean indicating :
3552 /// false if candidate ain't better
3553 /// true if candidate is better than the current best match
3555 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3556 MemberSpec best, AParametersCollection bparam, bool best_params)
3558 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3559 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3561 bool better_at_least_one = false;
3563 int args_count = args == null ? 0 : args.Count;
3567 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3570 // Default arguments are ignored for better decision
3571 if (a.IsDefaultArgument)
3575 // When comparing named argument the parameter type index has to be looked up
3576 // in original parameter set (override version for virtual members)
3578 NamedArgument na = a as NamedArgument;
3580 int idx = cparam.GetParameterIndexByName (na.Name);
3581 ct = candidate_pd.Types[idx];
3582 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3583 ct = TypeManager.GetElementType (ct);
3585 idx = bparam.GetParameterIndexByName (na.Name);
3586 bt = best_pd.Types[idx];
3587 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3588 bt = TypeManager.GetElementType (bt);
3590 ct = candidate_pd.Types[c_idx];
3591 bt = best_pd.Types[b_idx];
3593 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3594 ct = TypeManager.GetElementType (ct);
3598 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3599 bt = TypeManager.GetElementType (bt);
3604 if (TypeSpecComparer.IsEqual (ct, bt))
3608 int result = BetterExpressionConversion (ec, a, ct, bt);
3610 // for each argument, the conversion to 'ct' should be no worse than
3611 // the conversion to 'bt'.
3615 // for at least one argument, the conversion to 'ct' should be better than
3616 // the conversion to 'bt'.
3618 better_at_least_one = true;
3621 if (better_at_least_one)
3625 // This handles the case
3627 // Add (float f1, float f2, float f3);
3628 // Add (params decimal [] foo);
3630 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3631 // first candidate would've chosen as better.
3633 if (!same && !a.IsDefaultArgument)
3637 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3641 // This handles the following cases:
3643 // Foo (int i) is better than Foo (int i, long l = 0)
3644 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3646 // Prefer non-optional version
3648 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3650 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3651 if (candidate_pd.Count >= best_pd.Count)
3654 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3661 // One is a non-generic method and second is a generic method, then non-generic is better
3663 if (best.IsGeneric != candidate.IsGeneric)
3664 return best.IsGeneric;
3667 // This handles the following cases:
3669 // Trim () is better than Trim (params char[] chars)
3670 // Concat (string s1, string s2, string s3) is better than
3671 // Concat (string s1, params string [] srest)
3672 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3674 // Prefer non-expanded version
3676 if (candidate_params != best_params)
3679 int candidate_param_count = candidate_pd.Count;
3680 int best_param_count = best_pd.Count;
3682 if (candidate_param_count != best_param_count)
3683 // can only happen if (candidate_params && best_params)
3684 return candidate_param_count > best_param_count && best_pd.HasParams;
3687 // Both methods have the same number of parameters, and the parameters have equal types
3688 // Pick the "more specific" signature using rules over original (non-inflated) types
3690 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3691 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3693 bool specific_at_least_once = false;
3694 for (j = 0; j < args_count; ++j) {
3695 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3697 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3698 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3700 ct = candidate_def_pd.Types[j];
3701 bt = best_def_pd.Types[j];
3706 TypeSpec specific = MoreSpecific (ct, bt);
3710 specific_at_least_once = true;
3713 if (specific_at_least_once)
3719 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3721 rc.Report.Error (1729, loc,
3722 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3723 type.GetSignatureForError (), argCount.ToString ());
3727 // Determines if the candidate method is applicable to the given set of arguments
3728 // There could be two different set of parameters for same candidate where one
3729 // is the closest override for default values and named arguments checks and second
3730 // one being the virtual base for the parameter types and modifiers.
3732 // A return value rates candidate method compatibility,
3733 // 0 = the best, int.MaxValue = the worst
3735 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)
3737 // Parameters of most-derived type used mainly for named and optional parameters
3738 var pd = pm.Parameters;
3740 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3741 // params modifier instead of most-derived type
3742 var cpd = ((IParametersMember) candidate).Parameters;
3743 int param_count = pd.Count;
3744 int optional_count = 0;
3746 Arguments orig_args = arguments;
3748 if (arg_count != param_count) {
3749 for (int i = 0; i < pd.Count; ++i) {
3750 if (pd.FixedParameters[i].HasDefaultValue) {
3751 optional_count = pd.Count - i;
3756 if (optional_count != 0) {
3757 // Readjust expected number when params used
3758 if (cpd.HasParams) {
3760 if (arg_count < param_count)
3762 } else if (arg_count > param_count) {
3763 int args_gap = System.Math.Abs (arg_count - param_count);
3764 return int.MaxValue - 10000 + args_gap;
3766 } else if (arg_count != param_count) {
3767 int args_gap = System.Math.Abs (arg_count - param_count);
3769 return int.MaxValue - 10000 + args_gap;
3770 if (arg_count < param_count - 1)
3771 return int.MaxValue - 10000 + args_gap;
3774 // Resize to fit optional arguments
3775 if (optional_count != 0) {
3776 if (arguments == null) {
3777 arguments = new Arguments (optional_count);
3779 // Have to create a new container, so the next run can do same
3780 var resized = new Arguments (param_count);
3781 resized.AddRange (arguments);
3782 arguments = resized;
3785 for (int i = arg_count; i < param_count; ++i)
3786 arguments.Add (null);
3790 if (arg_count > 0) {
3792 // Shuffle named arguments to the right positions if there are any
3794 if (arguments[arg_count - 1] is NamedArgument) {
3795 arg_count = arguments.Count;
3797 for (int i = 0; i < arg_count; ++i) {
3798 bool arg_moved = false;
3800 NamedArgument na = arguments[i] as NamedArgument;
3804 int index = pd.GetParameterIndexByName (na.Name);
3806 // Named parameter not found
3810 // already reordered
3815 if (index >= param_count) {
3816 // When using parameters which should not be available to the user
3817 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3820 arguments.Add (null);
3824 temp = arguments[index];
3826 // The slot has been taken by positional argument
3827 if (temp != null && !(temp is NamedArgument))
3832 arguments = arguments.MarkOrderedArgument (na);
3836 arguments[index] = arguments[i];
3837 arguments[i] = temp;
3844 arg_count = arguments.Count;
3846 } else if (arguments != null) {
3847 arg_count = arguments.Count;
3851 // 1. Handle generic method using type arguments when specified or type inference
3854 var ms = candidate as MethodSpec;
3855 if (ms != null && ms.IsGeneric) {
3856 // Setup constraint checker for probing only
3857 ConstraintChecker cc = new ConstraintChecker (null);
3859 if (type_arguments != null) {
3860 var g_args_count = ms.Arity;
3861 if (g_args_count != type_arguments.Count)
3862 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3864 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3866 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3867 // for now it simplifies things. I should probably add a callback to ResolveContext
3868 if (lambda_conv_msgs == null) {
3869 lambda_conv_msgs = new SessionReportPrinter ();
3870 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3873 var ti = new TypeInference (arguments);
3874 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3875 lambda_conv_msgs.EndSession ();
3878 return ti.InferenceScore - 20000;
3880 if (i_args.Length != 0) {
3881 ms = ms.MakeGenericMethod (ec, i_args);
3884 cc.IgnoreInferredDynamic = true;
3888 // Type arguments constraints have to match for the method to be applicable
3890 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3892 return int.MaxValue - 25000;
3896 // We have a generic return type and at same time the method is override which
3897 // means we have to also inflate override return type in case the candidate is
3898 // best candidate and override return type is different to base return type.
3900 // virtual Foo<T, object> with override Foo<T, dynamic>
3902 if (candidate != pm) {
3903 MethodSpec override_ms = (MethodSpec) pm;
3904 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3905 returnType = inflator.Inflate (returnType);
3907 returnType = ms.ReturnType;
3911 ptypes = ms.Parameters.Types;
3913 if (type_arguments != null)
3914 return int.MaxValue - 15000;
3920 // 2. Each argument has to be implicitly convertible to method parameter
3922 Parameter.Modifier p_mod = 0;
3925 for (int i = 0; i < arg_count; i++) {
3926 Argument a = arguments[i];
3928 if (!pd.FixedParameters[i].HasDefaultValue) {
3929 arguments = orig_args;
3930 return arg_count * 2 + 2;
3934 // Get the default value expression, we can use the same expression
3935 // if the type matches
3937 Expression e = pd.FixedParameters[i].DefaultValue;
3938 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3940 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3942 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
3943 e = new MemberAccess (new MemberAccess (new MemberAccess (
3944 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3946 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3952 arguments[i] = new Argument (e, Argument.AType.Default);
3956 if (p_mod != Parameter.Modifier.PARAMS) {
3957 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3959 } else if (!params_expanded_form) {
3960 params_expanded_form = true;
3961 pt = ((ElementTypeSpec) pt).Element;
3967 if (!params_expanded_form) {
3968 if (a.ArgType == Argument.AType.ExtensionType) {
3970 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3973 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3974 Convert.ImplicitReferenceConversionExists (at, pt) ||
3975 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
3980 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3983 dynamicArgument = true;
3988 // It can be applicable in expanded form (when not doing exact match like for delegates)
3990 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3991 if (!params_expanded_form)
3992 pt = ((ElementTypeSpec) pt).Element;
3995 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3998 params_expanded_form = true;
3999 } else if (score < 0) {
4000 params_expanded_form = true;
4001 dynamicArgument = true;
4006 if (params_expanded_form)
4008 return (arg_count - i) * 2 + score;
4013 // When params parameter has no argument it will be provided later if the method is the best candidate
4015 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4016 params_expanded_form = true;
4019 // Restore original arguments for dynamic binder to keep the intention of original source code
4021 if (dynamicArgument)
4022 arguments = orig_args;
4028 // Tests argument compatibility with the parameter
4029 // The possible return values are
4031 // 1 - modifier mismatch
4032 // 2 - type mismatch
4033 // -1 - dynamic binding required
4035 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4038 // Types have to be identical when ref or out modifer
4039 // is used and argument is not of dynamic type
4041 if ((argument.Modifier | param_mod) != 0) {
4042 if (argument.Type != parameter) {
4044 // Do full equality check after quick path
4046 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4048 // Using dynamic for ref/out parameter can still succeed at runtime
4050 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4057 if (argument.Modifier != param_mod) {
4059 // Using dynamic for ref/out parameter can still succeed at runtime
4061 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4068 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4072 // Deploy custom error reporting for lambda methods. When probing lambda methods
4073 // keep all errors reported in separate set and once we are done and no best
4074 // candidate was found, this set is used to report more details about what was wrong
4077 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4078 if (lambda_conv_msgs == null) {
4079 lambda_conv_msgs = new SessionReportPrinter ();
4080 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4085 // Use implicit conversion in all modes to return same candidates when the expression
4086 // is used as argument or delegate conversion
4088 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4089 if (lambda_conv_msgs != null) {
4090 lambda_conv_msgs.EndSession ();
4100 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4102 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4104 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4107 var ac_p = p as ArrayContainer;
4109 var ac_q = ((ArrayContainer) q);
4110 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4111 if (specific == ac_p.Element)
4113 if (specific == ac_q.Element)
4115 } else if (TypeManager.IsGenericType (p)) {
4116 var pargs = TypeManager.GetTypeArguments (p);
4117 var qargs = TypeManager.GetTypeArguments (q);
4119 bool p_specific_at_least_once = false;
4120 bool q_specific_at_least_once = false;
4122 for (int i = 0; i < pargs.Length; i++) {
4123 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4124 if (specific == pargs[i])
4125 p_specific_at_least_once = true;
4126 if (specific == qargs[i])
4127 q_specific_at_least_once = true;
4130 if (p_specific_at_least_once && !q_specific_at_least_once)
4132 if (!p_specific_at_least_once && q_specific_at_least_once)
4140 // Find the best method from candidate list
4142 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4144 List<AmbiguousCandidate> ambiguous_candidates = null;
4146 MemberSpec best_candidate;
4147 Arguments best_candidate_args = null;
4148 bool best_candidate_params = false;
4149 bool best_candidate_dynamic = false;
4150 int best_candidate_rate;
4151 IParametersMember best_parameter_member = null;
4153 int args_count = args != null ? args.Count : 0;
4155 Arguments candidate_args = args;
4156 bool error_mode = false;
4157 MemberSpec invocable_member = null;
4159 // Be careful, cannot return until error reporter is restored
4161 best_candidate = null;
4162 best_candidate_rate = int.MaxValue;
4164 var type_members = members;
4168 for (int i = 0; i < type_members.Count; ++i) {
4169 var member = type_members[i];
4172 // Methods in a base class are not candidates if any method in a derived
4173 // class is applicable
4175 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4179 if (!member.IsAccessible (rc))
4182 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4186 IParametersMember pm = member as IParametersMember;
4189 // Will use it later to report ambiguity between best method and invocable member
4191 if (Invocation.IsMemberInvocable (member))
4192 invocable_member = member;
4198 // Overload resolution is looking for base member but using parameter names
4199 // and default values from the closest member. That means to do expensive lookup
4200 // for the closest override for virtual or abstract members
4202 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4203 var override_params = base_provider.GetOverrideMemberParameters (member);
4204 if (override_params != null)
4205 pm = override_params;
4209 // Check if the member candidate is applicable
4211 bool params_expanded_form = false;
4212 bool dynamic_argument = false;
4213 TypeSpec rt = pm.MemberType;
4214 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4217 // How does it score compare to others
4219 if (candidate_rate < best_candidate_rate) {
4220 best_candidate_rate = candidate_rate;
4221 best_candidate = member;
4222 best_candidate_args = candidate_args;
4223 best_candidate_params = params_expanded_form;
4224 best_candidate_dynamic = dynamic_argument;
4225 best_parameter_member = pm;
4226 best_candidate_return_type = rt;
4227 } else if (candidate_rate == 0) {
4229 // The member look is done per type for most operations but sometimes
4230 // it's not possible like for binary operators overload because they
4231 // are unioned between 2 sides
4233 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4234 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4239 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4241 // We pack all interface members into top level type which makes the overload resolution
4242 // more complicated for interfaces. We compensate it by removing methods with same
4243 // signature when building the cache hence this path should not really be hit often
4246 // interface IA { void Foo (int arg); }
4247 // interface IB : IA { void Foo (params int[] args); }
4249 // IB::Foo is the best overload when calling IB.Foo (1)
4252 if (ambiguous_candidates != null) {
4253 foreach (var amb_cand in ambiguous_candidates) {
4254 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4263 ambiguous_candidates = null;
4266 // Is the new candidate better
4267 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4271 best_candidate = member;
4272 best_candidate_args = candidate_args;
4273 best_candidate_params = params_expanded_form;
4274 best_candidate_dynamic = dynamic_argument;
4275 best_parameter_member = pm;
4276 best_candidate_return_type = rt;
4278 // It's not better but any other found later could be but we are not sure yet
4279 if (ambiguous_candidates == null)
4280 ambiguous_candidates = new List<AmbiguousCandidate> ();
4282 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4286 // Restore expanded arguments
4287 if (candidate_args != args)
4288 candidate_args = args;
4290 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4292 if (prev_recorder != null)
4293 rc.Report.SetPrinter (prev_recorder);
4297 // We've found exact match
4299 if (best_candidate_rate == 0)
4303 // Try extension methods lookup when no ordinary method match was found and provider enables it
4306 var emg = base_provider.LookupExtensionMethod (rc);
4308 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4310 best_candidate_extension_group = emg;
4311 return (T) (MemberSpec) emg.BestCandidate;
4316 // Don't run expensive error reporting mode for probing
4323 lambda_conv_msgs = null;
4328 // No best member match found, report an error
4330 if (best_candidate_rate != 0 || error_mode) {
4331 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4335 if (best_candidate_dynamic) {
4336 if (args[0].ArgType == Argument.AType.ExtensionType) {
4337 rc.Report.Error (1973, loc,
4338 "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",
4339 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4342 BestCandidateIsDynamic = true;
4347 // These flags indicates we are running delegate probing conversion. No need to
4348 // do more expensive checks
4350 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4351 return (T) best_candidate;
4353 if (ambiguous_candidates != null) {
4355 // Now check that there are no ambiguities i.e the selected method
4356 // should be better than all the others
4358 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4359 var candidate = ambiguous_candidates [ix];
4361 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4362 var ambiguous = candidate.Member;
4363 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4364 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4365 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4366 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4367 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4370 return (T) best_candidate;
4375 if (invocable_member != null) {
4376 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4377 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4378 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4379 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4383 // And now check if the arguments are all
4384 // compatible, perform conversions if
4385 // necessary etc. and return if everything is
4388 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4391 if (best_candidate == null)
4395 // Check ObsoleteAttribute on the best method
4397 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4398 if (oa != null && !rc.IsObsolete)
4399 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4401 var dep = best_candidate.GetMissingDependencies ();
4403 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4406 best_candidate.MemberDefinition.SetIsUsed ();
4408 args = best_candidate_args;
4409 return (T) best_candidate;
4412 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4414 return ResolveMember<MethodSpec> (rc, ref args);
4417 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4418 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4420 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4423 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4424 ec.Report.SymbolRelatedToPreviousError (method);
4425 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4426 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4427 TypeManager.CSharpSignature (method));
4430 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4431 TypeManager.CSharpSignature (method));
4432 } else if (IsDelegateInvoke) {
4433 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4434 DelegateType.GetSignatureForError ());
4436 ec.Report.SymbolRelatedToPreviousError (method);
4437 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4438 method.GetSignatureForError ());
4441 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4443 string index = (idx + 1).ToString ();
4444 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4445 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4446 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4447 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4448 index, Parameter.GetModifierSignature (a.Modifier));
4450 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4451 index, Parameter.GetModifierSignature (mod));
4452 } else if (a.Expr != ErrorExpression.Instance) {
4453 string p1 = a.GetSignatureForError ();
4454 string p2 = TypeManager.CSharpName (paramType);
4457 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4458 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4461 ec.Report.Error (1503, loc,
4462 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4467 // We have failed to find exact match so we return error info about the closest match
4469 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4471 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4472 int arg_count = args == null ? 0 : args.Count;
4474 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4475 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4476 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4480 if (lambda_conv_msgs != null) {
4481 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4486 // For candidates which match on parameters count report more details about incorrect arguments
4489 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4490 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4491 // Reject any inaccessible member
4492 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4493 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4494 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4498 var ms = best_candidate as MethodSpec;
4499 if (ms != null && ms.IsGeneric) {
4500 bool constr_ok = true;
4501 if (ms.TypeArguments != null)
4502 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4504 if (ta_count == 0) {
4505 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4509 rc.Report.Error (411, loc,
4510 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4511 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4518 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4524 // We failed to find any method with correct argument count, report best candidate
4526 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4529 if (best_candidate.Kind == MemberKind.Constructor) {
4530 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4531 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4532 } else if (IsDelegateInvoke) {
4533 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4534 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4535 DelegateType.GetSignatureForError (), arg_count.ToString ());
4537 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4538 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4539 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4540 name, arg_count.ToString ());
4544 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4546 var pd = pm.Parameters;
4547 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4549 Parameter.Modifier p_mod = 0;
4551 int a_idx = 0, a_pos = 0;
4553 ArrayInitializer params_initializers = null;
4554 bool has_unsafe_arg = pm.MemberType.IsPointer;
4555 int arg_count = args == null ? 0 : args.Count;
4557 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4559 if (p_mod != Parameter.Modifier.PARAMS) {
4560 p_mod = pd.FixedParameters[a_idx].ModFlags;
4562 has_unsafe_arg |= pt.IsPointer;
4564 if (p_mod == Parameter.Modifier.PARAMS) {
4565 if (chose_params_expanded) {
4566 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4567 pt = TypeManager.GetElementType (pt);
4573 // Types have to be identical when ref or out modifer is used
4575 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4576 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4579 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4585 NamedArgument na = a as NamedArgument;
4587 int name_index = pd.GetParameterIndexByName (na.Name);
4588 if (name_index < 0 || name_index >= pd.Count) {
4589 if (IsDelegateInvoke) {
4590 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4591 ec.Report.Error (1746, na.Location,
4592 "The delegate `{0}' does not contain a parameter named `{1}'",
4593 DelegateType.GetSignatureForError (), na.Name);
4595 ec.Report.SymbolRelatedToPreviousError (member);
4596 ec.Report.Error (1739, na.Location,
4597 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4598 TypeManager.CSharpSignature (member), na.Name);
4600 } else if (args[name_index] != a) {
4601 if (IsDelegateInvoke)
4602 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4604 ec.Report.SymbolRelatedToPreviousError (member);
4606 ec.Report.Error (1744, na.Location,
4607 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4612 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4615 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4616 custom_errors.NoArgumentMatch (ec, member);
4620 Expression conv = null;
4621 if (a.ArgType == Argument.AType.ExtensionType) {
4622 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4625 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4627 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4630 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4637 // Convert params arguments to an array initializer
4639 if (params_initializers != null) {
4640 // we choose to use 'a.Expr' rather than 'conv' so that
4641 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4642 params_initializers.Add (a.Expr);
4643 args.RemoveAt (a_idx--);
4648 // Update the argument with the implicit conversion
4652 if (a_idx != arg_count) {
4653 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4658 // Fill not provided arguments required by params modifier
4660 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4662 args = new Arguments (1);
4664 pt = ptypes[pd.Count - 1];
4665 pt = TypeManager.GetElementType (pt);
4666 has_unsafe_arg |= pt.IsPointer;
4667 params_initializers = new ArrayInitializer (0, loc);
4671 // Append an array argument with all params arguments
4673 if (params_initializers != null) {
4674 args.Add (new Argument (
4675 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4679 if (has_unsafe_arg && !ec.IsUnsafe) {
4680 Expression.UnsafeError (ec, loc);
4684 // We could infer inaccesible type arguments
4686 if (type_arguments == null && member.IsGeneric) {
4687 var ms = (MethodSpec) member;
4688 foreach (var ta in ms.TypeArguments) {
4689 if (!ta.IsAccessible (ec)) {
4690 ec.Report.SymbolRelatedToPreviousError (ta);
4691 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4701 public class ConstantExpr : MemberExpr
4703 readonly ConstSpec constant;
4705 public ConstantExpr (ConstSpec constant, Location loc)
4707 this.constant = constant;
4711 public override string Name {
4712 get { throw new NotImplementedException (); }
4715 public override bool IsInstance {
4716 get { return !IsStatic; }
4719 public override bool IsStatic {
4720 get { return true; }
4723 protected override TypeSpec DeclaringType {
4724 get { return constant.DeclaringType; }
4727 public override Expression CreateExpressionTree (ResolveContext ec)
4729 throw new NotSupportedException ("ET");
4732 protected override Expression DoResolve (ResolveContext rc)
4734 ResolveInstanceExpression (rc, null);
4735 DoBestMemberChecks (rc, constant);
4737 var c = constant.GetConstant (rc);
4739 // Creates reference expression to the constant value
4740 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4743 public override void Emit (EmitContext ec)
4745 throw new NotSupportedException ();
4748 public override string GetSignatureForError ()
4750 return constant.GetSignatureForError ();
4753 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4755 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
4760 /// Fully resolved expression that evaluates to a Field
4762 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4763 protected FieldSpec spec;
4764 VariableInfo variable_info;
4766 LocalTemporary temp;
4769 protected FieldExpr (Location l)
4774 public FieldExpr (FieldSpec spec, Location loc)
4779 type = spec.MemberType;
4782 public FieldExpr (FieldBase fi, Location l)
4789 public override string Name {
4795 public bool IsHoisted {
4797 IVariableReference hv = InstanceExpression as IVariableReference;
4798 return hv != null && hv.IsHoisted;
4802 public override bool IsInstance {
4804 return !spec.IsStatic;
4808 public override bool IsStatic {
4810 return spec.IsStatic;
4814 public FieldSpec Spec {
4820 protected override TypeSpec DeclaringType {
4822 return spec.DeclaringType;
4826 public VariableInfo VariableInfo {
4828 return variable_info;
4834 public override string GetSignatureForError ()
4836 return TypeManager.GetFullNameSignature (spec);
4839 public bool IsMarshalByRefAccess (ResolveContext rc)
4841 // Checks possible ldflda of field access expression
4842 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
4843 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
4844 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
4847 public void SetHasAddressTaken ()
4849 IVariableReference vr = InstanceExpression as IVariableReference;
4851 vr.SetHasAddressTaken ();
4854 public override Expression CreateExpressionTree (ResolveContext ec)
4856 Expression instance;
4857 if (InstanceExpression == null) {
4858 instance = new NullLiteral (loc);
4860 instance = InstanceExpression.CreateExpressionTree (ec);
4863 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4865 CreateTypeOfExpression ());
4867 return CreateExpressionFactoryCall (ec, "Field", args);
4870 public Expression CreateTypeOfExpression ()
4872 return new TypeOfField (spec, loc);
4875 protected override Expression DoResolve (ResolveContext ec)
4877 return DoResolve (ec, null);
4880 Expression DoResolve (ResolveContext ec, Expression rhs)
4882 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4885 if (ResolveInstanceExpression (ec, rhs)) {
4886 // Resolve the field's instance expression while flow analysis is turned
4887 // off: when accessing a field "a.b", we must check whether the field
4888 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4890 if (lvalue_instance) {
4891 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4892 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
4894 Expression right_side =
4895 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4897 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4900 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4901 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4905 if (InstanceExpression == null)
4909 DoBestMemberChecks (ec, spec);
4912 var fb = spec as FixedFieldSpec;
4913 IVariableReference var = InstanceExpression as IVariableReference;
4915 if (lvalue_instance && var != null && var.VariableInfo != null) {
4916 var.VariableInfo.SetFieldAssigned (ec, Name);
4920 IFixedExpression fe = InstanceExpression as IFixedExpression;
4921 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4922 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4925 if (InstanceExpression.eclass != ExprClass.Variable) {
4926 ec.Report.SymbolRelatedToPreviousError (spec);
4927 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4928 TypeManager.GetFullNameSignature (spec));
4929 } else if (var != null && var.IsHoisted) {
4930 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4933 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4936 eclass = ExprClass.Variable;
4938 // If the instance expression is a local variable or parameter.
4939 if (var == null || var.VariableInfo == null)
4942 VariableInfo vi = var.VariableInfo;
4943 if (!vi.IsFieldAssigned (ec, Name, loc))
4946 variable_info = vi.GetSubStruct (Name);
4950 static readonly int [] codes = {
4951 191, // instance, write access
4952 192, // instance, out access
4953 198, // static, write access
4954 199, // static, out access
4955 1648, // member of value instance, write access
4956 1649, // member of value instance, out access
4957 1650, // member of value static, write access
4958 1651 // member of value static, out access
4961 static readonly string [] msgs = {
4962 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4963 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4964 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4965 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4966 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4967 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4968 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4969 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4972 // The return value is always null. Returning a value simplifies calling code.
4973 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4976 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4980 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4982 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4987 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4989 Expression e = DoResolve (ec, right_side);
4994 spec.MemberDefinition.SetIsAssigned ();
4996 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
4997 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4998 ec.Report.Warning (420, 1, loc,
4999 "`{0}': A volatile field references will not be treated as volatile",
5000 spec.GetSignatureForError ());
5003 if (spec.IsReadOnly) {
5004 // InitOnly fields can only be assigned in constructors or initializers
5005 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5006 return Report_AssignToReadonly (ec, right_side);
5008 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5010 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5011 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5012 return Report_AssignToReadonly (ec, right_side);
5013 // static InitOnly fields cannot be assigned-to in an instance constructor
5014 if (IsStatic && !ec.IsStatic)
5015 return Report_AssignToReadonly (ec, right_side);
5016 // instance constructors can't modify InitOnly fields of other instances of the same type
5017 if (!IsStatic && !(InstanceExpression is This))
5018 return Report_AssignToReadonly (ec, right_side);
5022 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5023 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5024 ec.Report.Warning (197, 1, loc,
5025 "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",
5026 GetSignatureForError ());
5029 eclass = ExprClass.Variable;
5033 public override int GetHashCode ()
5035 return spec.GetHashCode ();
5038 public bool IsFixed {
5041 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5043 IVariableReference variable = InstanceExpression as IVariableReference;
5044 if (variable != null)
5045 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5047 IFixedExpression fe = InstanceExpression as IFixedExpression;
5048 return fe != null && fe.IsFixed;
5052 public override bool Equals (object obj)
5054 FieldExpr fe = obj as FieldExpr;
5058 if (spec != fe.spec)
5061 if (InstanceExpression == null || fe.InstanceExpression == null)
5064 return InstanceExpression.Equals (fe.InstanceExpression);
5067 public void Emit (EmitContext ec, bool leave_copy)
5069 bool is_volatile = false;
5071 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5074 spec.MemberDefinition.SetIsUsed ();
5078 ec.Emit (OpCodes.Volatile);
5080 ec.Emit (OpCodes.Ldsfld, spec);
5083 EmitInstance (ec, false);
5085 // Optimization for build-in types
5086 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5087 ec.EmitLoadFromPtr (type);
5089 var ff = spec as FixedFieldSpec;
5091 ec.Emit (OpCodes.Ldflda, spec);
5092 ec.Emit (OpCodes.Ldflda, ff.Element);
5095 ec.Emit (OpCodes.Volatile);
5097 ec.Emit (OpCodes.Ldfld, spec);
5103 ec.Emit (OpCodes.Dup);
5105 temp = new LocalTemporary (this.Type);
5111 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5113 var await_expr = source as Await;
5114 if (await_expr != null) {
5116 // Await is not ordinary expression (it contains jump), hence the usual flow cannot be used
5117 // to emit instance load before expression
5119 await_expr.EmitAssign (ec, this);
5121 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5123 EmitInstance (ec, prepared);
5129 ec.Emit (OpCodes.Dup);
5131 temp = new LocalTemporary (this.Type);
5136 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5137 ec.Emit (OpCodes.Volatile);
5139 spec.MemberDefinition.SetIsAssigned ();
5142 ec.Emit (OpCodes.Stsfld, spec);
5144 ec.Emit (OpCodes.Stfld, spec);
5153 public override void Emit (EmitContext ec)
5158 public override void EmitSideEffect (EmitContext ec)
5160 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5162 if (is_volatile) // || is_marshal_by_ref ())
5163 base.EmitSideEffect (ec);
5166 public void AddressOf (EmitContext ec, AddressOp mode)
5168 if ((mode & AddressOp.Store) != 0)
5169 spec.MemberDefinition.SetIsAssigned ();
5170 if ((mode & AddressOp.Load) != 0)
5171 spec.MemberDefinition.SetIsUsed ();
5174 // Handle initonly fields specially: make a copy and then
5175 // get the address of the copy.
5178 if (spec.IsReadOnly){
5180 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5192 var temp = ec.GetTemporaryLocal (type);
5193 ec.Emit (OpCodes.Stloc, temp, type);
5194 ec.Emit (OpCodes.Ldloca, temp, type);
5195 ec.FreeTemporaryLocal (temp, type);
5201 ec.Emit (OpCodes.Ldsflda, spec);
5204 EmitInstance (ec, false);
5205 ec.Emit (OpCodes.Ldflda, spec);
5209 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5211 return MakeExpression (ctx);
5214 public override SLE.Expression MakeExpression (BuilderContext ctx)
5217 return base.MakeExpression (ctx);
5219 return SLE.Expression.Field (
5220 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5221 spec.GetMetaInfo ());
5225 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5227 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5233 /// Expression that evaluates to a Property. The Assign class
5234 /// might set the `Value' expression if we are in an assignment.
5236 /// This is not an LValue because we need to re-write the expression, we
5237 /// can not take data from the stack and store it.
5239 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5241 public PropertyExpr (PropertySpec spec, Location l)
5244 best_candidate = spec;
5245 type = spec.MemberType;
5250 protected override TypeSpec DeclaringType {
5252 return best_candidate.DeclaringType;
5256 public override string Name {
5258 return best_candidate.Name;
5262 public override bool IsInstance {
5268 public override bool IsStatic {
5270 return best_candidate.IsStatic;
5274 public PropertySpec PropertyInfo {
5276 return best_candidate;
5282 public override Expression CreateExpressionTree (ResolveContext ec)
5285 if (IsSingleDimensionalArrayLength ()) {
5286 args = new Arguments (1);
5287 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5288 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5291 args = new Arguments (2);
5292 if (InstanceExpression == null)
5293 args.Add (new Argument (new NullLiteral (loc)));
5295 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5296 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5297 return CreateExpressionFactoryCall (ec, "Property", args);
5300 public Expression CreateSetterTypeOfExpression ()
5302 return new TypeOfMethod (Setter, loc);
5305 public override string GetSignatureForError ()
5307 return best_candidate.GetSignatureForError ();
5310 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5313 return base.MakeExpression (ctx);
5315 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5319 public override SLE.Expression MakeExpression (BuilderContext ctx)
5322 return base.MakeExpression (ctx);
5324 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5328 void Error_PropertyNotValid (ResolveContext ec)
5330 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5331 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5332 GetSignatureForError ());
5335 bool IsSingleDimensionalArrayLength ()
5337 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5340 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5341 return ac != null && ac.Rank == 1;
5344 public override void Emit (EmitContext ec, bool leave_copy)
5347 // Special case: length of single dimension array property is turned into ldlen
5349 if (IsSingleDimensionalArrayLength ()) {
5351 EmitInstance (ec, false);
5352 ec.Emit (OpCodes.Ldlen);
5353 ec.Emit (OpCodes.Conv_I4);
5357 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5360 ec.Emit (OpCodes.Dup);
5362 temp = new LocalTemporary (this.Type);
5368 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5372 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5373 args = new Arguments (0);
5378 ec.Emit (OpCodes.Dup);
5380 temp = new LocalTemporary (this.Type);
5385 args = new Arguments (1);
5389 temp = new LocalTemporary (this.Type);
5391 args.Add (new Argument (temp));
5393 args.Add (new Argument (source));
5397 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5405 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5407 eclass = ExprClass.PropertyAccess;
5409 if (best_candidate.IsNotCSharpCompatible) {
5410 Error_PropertyNotValid (rc);
5413 ResolveInstanceExpression (rc, right_side);
5415 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5416 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5417 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5419 type = p.MemberType;
5423 DoBestMemberChecks (rc, best_candidate);
5427 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5429 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5433 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5435 // getter and setter can be different for base calls
5436 MethodSpec getter, setter;
5437 protected T best_candidate;
5439 protected LocalTemporary temp;
5440 protected bool prepared;
5442 protected PropertyOrIndexerExpr (Location l)
5449 public MethodSpec Getter {
5458 public MethodSpec Setter {
5469 protected override Expression DoResolve (ResolveContext ec)
5471 if (eclass == ExprClass.Unresolved) {
5472 var expr = OverloadResolve (ec, null);
5477 return expr.Resolve (ec);
5480 if (!ResolveGetter (ec))
5486 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5488 if (right_side == EmptyExpression.OutAccess) {
5489 // TODO: best_candidate can be null at this point
5490 INamedBlockVariable variable = null;
5491 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5492 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5493 best_candidate.Name);
5495 right_side.DoResolveLValue (ec, this);
5500 // if the property/indexer returns a value type, and we try to set a field in it
5501 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5502 Error_CannotModifyIntermediateExpressionValue (ec);
5505 if (eclass == ExprClass.Unresolved) {
5506 var expr = OverloadResolve (ec, right_side);
5511 return expr.ResolveLValue (ec, right_side);
5514 if (!ResolveSetter (ec))
5521 // Implements the IAssignMethod interface for assignments
5523 public abstract void Emit (EmitContext ec, bool leave_copy);
5524 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5526 public override void Emit (EmitContext ec)
5531 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5533 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5535 bool ResolveGetter (ResolveContext rc)
5537 if (!best_candidate.HasGet) {
5538 if (InstanceExpression != EmptyExpression.Null) {
5539 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5540 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5541 best_candidate.GetSignatureForError ());
5544 } else if (!best_candidate.Get.IsAccessible (rc)) {
5545 if (best_candidate.HasDifferentAccessibility) {
5546 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5547 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5548 TypeManager.CSharpSignature (best_candidate));
5550 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5551 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5555 if (best_candidate.HasDifferentAccessibility) {
5556 CheckProtectedMemberAccess (rc, best_candidate.Get);
5559 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5563 bool ResolveSetter (ResolveContext rc)
5565 if (!best_candidate.HasSet) {
5566 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5567 GetSignatureForError ());
5571 if (!best_candidate.Set.IsAccessible (rc)) {
5572 if (best_candidate.HasDifferentAccessibility) {
5573 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5574 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5575 GetSignatureForError ());
5577 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5578 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5582 if (best_candidate.HasDifferentAccessibility)
5583 CheckProtectedMemberAccess (rc, best_candidate.Set);
5585 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5591 /// Fully resolved expression that evaluates to an Event
5593 public class EventExpr : MemberExpr, IAssignMethod
5595 readonly EventSpec spec;
5598 public EventExpr (EventSpec spec, Location loc)
5606 protected override TypeSpec DeclaringType {
5608 return spec.DeclaringType;
5612 public override string Name {
5618 public override bool IsInstance {
5620 return !spec.IsStatic;
5624 public override bool IsStatic {
5626 return spec.IsStatic;
5630 public MethodSpec Operator {
5638 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5641 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5643 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5644 if (spec.BackingField != null &&
5645 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5647 spec.MemberDefinition.SetIsUsed ();
5649 if (!ec.IsObsolete) {
5650 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5652 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5655 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5656 Error_AssignmentEventOnly (ec);
5658 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5660 InstanceExpression = null;
5662 return ml.ResolveMemberAccess (ec, left, original);
5666 return base.ResolveMemberAccess (ec, left, original);
5669 public override Expression CreateExpressionTree (ResolveContext ec)
5671 throw new NotSupportedException ("ET");
5674 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5676 if (right_side == EmptyExpression.EventAddition) {
5677 op = spec.AccessorAdd;
5678 } else if (right_side == EmptyExpression.EventSubtraction) {
5679 op = spec.AccessorRemove;
5683 Error_AssignmentEventOnly (ec);
5687 op = CandidateToBaseOverride (ec, op);
5691 protected override Expression DoResolve (ResolveContext ec)
5693 eclass = ExprClass.EventAccess;
5694 type = spec.MemberType;
5696 ResolveInstanceExpression (ec, null);
5698 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5699 Error_AssignmentEventOnly (ec);
5702 DoBestMemberChecks (ec, spec);
5706 public override void Emit (EmitContext ec)
5708 throw new NotSupportedException ();
5709 //Error_CannotAssign ();
5712 #region IAssignMethod Members
5714 public void Emit (EmitContext ec, bool leave_copy)
5716 throw new NotImplementedException ();
5719 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5721 if (leave_copy || !prepare_for_load)
5722 throw new NotImplementedException ("EventExpr::EmitAssign");
5724 Arguments args = new Arguments (1);
5725 args.Add (new Argument (source));
5726 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5731 void Error_AssignmentEventOnly (ResolveContext ec)
5733 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5734 ec.Report.Error (79, loc,
5735 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5736 GetSignatureForError ());
5738 ec.Report.Error (70, loc,
5739 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5740 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5744 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5746 name = name.Substring (0, name.LastIndexOf ('.'));
5747 base.Error_CannotCallAbstractBase (rc, name);
5750 public override string GetSignatureForError ()
5752 return TypeManager.CSharpSignature (spec);
5755 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5757 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
5761 public class TemporaryVariableReference : VariableReference
5763 public class Declarator : Statement
5765 TemporaryVariableReference variable;
5767 public Declarator (TemporaryVariableReference variable)
5769 this.variable = variable;
5773 protected override void DoEmit (EmitContext ec)
5775 variable.li.CreateBuilder (ec);
5778 protected override void CloneTo (CloneContext clonectx, Statement target)
5786 public TemporaryVariableReference (LocalVariable li, Location loc)
5789 this.type = li.Type;
5793 public override bool IsLockedByStatement {
5801 public LocalVariable LocalInfo {
5807 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5809 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5810 return new TemporaryVariableReference (li, loc);
5813 public override Expression CreateExpressionTree (ResolveContext ec)
5815 throw new NotSupportedException ("ET");
5818 protected override Expression DoResolve (ResolveContext ec)
5820 eclass = ExprClass.Variable;
5823 // Don't capture temporary variables except when using
5824 // iterator redirection
5826 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5827 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5828 storey.CaptureLocalVariable (ec, li);
5834 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5836 return Resolve (ec);
5839 public override void Emit (EmitContext ec)
5841 li.CreateBuilder (ec);
5846 public void EmitAssign (EmitContext ec, Expression source)
5848 li.CreateBuilder (ec);
5850 EmitAssign (ec, source, false, false);
5853 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5855 return li.HoistedVariant;
5858 public override bool IsFixed {
5859 get { return true; }
5862 public override bool IsRef {
5863 get { return false; }
5866 public override string Name {
5867 get { throw new NotImplementedException (); }
5870 public override void SetHasAddressTaken ()
5872 throw new NotImplementedException ();
5875 protected override ILocalVariable Variable {
5879 public override VariableInfo VariableInfo {
5880 get { throw new NotImplementedException (); }
5885 /// Handles `var' contextual keyword; var becomes a keyword only
5886 /// if no type called var exists in a variable scope
5888 class VarExpr : SimpleName
5890 public VarExpr (Location loc)
5895 public bool InferType (ResolveContext ec, Expression right_side)
5898 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5900 type = right_side.Type;
5901 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5902 ec.Report.Error (815, loc,
5903 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5904 type.GetSignatureForError ());
5908 eclass = ExprClass.Variable;
5912 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5914 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5915 base.Error_TypeOrNamespaceNotFound (ec);
5917 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");