2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 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 rc.Report.SymbolRelatedToPreviousError (type);
327 if (rc.CurrentInitializerVariable != null) {
328 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
329 type.GetSignatureForError (), GetSignatureForError ());
331 rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
332 GetSignatureForError ());
335 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
339 protected void Error_VoidPointerOperation (ResolveContext rc)
341 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
344 public ResolveFlags ExprClassToResolveFlags {
348 case ExprClass.Namespace:
349 return ResolveFlags.Type;
351 case ExprClass.MethodGroup:
352 return ResolveFlags.MethodGroup;
354 case ExprClass.TypeParameter:
355 return ResolveFlags.TypeParameter;
357 case ExprClass.Value:
358 case ExprClass.Variable:
359 case ExprClass.PropertyAccess:
360 case ExprClass.EventAccess:
361 case ExprClass.IndexerAccess:
362 return ResolveFlags.VariableOrValue;
365 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
370 public virtual string GetSignatureForError ()
372 return type.GetDefinition ().GetSignatureForError ();
376 /// Resolves an expression and performs semantic analysis on it.
380 /// Currently Resolve wraps DoResolve to perform sanity
381 /// checking and assertion checking on what we expect from Resolve.
383 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
385 if (eclass != ExprClass.Unresolved)
395 if ((flags & e.ExprClassToResolveFlags) == 0) {
396 e.Error_UnexpectedKind (ec, flags, loc);
401 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
404 } catch (Exception ex) {
405 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
408 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
409 return ErrorExpression.Instance; // TODO: Add location
414 /// Resolves an expression and performs semantic analysis on it.
416 public Expression Resolve (ResolveContext rc)
418 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
422 /// Resolves an expression for LValue assignment
426 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
427 /// checking and assertion checking on what we expect from Resolve
429 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
431 int errors = ec.Report.Errors;
432 bool out_access = right_side == EmptyExpression.OutAccess;
434 Expression e = DoResolveLValue (ec, right_side);
436 if (e != null && out_access && !(e is IMemoryLocation)) {
437 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
438 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
440 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
441 // e.GetType () + " " + e.GetSignatureForError ());
446 if (errors == ec.Report.Errors) {
448 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
450 Error_ValueAssignment (ec, right_side);
455 if (e.eclass == ExprClass.Unresolved)
456 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
458 if ((e.type == null) && !(e is GenericTypeExpr))
459 throw new Exception ("Expression " + e + " did not set its type after Resolve");
464 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
466 rc.Module.Compiler.Report.Error (182, loc,
467 "An attribute argument must be a constant expression, typeof expression or array creation expression");
471 /// Emits the code for the expression
475 /// The Emit method is invoked to generate the code
476 /// for the expression.
478 public abstract void Emit (EmitContext ec);
481 // Emit code to branch to @target if this expression is equivalent to @on_true.
482 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
483 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
484 // including the use of conditional branches. Note also that a branch MUST be emitted
485 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
488 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
491 // Emit this expression for its side effects, not for its value.
492 // The default implementation is to emit the value, and then throw it away.
493 // Subclasses can provide more efficient implementations, but those MUST be equivalent
494 public virtual void EmitSideEffect (EmitContext ec)
497 ec.Emit (OpCodes.Pop);
501 // Emits the expression into temporary field variable. The method
502 // should be used for await expressions only
504 public virtual Expression EmitToField (EmitContext ec)
507 // This is the await prepare Emit method. When emitting code like
508 // a + b we emit code like
514 // For await a + await b we have to interfere the flow to keep the
515 // stack clean because await yields from the expression. The emit
518 // a = a.EmitToField () // a is changed to temporary field access
519 // b = b.EmitToField ()
525 // The idea is to emit expression and leave the stack empty with
526 // result value still available.
528 // Expressions should override this default implementation when
529 // optimized version can be provided (e.g. FieldExpr)
532 // We can optimize for side-effect free expressions, they can be
533 // emitted out of order
535 if (IsSideEffectFree)
538 bool needs_temporary = ContainsEmitWithAwait ();
539 if (!needs_temporary)
542 // Emit original code
543 var field = EmitToFieldSource (ec);
546 // Store the result to temporary field when we
547 // cannot load `this' directly
549 field = ec.GetTemporaryField (type);
550 if (needs_temporary) {
552 // Create temporary local (we cannot load `this' before Emit)
554 var temp = ec.GetTemporaryLocal (type);
555 ec.Emit (OpCodes.Stloc, temp);
558 ec.Emit (OpCodes.Ldloc, temp);
559 field.EmitAssignFromStack (ec);
561 ec.FreeTemporaryLocal (temp, type);
563 field.EmitAssignFromStack (ec);
570 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
573 // Default implementation calls Emit method
579 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
581 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
582 bool contains_await = false;
584 for (int i = 1; i < expressions.Count; ++i) {
585 if (expressions[i].ContainsEmitWithAwait ()) {
586 contains_await = true;
591 if (contains_await) {
592 for (int i = 0; i < expressions.Count; ++i) {
593 expressions[i] = expressions[i].EmitToField (ec);
598 for (int i = 0; i < expressions.Count; ++i) {
599 expressions[i].Emit (ec);
604 /// Protected constructor. Only derivate types should
605 /// be able to be created
608 protected Expression ()
613 /// Returns a fully formed expression after a MemberLookup
616 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
618 if (spec is EventSpec)
619 return new EventExpr ((EventSpec) spec, loc);
620 if (spec is ConstSpec)
621 return new ConstantExpr ((ConstSpec) spec, loc);
622 if (spec is FieldSpec)
623 return new FieldExpr ((FieldSpec) spec, loc);
624 if (spec is PropertySpec)
625 return new PropertyExpr ((PropertySpec) spec, loc);
626 if (spec is TypeSpec)
627 return new TypeExpression (((TypeSpec) spec), loc);
632 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
634 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
636 rc.Report.SymbolRelatedToPreviousError (type);
638 // Report meaningful error for struct as they always have default ctor in C# context
639 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
641 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
642 type.GetSignatureForError ());
648 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
649 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
650 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
653 return r.ResolveMember<MethodSpec> (rc, ref args);
657 public enum MemberLookupRestrictions
666 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
667 // `qualifier_type' or null to lookup members in the current class.
669 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
671 var members = MemberCache.FindMembers (queried_type, name, false);
675 MemberSpec non_method = null;
676 MemberSpec ambig_non_method = null;
678 for (int i = 0; i < members.Count; ++i) {
679 var member = members[i];
681 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
682 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
685 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
688 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
692 if (!member.IsAccessible (rc))
696 // With runtime binder we can have a situation where queried type is inaccessible
697 // because it came via dynamic object, the check about inconsisted accessibility
698 // had no effect as the type was unknown during compilation
701 // private class N { }
703 // public dynamic Foo ()
709 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
713 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
714 if (member is MethodSpec)
715 return new MethodGroupExpr (members, queried_type, loc);
717 if (!Invocation.IsMemberInvocable (member))
721 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
723 } else if (!errorMode && !member.IsNotCSharpCompatible) {
724 ambig_non_method = member;
728 if (non_method != null) {
729 if (ambig_non_method != null && rc != null) {
730 var report = rc.Module.Compiler.Report;
731 report.SymbolRelatedToPreviousError (non_method);
732 report.SymbolRelatedToPreviousError (ambig_non_method);
733 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
734 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
737 if (non_method is MethodSpec)
738 return new MethodGroupExpr (members, queried_type, loc);
740 return ExprClassFromMemberInfo (non_method, loc);
743 if (members[0].DeclaringType.BaseType == null)
746 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
748 } while (members != null);
753 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
755 throw new NotImplementedException ();
758 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
760 if (t == InternalType.ErrorType)
763 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
764 oper, t.GetSignatureForError ());
767 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
769 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
773 /// Returns an expression that can be used to invoke operator true
774 /// on the expression if it exists.
776 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
778 return GetOperatorTrueOrFalse (ec, e, true, loc);
782 /// Returns an expression that can be used to invoke operator false
783 /// on the expression if it exists.
785 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
787 return GetOperatorTrueOrFalse (ec, e, false, loc);
790 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
792 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
793 var methods = MemberCache.GetUserOperator (e.type, op, false);
797 Arguments arguments = new Arguments (1);
798 arguments.Add (new Argument (e));
800 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
801 var oper = res.ResolveOperator (ec, ref arguments);
806 return new UserOperatorCall (oper, arguments, null, loc);
809 public virtual string ExprClassName
813 case ExprClass.Unresolved:
815 case ExprClass.Value:
817 case ExprClass.Variable:
819 case ExprClass.Namespace:
823 case ExprClass.MethodGroup:
824 return "method group";
825 case ExprClass.PropertyAccess:
826 return "property access";
827 case ExprClass.EventAccess:
828 return "event access";
829 case ExprClass.IndexerAccess:
830 return "indexer access";
831 case ExprClass.Nothing:
833 case ExprClass.TypeParameter:
834 return "type parameter";
836 throw new Exception ("Should not happen");
841 /// Reports that we were expecting `expr' to be of class `expected'
843 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
845 var name = memberExpr.GetSignatureForError ();
847 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
850 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
852 string [] valid = new string [4];
855 if ((flags & ResolveFlags.VariableOrValue) != 0) {
856 valid [count++] = "variable";
857 valid [count++] = "value";
860 if ((flags & ResolveFlags.Type) != 0)
861 valid [count++] = "type";
863 if ((flags & ResolveFlags.MethodGroup) != 0)
864 valid [count++] = "method group";
867 valid [count++] = "unknown";
869 StringBuilder sb = new StringBuilder (valid [0]);
870 for (int i = 1; i < count - 1; i++) {
872 sb.Append (valid [i]);
875 sb.Append ("' or `");
876 sb.Append (valid [count - 1]);
879 ec.Report.Error (119, loc,
880 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
883 public static void UnsafeError (ResolveContext ec, Location loc)
885 UnsafeError (ec.Report, loc);
888 public static void UnsafeError (Report Report, Location loc)
890 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
894 // Converts `source' to an int, uint, long or ulong.
896 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
898 var btypes = ec.BuiltinTypes;
900 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
901 Arguments args = new Arguments (1);
902 args.Add (new Argument (source));
903 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
906 Expression converted;
908 using (ec.Set (ResolveContext.Options.CheckedScope)) {
909 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
910 if (converted == null)
911 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
912 if (converted == null)
913 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
914 if (converted == null)
915 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
917 if (converted == null) {
918 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
924 // Only positive constants are allowed at compile time
926 Constant c = converted as Constant;
927 if (c != null && c.IsNegative)
928 Error_NegativeArrayIndex (ec, source.loc);
930 // No conversion needed to array index
931 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
934 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
938 // Derived classes implement this method by cloning the fields that
939 // could become altered during the Resolve stage
941 // Only expressions that are created for the parser need to implement
944 protected virtual void CloneTo (CloneContext clonectx, Expression target)
946 throw new NotImplementedException (
948 "CloneTo not implemented for expression {0}", this.GetType ()));
952 // Clones an expression created by the parser.
954 // We only support expressions created by the parser so far, not
955 // expressions that have been resolved (many more classes would need
956 // to implement CloneTo).
958 // This infrastructure is here merely for Lambda expressions which
959 // compile the same code using different type values for the same
960 // arguments to find the correct overload
962 public virtual Expression Clone (CloneContext clonectx)
964 Expression cloned = (Expression) MemberwiseClone ();
965 CloneTo (clonectx, cloned);
971 // Implementation of expression to expression tree conversion
973 public abstract Expression CreateExpressionTree (ResolveContext ec);
975 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
977 return CreateExpressionFactoryCall (ec, name, null, args, loc);
980 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
982 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
985 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
987 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
990 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
992 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
996 return new TypeExpression (t, loc);
1000 // Implemented by all expressions which support conversion from
1001 // compiler expression to invokable runtime expression. Used by
1002 // dynamic C# binder.
1004 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1006 throw new NotImplementedException ("MakeExpression for " + GetType ());
1009 public virtual object Accept (StructuralVisitor visitor)
1011 return visitor.Visit (this);
1016 /// This is just a base class for expressions that can
1017 /// appear on statements (invocations, object creation,
1018 /// assignments, post/pre increment and decrement). The idea
1019 /// being that they would support an extra Emition interface that
1020 /// does not leave a result on the stack.
1022 public abstract class ExpressionStatement : Expression {
1024 public ExpressionStatement ResolveStatement (BlockContext ec)
1026 Expression e = Resolve (ec);
1030 ExpressionStatement es = e as ExpressionStatement;
1032 Error_InvalidExpressionStatement (ec);
1034 if (ec.CurrentAnonymousMethod is AsyncInitializer && !(e is Assign) &&
1035 (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
1036 ec.Report.Warning (4014, 1, e.Location,
1037 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1044 /// Requests the expression to be emitted in a `statement'
1045 /// context. This means that no new value is left on the
1046 /// stack after invoking this method (constrasted with
1047 /// Emit that will always leave a value on the stack).
1049 public abstract void EmitStatement (EmitContext ec);
1051 public override void EmitSideEffect (EmitContext ec)
1058 /// This kind of cast is used to encapsulate the child
1059 /// whose type is child.Type into an expression that is
1060 /// reported to return "return_type". This is used to encapsulate
1061 /// expressions which have compatible types, but need to be dealt
1062 /// at higher levels with.
1064 /// For example, a "byte" expression could be encapsulated in one
1065 /// of these as an "unsigned int". The type for the expression
1066 /// would be "unsigned int".
1069 public abstract class TypeCast : Expression
1071 protected readonly Expression child;
1073 protected TypeCast (Expression child, TypeSpec return_type)
1075 eclass = child.eclass;
1076 loc = child.Location;
1081 public Expression Child {
1087 public override bool ContainsEmitWithAwait ()
1089 return child.ContainsEmitWithAwait ();
1092 public override Expression CreateExpressionTree (ResolveContext ec)
1094 Arguments args = new Arguments (2);
1095 args.Add (new Argument (child.CreateExpressionTree (ec)));
1096 args.Add (new Argument (new TypeOf (type, loc)));
1098 if (type.IsPointer || child.Type.IsPointer)
1099 Error_PointerInsideExpressionTree (ec);
1101 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1104 protected override Expression DoResolve (ResolveContext ec)
1106 // This should never be invoked, we are born in fully
1107 // initialized state.
1112 public override void Emit (EmitContext ec)
1117 public override SLE.Expression MakeExpression (BuilderContext ctx)
1120 return base.MakeExpression (ctx);
1122 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1123 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1124 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1128 protected override void CloneTo (CloneContext clonectx, Expression t)
1133 public override bool IsNull {
1134 get { return child.IsNull; }
1138 public class EmptyCast : TypeCast {
1139 EmptyCast (Expression child, TypeSpec target_type)
1140 : base (child, target_type)
1144 public static Expression Create (Expression child, TypeSpec type)
1146 Constant c = child as Constant;
1148 return new EmptyConstantCast (c, type);
1150 EmptyCast e = child as EmptyCast;
1152 return new EmptyCast (e.child, type);
1154 return new EmptyCast (child, type);
1157 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1159 child.EmitBranchable (ec, label, on_true);
1162 public override void EmitSideEffect (EmitContext ec)
1164 child.EmitSideEffect (ec);
1169 // Used for predefined type user operator (no obsolete check, etc.)
1171 public class OperatorCast : TypeCast
1173 readonly MethodSpec conversion_operator;
1175 public OperatorCast (Expression expr, TypeSpec target_type)
1176 : this (expr, target_type, target_type, false)
1180 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1181 : this (expr, target_type, target_type, find_explicit)
1185 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1186 : base (expr, returnType)
1188 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1189 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1192 foreach (MethodSpec oper in mi) {
1193 if (oper.ReturnType != returnType)
1196 if (oper.Parameters.Types[0] == expr.Type) {
1197 conversion_operator = oper;
1203 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1204 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1207 public override void Emit (EmitContext ec)
1210 ec.Emit (OpCodes.Call, conversion_operator);
1215 // Constant specialization of EmptyCast.
1216 // We need to special case this since an empty cast of
1217 // a constant is still a constant.
1219 public class EmptyConstantCast : Constant
1221 public readonly Constant child;
1223 public EmptyConstantCast (Constant child, TypeSpec type)
1224 : base (child.Location)
1227 throw new ArgumentNullException ("child");
1230 this.eclass = child.eclass;
1234 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1236 if (child.Type == target_type)
1239 // FIXME: check that 'type' can be converted to 'target_type' first
1240 return child.ConvertExplicitly (in_checked_context, target_type);
1243 public override Expression CreateExpressionTree (ResolveContext ec)
1245 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1246 child.CreateExpressionTree (ec),
1247 new TypeOf (type, loc));
1250 Error_PointerInsideExpressionTree (ec);
1252 return CreateExpressionFactoryCall (ec, "Convert", args);
1255 public override bool IsDefaultValue {
1256 get { return child.IsDefaultValue; }
1259 public override bool IsNegative {
1260 get { return child.IsNegative; }
1263 public override bool IsNull {
1264 get { return child.IsNull; }
1267 public override bool IsOneInteger {
1268 get { return child.IsOneInteger; }
1271 public override bool IsSideEffectFree {
1273 return child.IsSideEffectFree;
1277 public override bool IsZeroInteger {
1278 get { return child.IsZeroInteger; }
1281 public override void Emit (EmitContext ec)
1286 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1288 child.EmitBranchable (ec, label, on_true);
1290 // Only to make verifier happy
1291 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1292 ec.Emit (OpCodes.Unbox_Any, type);
1295 public override void EmitSideEffect (EmitContext ec)
1297 child.EmitSideEffect (ec);
1300 public override object GetValue ()
1302 return child.GetValue ();
1305 public override string GetValueAsLiteral ()
1307 return child.GetValueAsLiteral ();
1310 public override long GetValueAsLong ()
1312 return child.GetValueAsLong ();
1315 public override Constant ConvertImplicitly (TypeSpec target_type)
1317 if (type == target_type)
1320 // FIXME: Do we need to check user conversions?
1321 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1324 return child.ConvertImplicitly (target_type);
1329 /// This class is used to wrap literals which belong inside Enums
1331 public class EnumConstant : Constant
1333 public Constant Child;
1335 public EnumConstant (Constant child, TypeSpec enum_type)
1336 : base (child.Location)
1340 this.eclass = ExprClass.Value;
1341 this.type = enum_type;
1344 protected EnumConstant (Location loc)
1349 public override void Emit (EmitContext ec)
1354 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1356 Child.EncodeAttributeValue (rc, enc, Child.Type);
1359 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1361 Child.EmitBranchable (ec, label, on_true);
1364 public override void EmitSideEffect (EmitContext ec)
1366 Child.EmitSideEffect (ec);
1369 public override string GetSignatureForError()
1371 return TypeManager.CSharpName (Type);
1374 public override object GetValue ()
1376 return Child.GetValue ();
1380 public override object GetTypedValue ()
1383 // The method can be used in dynamic context only (on closed types)
1385 // System.Enum.ToObject cannot be called on dynamic types
1386 // EnumBuilder has to be used, but we cannot use EnumBuilder
1387 // because it does not properly support generics
1389 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1393 public override string GetValueAsLiteral ()
1395 return Child.GetValueAsLiteral ();
1398 public override long GetValueAsLong ()
1400 return Child.GetValueAsLong ();
1403 public EnumConstant Increment()
1405 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1408 public override bool IsDefaultValue {
1410 return Child.IsDefaultValue;
1414 public override bool IsSideEffectFree {
1416 return Child.IsSideEffectFree;
1420 public override bool IsZeroInteger {
1421 get { return Child.IsZeroInteger; }
1424 public override bool IsNegative {
1426 return Child.IsNegative;
1430 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1432 if (Child.Type == target_type)
1435 return Child.ConvertExplicitly (in_checked_context, target_type);
1438 public override Constant ConvertImplicitly (TypeSpec type)
1440 if (this.type == type) {
1444 if (!Convert.ImplicitStandardConversionExists (this, type)){
1448 return Child.ConvertImplicitly (type);
1453 /// This kind of cast is used to encapsulate Value Types in objects.
1455 /// The effect of it is to box the value type emitted by the previous
1458 public class BoxedCast : TypeCast {
1460 public BoxedCast (Expression expr, TypeSpec target_type)
1461 : base (expr, target_type)
1463 eclass = ExprClass.Value;
1466 protected override Expression DoResolve (ResolveContext ec)
1468 // This should never be invoked, we are born in fully
1469 // initialized state.
1474 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1476 // Only boxing to object type is supported
1477 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1478 base.EncodeAttributeValue (rc, enc, targetType);
1482 enc.Encode (child.Type);
1483 child.EncodeAttributeValue (rc, enc, child.Type);
1486 public override void Emit (EmitContext ec)
1490 ec.Emit (OpCodes.Box, child.Type);
1493 public override void EmitSideEffect (EmitContext ec)
1495 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1496 // so, we need to emit the box+pop instructions in most cases
1497 if (child.Type.IsStruct &&
1498 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1499 child.EmitSideEffect (ec);
1501 base.EmitSideEffect (ec);
1505 public class UnboxCast : TypeCast {
1506 public UnboxCast (Expression expr, TypeSpec return_type)
1507 : base (expr, return_type)
1511 protected override Expression DoResolve (ResolveContext ec)
1513 // This should never be invoked, we are born in fully
1514 // initialized state.
1519 public override void Emit (EmitContext ec)
1523 ec.Emit (OpCodes.Unbox_Any, type);
1528 /// This is used to perform explicit numeric conversions.
1530 /// Explicit numeric conversions might trigger exceptions in a checked
1531 /// context, so they should generate the conv.ovf opcodes instead of
1534 public class ConvCast : TypeCast {
1535 public enum Mode : byte {
1536 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1538 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1539 U2_I1, U2_U1, U2_I2, U2_CH,
1540 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1541 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1542 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1543 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1544 CH_I1, CH_U1, CH_I2,
1545 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1546 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1552 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1553 : base (child, return_type)
1558 protected override Expression DoResolve (ResolveContext ec)
1560 // This should never be invoked, we are born in fully
1561 // initialized state.
1566 public override string ToString ()
1568 return String.Format ("ConvCast ({0}, {1})", mode, child);
1571 public override void Emit (EmitContext ec)
1575 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1577 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1578 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1579 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1580 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1581 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1584 case Mode.U1_CH: /* nothing */ break;
1586 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1587 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1588 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1589 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1590 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1591 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1593 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1594 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1595 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1596 case Mode.U2_CH: /* nothing */ break;
1598 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1599 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1600 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1601 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1602 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1603 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1604 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1607 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1608 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1609 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1610 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1611 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1613 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1614 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1615 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1616 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1618 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1619 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1620 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1623 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1624 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1625 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1626 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1627 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1628 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1629 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1630 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1631 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1633 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1634 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1635 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1637 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1638 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1639 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1640 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1641 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1642 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1643 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1644 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1645 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1647 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1648 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1649 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1650 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1651 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1652 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1653 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1654 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1655 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1656 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1658 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1662 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1663 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1665 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1666 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1672 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1673 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1675 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1676 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.U2_CH: /* nothing */ break;
1683 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1684 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1685 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1686 case Mode.I4_U4: /* nothing */ break;
1687 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1689 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1692 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1693 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1694 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1695 case Mode.U4_I4: /* nothing */ break;
1696 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1698 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.I8_U8: /* nothing */ break;
1705 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1708 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1709 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1710 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1711 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1713 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1714 case Mode.U8_I8: /* nothing */ break;
1715 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1716 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1718 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1719 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1720 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1722 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1723 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1724 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1725 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1726 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1727 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1728 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1729 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1730 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1732 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1733 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1734 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1735 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1736 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1737 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1738 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1739 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1740 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1741 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1743 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1749 class OpcodeCast : TypeCast
1753 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1754 : base (child, return_type)
1759 protected override Expression DoResolve (ResolveContext ec)
1761 // This should never be invoked, we are born in fully
1762 // initialized state.
1767 public override void Emit (EmitContext ec)
1773 public TypeSpec UnderlyingType {
1774 get { return child.Type; }
1779 // Opcode casts expression with 2 opcodes but only
1780 // single expression tree node
1782 class OpcodeCastDuplex : OpcodeCast
1784 readonly OpCode second;
1786 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1787 : base (child, returnType, first)
1789 this.second = second;
1792 public override void Emit (EmitContext ec)
1800 /// This kind of cast is used to encapsulate a child and cast it
1801 /// to the class requested
1803 public sealed class ClassCast : TypeCast {
1804 readonly bool forced;
1806 public ClassCast (Expression child, TypeSpec return_type)
1807 : base (child, return_type)
1811 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1812 : base (child, return_type)
1814 this.forced = forced;
1817 public override void Emit (EmitContext ec)
1821 bool gen = TypeManager.IsGenericParameter (child.Type);
1823 ec.Emit (OpCodes.Box, child.Type);
1825 if (type.IsGenericParameter) {
1826 ec.Emit (OpCodes.Unbox_Any, type);
1833 ec.Emit (OpCodes.Castclass, type);
1838 // Created during resolving pahse when an expression is wrapped or constantified
1839 // and original expression can be used later (e.g. for expression trees)
1841 public class ReducedExpression : Expression
1843 sealed class ReducedConstantExpression : EmptyConstantCast
1845 readonly Expression orig_expr;
1847 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1848 : base (expr, expr.Type)
1850 this.orig_expr = orig_expr;
1853 public override Constant ConvertImplicitly (TypeSpec target_type)
1855 Constant c = base.ConvertImplicitly (target_type);
1857 c = new ReducedConstantExpression (c, orig_expr);
1862 public override Expression CreateExpressionTree (ResolveContext ec)
1864 return orig_expr.CreateExpressionTree (ec);
1867 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1869 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1871 c = new ReducedConstantExpression (c, orig_expr);
1875 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1878 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1880 if (orig_expr is Conditional)
1881 child.EncodeAttributeValue (rc, enc, targetType);
1883 base.EncodeAttributeValue (rc, enc, targetType);
1887 sealed class ReducedExpressionStatement : ExpressionStatement
1889 readonly Expression orig_expr;
1890 readonly ExpressionStatement stm;
1892 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1894 this.orig_expr = orig;
1896 this.eclass = stm.eclass;
1897 this.type = stm.Type;
1899 this.loc = orig.Location;
1902 public override bool ContainsEmitWithAwait ()
1904 return stm.ContainsEmitWithAwait ();
1907 public override Expression CreateExpressionTree (ResolveContext ec)
1909 return orig_expr.CreateExpressionTree (ec);
1912 protected override Expression DoResolve (ResolveContext ec)
1917 public override void Emit (EmitContext ec)
1922 public override void EmitStatement (EmitContext ec)
1924 stm.EmitStatement (ec);
1928 readonly Expression expr, orig_expr;
1930 private ReducedExpression (Expression expr, Expression orig_expr)
1933 this.eclass = expr.eclass;
1934 this.type = expr.Type;
1935 this.orig_expr = orig_expr;
1936 this.loc = orig_expr.Location;
1941 public override bool IsSideEffectFree {
1943 return expr.IsSideEffectFree;
1947 public Expression OriginalExpression {
1955 public override bool ContainsEmitWithAwait ()
1957 return expr.ContainsEmitWithAwait ();
1961 // Creates fully resolved expression switcher
1963 public static Constant Create (Constant expr, Expression original_expr)
1965 if (expr.eclass == ExprClass.Unresolved)
1966 throw new ArgumentException ("Unresolved expression");
1968 return new ReducedConstantExpression (expr, original_expr);
1971 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1973 return new ReducedExpressionStatement (s, orig);
1976 public static Expression Create (Expression expr, Expression original_expr)
1978 return Create (expr, original_expr, true);
1982 // Creates unresolved reduce expression. The original expression has to be
1983 // already resolved. Created expression is constant based based on `expr'
1984 // value unless canBeConstant is used
1986 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1988 if (canBeConstant) {
1989 Constant c = expr as Constant;
1991 return Create (c, original_expr);
1994 ExpressionStatement s = expr as ExpressionStatement;
1996 return Create (s, original_expr);
1998 if (expr.eclass == ExprClass.Unresolved)
1999 throw new ArgumentException ("Unresolved expression");
2001 return new ReducedExpression (expr, original_expr);
2004 public override Expression CreateExpressionTree (ResolveContext ec)
2006 return orig_expr.CreateExpressionTree (ec);
2009 protected override Expression DoResolve (ResolveContext ec)
2014 public override void Emit (EmitContext ec)
2019 public override Expression EmitToField (EmitContext ec)
2021 return expr.EmitToField(ec);
2024 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2026 expr.EmitBranchable (ec, target, on_true);
2029 public override SLE.Expression MakeExpression (BuilderContext ctx)
2031 return orig_expr.MakeExpression (ctx);
2036 // Standard composite pattern
2038 public abstract class CompositeExpression : Expression
2040 protected Expression expr;
2042 protected CompositeExpression (Expression expr)
2045 this.loc = expr.Location;
2048 public override bool ContainsEmitWithAwait ()
2050 return expr.ContainsEmitWithAwait ();
2053 public override Expression CreateExpressionTree (ResolveContext rc)
2055 return expr.CreateExpressionTree (rc);
2058 public Expression Child {
2059 get { return expr; }
2062 protected override Expression DoResolve (ResolveContext rc)
2064 expr = expr.Resolve (rc);
2067 eclass = expr.eclass;
2073 public override void Emit (EmitContext ec)
2078 public override bool IsNull {
2079 get { return expr.IsNull; }
2084 // Base of expressions used only to narrow resolve flow
2086 public abstract class ShimExpression : Expression
2088 protected Expression expr;
2090 protected ShimExpression (Expression expr)
2095 public Expression Expr {
2101 protected override void CloneTo (CloneContext clonectx, Expression t)
2106 ShimExpression target = (ShimExpression) t;
2107 target.expr = expr.Clone (clonectx);
2110 public override bool ContainsEmitWithAwait ()
2112 return expr.ContainsEmitWithAwait ();
2115 public override Expression CreateExpressionTree (ResolveContext ec)
2117 throw new NotSupportedException ("ET");
2120 public override void Emit (EmitContext ec)
2122 throw new InternalErrorException ("Missing Resolve call");
2128 // Unresolved type name expressions
2130 public abstract class ATypeNameExpression : FullNamedExpression
2133 protected TypeArguments targs;
2135 protected ATypeNameExpression (string name, Location l)
2141 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2148 protected ATypeNameExpression (string name, int arity, Location l)
2149 : this (name, new UnboundTypeArguments (arity), l)
2155 protected int Arity {
2157 return targs == null ? 0 : targs.Count;
2161 public bool HasTypeArguments {
2163 return targs != null && !targs.IsEmpty;
2167 public string Name {
2176 public TypeArguments TypeArguments {
2184 public override bool Equals (object obj)
2186 ATypeNameExpression atne = obj as ATypeNameExpression;
2187 return atne != null && atne.Name == Name &&
2188 (targs == null || targs.Equals (atne.targs));
2191 public override int GetHashCode ()
2193 return Name.GetHashCode ();
2196 // TODO: Move it to MemberCore
2197 public static string GetMemberType (MemberCore mc)
2203 if (mc is FieldBase)
2205 if (mc is MethodCore)
2207 if (mc is EnumMember)
2215 public override string GetSignatureForError ()
2217 if (targs != null) {
2218 return Name + "<" + targs.GetSignatureForError () + ">";
2224 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2228 /// SimpleName expressions are formed of a single word and only happen at the beginning
2229 /// of a dotted-name.
2231 public class SimpleName : ATypeNameExpression
2233 public SimpleName (string name, Location l)
2238 public SimpleName (string name, TypeArguments args, Location l)
2239 : base (name, args, l)
2243 public SimpleName (string name, int arity, Location l)
2244 : base (name, arity, l)
2248 public SimpleName GetMethodGroup ()
2250 return new SimpleName (Name, targs, loc);
2253 protected override Expression DoResolve (ResolveContext rc)
2255 var e = SimpleNameResolve (rc, null, false);
2257 var fe = e as FieldExpr;
2259 fe.VerifyAssignedStructField (rc, null);
2265 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2267 return SimpleNameResolve (ec, right_side, false);
2270 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2272 if (ctx.CurrentType != null) {
2273 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2274 if (member != null) {
2275 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2280 var report = ctx.Module.Compiler.Report;
2282 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2283 if (retval != null) {
2284 report.SymbolRelatedToPreviousError (retval.Type);
2285 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2289 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2290 if (retval != null) {
2291 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2295 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2296 if (ns_candidates != null) {
2297 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2298 report.Error (246, loc,
2299 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2302 report.Error (246, loc,
2303 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2308 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2310 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2313 if (fne.Type != null && Arity > 0) {
2314 if (HasTypeArguments) {
2315 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2316 if (ct.ResolveAsType (ec) == null)
2322 return new GenericOpenTypeExpr (fne.Type, loc);
2326 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2328 if (!(fne is Namespace))
2332 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2333 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2334 ec.Module.Compiler.Report.Error (1980, Location,
2335 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2336 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2339 fne = new DynamicTypeExpr (loc);
2340 fne.ResolveAsType (ec);
2346 Error_TypeOrNamespaceNotFound (ec);
2350 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2352 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2355 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2357 int lookup_arity = Arity;
2358 bool errorMode = false;
2360 Block current_block = rc.CurrentBlock;
2361 INamedBlockVariable variable = null;
2362 bool variable_found = false;
2366 // Stage 1: binding to local variables or parameters
2368 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2370 if (current_block != null && lookup_arity == 0) {
2371 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2372 if (!variable.IsDeclared) {
2373 // We found local name in accessible block but it's not
2374 // initialized yet, maybe the user wanted to bind to something else
2376 variable_found = true;
2378 e = variable.CreateReferenceExpression (rc, loc);
2381 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2390 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2392 TypeSpec member_type = rc.CurrentType;
2393 for (; member_type != null; member_type = member_type.DeclaringType) {
2394 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2398 var me = e as MemberExpr;
2400 // The name matches a type, defer to ResolveAsTypeStep
2408 if (variable != null) {
2409 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2410 rc.Report.Error (844, loc,
2411 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2412 Name, me.GetSignatureForError ());
2416 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2417 // Leave it to overload resolution to report correct error
2419 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2420 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2423 // LAMESPEC: again, ignores InvocableOnly
2424 if (variable != null) {
2425 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2426 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2430 // MemberLookup does not check accessors availability, this is actually needed for properties only
2432 var pe = me as PropertyExpr;
2435 // Break as there is no other overload available anyway
2436 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2437 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2440 pe.Getter = pe.PropertyInfo.Get;
2442 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2445 pe.Setter = pe.PropertyInfo.Set;
2450 // TODO: It's used by EventExpr -> FieldExpr transformation only
2451 // TODO: Should go to MemberAccess
2452 me = me.ResolveMemberAccess (rc, null, null);
2456 me.SetTypeArguments (rc, targs);
2463 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2465 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2466 if (IsPossibleTypeOrNamespace (rc)) {
2467 if (variable != null) {
2468 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2469 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2472 return ResolveAsTypeOrNamespace (rc);
2477 if (variable_found) {
2478 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2481 var tparams = rc.CurrentTypeParameters;
2482 if (tparams != null) {
2483 if (tparams.Find (Name) != null) {
2484 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2489 var ct = rc.CurrentType;
2491 if (ct.MemberDefinition.TypeParametersCount > 0) {
2492 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2493 if (ctp.Name == Name) {
2494 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2500 ct = ct.DeclaringType;
2501 } while (ct != null);
2504 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2505 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2507 rc.Report.SymbolRelatedToPreviousError (e.Type);
2508 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2512 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2514 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2515 return ErrorExpression.Instance;
2519 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2521 if (e.Type.Arity != Arity) {
2522 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2526 if (e is TypeExpr) {
2527 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2532 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2535 return ErrorExpression.Instance;
2538 if (rc.Module.Evaluator != null) {
2539 var fi = rc.Module.Evaluator.LookupField (Name);
2541 return new FieldExpr (fi.Item1, loc);
2549 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2551 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2556 if (right_side != null) {
2557 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2558 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2562 e = e.ResolveLValue (ec, right_side);
2570 public override object Accept (StructuralVisitor visitor)
2572 return visitor.Visit (this);
2577 /// Represents a namespace or a type. The name of the class was inspired by
2578 /// section 10.8.1 (Fully Qualified Names).
2580 public abstract class FullNamedExpression : Expression
2582 protected override void CloneTo (CloneContext clonectx, Expression target)
2584 // Do nothing, most unresolved type expressions cannot be
2585 // resolved to different type
2588 public override bool ContainsEmitWithAwait ()
2593 public override Expression CreateExpressionTree (ResolveContext ec)
2595 throw new NotSupportedException ("ET");
2598 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2601 // This is used to resolve the expression as a type, a null
2602 // value will be returned if the expression is not a type
2605 public override TypeSpec ResolveAsType (IMemberContext mc)
2607 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2612 TypeExpr te = fne as TypeExpr;
2614 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2622 var dep = type.GetMissingDependencies ();
2624 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2627 if (type.Kind == MemberKind.Void) {
2628 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2632 // Obsolete checks cannot be done when resolving base context as they
2633 // require type dependencies to be set but we are in process of resolving them
2635 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2636 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2637 if (obsolete_attr != null && !mc.IsObsolete) {
2638 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2646 public override void Emit (EmitContext ec)
2648 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2649 GetSignatureForError ());
2654 /// Expression that evaluates to a type
2656 public abstract class TypeExpr : FullNamedExpression
2658 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2664 protected sealed override Expression DoResolve (ResolveContext ec)
2670 public override bool Equals (object obj)
2672 TypeExpr tobj = obj as TypeExpr;
2676 return Type == tobj.Type;
2679 public override int GetHashCode ()
2681 return Type.GetHashCode ();
2686 /// Fully resolved Expression that already evaluated to a type
2688 public class TypeExpression : TypeExpr
2690 public TypeExpression (TypeSpec t, Location l)
2693 eclass = ExprClass.Type;
2697 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2704 /// This class denotes an expression which evaluates to a member
2705 /// of a struct or a class.
2707 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2710 // An instance expression associated with this member, if it's a
2711 // non-static member
2713 public Expression InstanceExpression;
2716 /// The name of this member.
2718 public abstract string Name {
2723 // When base.member is used
2725 public bool IsBase {
2726 get { return InstanceExpression is BaseThis; }
2730 /// Whether this is an instance member.
2732 public abstract bool IsInstance {
2737 /// Whether this is a static member.
2739 public abstract bool IsStatic {
2743 public abstract string KindName {
2747 protected abstract TypeSpec DeclaringType {
2751 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2753 return InstanceExpression.Type;
2758 // Converts best base candidate for virtual method starting from QueriedBaseType
2760 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2763 // Only when base.member is used and method is virtual
2769 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2770 // means for base.member access we have to find the closest match after we found best candidate
2772 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2774 // The method could already be what we are looking for
2776 TypeSpec[] targs = null;
2777 if (method.DeclaringType != InstanceExpression.Type) {
2778 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2779 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2780 if (base_override.IsGeneric)
2781 targs = method.TypeArguments;
2783 method = base_override;
2788 // When base access is used inside anonymous method/iterator/etc we need to
2789 // get back to the context of original type. We do it by emiting proxy
2790 // method in original class and rewriting base call to this compiler
2791 // generated method call which does the actual base invocation. This may
2792 // introduce redundant storey but with `this' only but it's tricky to avoid
2793 // at this stage as we don't know what expressions follow base
2795 if (rc.CurrentAnonymousMethod != null) {
2796 if (targs == null && method.IsGeneric) {
2797 targs = method.TypeArguments;
2798 method = method.GetGenericMethodDefinition ();
2801 if (method.Parameters.HasArglist)
2802 throw new NotImplementedException ("__arglist base call proxy");
2804 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2806 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2807 // get/set member expressions second call would fail to proxy because left expression
2808 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2809 // FIXME: The async check is another hack but will probably fail with mutators
2810 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2811 InstanceExpression = new This (loc).Resolve (rc);
2815 method = method.MakeGenericMethod (rc, targs);
2819 // Only base will allow this invocation to happen.
2821 if (method.IsAbstract) {
2822 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2828 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2830 if (InstanceExpression == null)
2833 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2834 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2835 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2840 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2842 if (InstanceExpression == null)
2845 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2848 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2850 var ct = rc.CurrentType;
2851 if (ct == qualifier)
2854 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2857 qualifier = qualifier.GetDefinition ();
2858 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2865 public override bool ContainsEmitWithAwait ()
2867 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2870 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2873 type = type.GetDefinition ();
2875 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2878 type = type.DeclaringType;
2879 } while (type != null);
2884 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2886 if (InstanceExpression != null) {
2887 InstanceExpression = InstanceExpression.Resolve (rc);
2888 CheckProtectedMemberAccess (rc, member);
2891 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2892 UnsafeError (rc, loc);
2895 var dep = member.GetMissingDependencies ();
2897 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2900 if (!rc.IsObsolete) {
2901 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2903 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2906 if (!(member is FieldSpec))
2907 member.MemberDefinition.SetIsUsed ();
2910 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2912 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2915 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2917 rc.Report.SymbolRelatedToPreviousError (member);
2918 rc.Report.Error (1540, loc,
2919 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2920 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2924 // Implements identicial simple name and type-name
2926 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2929 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2932 // 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
2933 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2935 if (left is MemberExpr || left is VariableReference) {
2936 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2937 if (identical_type != null && identical_type.Type == left.Type)
2938 return identical_type;
2944 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2947 if (InstanceExpression != null) {
2948 if (InstanceExpression is TypeExpr) {
2949 var t = InstanceExpression.Type;
2951 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2952 if (oa != null && !rc.IsObsolete) {
2953 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2956 t = t.DeclaringType;
2957 } while (t != null);
2959 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2960 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2961 rc.Report.Error (176, loc,
2962 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2963 GetSignatureForError ());
2967 InstanceExpression = null;
2973 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2974 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2975 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2976 rc.Report.Error (236, loc,
2977 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2978 GetSignatureForError ());
2980 rc.Report.Error (120, loc,
2981 "An object reference is required to access non-static member `{0}'",
2982 GetSignatureForError ());
2984 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
2988 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2989 rc.Report.Error (38, loc,
2990 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2991 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2994 InstanceExpression = new This (loc);
2995 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2996 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2997 InstanceExpression = InstanceExpression.Resolve (rc);
3000 InstanceExpression = InstanceExpression.Resolve (rc);
3006 var me = InstanceExpression as MemberExpr;
3008 me.ResolveInstanceExpression (rc, rhs);
3010 // Using this check to detect probing instance expression resolve
3011 if (!rc.OmitStructFlowAnalysis) {
3012 var fe = me as FieldExpr;
3013 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3014 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3015 rc.Report.Warning (1690, 1, loc,
3016 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3017 me.GetSignatureForError ());
3025 // Run member-access postponed check once we know that
3026 // the expression is not field expression which is the only
3027 // expression which can use uninitialized this
3029 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3030 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3034 // Additional checks for l-value member access
3037 if (InstanceExpression is UnboxCast) {
3038 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3045 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3047 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3048 ec.Report.Warning (1720, 1, left.Location,
3049 "Expression will always cause a `{0}'", "System.NullReferenceException");
3052 InstanceExpression = left;
3056 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3058 TypeSpec instance_type = InstanceExpression.Type;
3059 if (TypeSpec.IsValueType (instance_type)) {
3060 if (InstanceExpression is IMemoryLocation) {
3061 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3063 // Cannot release the temporary variable when its address
3064 // is required to be on stack for any parent
3065 LocalTemporary t = new LocalTemporary (instance_type);
3066 InstanceExpression.Emit (ec);
3068 t.AddressOf (ec, AddressOp.Store);
3071 InstanceExpression.Emit (ec);
3073 // Only to make verifier happy
3074 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3075 ec.Emit (OpCodes.Box, instance_type);
3078 if (prepare_for_load)
3079 ec.Emit (OpCodes.Dup);
3082 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3085 public class ExtensionMethodCandidates
3087 readonly NamespaceContainer container;
3088 readonly IList<MethodSpec> methods;
3090 readonly IMemberContext context;
3092 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3094 this.context = context;
3095 this.methods = methods;
3096 this.container = nsContainer;
3097 this.index = lookupIndex;
3100 public NamespaceContainer Container {
3106 public IMemberContext Context {
3112 public int LookupIndex {
3118 public IList<MethodSpec> Methods {
3126 // Represents a group of extension method candidates for whole namespace
3128 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3130 ExtensionMethodCandidates candidates;
3131 public readonly Expression ExtensionExpression;
3133 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3134 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3136 this.candidates = candidates;
3137 this.ExtensionExpression = extensionExpr;
3140 public override bool IsStatic {
3141 get { return true; }
3145 // For extension methodgroup we are not looking for base members but parent
3146 // namespace extension methods
3148 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3150 // TODO: candidates are null only when doing error reporting, that's
3151 // incorrect. We have to discover same extension methods in error mode
3152 if (candidates == null)
3155 int arity = type_arguments == null ? 0 : type_arguments.Count;
3157 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3158 if (candidates == null)
3161 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3164 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3166 // We are already here
3170 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3172 if (arguments == null)
3173 arguments = new Arguments (1);
3175 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3176 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3178 // Store resolved argument and restore original arguments
3180 // Clean-up modified arguments for error reporting
3181 arguments.RemoveAt (0);
3185 var me = ExtensionExpression as MemberExpr;
3187 me.ResolveInstanceExpression (ec, null);
3188 var fe = me as FieldExpr;
3190 fe.Spec.MemberDefinition.SetIsUsed ();
3193 InstanceExpression = null;
3197 #region IErrorHandler Members
3199 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3204 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3206 rc.Report.SymbolRelatedToPreviousError (best);
3207 rc.Report.Error (1928, loc,
3208 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3209 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3212 rc.Report.Error (1929, loc,
3213 "Extension method instance type `{0}' cannot be converted to `{1}'",
3214 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3220 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3225 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3234 /// MethodGroupExpr represents a group of method candidates which
3235 /// can be resolved to the best method overload
3237 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3239 protected IList<MemberSpec> Methods;
3240 MethodSpec best_candidate;
3241 TypeSpec best_candidate_return;
3242 protected TypeArguments type_arguments;
3244 SimpleName simple_name;
3245 protected TypeSpec queried_type;
3247 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3251 this.type = InternalType.MethodGroup;
3253 eclass = ExprClass.MethodGroup;
3254 queried_type = type;
3257 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3258 : this (new MemberSpec[] { m }, type, loc)
3264 public MethodSpec BestCandidate {
3266 return best_candidate;
3270 public TypeSpec BestCandidateReturnType {
3272 return best_candidate_return;
3276 public IList<MemberSpec> Candidates {
3282 protected override TypeSpec DeclaringType {
3284 return queried_type;
3288 public override bool IsInstance {
3290 if (best_candidate != null)
3291 return !best_candidate.IsStatic;
3297 public override bool IsStatic {
3299 if (best_candidate != null)
3300 return best_candidate.IsStatic;
3306 public override string KindName {
3307 get { return "method"; }
3310 public override string Name {
3312 if (best_candidate != null)
3313 return best_candidate.Name;
3316 return Methods.First ().Name;
3323 // When best candidate is already know this factory can be used
3324 // to avoid expensive overload resolution to be called
3326 // NOTE: InstanceExpression has to be set manually
3328 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3330 return new MethodGroupExpr (best, queriedType, loc) {
3331 best_candidate = best,
3332 best_candidate_return = best.ReturnType
3336 public override string GetSignatureForError ()
3338 if (best_candidate != null)
3339 return best_candidate.GetSignatureForError ();
3341 return Methods.First ().GetSignatureForError ();
3344 public override Expression CreateExpressionTree (ResolveContext ec)
3346 if (best_candidate == null) {
3347 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3351 if (best_candidate.IsConditionallyExcluded (ec, loc))
3352 ec.Report.Error (765, loc,
3353 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3355 return new TypeOfMethod (best_candidate, loc);
3358 protected override Expression DoResolve (ResolveContext ec)
3360 this.eclass = ExprClass.MethodGroup;
3362 if (InstanceExpression != null) {
3363 InstanceExpression = InstanceExpression.Resolve (ec);
3364 if (InstanceExpression == null)
3371 public override void Emit (EmitContext ec)
3373 throw new NotSupportedException ();
3376 public void EmitCall (EmitContext ec, Arguments arguments)
3378 var call = new CallEmitter ();
3379 call.InstanceExpression = InstanceExpression;
3380 call.Emit (ec, best_candidate, arguments, loc);
3383 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3385 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3386 Name, TypeManager.CSharpName (target));
3389 public static bool IsExtensionMethodArgument (Expression expr)
3392 // LAMESPEC: No details about which expressions are not allowed
3394 return !(expr is TypeExpr) && !(expr is BaseThis);
3398 /// Find the Applicable Function Members (7.4.2.1)
3400 /// me: Method Group expression with the members to select.
3401 /// it might contain constructors or methods (or anything
3402 /// that maps to a method).
3404 /// Arguments: ArrayList containing resolved Argument objects.
3406 /// loc: The location if we want an error to be reported, or a Null
3407 /// location for "probing" purposes.
3409 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3410 /// that is the best match of me on Arguments.
3413 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3415 // TODO: causes issues with probing mode, remove explicit Kind check
3416 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3419 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3420 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3421 r.BaseMembersProvider = this;
3422 r.InstanceQualifier = this;
3425 if (cerrors != null)
3426 r.CustomErrors = cerrors;
3428 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3429 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3430 if (best_candidate == null)
3431 return r.BestCandidateIsDynamic ? this : null;
3433 // Overload resolver had to create a new method group, all checks bellow have already been executed
3434 if (r.BestCandidateNewMethodGroup != null)
3435 return r.BestCandidateNewMethodGroup;
3437 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3438 if (InstanceExpression != null) {
3439 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3440 InstanceExpression = null;
3442 if (best_candidate.IsStatic && simple_name != null) {
3443 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3446 InstanceExpression.Resolve (ec);
3450 ResolveInstanceExpression (ec, null);
3453 var base_override = CandidateToBaseOverride (ec, best_candidate);
3454 if (base_override == best_candidate) {
3455 best_candidate_return = r.BestCandidateReturnType;
3457 best_candidate = base_override;
3458 best_candidate_return = best_candidate.ReturnType;
3461 if (best_candidate.IsGeneric && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3462 ConstraintChecker cc = new ConstraintChecker (ec);
3463 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3467 // Additional check for possible imported base override method which
3468 // could not be done during IsOverrideMethodBaseTypeAccessible
3470 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3471 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3472 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3473 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3479 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3481 var fe = left as FieldExpr;
3484 // Using method-group on struct fields makes the struct assigned. I am not sure
3485 // why but that's what .net does
3487 fe.Spec.MemberDefinition.SetIsAssigned ();
3490 simple_name = original;
3491 return base.ResolveMemberAccess (ec, left, original);
3494 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3496 type_arguments = ta;
3499 #region IBaseMembersProvider Members
3501 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3503 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3506 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3508 if (queried_type == member.DeclaringType)
3511 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3512 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3516 // Extension methods lookup after ordinary methods candidates failed to apply
3518 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3520 if (InstanceExpression == null)
3523 InstanceExpression = InstanceExpression.Resolve (rc);
3524 if (!IsExtensionMethodArgument (InstanceExpression))
3527 int arity = type_arguments == null ? 0 : type_arguments.Count;
3528 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3529 if (methods == null)
3532 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3533 emg.SetTypeArguments (rc, type_arguments);
3540 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3542 public ConstructorInstanceQualifier (TypeSpec type)
3545 InstanceType = type;
3548 public TypeSpec InstanceType { get; private set; }
3550 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3552 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3556 public struct OverloadResolver
3559 public enum Restrictions
3563 ProbingOnly = 1 << 1,
3564 CovariantDelegate = 1 << 2,
3565 NoBaseMembers = 1 << 3,
3566 BaseMembersIncluded = 1 << 4
3569 public interface IBaseMembersProvider
3571 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3572 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3573 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3576 public interface IErrorHandler
3578 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3579 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3580 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3581 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3584 public interface IInstanceQualifier
3586 TypeSpec InstanceType { get; }
3587 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3590 sealed class NoBaseMembers : IBaseMembersProvider
3592 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3594 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3599 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3604 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3610 struct AmbiguousCandidate
3612 public readonly MemberSpec Member;
3613 public readonly bool Expanded;
3614 public readonly AParametersCollection Parameters;
3616 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3619 Parameters = parameters;
3620 Expanded = expanded;
3625 IList<MemberSpec> members;
3626 TypeArguments type_arguments;
3627 IBaseMembersProvider base_provider;
3628 IErrorHandler custom_errors;
3629 IInstanceQualifier instance_qualifier;
3630 Restrictions restrictions;
3631 MethodGroupExpr best_candidate_extension_group;
3632 TypeSpec best_candidate_return_type;
3634 SessionReportPrinter lambda_conv_msgs;
3636 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3637 : this (members, null, restrictions, loc)
3641 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3644 if (members == null || members.Count == 0)
3645 throw new ArgumentException ("empty members set");
3647 this.members = members;
3649 type_arguments = targs;
3650 this.restrictions = restrictions;
3651 if (IsDelegateInvoke)
3652 this.restrictions |= Restrictions.NoBaseMembers;
3654 base_provider = NoBaseMembers.Instance;
3659 public IBaseMembersProvider BaseMembersProvider {
3661 return base_provider;
3664 base_provider = value;
3668 public bool BestCandidateIsDynamic { get; set; }
3671 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3673 public MethodGroupExpr BestCandidateNewMethodGroup {
3675 return best_candidate_extension_group;
3680 // Return type can be different between best candidate and closest override
3682 public TypeSpec BestCandidateReturnType {
3684 return best_candidate_return_type;
3688 public IErrorHandler CustomErrors {
3690 return custom_errors;
3693 custom_errors = value;
3697 TypeSpec DelegateType {
3699 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3700 throw new InternalErrorException ("Not running in delegate mode", loc);
3702 return members [0].DeclaringType;
3706 public IInstanceQualifier InstanceQualifier {
3708 return instance_qualifier;
3711 instance_qualifier = value;
3715 bool IsProbingOnly {
3717 return (restrictions & Restrictions.ProbingOnly) != 0;
3721 bool IsDelegateInvoke {
3723 return (restrictions & Restrictions.DelegateInvoke) != 0;
3730 // 7.4.3.3 Better conversion from expression
3731 // Returns : 1 if a->p is better,
3732 // 2 if a->q is better,
3733 // 0 if neither is better
3735 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3737 TypeSpec argument_type = a.Type;
3740 // If argument is an anonymous function
3742 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3744 // p and q are delegate types or expression tree types
3746 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3747 if (q.MemberDefinition != p.MemberDefinition) {
3752 // Uwrap delegate from Expression<T>
3754 q = TypeManager.GetTypeArguments (q)[0];
3755 p = TypeManager.GetTypeArguments (p)[0];
3758 var p_m = Delegate.GetInvokeMethod (p);
3759 var q_m = Delegate.GetInvokeMethod (q);
3762 // With identical parameter lists
3764 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3773 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3775 if (p.Kind == MemberKind.Void) {
3776 return q.Kind != MemberKind.Void ? 2 : 0;
3780 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3782 if (q.Kind == MemberKind.Void) {
3783 return p.Kind != MemberKind.Void ? 1: 0;
3786 var am = (AnonymousMethodExpression) a.Expr;
3789 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3790 // better conversion is performed between underlying types Y1 and Y2
3792 if (p.IsGenericTask || q.IsGenericTask) {
3793 if (am.Block.IsAsync) {
3794 if (p.IsGenericTask != q.IsGenericTask) {
3798 q = q.TypeArguments[0];
3799 p = p.TypeArguments[0];
3801 } else if (q != p) {
3803 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3805 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3806 var am_rt = am.InferReturnType (ec, null, orig_q);
3807 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3809 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3810 var am_rt = am.InferReturnType (ec, null, orig_p);
3811 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3817 // The parameters are identicial and return type is not void, use better type conversion
3818 // on return type to determine better one
3821 if (argument_type == p)
3824 if (argument_type == q)
3828 return BetterTypeConversion (ec, p, q);
3832 // 7.4.3.4 Better conversion from type
3834 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3836 if (p == null || q == null)
3837 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3839 switch (p.BuiltinType) {
3840 case BuiltinTypeSpec.Type.Int:
3841 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3844 case BuiltinTypeSpec.Type.Long:
3845 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3848 case BuiltinTypeSpec.Type.SByte:
3849 switch (q.BuiltinType) {
3850 case BuiltinTypeSpec.Type.Byte:
3851 case BuiltinTypeSpec.Type.UShort:
3852 case BuiltinTypeSpec.Type.UInt:
3853 case BuiltinTypeSpec.Type.ULong:
3857 case BuiltinTypeSpec.Type.Short:
3858 switch (q.BuiltinType) {
3859 case BuiltinTypeSpec.Type.UShort:
3860 case BuiltinTypeSpec.Type.UInt:
3861 case BuiltinTypeSpec.Type.ULong:
3865 case BuiltinTypeSpec.Type.Dynamic:
3866 // Dynamic is never better
3870 switch (q.BuiltinType) {
3871 case BuiltinTypeSpec.Type.Int:
3872 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3875 case BuiltinTypeSpec.Type.Long:
3876 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3879 case BuiltinTypeSpec.Type.SByte:
3880 switch (p.BuiltinType) {
3881 case BuiltinTypeSpec.Type.Byte:
3882 case BuiltinTypeSpec.Type.UShort:
3883 case BuiltinTypeSpec.Type.UInt:
3884 case BuiltinTypeSpec.Type.ULong:
3888 case BuiltinTypeSpec.Type.Short:
3889 switch (p.BuiltinType) {
3890 case BuiltinTypeSpec.Type.UShort:
3891 case BuiltinTypeSpec.Type.UInt:
3892 case BuiltinTypeSpec.Type.ULong:
3896 case BuiltinTypeSpec.Type.Dynamic:
3897 // Dynamic is never better
3901 // FIXME: handle lifted operators
3903 // TODO: this is expensive
3904 Expression p_tmp = new EmptyExpression (p);
3905 Expression q_tmp = new EmptyExpression (q);
3907 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3908 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3910 if (p_to_q && !q_to_p)
3913 if (q_to_p && !p_to_q)
3920 /// Determines "Better function" between candidate
3921 /// and the current best match
3924 /// Returns a boolean indicating :
3925 /// false if candidate ain't better
3926 /// true if candidate is better than the current best match
3928 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3929 MemberSpec best, AParametersCollection bparam, bool best_params)
3931 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3932 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3934 bool better_at_least_one = false;
3936 int args_count = args == null ? 0 : args.Count;
3940 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3943 // Default arguments are ignored for better decision
3944 if (a.IsDefaultArgument)
3948 // When comparing named argument the parameter type index has to be looked up
3949 // in original parameter set (override version for virtual members)
3951 NamedArgument na = a as NamedArgument;
3953 int idx = cparam.GetParameterIndexByName (na.Name);
3954 ct = candidate_pd.Types[idx];
3955 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3956 ct = TypeManager.GetElementType (ct);
3958 idx = bparam.GetParameterIndexByName (na.Name);
3959 bt = best_pd.Types[idx];
3960 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3961 bt = TypeManager.GetElementType (bt);
3963 ct = candidate_pd.Types[c_idx];
3964 bt = best_pd.Types[b_idx];
3966 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3967 ct = TypeManager.GetElementType (ct);
3971 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3972 bt = TypeManager.GetElementType (bt);
3977 if (TypeSpecComparer.IsEqual (ct, bt))
3981 int result = BetterExpressionConversion (ec, a, ct, bt);
3983 // for each argument, the conversion to 'ct' should be no worse than
3984 // the conversion to 'bt'.
3988 // for at least one argument, the conversion to 'ct' should be better than
3989 // the conversion to 'bt'.
3991 better_at_least_one = true;
3994 if (better_at_least_one)
3998 // This handles the case
4000 // Add (float f1, float f2, float f3);
4001 // Add (params decimal [] foo);
4003 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4004 // first candidate would've chosen as better.
4006 if (!same && !a.IsDefaultArgument)
4010 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4014 // This handles the following cases:
4016 // Foo (int i) is better than Foo (int i, long l = 0)
4017 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4018 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4020 // Prefer non-optional version
4022 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4024 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4025 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4028 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4031 return candidate_pd.Count >= best_pd.Count;
4035 // One is a non-generic method and second is a generic method, then non-generic is better
4037 if (best.IsGeneric != candidate.IsGeneric)
4038 return best.IsGeneric;
4041 // This handles the following cases:
4043 // Trim () is better than Trim (params char[] chars)
4044 // Concat (string s1, string s2, string s3) is better than
4045 // Concat (string s1, params string [] srest)
4046 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4048 // Prefer non-expanded version
4050 if (candidate_params != best_params)
4053 int candidate_param_count = candidate_pd.Count;
4054 int best_param_count = best_pd.Count;
4056 if (candidate_param_count != best_param_count)
4057 // can only happen if (candidate_params && best_params)
4058 return candidate_param_count > best_param_count && best_pd.HasParams;
4061 // Both methods have the same number of parameters, and the parameters have equal types
4062 // Pick the "more specific" signature using rules over original (non-inflated) types
4064 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4065 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4067 bool specific_at_least_once = false;
4068 for (j = 0; j < args_count; ++j) {
4069 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4071 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4072 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4074 ct = candidate_def_pd.Types[j];
4075 bt = best_def_pd.Types[j];
4080 TypeSpec specific = MoreSpecific (ct, bt);
4084 specific_at_least_once = true;
4087 if (specific_at_least_once)
4093 static bool CheckInflatedArguments (MethodSpec ms)
4095 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4098 // Setup constraint checker for probing only
4099 ConstraintChecker cc = new ConstraintChecker (null);
4101 var mp = ms.Parameters.Types;
4102 for (int i = 0; i < mp.Length; ++i) {
4103 var type = mp[i] as InflatedTypeSpec;
4107 var targs = type.TypeArguments;
4108 if (targs.Length == 0)
4111 // TODO: Checking inflated MVAR arguments should be enough
4112 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4119 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4121 rc.Report.Error (1729, loc,
4122 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4123 type.GetSignatureForError (), argCount.ToString ());
4127 // Determines if the candidate method is applicable to the given set of arguments
4128 // There could be two different set of parameters for same candidate where one
4129 // is the closest override for default values and named arguments checks and second
4130 // one being the virtual base for the parameter types and modifiers.
4132 // A return value rates candidate method compatibility,
4133 // 0 = the best, int.MaxValue = the worst
4136 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)
4138 // Parameters of most-derived type used mainly for named and optional parameters
4139 var pd = pm.Parameters;
4141 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4142 // params modifier instead of most-derived type
4143 var cpd = ((IParametersMember) candidate).Parameters;
4144 int param_count = pd.Count;
4145 int optional_count = 0;
4147 Arguments orig_args = arguments;
4149 if (arg_count != param_count) {
4151 // No arguments expansion when doing exact match for delegates
4153 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4154 for (int i = 0; i < pd.Count; ++i) {
4155 if (pd.FixedParameters[i].HasDefaultValue) {
4156 optional_count = pd.Count - i;
4162 if (optional_count != 0) {
4163 // Readjust expected number when params used
4164 if (cpd.HasParams) {
4166 if (arg_count < param_count)
4168 } else if (arg_count > param_count) {
4169 int args_gap = System.Math.Abs (arg_count - param_count);
4170 return int.MaxValue - 10000 + args_gap;
4172 } else if (arg_count != param_count) {
4173 int args_gap = System.Math.Abs (arg_count - param_count);
4175 return int.MaxValue - 10000 + args_gap;
4176 if (arg_count < param_count - 1)
4177 return int.MaxValue - 10000 + args_gap;
4180 // Resize to fit optional arguments
4181 if (optional_count != 0) {
4182 if (arguments == null) {
4183 arguments = new Arguments (optional_count);
4185 // Have to create a new container, so the next run can do same
4186 var resized = new Arguments (param_count);
4187 resized.AddRange (arguments);
4188 arguments = resized;
4191 for (int i = arg_count; i < param_count; ++i)
4192 arguments.Add (null);
4196 if (arg_count > 0) {
4198 // Shuffle named arguments to the right positions if there are any
4200 if (arguments[arg_count - 1] is NamedArgument) {
4201 arg_count = arguments.Count;
4203 for (int i = 0; i < arg_count; ++i) {
4204 bool arg_moved = false;
4206 NamedArgument na = arguments[i] as NamedArgument;
4210 int index = pd.GetParameterIndexByName (na.Name);
4212 // Named parameter not found
4216 // already reordered
4221 if (index >= param_count) {
4222 // When using parameters which should not be available to the user
4223 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4226 arguments.Add (null);
4230 temp = arguments[index];
4232 // The slot has been taken by positional argument
4233 if (temp != null && !(temp is NamedArgument))
4238 arguments = arguments.MarkOrderedArgument (na);
4242 arguments[index] = arguments[i];
4243 arguments[i] = temp;
4250 arg_count = arguments.Count;
4252 } else if (arguments != null) {
4253 arg_count = arguments.Count;
4257 // Don't do any expensive checks when the candidate cannot succeed
4259 if (arg_count != param_count && !cpd.HasParams)
4260 return (param_count - arg_count) * 2 + 1;
4262 var dep = candidate.GetMissingDependencies ();
4264 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4269 // 1. Handle generic method using type arguments when specified or type inference
4272 var ms = candidate as MethodSpec;
4273 if (ms != null && ms.IsGeneric) {
4274 if (type_arguments != null) {
4275 var g_args_count = ms.Arity;
4276 if (g_args_count != type_arguments.Count)
4277 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4279 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4282 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4283 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4284 // candidate was found use the set to report more details about what was wrong with lambda body.
4285 // The general idea is to distinguish between code errors and errors caused by
4286 // trial-and-error type inference
4288 if (lambda_conv_msgs == null) {
4289 for (int i = 0; i < arg_count; i++) {
4290 Argument a = arguments[i];
4294 var am = a.Expr as AnonymousMethodExpression;
4296 if (lambda_conv_msgs == null)
4297 lambda_conv_msgs = new SessionReportPrinter ();
4299 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4304 var ti = new TypeInference (arguments);
4305 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4308 return ti.InferenceScore - 20000;
4311 // Clear any error messages when the result was success
4313 if (lambda_conv_msgs != null)
4314 lambda_conv_msgs.ClearSession ();
4316 if (i_args.Length != 0) {
4317 ms = ms.MakeGenericMethod (ec, i_args);
4322 // Type arguments constraints have to match for the method to be applicable
4324 if (!CheckInflatedArguments (ms)) {
4326 return int.MaxValue - 25000;
4330 // We have a generic return type and at same time the method is override which
4331 // means we have to also inflate override return type in case the candidate is
4332 // best candidate and override return type is different to base return type.
4334 // virtual Foo<T, object> with override Foo<T, dynamic>
4336 if (candidate != pm) {
4337 MethodSpec override_ms = (MethodSpec) pm;
4338 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4339 returnType = inflator.Inflate (returnType);
4341 returnType = ms.ReturnType;
4345 ptypes = ms.Parameters.Types;
4347 if (type_arguments != null)
4348 return int.MaxValue - 15000;
4354 // 2. Each argument has to be implicitly convertible to method parameter
4356 Parameter.Modifier p_mod = 0;
4359 for (int i = 0; i < arg_count; i++) {
4360 Argument a = arguments[i];
4362 var fp = pd.FixedParameters[i];
4363 if (!fp.HasDefaultValue) {
4364 arguments = orig_args;
4365 return arg_count * 2 + 2;
4369 // Get the default value expression, we can use the same expression
4370 // if the type matches
4372 Expression e = fp.DefaultValue;
4373 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4375 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4377 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4378 e = new MemberAccess (new MemberAccess (new MemberAccess (
4379 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4381 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4387 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4389 // LAMESPEC: Attributes can be mixed together with build-in priority
4391 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4392 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4393 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4394 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4395 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4396 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4400 arguments[i] = new Argument (e, Argument.AType.Default);
4404 if (p_mod != Parameter.Modifier.PARAMS) {
4405 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4407 } else if (!params_expanded_form) {
4408 params_expanded_form = true;
4409 pt = ((ElementTypeSpec) pt).Element;
4415 if (!params_expanded_form) {
4416 if (a.ArgType == Argument.AType.ExtensionType) {
4418 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4420 // LAMESPEC: or implicit type parameter conversion
4423 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4424 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4425 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4430 score = IsArgumentCompatible (ec, a, p_mod, pt);
4433 dynamicArgument = true;
4438 // It can be applicable in expanded form (when not doing exact match like for delegates)
4440 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4441 if (!params_expanded_form)
4442 pt = ((ElementTypeSpec) pt).Element;
4445 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4448 params_expanded_form = true;
4449 } else if (score < 0) {
4450 params_expanded_form = true;
4451 dynamicArgument = true;
4456 if (params_expanded_form)
4458 return (arg_count - i) * 2 + score;
4463 // When params parameter has no argument it will be provided later if the method is the best candidate
4465 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4466 params_expanded_form = true;
4469 // Restore original arguments for dynamic binder to keep the intention of original source code
4471 if (dynamicArgument)
4472 arguments = orig_args;
4478 // Tests argument compatibility with the parameter
4479 // The possible return values are
4481 // 1 - modifier mismatch
4482 // 2 - type mismatch
4483 // -1 - dynamic binding required
4485 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4488 // Types have to be identical when ref or out modifer
4489 // is used and argument is not of dynamic type
4491 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4492 if (argument.Type != parameter) {
4494 // Do full equality check after quick path
4496 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4498 // Using dynamic for ref/out parameter can still succeed at runtime
4500 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4507 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4509 // Using dynamic for ref/out parameter can still succeed at runtime
4511 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4518 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4522 // Use implicit conversion in all modes to return same candidates when the expression
4523 // is used as argument or delegate conversion
4525 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4533 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4535 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4537 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4540 var ac_p = p as ArrayContainer;
4542 var ac_q = q as ArrayContainer;
4546 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4547 if (specific == ac_p.Element)
4549 if (specific == ac_q.Element)
4551 } else if (p.IsGeneric && q.IsGeneric) {
4552 var pargs = TypeManager.GetTypeArguments (p);
4553 var qargs = TypeManager.GetTypeArguments (q);
4555 bool p_specific_at_least_once = false;
4556 bool q_specific_at_least_once = false;
4558 for (int i = 0; i < pargs.Length; i++) {
4559 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4560 if (specific == pargs[i])
4561 p_specific_at_least_once = true;
4562 if (specific == qargs[i])
4563 q_specific_at_least_once = true;
4566 if (p_specific_at_least_once && !q_specific_at_least_once)
4568 if (!p_specific_at_least_once && q_specific_at_least_once)
4576 // Find the best method from candidate list
4578 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4580 List<AmbiguousCandidate> ambiguous_candidates = null;
4582 MemberSpec best_candidate;
4583 Arguments best_candidate_args = null;
4584 bool best_candidate_params = false;
4585 bool best_candidate_dynamic = false;
4586 int best_candidate_rate;
4587 IParametersMember best_parameter_member = null;
4589 int args_count = args != null ? args.Count : 0;
4591 Arguments candidate_args = args;
4592 bool error_mode = false;
4593 MemberSpec invocable_member = null;
4596 best_candidate = null;
4597 best_candidate_rate = int.MaxValue;
4599 var type_members = members;
4601 for (int i = 0; i < type_members.Count; ++i) {
4602 var member = type_members[i];
4605 // Methods in a base class are not candidates if any method in a derived
4606 // class is applicable
4608 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4612 if (!member.IsAccessible (rc))
4615 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4618 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4619 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4624 IParametersMember pm = member as IParametersMember;
4627 // Will use it later to report ambiguity between best method and invocable member
4629 if (Invocation.IsMemberInvocable (member))
4630 invocable_member = member;
4636 // Overload resolution is looking for base member but using parameter names
4637 // and default values from the closest member. That means to do expensive lookup
4638 // for the closest override for virtual or abstract members
4640 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4641 var override_params = base_provider.GetOverrideMemberParameters (member);
4642 if (override_params != null)
4643 pm = override_params;
4647 // Check if the member candidate is applicable
4649 bool params_expanded_form = false;
4650 bool dynamic_argument = false;
4651 TypeSpec rt = pm.MemberType;
4652 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4654 if (lambda_conv_msgs != null)
4655 lambda_conv_msgs.EndSession ();
4658 // How does it score compare to others
4660 if (candidate_rate < best_candidate_rate) {
4662 // Fatal error (missing dependency), cannot continue
4663 if (candidate_rate < 0)
4666 best_candidate_rate = candidate_rate;
4667 best_candidate = member;
4668 best_candidate_args = candidate_args;
4669 best_candidate_params = params_expanded_form;
4670 best_candidate_dynamic = dynamic_argument;
4671 best_parameter_member = pm;
4672 best_candidate_return_type = rt;
4673 } else if (candidate_rate == 0) {
4675 // The member look is done per type for most operations but sometimes
4676 // it's not possible like for binary operators overload because they
4677 // are unioned between 2 sides
4679 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4680 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4685 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4687 // We pack all interface members into top level type which makes the overload resolution
4688 // more complicated for interfaces. We compensate it by removing methods with same
4689 // signature when building the cache hence this path should not really be hit often
4692 // interface IA { void Foo (int arg); }
4693 // interface IB : IA { void Foo (params int[] args); }
4695 // IB::Foo is the best overload when calling IB.Foo (1)
4698 if (ambiguous_candidates != null) {
4699 foreach (var amb_cand in ambiguous_candidates) {
4700 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4709 ambiguous_candidates = null;
4712 // Is the new candidate better
4713 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4717 best_candidate = member;
4718 best_candidate_args = candidate_args;
4719 best_candidate_params = params_expanded_form;
4720 best_candidate_dynamic = dynamic_argument;
4721 best_parameter_member = pm;
4722 best_candidate_return_type = rt;
4724 // It's not better but any other found later could be but we are not sure yet
4725 if (ambiguous_candidates == null)
4726 ambiguous_candidates = new List<AmbiguousCandidate> ();
4728 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4732 // Restore expanded arguments
4733 if (candidate_args != args)
4734 candidate_args = args;
4736 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4739 // We've found exact match
4741 if (best_candidate_rate == 0)
4745 // Try extension methods lookup when no ordinary method match was found and provider enables it
4748 var emg = base_provider.LookupExtensionMethod (rc);
4750 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4752 best_candidate_extension_group = emg;
4753 return (T) (MemberSpec) emg.BestCandidate;
4758 // Don't run expensive error reporting mode for probing
4765 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4768 lambda_conv_msgs = null;
4773 // No best member match found, report an error
4775 if (best_candidate_rate != 0 || error_mode) {
4776 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4780 if (best_candidate_dynamic) {
4781 if (args[0].ArgType == Argument.AType.ExtensionType) {
4782 rc.Report.Error (1973, loc,
4783 "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",
4784 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4788 // Check type constraints only when explicit type arguments are used
4790 if (best_candidate.IsGeneric && type_arguments != null) {
4791 MethodSpec bc = best_candidate as MethodSpec;
4792 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4793 ConstraintChecker cc = new ConstraintChecker (rc);
4794 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4798 BestCandidateIsDynamic = true;
4803 // These flags indicates we are running delegate probing conversion. No need to
4804 // do more expensive checks
4806 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4807 return (T) best_candidate;
4809 if (ambiguous_candidates != null) {
4811 // Now check that there are no ambiguities i.e the selected method
4812 // should be better than all the others
4814 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4815 var candidate = ambiguous_candidates [ix];
4817 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4818 var ambiguous = candidate.Member;
4819 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4820 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4821 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4822 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4823 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4826 return (T) best_candidate;
4831 if (invocable_member != null) {
4832 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4833 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4834 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4835 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4839 // And now check if the arguments are all
4840 // compatible, perform conversions if
4841 // necessary etc. and return if everything is
4844 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4847 if (best_candidate == null)
4851 // Don't run possibly expensive checks in probing mode
4853 if (!rc.IsInProbingMode) {
4855 // Check ObsoleteAttribute on the best method
4857 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4858 if (oa != null && !rc.IsObsolete)
4859 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4861 best_candidate.MemberDefinition.SetIsUsed ();
4864 args = best_candidate_args;
4865 return (T) best_candidate;
4868 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4870 return ResolveMember<MethodSpec> (rc, ref args);
4873 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4874 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4876 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4879 if (a.Type == InternalType.ErrorType)
4882 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4883 ec.Report.SymbolRelatedToPreviousError (method);
4884 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4885 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
4886 TypeManager.CSharpSignature (method));
4889 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4890 TypeManager.CSharpSignature (method));
4891 } else if (IsDelegateInvoke) {
4892 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4893 DelegateType.GetSignatureForError ());
4895 ec.Report.SymbolRelatedToPreviousError (method);
4896 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4897 method.GetSignatureForError ());
4900 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4902 string index = (idx + 1).ToString ();
4903 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4904 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4905 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4906 index, Parameter.GetModifierSignature (a.Modifier));
4908 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4909 index, Parameter.GetModifierSignature (mod));
4911 string p1 = a.GetSignatureForError ();
4912 string p2 = TypeManager.CSharpName (paramType);
4915 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4916 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4919 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
4920 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
4921 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
4924 ec.Report.Error (1503, a.Expr.Location,
4925 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4930 // We have failed to find exact match so we return error info about the closest match
4932 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4934 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4935 int arg_count = args == null ? 0 : args.Count;
4937 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4938 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4939 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4943 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
4948 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4949 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4950 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4954 // For candidates which match on parameters count report more details about incorrect arguments
4957 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4958 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4959 // Reject any inaccessible member
4960 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4961 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4962 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4966 var ms = best_candidate as MethodSpec;
4967 if (ms != null && ms.IsGeneric) {
4968 bool constr_ok = true;
4969 if (ms.TypeArguments != null)
4970 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4972 if (ta_count == 0) {
4973 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4977 rc.Report.Error (411, loc,
4978 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4979 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4986 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4992 // We failed to find any method with correct argument count, report best candidate
4994 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4997 if (best_candidate.Kind == MemberKind.Constructor) {
4998 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4999 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5000 } else if (IsDelegateInvoke) {
5001 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5002 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5003 DelegateType.GetSignatureForError (), arg_count.ToString ());
5005 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5006 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5007 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5008 name, arg_count.ToString ());
5012 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5014 var pd = pm.Parameters;
5015 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5017 Parameter.Modifier p_mod = 0;
5019 int a_idx = 0, a_pos = 0;
5021 ArrayInitializer params_initializers = null;
5022 bool has_unsafe_arg = pm.MemberType.IsPointer;
5023 int arg_count = args == null ? 0 : args.Count;
5025 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5027 if (p_mod != Parameter.Modifier.PARAMS) {
5028 p_mod = pd.FixedParameters[a_idx].ModFlags;
5030 has_unsafe_arg |= pt.IsPointer;
5032 if (p_mod == Parameter.Modifier.PARAMS) {
5033 if (chose_params_expanded) {
5034 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5035 pt = TypeManager.GetElementType (pt);
5041 // Types have to be identical when ref or out modifer is used
5043 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5044 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5047 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5053 NamedArgument na = a as NamedArgument;
5055 int name_index = pd.GetParameterIndexByName (na.Name);
5056 if (name_index < 0 || name_index >= pd.Count) {
5057 if (IsDelegateInvoke) {
5058 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5059 ec.Report.Error (1746, na.Location,
5060 "The delegate `{0}' does not contain a parameter named `{1}'",
5061 DelegateType.GetSignatureForError (), na.Name);
5063 ec.Report.SymbolRelatedToPreviousError (member);
5064 ec.Report.Error (1739, na.Location,
5065 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5066 TypeManager.CSharpSignature (member), na.Name);
5068 } else if (args[name_index] != a) {
5069 if (IsDelegateInvoke)
5070 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5072 ec.Report.SymbolRelatedToPreviousError (member);
5074 ec.Report.Error (1744, na.Location,
5075 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5080 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5083 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5084 custom_errors.NoArgumentMatch (ec, member);
5088 Expression conv = null;
5089 if (a.ArgType == Argument.AType.ExtensionType) {
5090 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5093 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5095 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5098 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5105 // Convert params arguments to an array initializer
5107 if (params_initializers != null) {
5108 // we choose to use 'a.Expr' rather than 'conv' so that
5109 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5110 params_initializers.Add (a.Expr);
5111 args.RemoveAt (a_idx--);
5116 // Update the argument with the implicit conversion
5120 if (a_idx != arg_count) {
5121 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5126 // Fill not provided arguments required by params modifier
5128 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5130 args = new Arguments (1);
5132 pt = ptypes[pd.Count - 1];
5133 pt = TypeManager.GetElementType (pt);
5134 has_unsafe_arg |= pt.IsPointer;
5135 params_initializers = new ArrayInitializer (0, loc);
5139 // Append an array argument with all params arguments
5141 if (params_initializers != null) {
5142 args.Add (new Argument (
5143 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5147 if (has_unsafe_arg && !ec.IsUnsafe) {
5148 Expression.UnsafeError (ec, loc);
5152 // We could infer inaccesible type arguments
5154 if (type_arguments == null && member.IsGeneric) {
5155 var ms = (MethodSpec) member;
5156 foreach (var ta in ms.TypeArguments) {
5157 if (!ta.IsAccessible (ec)) {
5158 ec.Report.SymbolRelatedToPreviousError (ta);
5159 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5169 public class ConstantExpr : MemberExpr
5171 readonly ConstSpec constant;
5173 public ConstantExpr (ConstSpec constant, Location loc)
5175 this.constant = constant;
5179 public override string Name {
5180 get { throw new NotImplementedException (); }
5183 public override string KindName {
5184 get { return "constant"; }
5187 public override bool IsInstance {
5188 get { return !IsStatic; }
5191 public override bool IsStatic {
5192 get { return true; }
5195 protected override TypeSpec DeclaringType {
5196 get { return constant.DeclaringType; }
5199 public override Expression CreateExpressionTree (ResolveContext ec)
5201 throw new NotSupportedException ("ET");
5204 protected override Expression DoResolve (ResolveContext rc)
5206 ResolveInstanceExpression (rc, null);
5207 DoBestMemberChecks (rc, constant);
5209 var c = constant.GetConstant (rc);
5211 // Creates reference expression to the constant value
5212 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5215 public override void Emit (EmitContext ec)
5217 throw new NotSupportedException ();
5220 public override string GetSignatureForError ()
5222 return constant.GetSignatureForError ();
5225 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5227 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5232 // Fully resolved expression that references a Field
5234 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5236 protected FieldSpec spec;
5237 VariableInfo variable_info;
5239 LocalTemporary temp;
5242 protected FieldExpr (Location l)
5247 public FieldExpr (FieldSpec spec, Location loc)
5252 type = spec.MemberType;
5255 public FieldExpr (FieldBase fi, Location l)
5262 public override string Name {
5268 public bool IsHoisted {
5270 IVariableReference hv = InstanceExpression as IVariableReference;
5271 return hv != null && hv.IsHoisted;
5275 public override bool IsInstance {
5277 return !spec.IsStatic;
5281 public override bool IsStatic {
5283 return spec.IsStatic;
5287 public override string KindName {
5288 get { return "field"; }
5291 public FieldSpec Spec {
5297 protected override TypeSpec DeclaringType {
5299 return spec.DeclaringType;
5303 public VariableInfo VariableInfo {
5305 return variable_info;
5311 public override string GetSignatureForError ()
5313 return spec.GetSignatureForError ();
5316 public bool IsMarshalByRefAccess (ResolveContext rc)
5318 // Checks possible ldflda of field access expression
5319 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5320 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5321 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5324 public void SetHasAddressTaken ()
5326 IVariableReference vr = InstanceExpression as IVariableReference;
5328 vr.SetHasAddressTaken ();
5332 public override Expression CreateExpressionTree (ResolveContext ec)
5334 return CreateExpressionTree (ec, true);
5337 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5340 Expression instance;
5342 if (InstanceExpression == null) {
5343 instance = new NullLiteral (loc);
5344 } else if (convertInstance) {
5345 instance = InstanceExpression.CreateExpressionTree (ec);
5347 args = new Arguments (1);
5348 args.Add (new Argument (InstanceExpression));
5349 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5352 args = Arguments.CreateForExpressionTree (ec, null,
5354 CreateTypeOfExpression ());
5356 return CreateExpressionFactoryCall (ec, "Field", args);
5359 public Expression CreateTypeOfExpression ()
5361 return new TypeOfField (spec, loc);
5364 protected override Expression DoResolve (ResolveContext ec)
5366 spec.MemberDefinition.SetIsUsed ();
5368 return DoResolve (ec, null);
5371 Expression DoResolve (ResolveContext ec, Expression rhs)
5373 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5376 if (ResolveInstanceExpression (ec, rhs)) {
5377 // Resolve the field's instance expression while flow analysis is turned
5378 // off: when accessing a field "a.b", we must check whether the field
5379 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5381 if (lvalue_instance) {
5382 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5383 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5385 Expression right_side =
5386 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5388 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5391 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5392 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5396 if (InstanceExpression == null)
5400 DoBestMemberChecks (ec, spec);
5403 var fb = spec as FixedFieldSpec;
5404 IVariableReference var = InstanceExpression as IVariableReference;
5406 if (lvalue_instance && var != null && var.VariableInfo != null) {
5407 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5411 IFixedExpression fe = InstanceExpression as IFixedExpression;
5412 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5413 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5416 if (InstanceExpression.eclass != ExprClass.Variable) {
5417 ec.Report.SymbolRelatedToPreviousError (spec);
5418 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5419 TypeManager.GetFullNameSignature (spec));
5420 } else if (var != null && var.IsHoisted) {
5421 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5424 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5428 // Set flow-analysis variable info for struct member access. It will be check later
5429 // for precise error reporting
5431 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5432 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5433 if (rhs != null && variable_info != null)
5434 variable_info.SetStructFieldAssigned (ec, Name);
5437 eclass = ExprClass.Variable;
5441 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5446 var var = fe.InstanceExpression as IVariableReference;
5448 var vi = var.VariableInfo;
5450 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5452 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5454 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5461 fe = fe.InstanceExpression as FieldExpr;
5463 } while (fe != null);
5466 static readonly int [] codes = {
5467 191, // instance, write access
5468 192, // instance, out access
5469 198, // static, write access
5470 199, // static, out access
5471 1648, // member of value instance, write access
5472 1649, // member of value instance, out access
5473 1650, // member of value static, write access
5474 1651 // member of value static, out access
5477 static readonly string [] msgs = {
5478 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5479 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5480 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5481 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5482 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5483 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5484 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5485 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5488 // The return value is always null. Returning a value simplifies calling code.
5489 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5492 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5496 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5498 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5503 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5505 Expression e = DoResolve (ec, right_side);
5510 spec.MemberDefinition.SetIsAssigned ();
5512 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5513 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5514 ec.Report.Warning (420, 1, loc,
5515 "`{0}': A volatile field references will not be treated as volatile",
5516 spec.GetSignatureForError ());
5519 if (spec.IsReadOnly) {
5520 // InitOnly fields can only be assigned in constructors or initializers
5521 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5522 return Report_AssignToReadonly (ec, right_side);
5524 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5526 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5527 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5528 return Report_AssignToReadonly (ec, right_side);
5529 // static InitOnly fields cannot be assigned-to in an instance constructor
5530 if (IsStatic && !ec.IsStatic)
5531 return Report_AssignToReadonly (ec, right_side);
5532 // instance constructors can't modify InitOnly fields of other instances of the same type
5533 if (!IsStatic && !(InstanceExpression is This))
5534 return Report_AssignToReadonly (ec, right_side);
5538 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5539 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5540 ec.Report.Warning (197, 1, loc,
5541 "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",
5542 GetSignatureForError ());
5545 eclass = ExprClass.Variable;
5549 public override int GetHashCode ()
5551 return spec.GetHashCode ();
5554 public bool IsFixed {
5557 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5559 IVariableReference variable = InstanceExpression as IVariableReference;
5560 if (variable != null)
5561 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5563 IFixedExpression fe = InstanceExpression as IFixedExpression;
5564 return fe != null && fe.IsFixed;
5568 public override bool Equals (object obj)
5570 FieldExpr fe = obj as FieldExpr;
5574 if (spec != fe.spec)
5577 if (InstanceExpression == null || fe.InstanceExpression == null)
5580 return InstanceExpression.Equals (fe.InstanceExpression);
5583 public void Emit (EmitContext ec, bool leave_copy)
5585 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5589 ec.Emit (OpCodes.Volatile);
5591 ec.Emit (OpCodes.Ldsfld, spec);
5594 EmitInstance (ec, false);
5596 // Optimization for build-in types
5597 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5598 ec.EmitLoadFromPtr (type);
5600 var ff = spec as FixedFieldSpec;
5602 ec.Emit (OpCodes.Ldflda, spec);
5603 ec.Emit (OpCodes.Ldflda, ff.Element);
5606 ec.Emit (OpCodes.Volatile);
5608 ec.Emit (OpCodes.Ldfld, spec);
5614 ec.Emit (OpCodes.Dup);
5616 temp = new LocalTemporary (this.Type);
5622 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5624 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5625 if (isCompound && !(source is DynamicExpressionStatement)) {
5626 if (has_await_source) {
5628 InstanceExpression = InstanceExpression.EmitToField (ec);
5635 if (has_await_source)
5636 source = source.EmitToField (ec);
5638 EmitInstance (ec, prepared);
5644 ec.Emit (OpCodes.Dup);
5646 temp = new LocalTemporary (this.Type);
5651 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5652 ec.Emit (OpCodes.Volatile);
5654 spec.MemberDefinition.SetIsAssigned ();
5657 ec.Emit (OpCodes.Stsfld, spec);
5659 ec.Emit (OpCodes.Stfld, spec);
5669 // Emits store to field with prepared values on stack
5671 public void EmitAssignFromStack (EmitContext ec)
5674 ec.Emit (OpCodes.Stsfld, spec);
5676 ec.Emit (OpCodes.Stfld, spec);
5680 public override void Emit (EmitContext ec)
5685 public override void EmitSideEffect (EmitContext ec)
5687 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5689 if (is_volatile) // || is_marshal_by_ref ())
5690 base.EmitSideEffect (ec);
5693 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5695 if ((mode & AddressOp.Store) != 0)
5696 spec.MemberDefinition.SetIsAssigned ();
5697 if ((mode & AddressOp.Load) != 0)
5698 spec.MemberDefinition.SetIsUsed ();
5701 // Handle initonly fields specially: make a copy and then
5702 // get the address of the copy.
5705 if (spec.IsReadOnly){
5707 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5719 var temp = ec.GetTemporaryLocal (type);
5720 ec.Emit (OpCodes.Stloc, temp);
5721 ec.Emit (OpCodes.Ldloca, temp);
5722 ec.FreeTemporaryLocal (temp, type);
5728 ec.Emit (OpCodes.Ldsflda, spec);
5731 EmitInstance (ec, false);
5732 ec.Emit (OpCodes.Ldflda, spec);
5736 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5738 return MakeExpression (ctx);
5741 public override SLE.Expression MakeExpression (BuilderContext ctx)
5744 return base.MakeExpression (ctx);
5746 return SLE.Expression.Field (
5747 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5748 spec.GetMetaInfo ());
5752 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5754 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5760 // Expression that evaluates to a Property.
5762 // This is not an LValue because we need to re-write the expression. We
5763 // can not take data from the stack and store it.
5765 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5767 public PropertyExpr (PropertySpec spec, Location l)
5770 best_candidate = spec;
5771 type = spec.MemberType;
5776 protected override Arguments Arguments {
5784 protected override TypeSpec DeclaringType {
5786 return best_candidate.DeclaringType;
5790 public override string Name {
5792 return best_candidate.Name;
5796 public override bool IsInstance {
5802 public override bool IsStatic {
5804 return best_candidate.IsStatic;
5808 public override string KindName {
5809 get { return "property"; }
5812 public PropertySpec PropertyInfo {
5814 return best_candidate;
5820 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5822 return new PropertyExpr (spec, loc) {
5828 public override Expression CreateExpressionTree (ResolveContext ec)
5831 if (IsSingleDimensionalArrayLength ()) {
5832 args = new Arguments (1);
5833 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5834 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5837 args = new Arguments (2);
5838 if (InstanceExpression == null)
5839 args.Add (new Argument (new NullLiteral (loc)));
5841 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5842 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5843 return CreateExpressionFactoryCall (ec, "Property", args);
5846 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5848 DoResolveLValue (rc, null);
5849 return new TypeOfMethod (Setter, loc);
5852 public override string GetSignatureForError ()
5854 return best_candidate.GetSignatureForError ();
5857 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5860 return base.MakeExpression (ctx);
5862 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5866 public override SLE.Expression MakeExpression (BuilderContext ctx)
5869 return base.MakeExpression (ctx);
5871 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5875 void Error_PropertyNotValid (ResolveContext ec)
5877 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5878 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5879 GetSignatureForError ());
5882 bool IsSingleDimensionalArrayLength ()
5884 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5887 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5888 return ac != null && ac.Rank == 1;
5891 public override void Emit (EmitContext ec, bool leave_copy)
5894 // Special case: length of single dimension array property is turned into ldlen
5896 if (IsSingleDimensionalArrayLength ()) {
5897 EmitInstance (ec, false);
5898 ec.Emit (OpCodes.Ldlen);
5899 ec.Emit (OpCodes.Conv_I4);
5903 base.Emit (ec, leave_copy);
5906 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5909 LocalTemporary await_source_arg = null;
5911 if (isCompound && !(source is DynamicExpressionStatement)) {
5912 emitting_compound_assignment = true;
5915 if (has_await_arguments) {
5916 await_source_arg = new LocalTemporary (Type);
5917 await_source_arg.Store (ec);
5919 args = new Arguments (1);
5920 args.Add (new Argument (await_source_arg));
5923 temp = await_source_arg;
5926 has_await_arguments = false;
5931 ec.Emit (OpCodes.Dup);
5932 temp = new LocalTemporary (this.Type);
5937 args = new Arguments (1);
5941 temp = new LocalTemporary (this.Type);
5943 args.Add (new Argument (temp));
5945 args.Add (new Argument (source));
5949 emitting_compound_assignment = false;
5951 var call = new CallEmitter ();
5952 call.InstanceExpression = InstanceExpression;
5954 call.InstanceExpressionOnStack = true;
5956 call.Emit (ec, Setter, args, loc);
5963 if (await_source_arg != null) {
5964 await_source_arg.Release (ec);
5968 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5970 eclass = ExprClass.PropertyAccess;
5972 if (best_candidate.IsNotCSharpCompatible) {
5973 Error_PropertyNotValid (rc);
5976 ResolveInstanceExpression (rc, right_side);
5978 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5979 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5980 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5982 type = p.MemberType;
5986 DoBestMemberChecks (rc, best_candidate);
5990 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5992 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5996 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5998 // getter and setter can be different for base calls
5999 MethodSpec getter, setter;
6000 protected T best_candidate;
6002 protected LocalTemporary temp;
6003 protected bool emitting_compound_assignment;
6004 protected bool has_await_arguments;
6006 protected PropertyOrIndexerExpr (Location l)
6013 protected abstract Arguments Arguments { get; set; }
6015 public MethodSpec Getter {
6024 public MethodSpec Setter {
6035 protected override Expression DoResolve (ResolveContext ec)
6037 if (eclass == ExprClass.Unresolved) {
6038 var expr = OverloadResolve (ec, null);
6043 return expr.Resolve (ec);
6046 if (!ResolveGetter (ec))
6052 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6054 if (right_side == EmptyExpression.OutAccess) {
6055 // TODO: best_candidate can be null at this point
6056 INamedBlockVariable variable = null;
6057 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6058 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6059 best_candidate.Name);
6061 right_side.DoResolveLValue (ec, this);
6066 // if the property/indexer returns a value type, and we try to set a field in it
6067 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
6068 Error_ValueAssignment (ec, right_side);
6071 if (eclass == ExprClass.Unresolved) {
6072 var expr = OverloadResolve (ec, right_side);
6077 return expr.ResolveLValue (ec, right_side);
6080 if (!ResolveSetter (ec))
6087 // Implements the IAssignMethod interface for assignments
6089 public virtual void Emit (EmitContext ec, bool leave_copy)
6091 var call = new CallEmitter ();
6092 call.InstanceExpression = InstanceExpression;
6093 if (has_await_arguments)
6094 call.HasAwaitArguments = true;
6096 call.DuplicateArguments = emitting_compound_assignment;
6098 call.Emit (ec, Getter, Arguments, loc);
6100 if (call.HasAwaitArguments) {
6101 InstanceExpression = call.InstanceExpression;
6102 Arguments = call.EmittedArguments;
6103 has_await_arguments = true;
6107 ec.Emit (OpCodes.Dup);
6108 temp = new LocalTemporary (Type);
6113 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6115 public override void Emit (EmitContext ec)
6120 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6122 has_await_arguments = true;
6127 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6129 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6131 bool ResolveGetter (ResolveContext rc)
6133 if (!best_candidate.HasGet) {
6134 if (InstanceExpression != EmptyExpression.Null) {
6135 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6136 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6137 best_candidate.GetSignatureForError ());
6140 } else if (!best_candidate.Get.IsAccessible (rc)) {
6141 if (best_candidate.HasDifferentAccessibility) {
6142 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6143 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6144 TypeManager.CSharpSignature (best_candidate));
6146 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6147 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6151 if (best_candidate.HasDifferentAccessibility) {
6152 CheckProtectedMemberAccess (rc, best_candidate.Get);
6155 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6159 bool ResolveSetter (ResolveContext rc)
6161 if (!best_candidate.HasSet) {
6162 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6163 GetSignatureForError ());
6167 if (!best_candidate.Set.IsAccessible (rc)) {
6168 if (best_candidate.HasDifferentAccessibility) {
6169 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6170 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6171 GetSignatureForError ());
6173 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6174 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6178 if (best_candidate.HasDifferentAccessibility)
6179 CheckProtectedMemberAccess (rc, best_candidate.Set);
6181 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6187 /// Fully resolved expression that evaluates to an Event
6189 public class EventExpr : MemberExpr, IAssignMethod
6191 readonly EventSpec spec;
6194 public EventExpr (EventSpec spec, Location loc)
6202 protected override TypeSpec DeclaringType {
6204 return spec.DeclaringType;
6208 public override string Name {
6214 public override bool IsInstance {
6216 return !spec.IsStatic;
6220 public override bool IsStatic {
6222 return spec.IsStatic;
6226 public override string KindName {
6227 get { return "event"; }
6230 public MethodSpec Operator {
6238 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6241 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6243 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6244 if (spec.BackingField != null &&
6245 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6247 spec.MemberDefinition.SetIsUsed ();
6249 if (!ec.IsObsolete) {
6250 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6252 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6255 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6256 Error_AssignmentEventOnly (ec);
6258 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6260 InstanceExpression = null;
6262 return ml.ResolveMemberAccess (ec, left, original);
6266 return base.ResolveMemberAccess (ec, left, original);
6269 public override Expression CreateExpressionTree (ResolveContext ec)
6271 throw new NotSupportedException ("ET");
6274 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6276 if (right_side == EmptyExpression.EventAddition) {
6277 op = spec.AccessorAdd;
6278 } else if (right_side == EmptyExpression.EventSubtraction) {
6279 op = spec.AccessorRemove;
6283 Error_AssignmentEventOnly (ec);
6287 op = CandidateToBaseOverride (ec, op);
6291 protected override Expression DoResolve (ResolveContext ec)
6293 eclass = ExprClass.EventAccess;
6294 type = spec.MemberType;
6296 ResolveInstanceExpression (ec, null);
6298 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6299 Error_AssignmentEventOnly (ec);
6302 DoBestMemberChecks (ec, spec);
6306 public override void Emit (EmitContext ec)
6308 throw new NotSupportedException ();
6309 //Error_CannotAssign ();
6312 #region IAssignMethod Members
6314 public void Emit (EmitContext ec, bool leave_copy)
6316 throw new NotImplementedException ();
6319 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6321 if (leave_copy || !isCompound)
6322 throw new NotImplementedException ("EventExpr::EmitAssign");
6324 Arguments args = new Arguments (1);
6325 args.Add (new Argument (source));
6327 var call = new CallEmitter ();
6328 call.InstanceExpression = InstanceExpression;
6329 call.Emit (ec, op, args, loc);
6334 void Error_AssignmentEventOnly (ResolveContext ec)
6336 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6337 ec.Report.Error (79, loc,
6338 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6339 GetSignatureForError ());
6341 ec.Report.Error (70, loc,
6342 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6343 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6347 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6349 name = name.Substring (0, name.LastIndexOf ('.'));
6350 base.Error_CannotCallAbstractBase (rc, name);
6353 public override string GetSignatureForError ()
6355 return TypeManager.CSharpSignature (spec);
6358 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6360 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6364 public class TemporaryVariableReference : VariableReference
6366 public class Declarator : Statement
6368 TemporaryVariableReference variable;
6370 public Declarator (TemporaryVariableReference variable)
6372 this.variable = variable;
6376 protected override void DoEmit (EmitContext ec)
6378 variable.li.CreateBuilder (ec);
6381 public override void Emit (EmitContext ec)
6383 // Don't create sequence point
6387 protected override void CloneTo (CloneContext clonectx, Statement target)
6395 public TemporaryVariableReference (LocalVariable li, Location loc)
6398 this.type = li.Type;
6402 public override bool IsLockedByStatement {
6410 public LocalVariable LocalInfo {
6416 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6418 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6419 return new TemporaryVariableReference (li, loc);
6422 protected override Expression DoResolve (ResolveContext ec)
6424 eclass = ExprClass.Variable;
6427 // Don't capture temporary variables except when using
6428 // state machine redirection and block yields
6430 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6431 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6432 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6433 storey.CaptureLocalVariable (ec, li);
6439 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6441 return Resolve (ec);
6444 public override void Emit (EmitContext ec)
6446 li.CreateBuilder (ec);
6451 public void EmitAssign (EmitContext ec, Expression source)
6453 li.CreateBuilder (ec);
6455 EmitAssign (ec, source, false, false);
6458 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6460 return li.HoistedVariant;
6463 public override bool IsFixed {
6464 get { return true; }
6467 public override bool IsRef {
6468 get { return false; }
6471 public override string Name {
6472 get { throw new NotImplementedException (); }
6475 public override void SetHasAddressTaken ()
6477 throw new NotImplementedException ();
6480 protected override ILocalVariable Variable {
6484 public override VariableInfo VariableInfo {
6485 get { return null; }
6488 public override void VerifyAssigned (ResolveContext rc)
6494 /// Handles `var' contextual keyword; var becomes a keyword only
6495 /// if no type called var exists in a variable scope
6497 class VarExpr : SimpleName
6499 public VarExpr (Location loc)
6504 public bool InferType (ResolveContext ec, Expression right_side)
6507 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6509 type = right_side.Type;
6510 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6511 ec.Report.Error (815, loc,
6512 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6513 type.GetSignatureForError ());
6517 eclass = ExprClass.Variable;
6521 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6523 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6524 base.Error_TypeOrNamespaceNotFound (ec);
6526 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");