2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Returns true when the expression during Emit phase breaks stack
157 // by using await expression
159 public virtual bool ContainsEmitWithAwait ()
165 /// Performs semantic analysis on the Expression
169 /// The Resolve method is invoked to perform the semantic analysis
172 /// The return value is an expression (it can be the
173 /// same expression in some cases) or a new
174 /// expression that better represents this node.
176 /// For example, optimizations of Unary (LiteralInt)
177 /// would return a new LiteralInt with a negated
180 /// If there is an error during semantic analysis,
181 /// then an error should be reported (using Report)
182 /// and a null value should be returned.
184 /// There are two side effects expected from calling
185 /// Resolve(): the the field variable "eclass" should
186 /// be set to any value of the enumeration
187 /// `ExprClass' and the type variable should be set
188 /// to a valid type (this is the type of the
191 protected abstract Expression DoResolve (ResolveContext rc);
193 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
199 // This is used if the expression should be resolved as a type or namespace name.
200 // the default implementation fails.
202 public virtual TypeSpec ResolveAsType (IMemberContext mc)
204 ResolveContext ec = new ResolveContext (mc);
205 Expression e = Resolve (ec);
207 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
212 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
214 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
217 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
219 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
222 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
224 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
225 name, TypeManager.CSharpName (type));
228 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
230 Report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
233 public void Error_InvalidExpressionStatement (BlockContext ec)
235 Error_InvalidExpressionStatement (ec.Report, loc);
238 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
240 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
243 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
245 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
248 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
250 // The error was already reported as CS1660
251 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
254 string from_type = type.GetSignatureForError ();
255 string to_type = target.GetSignatureForError ();
256 if (from_type == to_type) {
257 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
258 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
262 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
267 ec.Report.DisableReporting ();
268 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
269 ec.Report.EnableReporting ();
272 ec.Report.Error (266, loc,
273 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
276 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
281 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
283 // Better message for possible generic expressions
284 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
285 var report = context.Module.Compiler.Report;
286 report.SymbolRelatedToPreviousError (member);
287 if (member is TypeSpec)
288 member = ((TypeSpec) member).GetDefinition ();
290 member = ((MethodSpec) member).GetGenericMethodDefinition ();
292 string name = member.Kind == MemberKind.Method ? "method" : "type";
293 if (member.IsGeneric) {
294 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
295 name, member.GetSignatureForError (), member.Arity.ToString ());
297 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
298 name, member.GetSignatureForError ());
301 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
305 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
307 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
311 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
313 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
316 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
318 ec.Report.SymbolRelatedToPreviousError (type);
319 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
320 TypeManager.CSharpName (type), name);
323 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
325 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
326 // Already reported as CS1612
328 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
332 protected void Error_VoidPointerOperation (ResolveContext rc)
334 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
337 public ResolveFlags ExprClassToResolveFlags {
341 case ExprClass.Namespace:
342 return ResolveFlags.Type;
344 case ExprClass.MethodGroup:
345 return ResolveFlags.MethodGroup;
347 case ExprClass.TypeParameter:
348 return ResolveFlags.TypeParameter;
350 case ExprClass.Value:
351 case ExprClass.Variable:
352 case ExprClass.PropertyAccess:
353 case ExprClass.EventAccess:
354 case ExprClass.IndexerAccess:
355 return ResolveFlags.VariableOrValue;
358 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
363 public virtual string GetSignatureForError ()
365 return type.GetDefinition ().GetSignatureForError ();
369 /// Resolves an expression and performs semantic analysis on it.
373 /// Currently Resolve wraps DoResolve to perform sanity
374 /// checking and assertion checking on what we expect from Resolve.
376 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
378 if (eclass != ExprClass.Unresolved)
388 if ((flags & e.ExprClassToResolveFlags) == 0) {
389 e.Error_UnexpectedKind (ec, flags, loc);
394 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
397 } catch (Exception ex) {
398 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
401 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
402 return ErrorExpression.Instance; // TODO: Add location
407 /// Resolves an expression and performs semantic analysis on it.
409 public Expression Resolve (ResolveContext rc)
411 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
415 /// Resolves an expression for LValue assignment
419 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
420 /// checking and assertion checking on what we expect from Resolve
422 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
424 int errors = ec.Report.Errors;
425 bool out_access = right_side == EmptyExpression.OutAccess;
427 Expression e = DoResolveLValue (ec, right_side);
429 if (e != null && out_access && !(e is IMemoryLocation)) {
430 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
431 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
433 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
434 // e.GetType () + " " + e.GetSignatureForError ());
439 if (errors == ec.Report.Errors) {
441 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
443 Error_ValueAssignment (ec, right_side);
448 if (e.eclass == ExprClass.Unresolved)
449 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
451 if ((e.type == null) && !(e is GenericTypeExpr))
452 throw new Exception ("Expression " + e + " did not set its type after Resolve");
457 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
459 rc.Module.Compiler.Report.Error (182, loc,
460 "An attribute argument must be a constant expression, typeof expression or array creation expression");
464 /// Emits the code for the expression
468 /// The Emit method is invoked to generate the code
469 /// for the expression.
471 public abstract void Emit (EmitContext ec);
474 // Emit code to branch to @target if this expression is equivalent to @on_true.
475 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
476 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
477 // including the use of conditional branches. Note also that a branch MUST be emitted
478 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
481 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
484 // Emit this expression for its side effects, not for its value.
485 // The default implementation is to emit the value, and then throw it away.
486 // Subclasses can provide more efficient implementations, but those MUST be equivalent
487 public virtual void EmitSideEffect (EmitContext ec)
490 ec.Emit (OpCodes.Pop);
494 // Emits the expression into temporary field variable. The method
495 // should be used for await expressions only
497 public virtual Expression EmitToField (EmitContext ec)
500 // This is the await prepare Emit method. When emitting code like
501 // a + b we emit code like
507 // For await a + await b we have to interfere the flow to keep the
508 // stack clean because await yields from the expression. The emit
511 // a = a.EmitToField () // a is changed to temporary field access
512 // b = b.EmitToField ()
518 // The idea is to emit expression and leave the stack empty with
519 // result value still available.
521 // Expressions should override this default implementation when
522 // optimized version can be provided (e.g. FieldExpr)
525 // We can optimize for side-effect free expressions, they can be
526 // emitted out of order
528 if (IsSideEffectFree)
531 bool needs_temporary = ContainsEmitWithAwait ();
532 if (!needs_temporary)
535 // Emit original code
536 var field = EmitToFieldSource (ec);
539 // Store the result to temporary field when we
540 // cannot load `this' directly
542 field = ec.GetTemporaryField (type);
543 if (needs_temporary) {
545 // Create temporary local (we cannot load `this' before Emit)
547 var temp = ec.GetTemporaryLocal (type);
548 ec.Emit (OpCodes.Stloc, temp);
551 ec.Emit (OpCodes.Ldloc, temp);
552 field.EmitAssignFromStack (ec);
554 ec.FreeTemporaryLocal (temp, type);
556 field.EmitAssignFromStack (ec);
563 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
566 // Default implementation calls Emit method
572 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
574 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
575 bool contains_await = false;
577 for (int i = 1; i < expressions.Count; ++i) {
578 if (expressions[i].ContainsEmitWithAwait ()) {
579 contains_await = true;
584 if (contains_await) {
585 for (int i = 0; i < expressions.Count; ++i) {
586 expressions[i] = expressions[i].EmitToField (ec);
591 for (int i = 0; i < expressions.Count; ++i) {
592 expressions[i].Emit (ec);
597 /// Protected constructor. Only derivate types should
598 /// be able to be created
601 protected Expression ()
606 /// Returns a fully formed expression after a MemberLookup
609 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
611 if (spec is EventSpec)
612 return new EventExpr ((EventSpec) spec, loc);
613 if (spec is ConstSpec)
614 return new ConstantExpr ((ConstSpec) spec, loc);
615 if (spec is FieldSpec)
616 return new FieldExpr ((FieldSpec) spec, loc);
617 if (spec is PropertySpec)
618 return new PropertyExpr ((PropertySpec) spec, loc);
619 if (spec is TypeSpec)
620 return new TypeExpression (((TypeSpec) spec), loc);
625 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
627 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
629 rc.Report.SymbolRelatedToPreviousError (type);
631 // Report meaningful error for struct as they always have default ctor in C# context
632 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
634 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
635 type.GetSignatureForError ());
641 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
642 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
643 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
646 return r.ResolveMember<MethodSpec> (rc, ref args);
650 public enum MemberLookupRestrictions
659 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
660 // `qualifier_type' or null to lookup members in the current class.
662 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
664 var members = MemberCache.FindMembers (queried_type, name, false);
668 MemberSpec non_method = null;
669 MemberSpec ambig_non_method = null;
671 for (int i = 0; i < members.Count; ++i) {
672 var member = members[i];
674 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
675 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
678 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
681 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
685 if (!member.IsAccessible (rc))
689 // With runtime binder we can have a situation where queried type is inaccessible
690 // because it came via dynamic object, the check about inconsisted accessibility
691 // had no effect as the type was unknown during compilation
694 // private class N { }
696 // public dynamic Foo ()
702 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
706 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
707 if (member is MethodSpec)
708 return new MethodGroupExpr (members, queried_type, loc);
710 if (!Invocation.IsMemberInvocable (member))
714 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
716 } else if (!errorMode && !member.IsNotCSharpCompatible) {
717 ambig_non_method = member;
721 if (non_method != null) {
722 if (ambig_non_method != null && rc != null) {
723 var report = rc.Module.Compiler.Report;
724 report.SymbolRelatedToPreviousError (non_method);
725 report.SymbolRelatedToPreviousError (ambig_non_method);
726 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
727 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
730 if (non_method is MethodSpec)
731 return new MethodGroupExpr (members, queried_type, loc);
733 return ExprClassFromMemberInfo (non_method, loc);
736 if (members[0].DeclaringType.BaseType == null)
739 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
741 } while (members != null);
746 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
748 throw new NotImplementedException ();
751 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
753 if (t == InternalType.ErrorType)
756 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
757 oper, t.GetSignatureForError ());
760 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
762 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
766 /// Returns an expression that can be used to invoke operator true
767 /// on the expression if it exists.
769 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
771 return GetOperatorTrueOrFalse (ec, e, true, loc);
775 /// Returns an expression that can be used to invoke operator false
776 /// on the expression if it exists.
778 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
780 return GetOperatorTrueOrFalse (ec, e, false, loc);
783 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
785 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
786 var methods = MemberCache.GetUserOperator (e.type, op, false);
790 Arguments arguments = new Arguments (1);
791 arguments.Add (new Argument (e));
793 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
794 var oper = res.ResolveOperator (ec, ref arguments);
799 return new UserOperatorCall (oper, arguments, null, loc);
802 public virtual string ExprClassName
806 case ExprClass.Unresolved:
808 case ExprClass.Value:
810 case ExprClass.Variable:
812 case ExprClass.Namespace:
816 case ExprClass.MethodGroup:
817 return "method group";
818 case ExprClass.PropertyAccess:
819 return "property access";
820 case ExprClass.EventAccess:
821 return "event access";
822 case ExprClass.IndexerAccess:
823 return "indexer access";
824 case ExprClass.Nothing:
826 case ExprClass.TypeParameter:
827 return "type parameter";
829 throw new Exception ("Should not happen");
834 /// Reports that we were expecting `expr' to be of class `expected'
836 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
838 var name = memberExpr.GetSignatureForError ();
840 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
843 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
845 string [] valid = new string [4];
848 if ((flags & ResolveFlags.VariableOrValue) != 0) {
849 valid [count++] = "variable";
850 valid [count++] = "value";
853 if ((flags & ResolveFlags.Type) != 0)
854 valid [count++] = "type";
856 if ((flags & ResolveFlags.MethodGroup) != 0)
857 valid [count++] = "method group";
860 valid [count++] = "unknown";
862 StringBuilder sb = new StringBuilder (valid [0]);
863 for (int i = 1; i < count - 1; i++) {
865 sb.Append (valid [i]);
868 sb.Append ("' or `");
869 sb.Append (valid [count - 1]);
872 ec.Report.Error (119, loc,
873 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
876 public static void UnsafeError (ResolveContext ec, Location loc)
878 UnsafeError (ec.Report, loc);
881 public static void UnsafeError (Report Report, Location loc)
883 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
887 // Converts `source' to an int, uint, long or ulong.
889 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
891 var btypes = ec.BuiltinTypes;
893 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
894 Arguments args = new Arguments (1);
895 args.Add (new Argument (source));
896 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
899 Expression converted;
901 using (ec.Set (ResolveContext.Options.CheckedScope)) {
902 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
903 if (converted == null)
904 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
905 if (converted == null)
906 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
907 if (converted == null)
908 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
910 if (converted == null) {
911 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
917 // Only positive constants are allowed at compile time
919 Constant c = converted as Constant;
920 if (c != null && c.IsNegative)
921 Error_NegativeArrayIndex (ec, source.loc);
923 // No conversion needed to array index
924 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
927 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
931 // Derived classes implement this method by cloning the fields that
932 // could become altered during the Resolve stage
934 // Only expressions that are created for the parser need to implement
937 protected virtual void CloneTo (CloneContext clonectx, Expression target)
939 throw new NotImplementedException (
941 "CloneTo not implemented for expression {0}", this.GetType ()));
945 // Clones an expression created by the parser.
947 // We only support expressions created by the parser so far, not
948 // expressions that have been resolved (many more classes would need
949 // to implement CloneTo).
951 // This infrastructure is here merely for Lambda expressions which
952 // compile the same code using different type values for the same
953 // arguments to find the correct overload
955 public virtual Expression Clone (CloneContext clonectx)
957 Expression cloned = (Expression) MemberwiseClone ();
958 CloneTo (clonectx, cloned);
964 // Implementation of expression to expression tree conversion
966 public abstract Expression CreateExpressionTree (ResolveContext ec);
968 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
970 return CreateExpressionFactoryCall (ec, name, null, args, loc);
973 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
975 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
978 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
980 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
983 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
985 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
989 return new TypeExpression (t, loc);
993 // Implemented by all expressions which support conversion from
994 // compiler expression to invokable runtime expression. Used by
995 // dynamic C# binder.
997 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
999 throw new NotImplementedException ("MakeExpression for " + GetType ());
1002 public virtual object Accept (StructuralVisitor visitor)
1004 return visitor.Visit (this);
1009 /// This is just a base class for expressions that can
1010 /// appear on statements (invocations, object creation,
1011 /// assignments, post/pre increment and decrement). The idea
1012 /// being that they would support an extra Emition interface that
1013 /// does not leave a result on the stack.
1015 public abstract class ExpressionStatement : Expression {
1017 public ExpressionStatement ResolveStatement (BlockContext ec)
1019 Expression e = Resolve (ec);
1023 ExpressionStatement es = e as ExpressionStatement;
1025 Error_InvalidExpressionStatement (ec);
1027 if (!(e is Assign) && (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
1028 WarningAsyncWithoutWait (ec, e);
1034 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1036 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1037 bc.Report.Warning (4014, 1, e.Location,
1038 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1042 var inv = e as Invocation;
1043 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1044 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1045 bc.Report.Warning (4014, 1, e.Location,
1046 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1052 /// Requests the expression to be emitted in a `statement'
1053 /// context. This means that no new value is left on the
1054 /// stack after invoking this method (constrasted with
1055 /// Emit that will always leave a value on the stack).
1057 public abstract void EmitStatement (EmitContext ec);
1059 public override void EmitSideEffect (EmitContext ec)
1066 /// This kind of cast is used to encapsulate the child
1067 /// whose type is child.Type into an expression that is
1068 /// reported to return "return_type". This is used to encapsulate
1069 /// expressions which have compatible types, but need to be dealt
1070 /// at higher levels with.
1072 /// For example, a "byte" expression could be encapsulated in one
1073 /// of these as an "unsigned int". The type for the expression
1074 /// would be "unsigned int".
1077 public abstract class TypeCast : Expression
1079 protected readonly Expression child;
1081 protected TypeCast (Expression child, TypeSpec return_type)
1083 eclass = child.eclass;
1084 loc = child.Location;
1089 public Expression Child {
1095 public override bool ContainsEmitWithAwait ()
1097 return child.ContainsEmitWithAwait ();
1100 public override Expression CreateExpressionTree (ResolveContext ec)
1102 Arguments args = new Arguments (2);
1103 args.Add (new Argument (child.CreateExpressionTree (ec)));
1104 args.Add (new Argument (new TypeOf (type, loc)));
1106 if (type.IsPointer || child.Type.IsPointer)
1107 Error_PointerInsideExpressionTree (ec);
1109 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1112 protected override Expression DoResolve (ResolveContext ec)
1114 // This should never be invoked, we are born in fully
1115 // initialized state.
1120 public override void Emit (EmitContext ec)
1125 public override SLE.Expression MakeExpression (BuilderContext ctx)
1128 return base.MakeExpression (ctx);
1130 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1131 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1132 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1136 protected override void CloneTo (CloneContext clonectx, Expression t)
1141 public override bool IsNull {
1142 get { return child.IsNull; }
1146 public class EmptyCast : TypeCast {
1147 EmptyCast (Expression child, TypeSpec target_type)
1148 : base (child, target_type)
1152 public static Expression Create (Expression child, TypeSpec type)
1154 Constant c = child as Constant;
1156 return new EmptyConstantCast (c, type);
1158 EmptyCast e = child as EmptyCast;
1160 return new EmptyCast (e.child, type);
1162 return new EmptyCast (child, type);
1165 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1167 child.EmitBranchable (ec, label, on_true);
1170 public override void EmitSideEffect (EmitContext ec)
1172 child.EmitSideEffect (ec);
1177 // Used for predefined type user operator (no obsolete check, etc.)
1179 public class OperatorCast : TypeCast
1181 readonly MethodSpec conversion_operator;
1183 public OperatorCast (Expression expr, TypeSpec target_type)
1184 : this (expr, target_type, target_type, false)
1188 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1189 : this (expr, target_type, target_type, find_explicit)
1193 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1194 : base (expr, returnType)
1196 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1197 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1200 foreach (MethodSpec oper in mi) {
1201 if (oper.ReturnType != returnType)
1204 if (oper.Parameters.Types[0] == expr.Type) {
1205 conversion_operator = oper;
1211 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1212 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1215 public override void Emit (EmitContext ec)
1218 ec.Emit (OpCodes.Call, conversion_operator);
1223 // Constant specialization of EmptyCast.
1224 // We need to special case this since an empty cast of
1225 // a constant is still a constant.
1227 public class EmptyConstantCast : Constant
1229 public readonly Constant child;
1231 public EmptyConstantCast (Constant child, TypeSpec type)
1232 : base (child.Location)
1235 throw new ArgumentNullException ("child");
1238 this.eclass = child.eclass;
1242 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1244 if (child.Type == target_type)
1247 // FIXME: check that 'type' can be converted to 'target_type' first
1248 return child.ConvertExplicitly (in_checked_context, target_type);
1251 public override Expression CreateExpressionTree (ResolveContext ec)
1253 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1254 child.CreateExpressionTree (ec),
1255 new TypeOf (type, loc));
1258 Error_PointerInsideExpressionTree (ec);
1260 return CreateExpressionFactoryCall (ec, "Convert", args);
1263 public override bool IsDefaultValue {
1264 get { return child.IsDefaultValue; }
1267 public override bool IsNegative {
1268 get { return child.IsNegative; }
1271 public override bool IsNull {
1272 get { return child.IsNull; }
1275 public override bool IsOneInteger {
1276 get { return child.IsOneInteger; }
1279 public override bool IsSideEffectFree {
1281 return child.IsSideEffectFree;
1285 public override bool IsZeroInteger {
1286 get { return child.IsZeroInteger; }
1289 public override void Emit (EmitContext ec)
1294 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1296 child.EmitBranchable (ec, label, on_true);
1298 // Only to make verifier happy
1299 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1300 ec.Emit (OpCodes.Unbox_Any, type);
1303 public override void EmitSideEffect (EmitContext ec)
1305 child.EmitSideEffect (ec);
1308 public override object GetValue ()
1310 return child.GetValue ();
1313 public override string GetValueAsLiteral ()
1315 return child.GetValueAsLiteral ();
1318 public override long GetValueAsLong ()
1320 return child.GetValueAsLong ();
1323 public override Constant ConvertImplicitly (TypeSpec target_type)
1325 if (type == target_type)
1328 // FIXME: Do we need to check user conversions?
1329 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1332 return child.ConvertImplicitly (target_type);
1337 /// This class is used to wrap literals which belong inside Enums
1339 public class EnumConstant : Constant
1341 public Constant Child;
1343 public EnumConstant (Constant child, TypeSpec enum_type)
1344 : base (child.Location)
1348 this.eclass = ExprClass.Value;
1349 this.type = enum_type;
1352 protected EnumConstant (Location loc)
1357 public override void Emit (EmitContext ec)
1362 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1364 Child.EncodeAttributeValue (rc, enc, Child.Type);
1367 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1369 Child.EmitBranchable (ec, label, on_true);
1372 public override void EmitSideEffect (EmitContext ec)
1374 Child.EmitSideEffect (ec);
1377 public override string GetSignatureForError()
1379 return TypeManager.CSharpName (Type);
1382 public override object GetValue ()
1384 return Child.GetValue ();
1388 public override object GetTypedValue ()
1391 // The method can be used in dynamic context only (on closed types)
1393 // System.Enum.ToObject cannot be called on dynamic types
1394 // EnumBuilder has to be used, but we cannot use EnumBuilder
1395 // because it does not properly support generics
1397 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1401 public override string GetValueAsLiteral ()
1403 return Child.GetValueAsLiteral ();
1406 public override long GetValueAsLong ()
1408 return Child.GetValueAsLong ();
1411 public EnumConstant Increment()
1413 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1416 public override bool IsDefaultValue {
1418 return Child.IsDefaultValue;
1422 public override bool IsSideEffectFree {
1424 return Child.IsSideEffectFree;
1428 public override bool IsZeroInteger {
1429 get { return Child.IsZeroInteger; }
1432 public override bool IsNegative {
1434 return Child.IsNegative;
1438 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1440 if (Child.Type == target_type)
1443 return Child.ConvertExplicitly (in_checked_context, target_type);
1446 public override Constant ConvertImplicitly (TypeSpec type)
1448 if (this.type == type) {
1452 if (!Convert.ImplicitStandardConversionExists (this, type)){
1456 return Child.ConvertImplicitly (type);
1461 /// This kind of cast is used to encapsulate Value Types in objects.
1463 /// The effect of it is to box the value type emitted by the previous
1466 public class BoxedCast : TypeCast {
1468 public BoxedCast (Expression expr, TypeSpec target_type)
1469 : base (expr, target_type)
1471 eclass = ExprClass.Value;
1474 protected override Expression DoResolve (ResolveContext ec)
1476 // This should never be invoked, we are born in fully
1477 // initialized state.
1482 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1484 // Only boxing to object type is supported
1485 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1486 base.EncodeAttributeValue (rc, enc, targetType);
1490 enc.Encode (child.Type);
1491 child.EncodeAttributeValue (rc, enc, child.Type);
1494 public override void Emit (EmitContext ec)
1498 ec.Emit (OpCodes.Box, child.Type);
1501 public override void EmitSideEffect (EmitContext ec)
1503 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1504 // so, we need to emit the box+pop instructions in most cases
1505 if (child.Type.IsStruct &&
1506 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1507 child.EmitSideEffect (ec);
1509 base.EmitSideEffect (ec);
1513 public class UnboxCast : TypeCast {
1514 public UnboxCast (Expression expr, TypeSpec return_type)
1515 : base (expr, return_type)
1519 protected override Expression DoResolve (ResolveContext ec)
1521 // This should never be invoked, we are born in fully
1522 // initialized state.
1527 public override void Emit (EmitContext ec)
1531 ec.Emit (OpCodes.Unbox_Any, type);
1536 /// This is used to perform explicit numeric conversions.
1538 /// Explicit numeric conversions might trigger exceptions in a checked
1539 /// context, so they should generate the conv.ovf opcodes instead of
1542 public class ConvCast : TypeCast {
1543 public enum Mode : byte {
1544 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1546 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1547 U2_I1, U2_U1, U2_I2, U2_CH,
1548 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1549 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1550 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1551 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1552 CH_I1, CH_U1, CH_I2,
1553 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1554 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1560 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1561 : base (child, return_type)
1566 protected override Expression DoResolve (ResolveContext ec)
1568 // This should never be invoked, we are born in fully
1569 // initialized state.
1574 public override string ToString ()
1576 return String.Format ("ConvCast ({0}, {1})", mode, child);
1579 public override void Emit (EmitContext ec)
1583 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1585 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1586 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1587 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1588 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1589 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1592 case Mode.U1_CH: /* nothing */ break;
1594 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1595 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1596 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1598 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1599 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1601 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1602 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1603 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1604 case Mode.U2_CH: /* nothing */ break;
1606 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1607 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1608 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1609 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1610 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1611 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1612 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1614 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1615 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1616 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1617 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1618 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1619 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1621 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1622 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1623 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1624 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1626 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1627 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1628 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1629 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1631 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1632 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1633 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1634 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1635 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1636 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1637 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1638 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1639 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1641 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1642 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1643 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1645 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1646 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1647 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1648 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1649 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1650 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1651 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1652 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1653 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1655 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1656 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1657 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1658 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1659 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1660 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1661 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1662 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1663 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1664 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1666 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1670 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1671 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1673 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1674 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1677 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1679 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1680 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1681 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1683 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1684 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1687 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1688 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1689 case Mode.U2_CH: /* nothing */ break;
1691 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1692 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1693 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1694 case Mode.I4_U4: /* nothing */ break;
1695 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1696 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1697 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1699 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1700 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1701 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1702 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1703 case Mode.U4_I4: /* nothing */ break;
1704 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1707 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1708 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1709 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1710 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1711 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1712 case Mode.I8_U8: /* nothing */ break;
1713 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1714 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1716 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1717 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1718 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1719 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1720 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1721 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1722 case Mode.U8_I8: /* nothing */ break;
1723 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1724 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1726 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1727 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1728 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1730 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1731 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1732 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1733 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1734 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1735 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1736 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1737 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1738 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1740 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1741 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1742 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1743 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1744 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1745 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1746 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1747 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1748 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1749 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1751 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1757 class OpcodeCast : TypeCast
1761 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1762 : base (child, return_type)
1767 protected override Expression DoResolve (ResolveContext ec)
1769 // This should never be invoked, we are born in fully
1770 // initialized state.
1775 public override void Emit (EmitContext ec)
1781 public TypeSpec UnderlyingType {
1782 get { return child.Type; }
1787 // Opcode casts expression with 2 opcodes but only
1788 // single expression tree node
1790 class OpcodeCastDuplex : OpcodeCast
1792 readonly OpCode second;
1794 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1795 : base (child, returnType, first)
1797 this.second = second;
1800 public override void Emit (EmitContext ec)
1808 /// This kind of cast is used to encapsulate a child and cast it
1809 /// to the class requested
1811 public sealed class ClassCast : TypeCast {
1812 readonly bool forced;
1814 public ClassCast (Expression child, TypeSpec return_type)
1815 : base (child, return_type)
1819 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1820 : base (child, return_type)
1822 this.forced = forced;
1825 public override void Emit (EmitContext ec)
1829 bool gen = TypeManager.IsGenericParameter (child.Type);
1831 ec.Emit (OpCodes.Box, child.Type);
1833 if (type.IsGenericParameter) {
1834 ec.Emit (OpCodes.Unbox_Any, type);
1841 ec.Emit (OpCodes.Castclass, type);
1846 // Created during resolving pahse when an expression is wrapped or constantified
1847 // and original expression can be used later (e.g. for expression trees)
1849 public class ReducedExpression : Expression
1851 sealed class ReducedConstantExpression : EmptyConstantCast
1853 readonly Expression orig_expr;
1855 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1856 : base (expr, expr.Type)
1858 this.orig_expr = orig_expr;
1861 public override Constant ConvertImplicitly (TypeSpec target_type)
1863 Constant c = base.ConvertImplicitly (target_type);
1865 c = new ReducedConstantExpression (c, orig_expr);
1870 public override Expression CreateExpressionTree (ResolveContext ec)
1872 return orig_expr.CreateExpressionTree (ec);
1875 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1877 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1879 c = new ReducedConstantExpression (c, orig_expr);
1883 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1886 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1888 if (orig_expr is Conditional)
1889 child.EncodeAttributeValue (rc, enc, targetType);
1891 base.EncodeAttributeValue (rc, enc, targetType);
1895 sealed class ReducedExpressionStatement : ExpressionStatement
1897 readonly Expression orig_expr;
1898 readonly ExpressionStatement stm;
1900 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1902 this.orig_expr = orig;
1904 this.eclass = stm.eclass;
1905 this.type = stm.Type;
1907 this.loc = orig.Location;
1910 public override bool ContainsEmitWithAwait ()
1912 return stm.ContainsEmitWithAwait ();
1915 public override Expression CreateExpressionTree (ResolveContext ec)
1917 return orig_expr.CreateExpressionTree (ec);
1920 protected override Expression DoResolve (ResolveContext ec)
1925 public override void Emit (EmitContext ec)
1930 public override void EmitStatement (EmitContext ec)
1932 stm.EmitStatement (ec);
1936 readonly Expression expr, orig_expr;
1938 private ReducedExpression (Expression expr, Expression orig_expr)
1941 this.eclass = expr.eclass;
1942 this.type = expr.Type;
1943 this.orig_expr = orig_expr;
1944 this.loc = orig_expr.Location;
1949 public override bool IsSideEffectFree {
1951 return expr.IsSideEffectFree;
1955 public Expression OriginalExpression {
1963 public override bool ContainsEmitWithAwait ()
1965 return expr.ContainsEmitWithAwait ();
1969 // Creates fully resolved expression switcher
1971 public static Constant Create (Constant expr, Expression original_expr)
1973 if (expr.eclass == ExprClass.Unresolved)
1974 throw new ArgumentException ("Unresolved expression");
1976 return new ReducedConstantExpression (expr, original_expr);
1979 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1981 return new ReducedExpressionStatement (s, orig);
1984 public static Expression Create (Expression expr, Expression original_expr)
1986 return Create (expr, original_expr, true);
1990 // Creates unresolved reduce expression. The original expression has to be
1991 // already resolved. Created expression is constant based based on `expr'
1992 // value unless canBeConstant is used
1994 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1996 if (canBeConstant) {
1997 Constant c = expr as Constant;
1999 return Create (c, original_expr);
2002 ExpressionStatement s = expr as ExpressionStatement;
2004 return Create (s, original_expr);
2006 if (expr.eclass == ExprClass.Unresolved)
2007 throw new ArgumentException ("Unresolved expression");
2009 return new ReducedExpression (expr, original_expr);
2012 public override Expression CreateExpressionTree (ResolveContext ec)
2014 return orig_expr.CreateExpressionTree (ec);
2017 protected override Expression DoResolve (ResolveContext ec)
2022 public override void Emit (EmitContext ec)
2027 public override Expression EmitToField (EmitContext ec)
2029 return expr.EmitToField(ec);
2032 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2034 expr.EmitBranchable (ec, target, on_true);
2037 public override SLE.Expression MakeExpression (BuilderContext ctx)
2039 return orig_expr.MakeExpression (ctx);
2044 // Standard composite pattern
2046 public abstract class CompositeExpression : Expression
2048 protected Expression expr;
2050 protected CompositeExpression (Expression expr)
2053 this.loc = expr.Location;
2056 public override bool ContainsEmitWithAwait ()
2058 return expr.ContainsEmitWithAwait ();
2061 public override Expression CreateExpressionTree (ResolveContext rc)
2063 return expr.CreateExpressionTree (rc);
2066 public Expression Child {
2067 get { return expr; }
2070 protected override Expression DoResolve (ResolveContext rc)
2072 expr = expr.Resolve (rc);
2075 eclass = expr.eclass;
2081 public override void Emit (EmitContext ec)
2086 public override bool IsNull {
2087 get { return expr.IsNull; }
2092 // Base of expressions used only to narrow resolve flow
2094 public abstract class ShimExpression : Expression
2096 protected Expression expr;
2098 protected ShimExpression (Expression expr)
2103 public Expression Expr {
2109 protected override void CloneTo (CloneContext clonectx, Expression t)
2114 ShimExpression target = (ShimExpression) t;
2115 target.expr = expr.Clone (clonectx);
2118 public override bool ContainsEmitWithAwait ()
2120 return expr.ContainsEmitWithAwait ();
2123 public override Expression CreateExpressionTree (ResolveContext ec)
2125 throw new NotSupportedException ("ET");
2128 public override void Emit (EmitContext ec)
2130 throw new InternalErrorException ("Missing Resolve call");
2136 // Unresolved type name expressions
2138 public abstract class ATypeNameExpression : FullNamedExpression
2141 protected TypeArguments targs;
2143 protected ATypeNameExpression (string name, Location l)
2149 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2156 protected ATypeNameExpression (string name, int arity, Location l)
2157 : this (name, new UnboundTypeArguments (arity), l)
2163 protected int Arity {
2165 return targs == null ? 0 : targs.Count;
2169 public bool HasTypeArguments {
2171 return targs != null && !targs.IsEmpty;
2175 public string Name {
2184 public TypeArguments TypeArguments {
2192 public override bool Equals (object obj)
2194 ATypeNameExpression atne = obj as ATypeNameExpression;
2195 return atne != null && atne.Name == Name &&
2196 (targs == null || targs.Equals (atne.targs));
2199 public override int GetHashCode ()
2201 return Name.GetHashCode ();
2204 // TODO: Move it to MemberCore
2205 public static string GetMemberType (MemberCore mc)
2211 if (mc is FieldBase)
2213 if (mc is MethodCore)
2215 if (mc is EnumMember)
2223 public override string GetSignatureForError ()
2225 if (targs != null) {
2226 return Name + "<" + targs.GetSignatureForError () + ">";
2232 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2236 /// SimpleName expressions are formed of a single word and only happen at the beginning
2237 /// of a dotted-name.
2239 public class SimpleName : ATypeNameExpression
2241 public SimpleName (string name, Location l)
2246 public SimpleName (string name, TypeArguments args, Location l)
2247 : base (name, args, l)
2251 public SimpleName (string name, int arity, Location l)
2252 : base (name, arity, l)
2256 public SimpleName GetMethodGroup ()
2258 return new SimpleName (Name, targs, loc);
2261 protected override Expression DoResolve (ResolveContext rc)
2263 var e = SimpleNameResolve (rc, null, false);
2265 var fe = e as FieldExpr;
2267 fe.VerifyAssignedStructField (rc, null);
2273 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2275 return SimpleNameResolve (ec, right_side, false);
2278 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2280 if (ctx.CurrentType != null) {
2281 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2282 if (member != null) {
2283 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2288 var report = ctx.Module.Compiler.Report;
2290 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2291 if (retval != null) {
2292 report.SymbolRelatedToPreviousError (retval.Type);
2293 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2297 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2298 if (retval != null) {
2299 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2303 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2304 if (ns_candidates != null) {
2305 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2306 report.Error (246, loc,
2307 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2310 report.Error (246, loc,
2311 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2316 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2318 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2321 if (fne.Type != null && Arity > 0) {
2322 if (HasTypeArguments) {
2323 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2324 if (ct.ResolveAsType (ec) == null)
2330 return new GenericOpenTypeExpr (fne.Type, loc);
2334 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2336 if (!(fne is Namespace))
2340 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2341 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2342 ec.Module.Compiler.Report.Error (1980, Location,
2343 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2344 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2347 fne = new DynamicTypeExpr (loc);
2348 fne.ResolveAsType (ec);
2354 Error_TypeOrNamespaceNotFound (ec);
2358 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2360 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2363 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2365 int lookup_arity = Arity;
2366 bool errorMode = false;
2368 Block current_block = rc.CurrentBlock;
2369 INamedBlockVariable variable = null;
2370 bool variable_found = false;
2374 // Stage 1: binding to local variables or parameters
2376 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2378 if (current_block != null && lookup_arity == 0) {
2379 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2380 if (!variable.IsDeclared) {
2381 // We found local name in accessible block but it's not
2382 // initialized yet, maybe the user wanted to bind to something else
2384 variable_found = true;
2386 e = variable.CreateReferenceExpression (rc, loc);
2389 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2398 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2400 TypeSpec member_type = rc.CurrentType;
2401 for (; member_type != null; member_type = member_type.DeclaringType) {
2402 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2406 var me = e as MemberExpr;
2408 // The name matches a type, defer to ResolveAsTypeStep
2416 if (variable != null) {
2417 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2418 rc.Report.Error (844, loc,
2419 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2420 Name, me.GetSignatureForError ());
2424 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2425 // Leave it to overload resolution to report correct error
2427 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2428 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2431 // LAMESPEC: again, ignores InvocableOnly
2432 if (variable != null) {
2433 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2434 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2438 // MemberLookup does not check accessors availability, this is actually needed for properties only
2440 var pe = me as PropertyExpr;
2443 // Break as there is no other overload available anyway
2444 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2445 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2448 pe.Getter = pe.PropertyInfo.Get;
2450 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2453 pe.Setter = pe.PropertyInfo.Set;
2458 // TODO: It's used by EventExpr -> FieldExpr transformation only
2459 // TODO: Should go to MemberAccess
2460 me = me.ResolveMemberAccess (rc, null, null);
2464 me.SetTypeArguments (rc, targs);
2471 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2473 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2474 if (IsPossibleTypeOrNamespace (rc)) {
2475 if (variable != null) {
2476 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2477 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2480 return ResolveAsTypeOrNamespace (rc);
2485 if (variable_found) {
2486 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2489 var tparams = rc.CurrentTypeParameters;
2490 if (tparams != null) {
2491 if (tparams.Find (Name) != null) {
2492 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2497 var ct = rc.CurrentType;
2499 if (ct.MemberDefinition.TypeParametersCount > 0) {
2500 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2501 if (ctp.Name == Name) {
2502 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2508 ct = ct.DeclaringType;
2509 } while (ct != null);
2512 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2513 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2515 rc.Report.SymbolRelatedToPreviousError (e.Type);
2516 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2520 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2522 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2523 return ErrorExpression.Instance;
2527 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2529 if (e.Type.Arity != Arity) {
2530 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2534 if (e is TypeExpr) {
2535 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2540 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2543 return ErrorExpression.Instance;
2546 if (rc.Module.Evaluator != null) {
2547 var fi = rc.Module.Evaluator.LookupField (Name);
2549 return new FieldExpr (fi.Item1, loc);
2557 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2559 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2564 if (right_side != null) {
2565 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2566 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2570 e = e.ResolveLValue (ec, right_side);
2578 public override object Accept (StructuralVisitor visitor)
2580 return visitor.Visit (this);
2585 /// Represents a namespace or a type. The name of the class was inspired by
2586 /// section 10.8.1 (Fully Qualified Names).
2588 public abstract class FullNamedExpression : Expression
2590 protected override void CloneTo (CloneContext clonectx, Expression target)
2592 // Do nothing, most unresolved type expressions cannot be
2593 // resolved to different type
2596 public override bool ContainsEmitWithAwait ()
2601 public override Expression CreateExpressionTree (ResolveContext ec)
2603 throw new NotSupportedException ("ET");
2606 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2609 // This is used to resolve the expression as a type, a null
2610 // value will be returned if the expression is not a type
2613 public override TypeSpec ResolveAsType (IMemberContext mc)
2615 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2620 TypeExpr te = fne as TypeExpr;
2622 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2630 var dep = type.GetMissingDependencies ();
2632 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2635 if (type.Kind == MemberKind.Void) {
2636 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2640 // Obsolete checks cannot be done when resolving base context as they
2641 // require type dependencies to be set but we are in process of resolving them
2643 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2644 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2645 if (obsolete_attr != null && !mc.IsObsolete) {
2646 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2654 public override void Emit (EmitContext ec)
2656 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2657 GetSignatureForError ());
2662 /// Expression that evaluates to a type
2664 public abstract class TypeExpr : FullNamedExpression
2666 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2672 protected sealed override Expression DoResolve (ResolveContext ec)
2678 public override bool Equals (object obj)
2680 TypeExpr tobj = obj as TypeExpr;
2684 return Type == tobj.Type;
2687 public override int GetHashCode ()
2689 return Type.GetHashCode ();
2694 /// Fully resolved Expression that already evaluated to a type
2696 public class TypeExpression : TypeExpr
2698 public TypeExpression (TypeSpec t, Location l)
2701 eclass = ExprClass.Type;
2705 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2712 /// This class denotes an expression which evaluates to a member
2713 /// of a struct or a class.
2715 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2718 // An instance expression associated with this member, if it's a
2719 // non-static member
2721 public Expression InstanceExpression;
2724 /// The name of this member.
2726 public abstract string Name {
2731 // When base.member is used
2733 public bool IsBase {
2734 get { return InstanceExpression is BaseThis; }
2738 /// Whether this is an instance member.
2740 public abstract bool IsInstance {
2745 /// Whether this is a static member.
2747 public abstract bool IsStatic {
2751 public abstract string KindName {
2755 protected abstract TypeSpec DeclaringType {
2759 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2761 return InstanceExpression.Type;
2766 // Converts best base candidate for virtual method starting from QueriedBaseType
2768 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2771 // Only when base.member is used and method is virtual
2777 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2778 // means for base.member access we have to find the closest match after we found best candidate
2780 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2782 // The method could already be what we are looking for
2784 TypeSpec[] targs = null;
2785 if (method.DeclaringType != InstanceExpression.Type) {
2786 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2787 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2788 if (base_override.IsGeneric)
2789 targs = method.TypeArguments;
2791 method = base_override;
2796 // When base access is used inside anonymous method/iterator/etc we need to
2797 // get back to the context of original type. We do it by emiting proxy
2798 // method in original class and rewriting base call to this compiler
2799 // generated method call which does the actual base invocation. This may
2800 // introduce redundant storey but with `this' only but it's tricky to avoid
2801 // at this stage as we don't know what expressions follow base
2803 if (rc.CurrentAnonymousMethod != null) {
2804 if (targs == null && method.IsGeneric) {
2805 targs = method.TypeArguments;
2806 method = method.GetGenericMethodDefinition ();
2809 if (method.Parameters.HasArglist)
2810 throw new NotImplementedException ("__arglist base call proxy");
2812 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2814 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2815 // get/set member expressions second call would fail to proxy because left expression
2816 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2817 // FIXME: The async check is another hack but will probably fail with mutators
2818 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2819 InstanceExpression = new This (loc).Resolve (rc);
2823 method = method.MakeGenericMethod (rc, targs);
2827 // Only base will allow this invocation to happen.
2829 if (method.IsAbstract) {
2830 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2836 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2838 if (InstanceExpression == null)
2841 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2842 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2843 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2848 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2850 if (InstanceExpression == null)
2853 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2856 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2858 var ct = rc.CurrentType;
2859 if (ct == qualifier)
2862 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2865 qualifier = qualifier.GetDefinition ();
2866 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2873 public override bool ContainsEmitWithAwait ()
2875 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2878 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2881 type = type.GetDefinition ();
2883 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2886 type = type.DeclaringType;
2887 } while (type != null);
2892 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2894 if (InstanceExpression != null) {
2895 InstanceExpression = InstanceExpression.Resolve (rc);
2896 CheckProtectedMemberAccess (rc, member);
2899 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2900 UnsafeError (rc, loc);
2903 var dep = member.GetMissingDependencies ();
2905 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2908 if (!rc.IsObsolete) {
2909 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2911 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2914 if (!(member is FieldSpec))
2915 member.MemberDefinition.SetIsUsed ();
2918 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2920 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2923 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2925 rc.Report.SymbolRelatedToPreviousError (member);
2926 rc.Report.Error (1540, loc,
2927 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2928 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2932 // Implements identicial simple name and type-name
2934 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2937 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2940 // 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
2941 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2943 if (left is MemberExpr || left is VariableReference) {
2944 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2945 if (identical_type != null && identical_type.Type == left.Type)
2946 return identical_type;
2952 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2954 if (!ResolveInstanceExpressionCore (rc, rhs))
2958 // Check intermediate value modification which won't have any effect
2960 if (rhs != null && InstanceExpression.Type.IsStruct &&
2961 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
2963 if (rc.CurrentInitializerVariable != null) {
2964 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
2965 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
2967 rc.Report.Error (1612, loc,
2968 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
2969 InstanceExpression.GetSignatureForError ());
2976 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
2979 if (InstanceExpression != null) {
2980 if (InstanceExpression is TypeExpr) {
2981 var t = InstanceExpression.Type;
2983 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2984 if (oa != null && !rc.IsObsolete) {
2985 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2988 t = t.DeclaringType;
2989 } while (t != null);
2991 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2992 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2993 rc.Report.Error (176, loc,
2994 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2995 GetSignatureForError ());
2999 InstanceExpression = null;
3005 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3006 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3007 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3008 rc.Report.Error (236, loc,
3009 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3010 GetSignatureForError ());
3012 rc.Report.Error (120, loc,
3013 "An object reference is required to access non-static member `{0}'",
3014 GetSignatureForError ());
3016 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3020 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3021 rc.Report.Error (38, loc,
3022 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3023 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3026 InstanceExpression = new This (loc);
3027 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3028 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3029 InstanceExpression = InstanceExpression.Resolve (rc);
3032 InstanceExpression = InstanceExpression.Resolve (rc);
3038 var me = InstanceExpression as MemberExpr;
3040 me.ResolveInstanceExpressionCore (rc, rhs);
3042 // Using this check to detect probing instance expression resolve
3043 if (!rc.OmitStructFlowAnalysis) {
3044 var fe = me as FieldExpr;
3045 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3046 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3047 rc.Report.Warning (1690, 1, loc,
3048 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3049 me.GetSignatureForError ());
3057 // Run member-access postponed check once we know that
3058 // the expression is not field expression which is the only
3059 // expression which can use uninitialized this
3061 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3062 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3066 // Additional checks for l-value member access
3069 if (InstanceExpression is UnboxCast) {
3070 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3077 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3079 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3080 ec.Report.Warning (1720, 1, left.Location,
3081 "Expression will always cause a `{0}'", "System.NullReferenceException");
3084 InstanceExpression = left;
3088 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3090 TypeSpec instance_type = InstanceExpression.Type;
3091 if (TypeSpec.IsValueType (instance_type)) {
3092 if (InstanceExpression is IMemoryLocation) {
3093 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3095 // Cannot release the temporary variable when its address
3096 // is required to be on stack for any parent
3097 LocalTemporary t = new LocalTemporary (instance_type);
3098 InstanceExpression.Emit (ec);
3100 t.AddressOf (ec, AddressOp.Store);
3103 InstanceExpression.Emit (ec);
3105 // Only to make verifier happy
3106 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3107 ec.Emit (OpCodes.Box, instance_type);
3110 if (prepare_for_load)
3111 ec.Emit (OpCodes.Dup);
3114 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3117 public class ExtensionMethodCandidates
3119 readonly NamespaceContainer container;
3120 readonly IList<MethodSpec> methods;
3122 readonly IMemberContext context;
3124 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3126 this.context = context;
3127 this.methods = methods;
3128 this.container = nsContainer;
3129 this.index = lookupIndex;
3132 public NamespaceContainer Container {
3138 public IMemberContext Context {
3144 public int LookupIndex {
3150 public IList<MethodSpec> Methods {
3158 // Represents a group of extension method candidates for whole namespace
3160 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3162 ExtensionMethodCandidates candidates;
3163 public readonly Expression ExtensionExpression;
3165 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3166 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3168 this.candidates = candidates;
3169 this.ExtensionExpression = extensionExpr;
3172 public override bool IsStatic {
3173 get { return true; }
3177 // For extension methodgroup we are not looking for base members but parent
3178 // namespace extension methods
3180 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3182 // TODO: candidates are null only when doing error reporting, that's
3183 // incorrect. We have to discover same extension methods in error mode
3184 if (candidates == null)
3187 int arity = type_arguments == null ? 0 : type_arguments.Count;
3189 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3190 if (candidates == null)
3193 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3196 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3198 // We are already here
3202 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3204 if (arguments == null)
3205 arguments = new Arguments (1);
3207 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3208 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3210 // Store resolved argument and restore original arguments
3212 // Clean-up modified arguments for error reporting
3213 arguments.RemoveAt (0);
3217 var me = ExtensionExpression as MemberExpr;
3219 me.ResolveInstanceExpression (ec, null);
3220 var fe = me as FieldExpr;
3222 fe.Spec.MemberDefinition.SetIsUsed ();
3225 InstanceExpression = null;
3229 #region IErrorHandler Members
3231 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3236 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3238 rc.Report.SymbolRelatedToPreviousError (best);
3239 rc.Report.Error (1928, loc,
3240 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3241 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3244 rc.Report.Error (1929, loc,
3245 "Extension method instance type `{0}' cannot be converted to `{1}'",
3246 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3252 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3257 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3266 /// MethodGroupExpr represents a group of method candidates which
3267 /// can be resolved to the best method overload
3269 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3271 protected IList<MemberSpec> Methods;
3272 MethodSpec best_candidate;
3273 TypeSpec best_candidate_return;
3274 protected TypeArguments type_arguments;
3276 SimpleName simple_name;
3277 protected TypeSpec queried_type;
3279 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3283 this.type = InternalType.MethodGroup;
3285 eclass = ExprClass.MethodGroup;
3286 queried_type = type;
3289 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3290 : this (new MemberSpec[] { m }, type, loc)
3296 public MethodSpec BestCandidate {
3298 return best_candidate;
3302 public TypeSpec BestCandidateReturnType {
3304 return best_candidate_return;
3308 public IList<MemberSpec> Candidates {
3314 protected override TypeSpec DeclaringType {
3316 return queried_type;
3320 public override bool IsInstance {
3322 if (best_candidate != null)
3323 return !best_candidate.IsStatic;
3329 public override bool IsStatic {
3331 if (best_candidate != null)
3332 return best_candidate.IsStatic;
3338 public override string KindName {
3339 get { return "method"; }
3342 public override string Name {
3344 if (best_candidate != null)
3345 return best_candidate.Name;
3348 return Methods.First ().Name;
3355 // When best candidate is already know this factory can be used
3356 // to avoid expensive overload resolution to be called
3358 // NOTE: InstanceExpression has to be set manually
3360 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3362 return new MethodGroupExpr (best, queriedType, loc) {
3363 best_candidate = best,
3364 best_candidate_return = best.ReturnType
3368 public override string GetSignatureForError ()
3370 if (best_candidate != null)
3371 return best_candidate.GetSignatureForError ();
3373 return Methods.First ().GetSignatureForError ();
3376 public override Expression CreateExpressionTree (ResolveContext ec)
3378 if (best_candidate == null) {
3379 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3383 if (best_candidate.IsConditionallyExcluded (ec, loc))
3384 ec.Report.Error (765, loc,
3385 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3387 return new TypeOfMethod (best_candidate, loc);
3390 protected override Expression DoResolve (ResolveContext ec)
3392 this.eclass = ExprClass.MethodGroup;
3394 if (InstanceExpression != null) {
3395 InstanceExpression = InstanceExpression.Resolve (ec);
3396 if (InstanceExpression == null)
3403 public override void Emit (EmitContext ec)
3405 throw new NotSupportedException ();
3408 public void EmitCall (EmitContext ec, Arguments arguments)
3410 var call = new CallEmitter ();
3411 call.InstanceExpression = InstanceExpression;
3412 call.Emit (ec, best_candidate, arguments, loc);
3415 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3417 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3418 Name, TypeManager.CSharpName (target));
3421 public static bool IsExtensionMethodArgument (Expression expr)
3424 // LAMESPEC: No details about which expressions are not allowed
3426 return !(expr is TypeExpr) && !(expr is BaseThis);
3430 /// Find the Applicable Function Members (7.4.2.1)
3432 /// me: Method Group expression with the members to select.
3433 /// it might contain constructors or methods (or anything
3434 /// that maps to a method).
3436 /// Arguments: ArrayList containing resolved Argument objects.
3438 /// loc: The location if we want an error to be reported, or a Null
3439 /// location for "probing" purposes.
3441 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3442 /// that is the best match of me on Arguments.
3445 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3447 // TODO: causes issues with probing mode, remove explicit Kind check
3448 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3451 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3452 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3453 r.BaseMembersProvider = this;
3454 r.InstanceQualifier = this;
3457 if (cerrors != null)
3458 r.CustomErrors = cerrors;
3460 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3461 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3462 if (best_candidate == null)
3463 return r.BestCandidateIsDynamic ? this : null;
3465 // Overload resolver had to create a new method group, all checks bellow have already been executed
3466 if (r.BestCandidateNewMethodGroup != null)
3467 return r.BestCandidateNewMethodGroup;
3469 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3470 if (InstanceExpression != null) {
3471 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3472 InstanceExpression = null;
3474 if (best_candidate.IsStatic && simple_name != null) {
3475 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3478 InstanceExpression.Resolve (ec);
3482 ResolveInstanceExpression (ec, null);
3485 var base_override = CandidateToBaseOverride (ec, best_candidate);
3486 if (base_override == best_candidate) {
3487 best_candidate_return = r.BestCandidateReturnType;
3489 best_candidate = base_override;
3490 best_candidate_return = best_candidate.ReturnType;
3493 if (best_candidate.IsGeneric && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3494 ConstraintChecker cc = new ConstraintChecker (ec);
3495 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3499 // Additional check for possible imported base override method which
3500 // could not be done during IsOverrideMethodBaseTypeAccessible
3502 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3503 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3504 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3505 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3511 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3513 var fe = left as FieldExpr;
3516 // Using method-group on struct fields makes the struct assigned. I am not sure
3517 // why but that's what .net does
3519 fe.Spec.MemberDefinition.SetIsAssigned ();
3522 simple_name = original;
3523 return base.ResolveMemberAccess (ec, left, original);
3526 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3528 type_arguments = ta;
3531 #region IBaseMembersProvider Members
3533 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3535 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3538 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3540 if (queried_type == member.DeclaringType)
3543 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3544 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3548 // Extension methods lookup after ordinary methods candidates failed to apply
3550 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3552 if (InstanceExpression == null)
3555 InstanceExpression = InstanceExpression.Resolve (rc);
3556 if (!IsExtensionMethodArgument (InstanceExpression))
3559 int arity = type_arguments == null ? 0 : type_arguments.Count;
3560 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3561 if (methods == null)
3564 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3565 emg.SetTypeArguments (rc, type_arguments);
3572 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3574 public ConstructorInstanceQualifier (TypeSpec type)
3577 InstanceType = type;
3580 public TypeSpec InstanceType { get; private set; }
3582 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3584 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3588 public struct OverloadResolver
3591 public enum Restrictions
3595 ProbingOnly = 1 << 1,
3596 CovariantDelegate = 1 << 2,
3597 NoBaseMembers = 1 << 3,
3598 BaseMembersIncluded = 1 << 4
3601 public interface IBaseMembersProvider
3603 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3604 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3605 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3608 public interface IErrorHandler
3610 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3611 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3612 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3613 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3616 public interface IInstanceQualifier
3618 TypeSpec InstanceType { get; }
3619 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3622 sealed class NoBaseMembers : IBaseMembersProvider
3624 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3626 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3631 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3636 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3642 struct AmbiguousCandidate
3644 public readonly MemberSpec Member;
3645 public readonly bool Expanded;
3646 public readonly AParametersCollection Parameters;
3648 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3651 Parameters = parameters;
3652 Expanded = expanded;
3657 IList<MemberSpec> members;
3658 TypeArguments type_arguments;
3659 IBaseMembersProvider base_provider;
3660 IErrorHandler custom_errors;
3661 IInstanceQualifier instance_qualifier;
3662 Restrictions restrictions;
3663 MethodGroupExpr best_candidate_extension_group;
3664 TypeSpec best_candidate_return_type;
3666 SessionReportPrinter lambda_conv_msgs;
3668 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3669 : this (members, null, restrictions, loc)
3673 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3676 if (members == null || members.Count == 0)
3677 throw new ArgumentException ("empty members set");
3679 this.members = members;
3681 type_arguments = targs;
3682 this.restrictions = restrictions;
3683 if (IsDelegateInvoke)
3684 this.restrictions |= Restrictions.NoBaseMembers;
3686 base_provider = NoBaseMembers.Instance;
3691 public IBaseMembersProvider BaseMembersProvider {
3693 return base_provider;
3696 base_provider = value;
3700 public bool BestCandidateIsDynamic { get; set; }
3703 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3705 public MethodGroupExpr BestCandidateNewMethodGroup {
3707 return best_candidate_extension_group;
3712 // Return type can be different between best candidate and closest override
3714 public TypeSpec BestCandidateReturnType {
3716 return best_candidate_return_type;
3720 public IErrorHandler CustomErrors {
3722 return custom_errors;
3725 custom_errors = value;
3729 TypeSpec DelegateType {
3731 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3732 throw new InternalErrorException ("Not running in delegate mode", loc);
3734 return members [0].DeclaringType;
3738 public IInstanceQualifier InstanceQualifier {
3740 return instance_qualifier;
3743 instance_qualifier = value;
3747 bool IsProbingOnly {
3749 return (restrictions & Restrictions.ProbingOnly) != 0;
3753 bool IsDelegateInvoke {
3755 return (restrictions & Restrictions.DelegateInvoke) != 0;
3762 // 7.4.3.3 Better conversion from expression
3763 // Returns : 1 if a->p is better,
3764 // 2 if a->q is better,
3765 // 0 if neither is better
3767 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3769 TypeSpec argument_type = a.Type;
3772 // If argument is an anonymous function
3774 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3776 // p and q are delegate types or expression tree types
3778 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3779 if (q.MemberDefinition != p.MemberDefinition) {
3784 // Uwrap delegate from Expression<T>
3786 q = TypeManager.GetTypeArguments (q)[0];
3787 p = TypeManager.GetTypeArguments (p)[0];
3790 var p_m = Delegate.GetInvokeMethod (p);
3791 var q_m = Delegate.GetInvokeMethod (q);
3794 // With identical parameter lists
3796 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3805 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3807 if (p.Kind == MemberKind.Void) {
3808 return q.Kind != MemberKind.Void ? 2 : 0;
3812 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3814 if (q.Kind == MemberKind.Void) {
3815 return p.Kind != MemberKind.Void ? 1: 0;
3818 var am = (AnonymousMethodExpression) a.Expr;
3821 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3822 // better conversion is performed between underlying types Y1 and Y2
3824 if (p.IsGenericTask || q.IsGenericTask) {
3825 if (am.Block.IsAsync) {
3826 if (p.IsGenericTask != q.IsGenericTask) {
3830 q = q.TypeArguments[0];
3831 p = p.TypeArguments[0];
3833 } else if (q != p) {
3835 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3837 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3838 var am_rt = am.InferReturnType (ec, null, orig_q);
3839 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3841 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3842 var am_rt = am.InferReturnType (ec, null, orig_p);
3843 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3849 // The parameters are identicial and return type is not void, use better type conversion
3850 // on return type to determine better one
3853 if (argument_type == p)
3856 if (argument_type == q)
3860 return BetterTypeConversion (ec, p, q);
3864 // 7.4.3.4 Better conversion from type
3866 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3868 if (p == null || q == null)
3869 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3871 switch (p.BuiltinType) {
3872 case BuiltinTypeSpec.Type.Int:
3873 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3876 case BuiltinTypeSpec.Type.Long:
3877 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3880 case BuiltinTypeSpec.Type.SByte:
3881 switch (q.BuiltinType) {
3882 case BuiltinTypeSpec.Type.Byte:
3883 case BuiltinTypeSpec.Type.UShort:
3884 case BuiltinTypeSpec.Type.UInt:
3885 case BuiltinTypeSpec.Type.ULong:
3889 case BuiltinTypeSpec.Type.Short:
3890 switch (q.BuiltinType) {
3891 case BuiltinTypeSpec.Type.UShort:
3892 case BuiltinTypeSpec.Type.UInt:
3893 case BuiltinTypeSpec.Type.ULong:
3897 case BuiltinTypeSpec.Type.Dynamic:
3898 // Dynamic is never better
3902 switch (q.BuiltinType) {
3903 case BuiltinTypeSpec.Type.Int:
3904 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3907 case BuiltinTypeSpec.Type.Long:
3908 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3911 case BuiltinTypeSpec.Type.SByte:
3912 switch (p.BuiltinType) {
3913 case BuiltinTypeSpec.Type.Byte:
3914 case BuiltinTypeSpec.Type.UShort:
3915 case BuiltinTypeSpec.Type.UInt:
3916 case BuiltinTypeSpec.Type.ULong:
3920 case BuiltinTypeSpec.Type.Short:
3921 switch (p.BuiltinType) {
3922 case BuiltinTypeSpec.Type.UShort:
3923 case BuiltinTypeSpec.Type.UInt:
3924 case BuiltinTypeSpec.Type.ULong:
3928 case BuiltinTypeSpec.Type.Dynamic:
3929 // Dynamic is never better
3933 // FIXME: handle lifted operators
3935 // TODO: this is expensive
3936 Expression p_tmp = new EmptyExpression (p);
3937 Expression q_tmp = new EmptyExpression (q);
3939 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3940 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3942 if (p_to_q && !q_to_p)
3945 if (q_to_p && !p_to_q)
3952 /// Determines "Better function" between candidate
3953 /// and the current best match
3956 /// Returns a boolean indicating :
3957 /// false if candidate ain't better
3958 /// true if candidate is better than the current best match
3960 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3961 MemberSpec best, AParametersCollection bparam, bool best_params)
3963 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3964 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3966 bool better_at_least_one = false;
3968 int args_count = args == null ? 0 : args.Count;
3972 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3975 // Default arguments are ignored for better decision
3976 if (a.IsDefaultArgument)
3980 // When comparing named argument the parameter type index has to be looked up
3981 // in original parameter set (override version for virtual members)
3983 NamedArgument na = a as NamedArgument;
3985 int idx = cparam.GetParameterIndexByName (na.Name);
3986 ct = candidate_pd.Types[idx];
3987 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3988 ct = TypeManager.GetElementType (ct);
3990 idx = bparam.GetParameterIndexByName (na.Name);
3991 bt = best_pd.Types[idx];
3992 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3993 bt = TypeManager.GetElementType (bt);
3995 ct = candidate_pd.Types[c_idx];
3996 bt = best_pd.Types[b_idx];
3998 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3999 ct = TypeManager.GetElementType (ct);
4003 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4004 bt = TypeManager.GetElementType (bt);
4009 if (TypeSpecComparer.IsEqual (ct, bt))
4013 int result = BetterExpressionConversion (ec, a, ct, bt);
4015 // for each argument, the conversion to 'ct' should be no worse than
4016 // the conversion to 'bt'.
4020 // for at least one argument, the conversion to 'ct' should be better than
4021 // the conversion to 'bt'.
4023 better_at_least_one = true;
4026 if (better_at_least_one)
4030 // This handles the case
4032 // Add (float f1, float f2, float f3);
4033 // Add (params decimal [] foo);
4035 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4036 // first candidate would've chosen as better.
4038 if (!same && !a.IsDefaultArgument)
4042 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4046 // This handles the following cases:
4048 // Foo (int i) is better than Foo (int i, long l = 0)
4049 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4050 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4052 // Prefer non-optional version
4054 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4056 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4057 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4060 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4063 return candidate_pd.Count >= best_pd.Count;
4067 // One is a non-generic method and second is a generic method, then non-generic is better
4069 if (best.IsGeneric != candidate.IsGeneric)
4070 return best.IsGeneric;
4073 // This handles the following cases:
4075 // Trim () is better than Trim (params char[] chars)
4076 // Concat (string s1, string s2, string s3) is better than
4077 // Concat (string s1, params string [] srest)
4078 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4080 // Prefer non-expanded version
4082 if (candidate_params != best_params)
4085 int candidate_param_count = candidate_pd.Count;
4086 int best_param_count = best_pd.Count;
4088 if (candidate_param_count != best_param_count)
4089 // can only happen if (candidate_params && best_params)
4090 return candidate_param_count > best_param_count && best_pd.HasParams;
4093 // Both methods have the same number of parameters, and the parameters have equal types
4094 // Pick the "more specific" signature using rules over original (non-inflated) types
4096 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4097 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4099 bool specific_at_least_once = false;
4100 for (j = 0; j < args_count; ++j) {
4101 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4103 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4104 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4106 ct = candidate_def_pd.Types[j];
4107 bt = best_def_pd.Types[j];
4112 TypeSpec specific = MoreSpecific (ct, bt);
4116 specific_at_least_once = true;
4119 if (specific_at_least_once)
4125 static bool CheckInflatedArguments (MethodSpec ms)
4127 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4130 // Setup constraint checker for probing only
4131 ConstraintChecker cc = new ConstraintChecker (null);
4133 var mp = ms.Parameters.Types;
4134 for (int i = 0; i < mp.Length; ++i) {
4135 var type = mp[i] as InflatedTypeSpec;
4139 var targs = type.TypeArguments;
4140 if (targs.Length == 0)
4143 // TODO: Checking inflated MVAR arguments should be enough
4144 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4151 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4153 rc.Report.Error (1729, loc,
4154 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4155 type.GetSignatureForError (), argCount.ToString ());
4159 // Determines if the candidate method is applicable to the given set of arguments
4160 // There could be two different set of parameters for same candidate where one
4161 // is the closest override for default values and named arguments checks and second
4162 // one being the virtual base for the parameter types and modifiers.
4164 // A return value rates candidate method compatibility,
4165 // 0 = the best, int.MaxValue = the worst
4168 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)
4170 // Parameters of most-derived type used mainly for named and optional parameters
4171 var pd = pm.Parameters;
4173 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4174 // params modifier instead of most-derived type
4175 var cpd = ((IParametersMember) candidate).Parameters;
4176 int param_count = pd.Count;
4177 int optional_count = 0;
4179 Arguments orig_args = arguments;
4181 if (arg_count != param_count) {
4183 // No arguments expansion when doing exact match for delegates
4185 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4186 for (int i = 0; i < pd.Count; ++i) {
4187 if (pd.FixedParameters[i].HasDefaultValue) {
4188 optional_count = pd.Count - i;
4194 if (optional_count != 0) {
4195 // Readjust expected number when params used
4196 if (cpd.HasParams) {
4198 if (arg_count < param_count)
4200 } else if (arg_count > param_count) {
4201 int args_gap = System.Math.Abs (arg_count - param_count);
4202 return int.MaxValue - 10000 + args_gap;
4204 } else if (arg_count != param_count) {
4205 int args_gap = System.Math.Abs (arg_count - param_count);
4207 return int.MaxValue - 10000 + args_gap;
4208 if (arg_count < param_count - 1)
4209 return int.MaxValue - 10000 + args_gap;
4212 // Resize to fit optional arguments
4213 if (optional_count != 0) {
4214 if (arguments == null) {
4215 arguments = new Arguments (optional_count);
4217 // Have to create a new container, so the next run can do same
4218 var resized = new Arguments (param_count);
4219 resized.AddRange (arguments);
4220 arguments = resized;
4223 for (int i = arg_count; i < param_count; ++i)
4224 arguments.Add (null);
4228 if (arg_count > 0) {
4230 // Shuffle named arguments to the right positions if there are any
4232 if (arguments[arg_count - 1] is NamedArgument) {
4233 arg_count = arguments.Count;
4235 for (int i = 0; i < arg_count; ++i) {
4236 bool arg_moved = false;
4238 NamedArgument na = arguments[i] as NamedArgument;
4242 int index = pd.GetParameterIndexByName (na.Name);
4244 // Named parameter not found
4248 // already reordered
4253 if (index >= param_count) {
4254 // When using parameters which should not be available to the user
4255 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4258 arguments.Add (null);
4262 temp = arguments[index];
4264 // The slot has been taken by positional argument
4265 if (temp != null && !(temp is NamedArgument))
4270 arguments = arguments.MarkOrderedArgument (na);
4274 arguments[index] = arguments[i];
4275 arguments[i] = temp;
4282 arg_count = arguments.Count;
4284 } else if (arguments != null) {
4285 arg_count = arguments.Count;
4289 // Don't do any expensive checks when the candidate cannot succeed
4291 if (arg_count != param_count && !cpd.HasParams)
4292 return (param_count - arg_count) * 2 + 1;
4294 var dep = candidate.GetMissingDependencies ();
4296 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4301 // 1. Handle generic method using type arguments when specified or type inference
4304 var ms = candidate as MethodSpec;
4305 if (ms != null && ms.IsGeneric) {
4306 if (type_arguments != null) {
4307 var g_args_count = ms.Arity;
4308 if (g_args_count != type_arguments.Count)
4309 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4311 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4314 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4315 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4316 // candidate was found use the set to report more details about what was wrong with lambda body.
4317 // The general idea is to distinguish between code errors and errors caused by
4318 // trial-and-error type inference
4320 if (lambda_conv_msgs == null) {
4321 for (int i = 0; i < arg_count; i++) {
4322 Argument a = arguments[i];
4326 var am = a.Expr as AnonymousMethodExpression;
4328 if (lambda_conv_msgs == null)
4329 lambda_conv_msgs = new SessionReportPrinter ();
4331 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4336 var ti = new TypeInference (arguments);
4337 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4340 return ti.InferenceScore - 20000;
4343 // Clear any error messages when the result was success
4345 if (lambda_conv_msgs != null)
4346 lambda_conv_msgs.ClearSession ();
4348 if (i_args.Length != 0) {
4349 ms = ms.MakeGenericMethod (ec, i_args);
4354 // Type arguments constraints have to match for the method to be applicable
4356 if (!CheckInflatedArguments (ms)) {
4358 return int.MaxValue - 25000;
4362 // We have a generic return type and at same time the method is override which
4363 // means we have to also inflate override return type in case the candidate is
4364 // best candidate and override return type is different to base return type.
4366 // virtual Foo<T, object> with override Foo<T, dynamic>
4368 if (candidate != pm) {
4369 MethodSpec override_ms = (MethodSpec) pm;
4370 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4371 returnType = inflator.Inflate (returnType);
4373 returnType = ms.ReturnType;
4377 ptypes = ms.Parameters.Types;
4379 if (type_arguments != null)
4380 return int.MaxValue - 15000;
4386 // 2. Each argument has to be implicitly convertible to method parameter
4388 Parameter.Modifier p_mod = 0;
4391 for (int i = 0; i < arg_count; i++) {
4392 Argument a = arguments[i];
4394 var fp = pd.FixedParameters[i];
4395 if (!fp.HasDefaultValue) {
4396 arguments = orig_args;
4397 return arg_count * 2 + 2;
4401 // Get the default value expression, we can use the same expression
4402 // if the type matches
4404 Expression e = fp.DefaultValue;
4405 if (!(e is Constant) || e.Type != ptypes [i]) {
4407 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4409 var ptype = ptypes [i];
4410 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4411 e = new MemberAccess (new MemberAccess (new MemberAccess (
4412 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4413 } else if (e is Constant) {
4415 // Handles int to int? conversions
4417 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4420 // When constant type paramter contains type argument
4422 // Foo (T[] arg = null)
4425 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4428 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4435 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4437 // LAMESPEC: Attributes can be mixed together with build-in priority
4439 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4440 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4441 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4442 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4443 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4444 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4448 arguments[i] = new Argument (e, Argument.AType.Default);
4452 if (p_mod != Parameter.Modifier.PARAMS) {
4453 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4455 } else if (!params_expanded_form) {
4456 params_expanded_form = true;
4457 pt = ((ElementTypeSpec) pt).Element;
4463 if (!params_expanded_form) {
4464 if (a.ArgType == Argument.AType.ExtensionType) {
4466 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4468 // LAMESPEC: or implicit type parameter conversion
4471 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4472 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4473 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4478 score = IsArgumentCompatible (ec, a, p_mod, pt);
4481 dynamicArgument = true;
4486 // It can be applicable in expanded form (when not doing exact match like for delegates)
4488 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4489 if (!params_expanded_form)
4490 pt = ((ElementTypeSpec) pt).Element;
4493 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4496 params_expanded_form = true;
4497 } else if (score < 0) {
4498 params_expanded_form = true;
4499 dynamicArgument = true;
4504 if (params_expanded_form)
4506 return (arg_count - i) * 2 + score;
4511 // When params parameter has no argument it will be provided later if the method is the best candidate
4513 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4514 params_expanded_form = true;
4517 // Restore original arguments for dynamic binder to keep the intention of original source code
4519 if (dynamicArgument)
4520 arguments = orig_args;
4526 // Tests argument compatibility with the parameter
4527 // The possible return values are
4529 // 1 - modifier mismatch
4530 // 2 - type mismatch
4531 // -1 - dynamic binding required
4533 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4536 // Types have to be identical when ref or out modifer
4537 // is used and argument is not of dynamic type
4539 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4540 if (argument.Type != parameter) {
4542 // Do full equality check after quick path
4544 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4546 // Using dynamic for ref/out parameter can still succeed at runtime
4548 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4555 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4557 // Using dynamic for ref/out parameter can still succeed at runtime
4559 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4566 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4570 // Use implicit conversion in all modes to return same candidates when the expression
4571 // is used as argument or delegate conversion
4573 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4581 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4583 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4585 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4588 var ac_p = p as ArrayContainer;
4590 var ac_q = q as ArrayContainer;
4594 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4595 if (specific == ac_p.Element)
4597 if (specific == ac_q.Element)
4599 } else if (p.IsGeneric && q.IsGeneric) {
4600 var pargs = TypeManager.GetTypeArguments (p);
4601 var qargs = TypeManager.GetTypeArguments (q);
4603 bool p_specific_at_least_once = false;
4604 bool q_specific_at_least_once = false;
4606 for (int i = 0; i < pargs.Length; i++) {
4607 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4608 if (specific == pargs[i])
4609 p_specific_at_least_once = true;
4610 if (specific == qargs[i])
4611 q_specific_at_least_once = true;
4614 if (p_specific_at_least_once && !q_specific_at_least_once)
4616 if (!p_specific_at_least_once && q_specific_at_least_once)
4624 // Find the best method from candidate list
4626 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4628 List<AmbiguousCandidate> ambiguous_candidates = null;
4630 MemberSpec best_candidate;
4631 Arguments best_candidate_args = null;
4632 bool best_candidate_params = false;
4633 bool best_candidate_dynamic = false;
4634 int best_candidate_rate;
4635 IParametersMember best_parameter_member = null;
4637 int args_count = args != null ? args.Count : 0;
4639 Arguments candidate_args = args;
4640 bool error_mode = false;
4641 MemberSpec invocable_member = null;
4644 best_candidate = null;
4645 best_candidate_rate = int.MaxValue;
4647 var type_members = members;
4649 for (int i = 0; i < type_members.Count; ++i) {
4650 var member = type_members[i];
4653 // Methods in a base class are not candidates if any method in a derived
4654 // class is applicable
4656 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4660 if (!member.IsAccessible (rc))
4663 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4666 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4667 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4672 IParametersMember pm = member as IParametersMember;
4675 // Will use it later to report ambiguity between best method and invocable member
4677 if (Invocation.IsMemberInvocable (member))
4678 invocable_member = member;
4684 // Overload resolution is looking for base member but using parameter names
4685 // and default values from the closest member. That means to do expensive lookup
4686 // for the closest override for virtual or abstract members
4688 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4689 var override_params = base_provider.GetOverrideMemberParameters (member);
4690 if (override_params != null)
4691 pm = override_params;
4695 // Check if the member candidate is applicable
4697 bool params_expanded_form = false;
4698 bool dynamic_argument = false;
4699 TypeSpec rt = pm.MemberType;
4700 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4702 if (lambda_conv_msgs != null)
4703 lambda_conv_msgs.EndSession ();
4706 // How does it score compare to others
4708 if (candidate_rate < best_candidate_rate) {
4710 // Fatal error (missing dependency), cannot continue
4711 if (candidate_rate < 0)
4714 best_candidate_rate = candidate_rate;
4715 best_candidate = member;
4716 best_candidate_args = candidate_args;
4717 best_candidate_params = params_expanded_form;
4718 best_candidate_dynamic = dynamic_argument;
4719 best_parameter_member = pm;
4720 best_candidate_return_type = rt;
4721 } else if (candidate_rate == 0) {
4723 // The member look is done per type for most operations but sometimes
4724 // it's not possible like for binary operators overload because they
4725 // are unioned between 2 sides
4727 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4728 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4733 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4735 // We pack all interface members into top level type which makes the overload resolution
4736 // more complicated for interfaces. We compensate it by removing methods with same
4737 // signature when building the cache hence this path should not really be hit often
4740 // interface IA { void Foo (int arg); }
4741 // interface IB : IA { void Foo (params int[] args); }
4743 // IB::Foo is the best overload when calling IB.Foo (1)
4746 if (ambiguous_candidates != null) {
4747 foreach (var amb_cand in ambiguous_candidates) {
4748 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4757 ambiguous_candidates = null;
4760 // Is the new candidate better
4761 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4765 best_candidate = member;
4766 best_candidate_args = candidate_args;
4767 best_candidate_params = params_expanded_form;
4768 best_candidate_dynamic = dynamic_argument;
4769 best_parameter_member = pm;
4770 best_candidate_return_type = rt;
4772 // It's not better but any other found later could be but we are not sure yet
4773 if (ambiguous_candidates == null)
4774 ambiguous_candidates = new List<AmbiguousCandidate> ();
4776 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4780 // Restore expanded arguments
4781 if (candidate_args != args)
4782 candidate_args = args;
4784 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4787 // We've found exact match
4789 if (best_candidate_rate == 0)
4793 // Try extension methods lookup when no ordinary method match was found and provider enables it
4796 var emg = base_provider.LookupExtensionMethod (rc);
4798 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4800 best_candidate_extension_group = emg;
4801 return (T) (MemberSpec) emg.BestCandidate;
4806 // Don't run expensive error reporting mode for probing
4813 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4816 lambda_conv_msgs = null;
4821 // No best member match found, report an error
4823 if (best_candidate_rate != 0 || error_mode) {
4824 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4828 if (best_candidate_dynamic) {
4829 if (args[0].ArgType == Argument.AType.ExtensionType) {
4830 rc.Report.Error (1973, loc,
4831 "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",
4832 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4836 // Check type constraints only when explicit type arguments are used
4838 if (best_candidate.IsGeneric && type_arguments != null) {
4839 MethodSpec bc = best_candidate as MethodSpec;
4840 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4841 ConstraintChecker cc = new ConstraintChecker (rc);
4842 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4846 BestCandidateIsDynamic = true;
4851 // These flags indicates we are running delegate probing conversion. No need to
4852 // do more expensive checks
4854 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4855 return (T) best_candidate;
4857 if (ambiguous_candidates != null) {
4859 // Now check that there are no ambiguities i.e the selected method
4860 // should be better than all the others
4862 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4863 var candidate = ambiguous_candidates [ix];
4865 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4866 var ambiguous = candidate.Member;
4867 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4868 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4869 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4870 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4871 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4874 return (T) best_candidate;
4879 if (invocable_member != null) {
4880 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4881 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4882 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4883 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4887 // And now check if the arguments are all
4888 // compatible, perform conversions if
4889 // necessary etc. and return if everything is
4892 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4895 if (best_candidate == null)
4899 // Don't run possibly expensive checks in probing mode
4901 if (!rc.IsInProbingMode) {
4903 // Check ObsoleteAttribute on the best method
4905 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4906 if (oa != null && !rc.IsObsolete)
4907 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4909 best_candidate.MemberDefinition.SetIsUsed ();
4912 args = best_candidate_args;
4913 return (T) best_candidate;
4916 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4918 return ResolveMember<MethodSpec> (rc, ref args);
4921 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4922 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4924 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4927 if (a.Type == InternalType.ErrorType)
4930 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4931 ec.Report.SymbolRelatedToPreviousError (method);
4932 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4933 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
4934 TypeManager.CSharpSignature (method));
4937 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4938 TypeManager.CSharpSignature (method));
4939 } else if (IsDelegateInvoke) {
4940 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4941 DelegateType.GetSignatureForError ());
4943 ec.Report.SymbolRelatedToPreviousError (method);
4944 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4945 method.GetSignatureForError ());
4948 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4950 string index = (idx + 1).ToString ();
4951 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4952 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4953 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4954 index, Parameter.GetModifierSignature (a.Modifier));
4956 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4957 index, Parameter.GetModifierSignature (mod));
4959 string p1 = a.GetSignatureForError ();
4960 string p2 = TypeManager.CSharpName (paramType);
4963 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4964 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4967 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
4968 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
4969 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
4972 ec.Report.Error (1503, a.Expr.Location,
4973 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4978 // We have failed to find exact match so we return error info about the closest match
4980 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4982 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4983 int arg_count = args == null ? 0 : args.Count;
4985 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4986 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4987 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4991 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
4996 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4997 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4998 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5002 // For candidates which match on parameters count report more details about incorrect arguments
5005 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5006 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5007 // Reject any inaccessible member
5008 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5009 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5010 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5014 var ms = best_candidate as MethodSpec;
5015 if (ms != null && ms.IsGeneric) {
5016 bool constr_ok = true;
5017 if (ms.TypeArguments != null)
5018 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5020 if (ta_count == 0) {
5021 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5025 rc.Report.Error (411, loc,
5026 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5027 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5034 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5040 // We failed to find any method with correct argument count, report best candidate
5042 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5045 if (best_candidate.Kind == MemberKind.Constructor) {
5046 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5047 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5048 } else if (IsDelegateInvoke) {
5049 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5050 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5051 DelegateType.GetSignatureForError (), arg_count.ToString ());
5053 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5054 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5055 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5056 name, arg_count.ToString ());
5060 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5062 var pd = pm.Parameters;
5063 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5065 Parameter.Modifier p_mod = 0;
5067 int a_idx = 0, a_pos = 0;
5069 ArrayInitializer params_initializers = null;
5070 bool has_unsafe_arg = pm.MemberType.IsPointer;
5071 int arg_count = args == null ? 0 : args.Count;
5073 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5075 if (p_mod != Parameter.Modifier.PARAMS) {
5076 p_mod = pd.FixedParameters[a_idx].ModFlags;
5078 has_unsafe_arg |= pt.IsPointer;
5080 if (p_mod == Parameter.Modifier.PARAMS) {
5081 if (chose_params_expanded) {
5082 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5083 pt = TypeManager.GetElementType (pt);
5089 // Types have to be identical when ref or out modifer is used
5091 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5092 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5095 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5101 NamedArgument na = a as NamedArgument;
5103 int name_index = pd.GetParameterIndexByName (na.Name);
5104 if (name_index < 0 || name_index >= pd.Count) {
5105 if (IsDelegateInvoke) {
5106 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5107 ec.Report.Error (1746, na.Location,
5108 "The delegate `{0}' does not contain a parameter named `{1}'",
5109 DelegateType.GetSignatureForError (), na.Name);
5111 ec.Report.SymbolRelatedToPreviousError (member);
5112 ec.Report.Error (1739, na.Location,
5113 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5114 TypeManager.CSharpSignature (member), na.Name);
5116 } else if (args[name_index] != a) {
5117 if (IsDelegateInvoke)
5118 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5120 ec.Report.SymbolRelatedToPreviousError (member);
5122 ec.Report.Error (1744, na.Location,
5123 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5128 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5131 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5132 custom_errors.NoArgumentMatch (ec, member);
5136 Expression conv = null;
5137 if (a.ArgType == Argument.AType.ExtensionType) {
5138 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5141 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5143 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5146 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5153 // Convert params arguments to an array initializer
5155 if (params_initializers != null) {
5156 // we choose to use 'a.Expr' rather than 'conv' so that
5157 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5158 params_initializers.Add (a.Expr);
5159 args.RemoveAt (a_idx--);
5164 // Update the argument with the implicit conversion
5168 if (a_idx != arg_count) {
5169 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5174 // Fill not provided arguments required by params modifier
5176 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5178 args = new Arguments (1);
5180 pt = ptypes[pd.Count - 1];
5181 pt = TypeManager.GetElementType (pt);
5182 has_unsafe_arg |= pt.IsPointer;
5183 params_initializers = new ArrayInitializer (0, loc);
5187 // Append an array argument with all params arguments
5189 if (params_initializers != null) {
5190 args.Add (new Argument (
5191 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5195 if (has_unsafe_arg && !ec.IsUnsafe) {
5196 Expression.UnsafeError (ec, loc);
5200 // We could infer inaccesible type arguments
5202 if (type_arguments == null && member.IsGeneric) {
5203 var ms = (MethodSpec) member;
5204 foreach (var ta in ms.TypeArguments) {
5205 if (!ta.IsAccessible (ec)) {
5206 ec.Report.SymbolRelatedToPreviousError (ta);
5207 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5217 public class ConstantExpr : MemberExpr
5219 readonly ConstSpec constant;
5221 public ConstantExpr (ConstSpec constant, Location loc)
5223 this.constant = constant;
5227 public override string Name {
5228 get { throw new NotImplementedException (); }
5231 public override string KindName {
5232 get { return "constant"; }
5235 public override bool IsInstance {
5236 get { return !IsStatic; }
5239 public override bool IsStatic {
5240 get { return true; }
5243 protected override TypeSpec DeclaringType {
5244 get { return constant.DeclaringType; }
5247 public override Expression CreateExpressionTree (ResolveContext ec)
5249 throw new NotSupportedException ("ET");
5252 protected override Expression DoResolve (ResolveContext rc)
5254 ResolveInstanceExpression (rc, null);
5255 DoBestMemberChecks (rc, constant);
5257 var c = constant.GetConstant (rc);
5259 // Creates reference expression to the constant value
5260 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5263 public override void Emit (EmitContext ec)
5265 throw new NotSupportedException ();
5268 public override string GetSignatureForError ()
5270 return constant.GetSignatureForError ();
5273 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5275 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5280 // Fully resolved expression that references a Field
5282 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5284 protected FieldSpec spec;
5285 VariableInfo variable_info;
5287 LocalTemporary temp;
5290 protected FieldExpr (Location l)
5295 public FieldExpr (FieldSpec spec, Location loc)
5300 type = spec.MemberType;
5303 public FieldExpr (FieldBase fi, Location l)
5310 public override string Name {
5316 public bool IsHoisted {
5318 IVariableReference hv = InstanceExpression as IVariableReference;
5319 return hv != null && hv.IsHoisted;
5323 public override bool IsInstance {
5325 return !spec.IsStatic;
5329 public override bool IsStatic {
5331 return spec.IsStatic;
5335 public override string KindName {
5336 get { return "field"; }
5339 public FieldSpec Spec {
5345 protected override TypeSpec DeclaringType {
5347 return spec.DeclaringType;
5351 public VariableInfo VariableInfo {
5353 return variable_info;
5359 public override string GetSignatureForError ()
5361 return spec.GetSignatureForError ();
5364 public bool IsMarshalByRefAccess (ResolveContext rc)
5366 // Checks possible ldflda of field access expression
5367 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5368 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5369 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5372 public void SetHasAddressTaken ()
5374 IVariableReference vr = InstanceExpression as IVariableReference;
5376 vr.SetHasAddressTaken ();
5380 public override Expression CreateExpressionTree (ResolveContext ec)
5382 return CreateExpressionTree (ec, true);
5385 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5388 Expression instance;
5390 if (InstanceExpression == null) {
5391 instance = new NullLiteral (loc);
5392 } else if (convertInstance) {
5393 instance = InstanceExpression.CreateExpressionTree (ec);
5395 args = new Arguments (1);
5396 args.Add (new Argument (InstanceExpression));
5397 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5400 args = Arguments.CreateForExpressionTree (ec, null,
5402 CreateTypeOfExpression ());
5404 return CreateExpressionFactoryCall (ec, "Field", args);
5407 public Expression CreateTypeOfExpression ()
5409 return new TypeOfField (spec, loc);
5412 protected override Expression DoResolve (ResolveContext ec)
5414 spec.MemberDefinition.SetIsUsed ();
5416 return DoResolve (ec, null);
5419 Expression DoResolve (ResolveContext ec, Expression rhs)
5421 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5424 if (ResolveInstanceExpression (ec, rhs)) {
5425 // Resolve the field's instance expression while flow analysis is turned
5426 // off: when accessing a field "a.b", we must check whether the field
5427 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5429 if (lvalue_instance) {
5430 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5431 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5433 Expression right_side =
5434 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5436 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5439 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5440 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5444 if (InstanceExpression == null)
5448 DoBestMemberChecks (ec, spec);
5451 var fb = spec as FixedFieldSpec;
5452 IVariableReference var = InstanceExpression as IVariableReference;
5454 if (lvalue_instance && var != null && var.VariableInfo != null) {
5455 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5459 IFixedExpression fe = InstanceExpression as IFixedExpression;
5460 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5461 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5464 if (InstanceExpression.eclass != ExprClass.Variable) {
5465 ec.Report.SymbolRelatedToPreviousError (spec);
5466 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5467 TypeManager.GetFullNameSignature (spec));
5468 } else if (var != null && var.IsHoisted) {
5469 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5472 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5476 // Set flow-analysis variable info for struct member access. It will be check later
5477 // for precise error reporting
5479 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5480 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5481 if (rhs != null && variable_info != null)
5482 variable_info.SetStructFieldAssigned (ec, Name);
5485 eclass = ExprClass.Variable;
5489 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5494 var var = fe.InstanceExpression as IVariableReference;
5496 var vi = var.VariableInfo;
5498 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5500 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5502 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5509 fe = fe.InstanceExpression as FieldExpr;
5511 } while (fe != null);
5514 static readonly int [] codes = {
5515 191, // instance, write access
5516 192, // instance, out access
5517 198, // static, write access
5518 199, // static, out access
5519 1648, // member of value instance, write access
5520 1649, // member of value instance, out access
5521 1650, // member of value static, write access
5522 1651 // member of value static, out access
5525 static readonly string [] msgs = {
5526 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5527 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5528 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5529 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5530 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5531 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5532 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5533 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5536 // The return value is always null. Returning a value simplifies calling code.
5537 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5540 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5544 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5546 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5551 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5553 Expression e = DoResolve (ec, right_side);
5558 spec.MemberDefinition.SetIsAssigned ();
5560 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5561 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5562 ec.Report.Warning (420, 1, loc,
5563 "`{0}': A volatile field references will not be treated as volatile",
5564 spec.GetSignatureForError ());
5567 if (spec.IsReadOnly) {
5568 // InitOnly fields can only be assigned in constructors or initializers
5569 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5570 return Report_AssignToReadonly (ec, right_side);
5572 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5574 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5575 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5576 return Report_AssignToReadonly (ec, right_side);
5577 // static InitOnly fields cannot be assigned-to in an instance constructor
5578 if (IsStatic && !ec.IsStatic)
5579 return Report_AssignToReadonly (ec, right_side);
5580 // instance constructors can't modify InitOnly fields of other instances of the same type
5581 if (!IsStatic && !(InstanceExpression is This))
5582 return Report_AssignToReadonly (ec, right_side);
5586 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5587 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5588 ec.Report.Warning (197, 1, loc,
5589 "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",
5590 GetSignatureForError ());
5593 eclass = ExprClass.Variable;
5597 public override int GetHashCode ()
5599 return spec.GetHashCode ();
5602 public bool IsFixed {
5605 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5607 IVariableReference variable = InstanceExpression as IVariableReference;
5608 if (variable != null)
5609 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5611 IFixedExpression fe = InstanceExpression as IFixedExpression;
5612 return fe != null && fe.IsFixed;
5616 public override bool Equals (object obj)
5618 FieldExpr fe = obj as FieldExpr;
5622 if (spec != fe.spec)
5625 if (InstanceExpression == null || fe.InstanceExpression == null)
5628 return InstanceExpression.Equals (fe.InstanceExpression);
5631 public void Emit (EmitContext ec, bool leave_copy)
5633 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5637 ec.Emit (OpCodes.Volatile);
5639 ec.Emit (OpCodes.Ldsfld, spec);
5642 EmitInstance (ec, false);
5644 // Optimization for build-in types
5645 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5646 ec.EmitLoadFromPtr (type);
5648 var ff = spec as FixedFieldSpec;
5650 ec.Emit (OpCodes.Ldflda, spec);
5651 ec.Emit (OpCodes.Ldflda, ff.Element);
5654 ec.Emit (OpCodes.Volatile);
5656 ec.Emit (OpCodes.Ldfld, spec);
5662 ec.Emit (OpCodes.Dup);
5664 temp = new LocalTemporary (this.Type);
5670 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5672 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5673 if (isCompound && !(source is DynamicExpressionStatement)) {
5674 if (has_await_source) {
5676 InstanceExpression = InstanceExpression.EmitToField (ec);
5683 if (has_await_source)
5684 source = source.EmitToField (ec);
5686 EmitInstance (ec, prepared);
5692 ec.Emit (OpCodes.Dup);
5694 temp = new LocalTemporary (this.Type);
5699 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5700 ec.Emit (OpCodes.Volatile);
5702 spec.MemberDefinition.SetIsAssigned ();
5705 ec.Emit (OpCodes.Stsfld, spec);
5707 ec.Emit (OpCodes.Stfld, spec);
5717 // Emits store to field with prepared values on stack
5719 public void EmitAssignFromStack (EmitContext ec)
5722 ec.Emit (OpCodes.Stsfld, spec);
5724 ec.Emit (OpCodes.Stfld, spec);
5728 public override void Emit (EmitContext ec)
5733 public override void EmitSideEffect (EmitContext ec)
5735 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5737 if (is_volatile) // || is_marshal_by_ref ())
5738 base.EmitSideEffect (ec);
5741 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5743 if ((mode & AddressOp.Store) != 0)
5744 spec.MemberDefinition.SetIsAssigned ();
5745 if ((mode & AddressOp.Load) != 0)
5746 spec.MemberDefinition.SetIsUsed ();
5749 // Handle initonly fields specially: make a copy and then
5750 // get the address of the copy.
5753 if (spec.IsReadOnly){
5755 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5767 var temp = ec.GetTemporaryLocal (type);
5768 ec.Emit (OpCodes.Stloc, temp);
5769 ec.Emit (OpCodes.Ldloca, temp);
5770 ec.FreeTemporaryLocal (temp, type);
5776 ec.Emit (OpCodes.Ldsflda, spec);
5779 EmitInstance (ec, false);
5780 ec.Emit (OpCodes.Ldflda, spec);
5784 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5786 return MakeExpression (ctx);
5789 public override SLE.Expression MakeExpression (BuilderContext ctx)
5792 return base.MakeExpression (ctx);
5794 return SLE.Expression.Field (
5795 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5796 spec.GetMetaInfo ());
5800 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5802 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5808 // Expression that evaluates to a Property.
5810 // This is not an LValue because we need to re-write the expression. We
5811 // can not take data from the stack and store it.
5813 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5815 public PropertyExpr (PropertySpec spec, Location l)
5818 best_candidate = spec;
5819 type = spec.MemberType;
5824 protected override Arguments Arguments {
5832 protected override TypeSpec DeclaringType {
5834 return best_candidate.DeclaringType;
5838 public override string Name {
5840 return best_candidate.Name;
5844 public override bool IsInstance {
5850 public override bool IsStatic {
5852 return best_candidate.IsStatic;
5856 public override string KindName {
5857 get { return "property"; }
5860 public PropertySpec PropertyInfo {
5862 return best_candidate;
5868 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5870 return new PropertyExpr (spec, loc) {
5876 public override Expression CreateExpressionTree (ResolveContext ec)
5879 if (IsSingleDimensionalArrayLength ()) {
5880 args = new Arguments (1);
5881 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5882 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5885 args = new Arguments (2);
5886 if (InstanceExpression == null)
5887 args.Add (new Argument (new NullLiteral (loc)));
5889 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5890 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5891 return CreateExpressionFactoryCall (ec, "Property", args);
5894 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5896 DoResolveLValue (rc, null);
5897 return new TypeOfMethod (Setter, loc);
5900 public override string GetSignatureForError ()
5902 return best_candidate.GetSignatureForError ();
5905 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5908 return base.MakeExpression (ctx);
5910 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5914 public override SLE.Expression MakeExpression (BuilderContext ctx)
5917 return base.MakeExpression (ctx);
5919 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5923 void Error_PropertyNotValid (ResolveContext ec)
5925 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5926 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5927 GetSignatureForError ());
5930 bool IsSingleDimensionalArrayLength ()
5932 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5935 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5936 return ac != null && ac.Rank == 1;
5939 public override void Emit (EmitContext ec, bool leave_copy)
5942 // Special case: length of single dimension array property is turned into ldlen
5944 if (IsSingleDimensionalArrayLength ()) {
5945 EmitInstance (ec, false);
5946 ec.Emit (OpCodes.Ldlen);
5947 ec.Emit (OpCodes.Conv_I4);
5951 base.Emit (ec, leave_copy);
5954 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5957 LocalTemporary await_source_arg = null;
5959 if (isCompound && !(source is DynamicExpressionStatement)) {
5960 emitting_compound_assignment = true;
5963 if (has_await_arguments) {
5964 await_source_arg = new LocalTemporary (Type);
5965 await_source_arg.Store (ec);
5967 args = new Arguments (1);
5968 args.Add (new Argument (await_source_arg));
5971 temp = await_source_arg;
5974 has_await_arguments = false;
5979 ec.Emit (OpCodes.Dup);
5980 temp = new LocalTemporary (this.Type);
5985 args = new Arguments (1);
5989 temp = new LocalTemporary (this.Type);
5991 args.Add (new Argument (temp));
5993 args.Add (new Argument (source));
5997 emitting_compound_assignment = false;
5999 var call = new CallEmitter ();
6000 call.InstanceExpression = InstanceExpression;
6002 call.InstanceExpressionOnStack = true;
6004 call.Emit (ec, Setter, args, loc);
6011 if (await_source_arg != null) {
6012 await_source_arg.Release (ec);
6016 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6018 eclass = ExprClass.PropertyAccess;
6020 if (best_candidate.IsNotCSharpCompatible) {
6021 Error_PropertyNotValid (rc);
6024 ResolveInstanceExpression (rc, right_side);
6026 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6027 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6028 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6030 type = p.MemberType;
6034 DoBestMemberChecks (rc, best_candidate);
6038 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6040 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6044 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6046 // getter and setter can be different for base calls
6047 MethodSpec getter, setter;
6048 protected T best_candidate;
6050 protected LocalTemporary temp;
6051 protected bool emitting_compound_assignment;
6052 protected bool has_await_arguments;
6054 protected PropertyOrIndexerExpr (Location l)
6061 protected abstract Arguments Arguments { get; set; }
6063 public MethodSpec Getter {
6072 public MethodSpec Setter {
6083 protected override Expression DoResolve (ResolveContext ec)
6085 if (eclass == ExprClass.Unresolved) {
6086 var expr = OverloadResolve (ec, null);
6091 return expr.Resolve (ec);
6094 if (!ResolveGetter (ec))
6100 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6102 if (right_side == EmptyExpression.OutAccess) {
6103 // TODO: best_candidate can be null at this point
6104 INamedBlockVariable variable = null;
6105 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6106 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6107 best_candidate.Name);
6109 right_side.DoResolveLValue (ec, this);
6114 if (eclass == ExprClass.Unresolved) {
6115 var expr = OverloadResolve (ec, right_side);
6120 return expr.ResolveLValue (ec, right_side);
6123 if (!ResolveSetter (ec))
6130 // Implements the IAssignMethod interface for assignments
6132 public virtual void Emit (EmitContext ec, bool leave_copy)
6134 var call = new CallEmitter ();
6135 call.InstanceExpression = InstanceExpression;
6136 if (has_await_arguments)
6137 call.HasAwaitArguments = true;
6139 call.DuplicateArguments = emitting_compound_assignment;
6141 call.Emit (ec, Getter, Arguments, loc);
6143 if (call.HasAwaitArguments) {
6144 InstanceExpression = call.InstanceExpression;
6145 Arguments = call.EmittedArguments;
6146 has_await_arguments = true;
6150 ec.Emit (OpCodes.Dup);
6151 temp = new LocalTemporary (Type);
6156 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6158 public override void Emit (EmitContext ec)
6163 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6165 has_await_arguments = true;
6170 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6172 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6174 bool ResolveGetter (ResolveContext rc)
6176 if (!best_candidate.HasGet) {
6177 if (InstanceExpression != EmptyExpression.Null) {
6178 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6179 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6180 best_candidate.GetSignatureForError ());
6183 } else if (!best_candidate.Get.IsAccessible (rc)) {
6184 if (best_candidate.HasDifferentAccessibility) {
6185 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6186 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6187 TypeManager.CSharpSignature (best_candidate));
6189 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6190 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6194 if (best_candidate.HasDifferentAccessibility) {
6195 CheckProtectedMemberAccess (rc, best_candidate.Get);
6198 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6202 bool ResolveSetter (ResolveContext rc)
6204 if (!best_candidate.HasSet) {
6205 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6206 GetSignatureForError ());
6210 if (!best_candidate.Set.IsAccessible (rc)) {
6211 if (best_candidate.HasDifferentAccessibility) {
6212 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6213 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6214 GetSignatureForError ());
6216 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6217 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6221 if (best_candidate.HasDifferentAccessibility)
6222 CheckProtectedMemberAccess (rc, best_candidate.Set);
6224 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6230 /// Fully resolved expression that evaluates to an Event
6232 public class EventExpr : MemberExpr, IAssignMethod
6234 readonly EventSpec spec;
6237 public EventExpr (EventSpec spec, Location loc)
6245 protected override TypeSpec DeclaringType {
6247 return spec.DeclaringType;
6251 public override string Name {
6257 public override bool IsInstance {
6259 return !spec.IsStatic;
6263 public override bool IsStatic {
6265 return spec.IsStatic;
6269 public override string KindName {
6270 get { return "event"; }
6273 public MethodSpec Operator {
6281 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6284 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6286 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6287 if (spec.BackingField != null &&
6288 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6290 spec.MemberDefinition.SetIsUsed ();
6292 if (!ec.IsObsolete) {
6293 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6295 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6298 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6299 Error_AssignmentEventOnly (ec);
6301 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6303 InstanceExpression = null;
6305 return ml.ResolveMemberAccess (ec, left, original);
6309 return base.ResolveMemberAccess (ec, left, original);
6312 public override Expression CreateExpressionTree (ResolveContext ec)
6314 throw new NotSupportedException ("ET");
6317 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6319 if (right_side == EmptyExpression.EventAddition) {
6320 op = spec.AccessorAdd;
6321 } else if (right_side == EmptyExpression.EventSubtraction) {
6322 op = spec.AccessorRemove;
6326 Error_AssignmentEventOnly (ec);
6330 op = CandidateToBaseOverride (ec, op);
6334 protected override Expression DoResolve (ResolveContext ec)
6336 eclass = ExprClass.EventAccess;
6337 type = spec.MemberType;
6339 ResolveInstanceExpression (ec, null);
6341 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6342 Error_AssignmentEventOnly (ec);
6345 DoBestMemberChecks (ec, spec);
6349 public override void Emit (EmitContext ec)
6351 throw new NotSupportedException ();
6352 //Error_CannotAssign ();
6355 #region IAssignMethod Members
6357 public void Emit (EmitContext ec, bool leave_copy)
6359 throw new NotImplementedException ();
6362 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6364 if (leave_copy || !isCompound)
6365 throw new NotImplementedException ("EventExpr::EmitAssign");
6367 Arguments args = new Arguments (1);
6368 args.Add (new Argument (source));
6370 var call = new CallEmitter ();
6371 call.InstanceExpression = InstanceExpression;
6372 call.Emit (ec, op, args, loc);
6377 void Error_AssignmentEventOnly (ResolveContext ec)
6379 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6380 ec.Report.Error (79, loc,
6381 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6382 GetSignatureForError ());
6384 ec.Report.Error (70, loc,
6385 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6386 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6390 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6392 name = name.Substring (0, name.LastIndexOf ('.'));
6393 base.Error_CannotCallAbstractBase (rc, name);
6396 public override string GetSignatureForError ()
6398 return TypeManager.CSharpSignature (spec);
6401 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6403 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6407 public class TemporaryVariableReference : VariableReference
6409 public class Declarator : Statement
6411 TemporaryVariableReference variable;
6413 public Declarator (TemporaryVariableReference variable)
6415 this.variable = variable;
6419 protected override void DoEmit (EmitContext ec)
6421 variable.li.CreateBuilder (ec);
6424 public override void Emit (EmitContext ec)
6426 // Don't create sequence point
6430 protected override void CloneTo (CloneContext clonectx, Statement target)
6438 public TemporaryVariableReference (LocalVariable li, Location loc)
6441 this.type = li.Type;
6445 public override bool IsLockedByStatement {
6453 public LocalVariable LocalInfo {
6459 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6461 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6462 return new TemporaryVariableReference (li, loc);
6465 protected override Expression DoResolve (ResolveContext ec)
6467 eclass = ExprClass.Variable;
6470 // Don't capture temporary variables except when using
6471 // state machine redirection and block yields
6473 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6474 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6475 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6476 storey.CaptureLocalVariable (ec, li);
6482 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6484 return Resolve (ec);
6487 public override void Emit (EmitContext ec)
6489 li.CreateBuilder (ec);
6494 public void EmitAssign (EmitContext ec, Expression source)
6496 li.CreateBuilder (ec);
6498 EmitAssign (ec, source, false, false);
6501 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6503 return li.HoistedVariant;
6506 public override bool IsFixed {
6507 get { return true; }
6510 public override bool IsRef {
6511 get { return false; }
6514 public override string Name {
6515 get { throw new NotImplementedException (); }
6518 public override void SetHasAddressTaken ()
6520 throw new NotImplementedException ();
6523 protected override ILocalVariable Variable {
6527 public override VariableInfo VariableInfo {
6528 get { return null; }
6531 public override void VerifyAssigned (ResolveContext rc)
6537 /// Handles `var' contextual keyword; var becomes a keyword only
6538 /// if no type called var exists in a variable scope
6540 class VarExpr : SimpleName
6542 public VarExpr (Location loc)
6547 public bool InferType (ResolveContext ec, Expression right_side)
6550 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6552 type = right_side.Type;
6553 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6554 ec.Report.Error (815, loc,
6555 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6556 type.GetSignatureForError ());
6560 eclass = ExprClass.Variable;
6564 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6566 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6567 base.Error_TypeOrNamespaceNotFound (ec);
6569 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");