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)
4019 // Prefer non-optional version
4021 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4023 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4024 if (candidate_pd.Count >= best_pd.Count)
4027 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4034 // One is a non-generic method and second is a generic method, then non-generic is better
4036 if (best.IsGeneric != candidate.IsGeneric)
4037 return best.IsGeneric;
4040 // This handles the following cases:
4042 // Trim () is better than Trim (params char[] chars)
4043 // Concat (string s1, string s2, string s3) is better than
4044 // Concat (string s1, params string [] srest)
4045 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4047 // Prefer non-expanded version
4049 if (candidate_params != best_params)
4052 int candidate_param_count = candidate_pd.Count;
4053 int best_param_count = best_pd.Count;
4055 if (candidate_param_count != best_param_count)
4056 // can only happen if (candidate_params && best_params)
4057 return candidate_param_count > best_param_count && best_pd.HasParams;
4060 // Both methods have the same number of parameters, and the parameters have equal types
4061 // Pick the "more specific" signature using rules over original (non-inflated) types
4063 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4064 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4066 bool specific_at_least_once = false;
4067 for (j = 0; j < args_count; ++j) {
4068 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4070 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4071 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4073 ct = candidate_def_pd.Types[j];
4074 bt = best_def_pd.Types[j];
4079 TypeSpec specific = MoreSpecific (ct, bt);
4083 specific_at_least_once = true;
4086 if (specific_at_least_once)
4092 static bool CheckInflatedArguments (MethodSpec ms)
4094 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4097 // Setup constraint checker for probing only
4098 ConstraintChecker cc = new ConstraintChecker (null);
4100 var mp = ms.Parameters.Types;
4101 for (int i = 0; i < mp.Length; ++i) {
4102 var type = mp[i] as InflatedTypeSpec;
4106 var targs = type.TypeArguments;
4107 if (targs.Length == 0)
4110 // TODO: Checking inflated MVAR arguments should be enough
4111 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4118 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4120 rc.Report.Error (1729, loc,
4121 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4122 type.GetSignatureForError (), argCount.ToString ());
4126 // Determines if the candidate method is applicable to the given set of arguments
4127 // There could be two different set of parameters for same candidate where one
4128 // is the closest override for default values and named arguments checks and second
4129 // one being the virtual base for the parameter types and modifiers.
4131 // A return value rates candidate method compatibility,
4132 // 0 = the best, int.MaxValue = the worst
4135 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)
4137 // Parameters of most-derived type used mainly for named and optional parameters
4138 var pd = pm.Parameters;
4140 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4141 // params modifier instead of most-derived type
4142 var cpd = ((IParametersMember) candidate).Parameters;
4143 int param_count = pd.Count;
4144 int optional_count = 0;
4146 Arguments orig_args = arguments;
4148 if (arg_count != param_count) {
4150 // No arguments expansion when doing exact match for delegates
4152 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4153 for (int i = 0; i < pd.Count; ++i) {
4154 if (pd.FixedParameters[i].HasDefaultValue) {
4155 optional_count = pd.Count - i;
4161 if (optional_count != 0) {
4162 // Readjust expected number when params used
4163 if (cpd.HasParams) {
4165 if (arg_count < param_count)
4167 } else if (arg_count > param_count) {
4168 int args_gap = System.Math.Abs (arg_count - param_count);
4169 return int.MaxValue - 10000 + args_gap;
4171 } else if (arg_count != param_count) {
4172 int args_gap = System.Math.Abs (arg_count - param_count);
4174 return int.MaxValue - 10000 + args_gap;
4175 if (arg_count < param_count - 1)
4176 return int.MaxValue - 10000 + args_gap;
4179 // Resize to fit optional arguments
4180 if (optional_count != 0) {
4181 if (arguments == null) {
4182 arguments = new Arguments (optional_count);
4184 // Have to create a new container, so the next run can do same
4185 var resized = new Arguments (param_count);
4186 resized.AddRange (arguments);
4187 arguments = resized;
4190 for (int i = arg_count; i < param_count; ++i)
4191 arguments.Add (null);
4195 if (arg_count > 0) {
4197 // Shuffle named arguments to the right positions if there are any
4199 if (arguments[arg_count - 1] is NamedArgument) {
4200 arg_count = arguments.Count;
4202 for (int i = 0; i < arg_count; ++i) {
4203 bool arg_moved = false;
4205 NamedArgument na = arguments[i] as NamedArgument;
4209 int index = pd.GetParameterIndexByName (na.Name);
4211 // Named parameter not found
4215 // already reordered
4220 if (index >= param_count) {
4221 // When using parameters which should not be available to the user
4222 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4225 arguments.Add (null);
4229 temp = arguments[index];
4231 // The slot has been taken by positional argument
4232 if (temp != null && !(temp is NamedArgument))
4237 arguments = arguments.MarkOrderedArgument (na);
4241 arguments[index] = arguments[i];
4242 arguments[i] = temp;
4249 arg_count = arguments.Count;
4251 } else if (arguments != null) {
4252 arg_count = arguments.Count;
4256 // Don't do any expensive checks when the candidate cannot succeed
4258 if (arg_count != param_count && !cpd.HasParams)
4259 return (param_count - arg_count) * 2 + 1;
4261 var dep = candidate.GetMissingDependencies ();
4263 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4268 // 1. Handle generic method using type arguments when specified or type inference
4271 var ms = candidate as MethodSpec;
4272 if (ms != null && ms.IsGeneric) {
4273 if (type_arguments != null) {
4274 var g_args_count = ms.Arity;
4275 if (g_args_count != type_arguments.Count)
4276 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4278 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4281 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4282 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4283 // candidate was found use the set to report more details about what was wrong with lambda body.
4284 // The general idea is to distinguish between code errors and errors caused by
4285 // trial-and-error type inference
4287 if (lambda_conv_msgs == null) {
4288 for (int i = 0; i < arg_count; i++) {
4289 Argument a = arguments[i];
4293 var am = a.Expr as AnonymousMethodExpression;
4295 if (lambda_conv_msgs == null)
4296 lambda_conv_msgs = new SessionReportPrinter ();
4298 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4303 var ti = new TypeInference (arguments);
4304 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4307 return ti.InferenceScore - 20000;
4310 // Clear any error messages when the result was success
4312 if (lambda_conv_msgs != null)
4313 lambda_conv_msgs.ClearSession ();
4315 if (i_args.Length != 0) {
4316 ms = ms.MakeGenericMethod (ec, i_args);
4321 // Type arguments constraints have to match for the method to be applicable
4323 if (!CheckInflatedArguments (ms)) {
4325 return int.MaxValue - 25000;
4329 // We have a generic return type and at same time the method is override which
4330 // means we have to also inflate override return type in case the candidate is
4331 // best candidate and override return type is different to base return type.
4333 // virtual Foo<T, object> with override Foo<T, dynamic>
4335 if (candidate != pm) {
4336 MethodSpec override_ms = (MethodSpec) pm;
4337 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4338 returnType = inflator.Inflate (returnType);
4340 returnType = ms.ReturnType;
4344 ptypes = ms.Parameters.Types;
4346 if (type_arguments != null)
4347 return int.MaxValue - 15000;
4353 // 2. Each argument has to be implicitly convertible to method parameter
4355 Parameter.Modifier p_mod = 0;
4358 for (int i = 0; i < arg_count; i++) {
4359 Argument a = arguments[i];
4361 var fp = pd.FixedParameters[i];
4362 if (!fp.HasDefaultValue) {
4363 arguments = orig_args;
4364 return arg_count * 2 + 2;
4368 // Get the default value expression, we can use the same expression
4369 // if the type matches
4371 Expression e = fp.DefaultValue;
4372 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4374 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4376 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4377 e = new MemberAccess (new MemberAccess (new MemberAccess (
4378 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4380 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4386 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4388 // LAMESPEC: Attributes can be mixed together with build-in priority
4390 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4391 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4392 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4393 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4394 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4395 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4399 arguments[i] = new Argument (e, Argument.AType.Default);
4403 if (p_mod != Parameter.Modifier.PARAMS) {
4404 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4406 } else if (!params_expanded_form) {
4407 params_expanded_form = true;
4408 pt = ((ElementTypeSpec) pt).Element;
4414 if (!params_expanded_form) {
4415 if (a.ArgType == Argument.AType.ExtensionType) {
4417 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4419 // LAMESPEC: or implicit type parameter conversion
4422 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4423 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4424 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4429 score = IsArgumentCompatible (ec, a, p_mod, pt);
4432 dynamicArgument = true;
4437 // It can be applicable in expanded form (when not doing exact match like for delegates)
4439 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4440 if (!params_expanded_form)
4441 pt = ((ElementTypeSpec) pt).Element;
4444 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4447 params_expanded_form = true;
4448 } else if (score < 0) {
4449 params_expanded_form = true;
4450 dynamicArgument = true;
4455 if (params_expanded_form)
4457 return (arg_count - i) * 2 + score;
4462 // When params parameter has no argument it will be provided later if the method is the best candidate
4464 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4465 params_expanded_form = true;
4468 // Restore original arguments for dynamic binder to keep the intention of original source code
4470 if (dynamicArgument)
4471 arguments = orig_args;
4477 // Tests argument compatibility with the parameter
4478 // The possible return values are
4480 // 1 - modifier mismatch
4481 // 2 - type mismatch
4482 // -1 - dynamic binding required
4484 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4487 // Types have to be identical when ref or out modifer
4488 // is used and argument is not of dynamic type
4490 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4491 if (argument.Type != parameter) {
4493 // Do full equality check after quick path
4495 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4497 // Using dynamic for ref/out parameter can still succeed at runtime
4499 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4506 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4508 // Using dynamic for ref/out parameter can still succeed at runtime
4510 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4517 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4521 // Use implicit conversion in all modes to return same candidates when the expression
4522 // is used as argument or delegate conversion
4524 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4532 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4534 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4536 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4539 var ac_p = p as ArrayContainer;
4541 var ac_q = q as ArrayContainer;
4545 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4546 if (specific == ac_p.Element)
4548 if (specific == ac_q.Element)
4550 } else if (p.IsGeneric && q.IsGeneric) {
4551 var pargs = TypeManager.GetTypeArguments (p);
4552 var qargs = TypeManager.GetTypeArguments (q);
4554 bool p_specific_at_least_once = false;
4555 bool q_specific_at_least_once = false;
4557 for (int i = 0; i < pargs.Length; i++) {
4558 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4559 if (specific == pargs[i])
4560 p_specific_at_least_once = true;
4561 if (specific == qargs[i])
4562 q_specific_at_least_once = true;
4565 if (p_specific_at_least_once && !q_specific_at_least_once)
4567 if (!p_specific_at_least_once && q_specific_at_least_once)
4575 // Find the best method from candidate list
4577 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4579 List<AmbiguousCandidate> ambiguous_candidates = null;
4581 MemberSpec best_candidate;
4582 Arguments best_candidate_args = null;
4583 bool best_candidate_params = false;
4584 bool best_candidate_dynamic = false;
4585 int best_candidate_rate;
4586 IParametersMember best_parameter_member = null;
4588 int args_count = args != null ? args.Count : 0;
4590 Arguments candidate_args = args;
4591 bool error_mode = false;
4592 MemberSpec invocable_member = null;
4595 best_candidate = null;
4596 best_candidate_rate = int.MaxValue;
4598 var type_members = members;
4600 for (int i = 0; i < type_members.Count; ++i) {
4601 var member = type_members[i];
4604 // Methods in a base class are not candidates if any method in a derived
4605 // class is applicable
4607 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4611 if (!member.IsAccessible (rc))
4614 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4617 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4618 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4623 IParametersMember pm = member as IParametersMember;
4626 // Will use it later to report ambiguity between best method and invocable member
4628 if (Invocation.IsMemberInvocable (member))
4629 invocable_member = member;
4635 // Overload resolution is looking for base member but using parameter names
4636 // and default values from the closest member. That means to do expensive lookup
4637 // for the closest override for virtual or abstract members
4639 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4640 var override_params = base_provider.GetOverrideMemberParameters (member);
4641 if (override_params != null)
4642 pm = override_params;
4646 // Check if the member candidate is applicable
4648 bool params_expanded_form = false;
4649 bool dynamic_argument = false;
4650 TypeSpec rt = pm.MemberType;
4651 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4653 if (lambda_conv_msgs != null)
4654 lambda_conv_msgs.EndSession ();
4657 // How does it score compare to others
4659 if (candidate_rate < best_candidate_rate) {
4661 // Fatal error (missing dependency), cannot continue
4662 if (candidate_rate < 0)
4665 best_candidate_rate = candidate_rate;
4666 best_candidate = member;
4667 best_candidate_args = candidate_args;
4668 best_candidate_params = params_expanded_form;
4669 best_candidate_dynamic = dynamic_argument;
4670 best_parameter_member = pm;
4671 best_candidate_return_type = rt;
4672 } else if (candidate_rate == 0) {
4674 // The member look is done per type for most operations but sometimes
4675 // it's not possible like for binary operators overload because they
4676 // are unioned between 2 sides
4678 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4679 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4684 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4686 // We pack all interface members into top level type which makes the overload resolution
4687 // more complicated for interfaces. We compensate it by removing methods with same
4688 // signature when building the cache hence this path should not really be hit often
4691 // interface IA { void Foo (int arg); }
4692 // interface IB : IA { void Foo (params int[] args); }
4694 // IB::Foo is the best overload when calling IB.Foo (1)
4697 if (ambiguous_candidates != null) {
4698 foreach (var amb_cand in ambiguous_candidates) {
4699 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4708 ambiguous_candidates = null;
4711 // Is the new candidate better
4712 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4716 best_candidate = member;
4717 best_candidate_args = candidate_args;
4718 best_candidate_params = params_expanded_form;
4719 best_candidate_dynamic = dynamic_argument;
4720 best_parameter_member = pm;
4721 best_candidate_return_type = rt;
4723 // It's not better but any other found later could be but we are not sure yet
4724 if (ambiguous_candidates == null)
4725 ambiguous_candidates = new List<AmbiguousCandidate> ();
4727 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4731 // Restore expanded arguments
4732 if (candidate_args != args)
4733 candidate_args = args;
4735 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4738 // We've found exact match
4740 if (best_candidate_rate == 0)
4744 // Try extension methods lookup when no ordinary method match was found and provider enables it
4747 var emg = base_provider.LookupExtensionMethod (rc);
4749 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4751 best_candidate_extension_group = emg;
4752 return (T) (MemberSpec) emg.BestCandidate;
4757 // Don't run expensive error reporting mode for probing
4764 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4767 lambda_conv_msgs = null;
4772 // No best member match found, report an error
4774 if (best_candidate_rate != 0 || error_mode) {
4775 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4779 if (best_candidate_dynamic) {
4780 if (args[0].ArgType == Argument.AType.ExtensionType) {
4781 rc.Report.Error (1973, loc,
4782 "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",
4783 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4787 // Check type constraints only when explicit type arguments are used
4789 if (best_candidate.IsGeneric && type_arguments != null) {
4790 MethodSpec bc = best_candidate as MethodSpec;
4791 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4792 ConstraintChecker cc = new ConstraintChecker (rc);
4793 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4797 BestCandidateIsDynamic = true;
4802 // These flags indicates we are running delegate probing conversion. No need to
4803 // do more expensive checks
4805 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4806 return (T) best_candidate;
4808 if (ambiguous_candidates != null) {
4810 // Now check that there are no ambiguities i.e the selected method
4811 // should be better than all the others
4813 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4814 var candidate = ambiguous_candidates [ix];
4816 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4817 var ambiguous = candidate.Member;
4818 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4819 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4820 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4821 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4822 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4825 return (T) best_candidate;
4830 if (invocable_member != null) {
4831 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4832 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4833 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4834 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4838 // And now check if the arguments are all
4839 // compatible, perform conversions if
4840 // necessary etc. and return if everything is
4843 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4846 if (best_candidate == null)
4850 // Check ObsoleteAttribute on the best method
4852 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4853 if (oa != null && !rc.IsObsolete)
4854 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4856 best_candidate.MemberDefinition.SetIsUsed ();
4858 args = best_candidate_args;
4859 return (T) best_candidate;
4862 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4864 return ResolveMember<MethodSpec> (rc, ref args);
4867 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4868 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4870 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4873 if (a.Type == InternalType.ErrorType)
4876 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4877 ec.Report.SymbolRelatedToPreviousError (method);
4878 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4879 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4880 TypeManager.CSharpSignature (method));
4883 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4884 TypeManager.CSharpSignature (method));
4885 } else if (IsDelegateInvoke) {
4886 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4887 DelegateType.GetSignatureForError ());
4889 ec.Report.SymbolRelatedToPreviousError (method);
4890 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4891 method.GetSignatureForError ());
4894 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4896 string index = (idx + 1).ToString ();
4897 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4898 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4899 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4900 index, Parameter.GetModifierSignature (a.Modifier));
4902 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4903 index, Parameter.GetModifierSignature (mod));
4905 string p1 = a.GetSignatureForError ();
4906 string p2 = TypeManager.CSharpName (paramType);
4909 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4910 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4913 ec.Report.Error (1503, loc,
4914 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4919 // We have failed to find exact match so we return error info about the closest match
4921 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4923 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4924 int arg_count = args == null ? 0 : args.Count;
4926 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4927 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4928 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4932 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
4937 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4938 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4939 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4943 // For candidates which match on parameters count report more details about incorrect arguments
4946 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4947 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4948 // Reject any inaccessible member
4949 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4950 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4951 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4955 var ms = best_candidate as MethodSpec;
4956 if (ms != null && ms.IsGeneric) {
4957 bool constr_ok = true;
4958 if (ms.TypeArguments != null)
4959 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4961 if (ta_count == 0) {
4962 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4966 rc.Report.Error (411, loc,
4967 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4968 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4975 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4981 // We failed to find any method with correct argument count, report best candidate
4983 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4986 if (best_candidate.Kind == MemberKind.Constructor) {
4987 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4988 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4989 } else if (IsDelegateInvoke) {
4990 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4991 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4992 DelegateType.GetSignatureForError (), arg_count.ToString ());
4994 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4995 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4996 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4997 name, arg_count.ToString ());
5001 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5003 var pd = pm.Parameters;
5004 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5006 Parameter.Modifier p_mod = 0;
5008 int a_idx = 0, a_pos = 0;
5010 ArrayInitializer params_initializers = null;
5011 bool has_unsafe_arg = pm.MemberType.IsPointer;
5012 int arg_count = args == null ? 0 : args.Count;
5014 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5016 if (p_mod != Parameter.Modifier.PARAMS) {
5017 p_mod = pd.FixedParameters[a_idx].ModFlags;
5019 has_unsafe_arg |= pt.IsPointer;
5021 if (p_mod == Parameter.Modifier.PARAMS) {
5022 if (chose_params_expanded) {
5023 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5024 pt = TypeManager.GetElementType (pt);
5030 // Types have to be identical when ref or out modifer is used
5032 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5033 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5036 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5042 NamedArgument na = a as NamedArgument;
5044 int name_index = pd.GetParameterIndexByName (na.Name);
5045 if (name_index < 0 || name_index >= pd.Count) {
5046 if (IsDelegateInvoke) {
5047 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5048 ec.Report.Error (1746, na.Location,
5049 "The delegate `{0}' does not contain a parameter named `{1}'",
5050 DelegateType.GetSignatureForError (), na.Name);
5052 ec.Report.SymbolRelatedToPreviousError (member);
5053 ec.Report.Error (1739, na.Location,
5054 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5055 TypeManager.CSharpSignature (member), na.Name);
5057 } else if (args[name_index] != a) {
5058 if (IsDelegateInvoke)
5059 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5061 ec.Report.SymbolRelatedToPreviousError (member);
5063 ec.Report.Error (1744, na.Location,
5064 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5069 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5072 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5073 custom_errors.NoArgumentMatch (ec, member);
5077 Expression conv = null;
5078 if (a.ArgType == Argument.AType.ExtensionType) {
5079 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5082 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5084 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5087 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5094 // Convert params arguments to an array initializer
5096 if (params_initializers != null) {
5097 // we choose to use 'a.Expr' rather than 'conv' so that
5098 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5099 params_initializers.Add (a.Expr);
5100 args.RemoveAt (a_idx--);
5105 // Update the argument with the implicit conversion
5109 if (a_idx != arg_count) {
5110 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5115 // Fill not provided arguments required by params modifier
5117 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5119 args = new Arguments (1);
5121 pt = ptypes[pd.Count - 1];
5122 pt = TypeManager.GetElementType (pt);
5123 has_unsafe_arg |= pt.IsPointer;
5124 params_initializers = new ArrayInitializer (0, loc);
5128 // Append an array argument with all params arguments
5130 if (params_initializers != null) {
5131 args.Add (new Argument (
5132 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5136 if (has_unsafe_arg && !ec.IsUnsafe) {
5137 Expression.UnsafeError (ec, loc);
5141 // We could infer inaccesible type arguments
5143 if (type_arguments == null && member.IsGeneric) {
5144 var ms = (MethodSpec) member;
5145 foreach (var ta in ms.TypeArguments) {
5146 if (!ta.IsAccessible (ec)) {
5147 ec.Report.SymbolRelatedToPreviousError (ta);
5148 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5158 public class ConstantExpr : MemberExpr
5160 readonly ConstSpec constant;
5162 public ConstantExpr (ConstSpec constant, Location loc)
5164 this.constant = constant;
5168 public override string Name {
5169 get { throw new NotImplementedException (); }
5172 public override string KindName {
5173 get { return "constant"; }
5176 public override bool IsInstance {
5177 get { return !IsStatic; }
5180 public override bool IsStatic {
5181 get { return true; }
5184 protected override TypeSpec DeclaringType {
5185 get { return constant.DeclaringType; }
5188 public override Expression CreateExpressionTree (ResolveContext ec)
5190 throw new NotSupportedException ("ET");
5193 protected override Expression DoResolve (ResolveContext rc)
5195 ResolveInstanceExpression (rc, null);
5196 DoBestMemberChecks (rc, constant);
5198 var c = constant.GetConstant (rc);
5200 // Creates reference expression to the constant value
5201 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5204 public override void Emit (EmitContext ec)
5206 throw new NotSupportedException ();
5209 public override string GetSignatureForError ()
5211 return constant.GetSignatureForError ();
5214 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5216 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5221 // Fully resolved expression that references a Field
5223 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5225 protected FieldSpec spec;
5226 VariableInfo variable_info;
5228 LocalTemporary temp;
5231 protected FieldExpr (Location l)
5236 public FieldExpr (FieldSpec spec, Location loc)
5241 type = spec.MemberType;
5244 public FieldExpr (FieldBase fi, Location l)
5251 public override string Name {
5257 public bool IsHoisted {
5259 IVariableReference hv = InstanceExpression as IVariableReference;
5260 return hv != null && hv.IsHoisted;
5264 public override bool IsInstance {
5266 return !spec.IsStatic;
5270 public override bool IsStatic {
5272 return spec.IsStatic;
5276 public override string KindName {
5277 get { return "field"; }
5280 public FieldSpec Spec {
5286 protected override TypeSpec DeclaringType {
5288 return spec.DeclaringType;
5292 public VariableInfo VariableInfo {
5294 return variable_info;
5300 public override string GetSignatureForError ()
5302 return spec.GetSignatureForError ();
5305 public bool IsMarshalByRefAccess (ResolveContext rc)
5307 // Checks possible ldflda of field access expression
5308 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5309 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5310 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5313 public void SetHasAddressTaken ()
5315 IVariableReference vr = InstanceExpression as IVariableReference;
5317 vr.SetHasAddressTaken ();
5321 public override Expression CreateExpressionTree (ResolveContext ec)
5323 return CreateExpressionTree (ec, true);
5326 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5329 Expression instance;
5331 if (InstanceExpression == null) {
5332 instance = new NullLiteral (loc);
5333 } else if (convertInstance) {
5334 instance = InstanceExpression.CreateExpressionTree (ec);
5336 args = new Arguments (1);
5337 args.Add (new Argument (InstanceExpression));
5338 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5341 args = Arguments.CreateForExpressionTree (ec, null,
5343 CreateTypeOfExpression ());
5345 return CreateExpressionFactoryCall (ec, "Field", args);
5348 public Expression CreateTypeOfExpression ()
5350 return new TypeOfField (spec, loc);
5353 protected override Expression DoResolve (ResolveContext ec)
5355 spec.MemberDefinition.SetIsUsed ();
5357 return DoResolve (ec, null);
5360 Expression DoResolve (ResolveContext ec, Expression rhs)
5362 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5365 if (ResolveInstanceExpression (ec, rhs)) {
5366 // Resolve the field's instance expression while flow analysis is turned
5367 // off: when accessing a field "a.b", we must check whether the field
5368 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5370 if (lvalue_instance) {
5371 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5372 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5374 Expression right_side =
5375 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5377 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5380 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5381 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5385 if (InstanceExpression == null)
5389 DoBestMemberChecks (ec, spec);
5392 var fb = spec as FixedFieldSpec;
5393 IVariableReference var = InstanceExpression as IVariableReference;
5395 if (lvalue_instance && var != null && var.VariableInfo != null) {
5396 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5400 IFixedExpression fe = InstanceExpression as IFixedExpression;
5401 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5402 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5405 if (InstanceExpression.eclass != ExprClass.Variable) {
5406 ec.Report.SymbolRelatedToPreviousError (spec);
5407 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5408 TypeManager.GetFullNameSignature (spec));
5409 } else if (var != null && var.IsHoisted) {
5410 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5413 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5417 // Set flow-analysis variable info for struct member access. It will be check later
5418 // for precise error reporting
5420 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5421 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5422 if (rhs != null && variable_info != null)
5423 variable_info.SetStructFieldAssigned (ec, Name);
5426 eclass = ExprClass.Variable;
5430 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5435 var var = fe.InstanceExpression as IVariableReference;
5437 var vi = var.VariableInfo;
5439 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5441 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5443 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5450 fe = fe.InstanceExpression as FieldExpr;
5452 } while (fe != null);
5455 static readonly int [] codes = {
5456 191, // instance, write access
5457 192, // instance, out access
5458 198, // static, write access
5459 199, // static, out access
5460 1648, // member of value instance, write access
5461 1649, // member of value instance, out access
5462 1650, // member of value static, write access
5463 1651 // member of value static, out access
5466 static readonly string [] msgs = {
5467 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5468 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5469 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5470 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5471 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5472 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5473 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5474 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5477 // The return value is always null. Returning a value simplifies calling code.
5478 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5481 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5485 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5487 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5492 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5494 Expression e = DoResolve (ec, right_side);
5499 spec.MemberDefinition.SetIsAssigned ();
5501 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5502 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5503 ec.Report.Warning (420, 1, loc,
5504 "`{0}': A volatile field references will not be treated as volatile",
5505 spec.GetSignatureForError ());
5508 if (spec.IsReadOnly) {
5509 // InitOnly fields can only be assigned in constructors or initializers
5510 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5511 return Report_AssignToReadonly (ec, right_side);
5513 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5515 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5516 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5517 return Report_AssignToReadonly (ec, right_side);
5518 // static InitOnly fields cannot be assigned-to in an instance constructor
5519 if (IsStatic && !ec.IsStatic)
5520 return Report_AssignToReadonly (ec, right_side);
5521 // instance constructors can't modify InitOnly fields of other instances of the same type
5522 if (!IsStatic && !(InstanceExpression is This))
5523 return Report_AssignToReadonly (ec, right_side);
5527 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5528 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5529 ec.Report.Warning (197, 1, loc,
5530 "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",
5531 GetSignatureForError ());
5534 eclass = ExprClass.Variable;
5538 public override int GetHashCode ()
5540 return spec.GetHashCode ();
5543 public bool IsFixed {
5546 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5548 IVariableReference variable = InstanceExpression as IVariableReference;
5549 if (variable != null)
5550 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5552 IFixedExpression fe = InstanceExpression as IFixedExpression;
5553 return fe != null && fe.IsFixed;
5557 public override bool Equals (object obj)
5559 FieldExpr fe = obj as FieldExpr;
5563 if (spec != fe.spec)
5566 if (InstanceExpression == null || fe.InstanceExpression == null)
5569 return InstanceExpression.Equals (fe.InstanceExpression);
5572 public void Emit (EmitContext ec, bool leave_copy)
5574 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5578 ec.Emit (OpCodes.Volatile);
5580 ec.Emit (OpCodes.Ldsfld, spec);
5583 EmitInstance (ec, false);
5585 // Optimization for build-in types
5586 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5587 ec.EmitLoadFromPtr (type);
5589 var ff = spec as FixedFieldSpec;
5591 ec.Emit (OpCodes.Ldflda, spec);
5592 ec.Emit (OpCodes.Ldflda, ff.Element);
5595 ec.Emit (OpCodes.Volatile);
5597 ec.Emit (OpCodes.Ldfld, spec);
5603 ec.Emit (OpCodes.Dup);
5605 temp = new LocalTemporary (this.Type);
5611 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5613 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5614 if (isCompound && !(source is DynamicExpressionStatement)) {
5615 if (has_await_source) {
5617 InstanceExpression = InstanceExpression.EmitToField (ec);
5624 if (has_await_source)
5625 source = source.EmitToField (ec);
5627 EmitInstance (ec, prepared);
5633 ec.Emit (OpCodes.Dup);
5635 temp = new LocalTemporary (this.Type);
5640 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5641 ec.Emit (OpCodes.Volatile);
5643 spec.MemberDefinition.SetIsAssigned ();
5646 ec.Emit (OpCodes.Stsfld, spec);
5648 ec.Emit (OpCodes.Stfld, spec);
5658 // Emits store to field with prepared values on stack
5660 public void EmitAssignFromStack (EmitContext ec)
5663 ec.Emit (OpCodes.Stsfld, spec);
5665 ec.Emit (OpCodes.Stfld, spec);
5669 public override void Emit (EmitContext ec)
5674 public override void EmitSideEffect (EmitContext ec)
5676 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5678 if (is_volatile) // || is_marshal_by_ref ())
5679 base.EmitSideEffect (ec);
5682 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5684 if ((mode & AddressOp.Store) != 0)
5685 spec.MemberDefinition.SetIsAssigned ();
5686 if ((mode & AddressOp.Load) != 0)
5687 spec.MemberDefinition.SetIsUsed ();
5690 // Handle initonly fields specially: make a copy and then
5691 // get the address of the copy.
5694 if (spec.IsReadOnly){
5696 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5708 var temp = ec.GetTemporaryLocal (type);
5709 ec.Emit (OpCodes.Stloc, temp);
5710 ec.Emit (OpCodes.Ldloca, temp);
5711 ec.FreeTemporaryLocal (temp, type);
5717 ec.Emit (OpCodes.Ldsflda, spec);
5720 EmitInstance (ec, false);
5721 ec.Emit (OpCodes.Ldflda, spec);
5725 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5727 return MakeExpression (ctx);
5730 public override SLE.Expression MakeExpression (BuilderContext ctx)
5733 return base.MakeExpression (ctx);
5735 return SLE.Expression.Field (
5736 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5737 spec.GetMetaInfo ());
5741 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5743 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5749 // Expression that evaluates to a Property.
5751 // This is not an LValue because we need to re-write the expression. We
5752 // can not take data from the stack and store it.
5754 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5756 public PropertyExpr (PropertySpec spec, Location l)
5759 best_candidate = spec;
5760 type = spec.MemberType;
5765 protected override Arguments Arguments {
5773 protected override TypeSpec DeclaringType {
5775 return best_candidate.DeclaringType;
5779 public override string Name {
5781 return best_candidate.Name;
5785 public override bool IsInstance {
5791 public override bool IsStatic {
5793 return best_candidate.IsStatic;
5797 public override string KindName {
5798 get { return "property"; }
5801 public PropertySpec PropertyInfo {
5803 return best_candidate;
5809 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5811 return new PropertyExpr (spec, loc) {
5817 public override Expression CreateExpressionTree (ResolveContext ec)
5820 if (IsSingleDimensionalArrayLength ()) {
5821 args = new Arguments (1);
5822 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5823 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5826 args = new Arguments (2);
5827 if (InstanceExpression == null)
5828 args.Add (new Argument (new NullLiteral (loc)));
5830 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5831 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5832 return CreateExpressionFactoryCall (ec, "Property", args);
5835 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5837 DoResolveLValue (rc, null);
5838 return new TypeOfMethod (Setter, loc);
5841 public override string GetSignatureForError ()
5843 return best_candidate.GetSignatureForError ();
5846 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5849 return base.MakeExpression (ctx);
5851 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5855 public override SLE.Expression MakeExpression (BuilderContext ctx)
5858 return base.MakeExpression (ctx);
5860 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5864 void Error_PropertyNotValid (ResolveContext ec)
5866 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5867 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5868 GetSignatureForError ());
5871 bool IsSingleDimensionalArrayLength ()
5873 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5876 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5877 return ac != null && ac.Rank == 1;
5880 public override void Emit (EmitContext ec, bool leave_copy)
5883 // Special case: length of single dimension array property is turned into ldlen
5885 if (IsSingleDimensionalArrayLength ()) {
5886 EmitInstance (ec, false);
5887 ec.Emit (OpCodes.Ldlen);
5888 ec.Emit (OpCodes.Conv_I4);
5892 base.Emit (ec, leave_copy);
5895 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5898 LocalTemporary await_source_arg = null;
5900 if (isCompound && !(source is DynamicExpressionStatement)) {
5901 emitting_compound_assignment = true;
5904 if (has_await_arguments) {
5905 await_source_arg = new LocalTemporary (Type);
5906 await_source_arg.Store (ec);
5908 args = new Arguments (1);
5909 args.Add (new Argument (await_source_arg));
5912 temp = await_source_arg;
5915 has_await_arguments = false;
5920 ec.Emit (OpCodes.Dup);
5921 temp = new LocalTemporary (this.Type);
5926 args = new Arguments (1);
5930 temp = new LocalTemporary (this.Type);
5932 args.Add (new Argument (temp));
5934 args.Add (new Argument (source));
5938 emitting_compound_assignment = false;
5940 var call = new CallEmitter ();
5941 call.InstanceExpression = InstanceExpression;
5943 call.InstanceExpressionOnStack = true;
5945 call.Emit (ec, Setter, args, loc);
5952 if (await_source_arg != null) {
5953 await_source_arg.Release (ec);
5957 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5959 eclass = ExprClass.PropertyAccess;
5961 if (best_candidate.IsNotCSharpCompatible) {
5962 Error_PropertyNotValid (rc);
5965 ResolveInstanceExpression (rc, right_side);
5967 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5968 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5969 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5971 type = p.MemberType;
5975 DoBestMemberChecks (rc, best_candidate);
5979 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5981 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5985 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5987 // getter and setter can be different for base calls
5988 MethodSpec getter, setter;
5989 protected T best_candidate;
5991 protected LocalTemporary temp;
5992 protected bool emitting_compound_assignment;
5993 protected bool has_await_arguments;
5995 protected PropertyOrIndexerExpr (Location l)
6002 protected abstract Arguments Arguments { get; set; }
6004 public MethodSpec Getter {
6013 public MethodSpec Setter {
6024 protected override Expression DoResolve (ResolveContext ec)
6026 if (eclass == ExprClass.Unresolved) {
6027 var expr = OverloadResolve (ec, null);
6032 return expr.Resolve (ec);
6035 if (!ResolveGetter (ec))
6041 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6043 if (right_side == EmptyExpression.OutAccess) {
6044 // TODO: best_candidate can be null at this point
6045 INamedBlockVariable variable = null;
6046 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6047 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6048 best_candidate.Name);
6050 right_side.DoResolveLValue (ec, this);
6055 // if the property/indexer returns a value type, and we try to set a field in it
6056 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
6057 Error_ValueAssignment (ec, right_side);
6060 if (eclass == ExprClass.Unresolved) {
6061 var expr = OverloadResolve (ec, right_side);
6066 return expr.ResolveLValue (ec, right_side);
6069 if (!ResolveSetter (ec))
6076 // Implements the IAssignMethod interface for assignments
6078 public virtual void Emit (EmitContext ec, bool leave_copy)
6080 var call = new CallEmitter ();
6081 call.InstanceExpression = InstanceExpression;
6082 if (has_await_arguments)
6083 call.HasAwaitArguments = true;
6085 call.DuplicateArguments = emitting_compound_assignment;
6087 call.Emit (ec, Getter, Arguments, loc);
6089 if (call.HasAwaitArguments) {
6090 InstanceExpression = call.InstanceExpression;
6091 Arguments = call.EmittedArguments;
6092 has_await_arguments = true;
6096 ec.Emit (OpCodes.Dup);
6097 temp = new LocalTemporary (Type);
6102 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6104 public override void Emit (EmitContext ec)
6109 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6111 has_await_arguments = true;
6116 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6118 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6120 bool ResolveGetter (ResolveContext rc)
6122 if (!best_candidate.HasGet) {
6123 if (InstanceExpression != EmptyExpression.Null) {
6124 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6125 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6126 best_candidate.GetSignatureForError ());
6129 } else if (!best_candidate.Get.IsAccessible (rc)) {
6130 if (best_candidate.HasDifferentAccessibility) {
6131 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6132 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6133 TypeManager.CSharpSignature (best_candidate));
6135 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6136 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6140 if (best_candidate.HasDifferentAccessibility) {
6141 CheckProtectedMemberAccess (rc, best_candidate.Get);
6144 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6148 bool ResolveSetter (ResolveContext rc)
6150 if (!best_candidate.HasSet) {
6151 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6152 GetSignatureForError ());
6156 if (!best_candidate.Set.IsAccessible (rc)) {
6157 if (best_candidate.HasDifferentAccessibility) {
6158 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6159 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6160 GetSignatureForError ());
6162 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6163 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6167 if (best_candidate.HasDifferentAccessibility)
6168 CheckProtectedMemberAccess (rc, best_candidate.Set);
6170 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6176 /// Fully resolved expression that evaluates to an Event
6178 public class EventExpr : MemberExpr, IAssignMethod
6180 readonly EventSpec spec;
6183 public EventExpr (EventSpec spec, Location loc)
6191 protected override TypeSpec DeclaringType {
6193 return spec.DeclaringType;
6197 public override string Name {
6203 public override bool IsInstance {
6205 return !spec.IsStatic;
6209 public override bool IsStatic {
6211 return spec.IsStatic;
6215 public override string KindName {
6216 get { return "event"; }
6219 public MethodSpec Operator {
6227 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6230 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6232 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6233 if (spec.BackingField != null &&
6234 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6236 spec.MemberDefinition.SetIsUsed ();
6238 if (!ec.IsObsolete) {
6239 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6241 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6244 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6245 Error_AssignmentEventOnly (ec);
6247 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6249 InstanceExpression = null;
6251 return ml.ResolveMemberAccess (ec, left, original);
6255 return base.ResolveMemberAccess (ec, left, original);
6258 public override Expression CreateExpressionTree (ResolveContext ec)
6260 throw new NotSupportedException ("ET");
6263 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6265 if (right_side == EmptyExpression.EventAddition) {
6266 op = spec.AccessorAdd;
6267 } else if (right_side == EmptyExpression.EventSubtraction) {
6268 op = spec.AccessorRemove;
6272 Error_AssignmentEventOnly (ec);
6276 op = CandidateToBaseOverride (ec, op);
6280 protected override Expression DoResolve (ResolveContext ec)
6282 eclass = ExprClass.EventAccess;
6283 type = spec.MemberType;
6285 ResolveInstanceExpression (ec, null);
6287 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6288 Error_AssignmentEventOnly (ec);
6291 DoBestMemberChecks (ec, spec);
6295 public override void Emit (EmitContext ec)
6297 throw new NotSupportedException ();
6298 //Error_CannotAssign ();
6301 #region IAssignMethod Members
6303 public void Emit (EmitContext ec, bool leave_copy)
6305 throw new NotImplementedException ();
6308 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6310 if (leave_copy || !isCompound)
6311 throw new NotImplementedException ("EventExpr::EmitAssign");
6313 Arguments args = new Arguments (1);
6314 args.Add (new Argument (source));
6316 var call = new CallEmitter ();
6317 call.InstanceExpression = InstanceExpression;
6318 call.Emit (ec, op, args, loc);
6323 void Error_AssignmentEventOnly (ResolveContext ec)
6325 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6326 ec.Report.Error (79, loc,
6327 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6328 GetSignatureForError ());
6330 ec.Report.Error (70, loc,
6331 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6332 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6336 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6338 name = name.Substring (0, name.LastIndexOf ('.'));
6339 base.Error_CannotCallAbstractBase (rc, name);
6342 public override string GetSignatureForError ()
6344 return TypeManager.CSharpSignature (spec);
6347 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6349 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6353 public class TemporaryVariableReference : VariableReference
6355 public class Declarator : Statement
6357 TemporaryVariableReference variable;
6359 public Declarator (TemporaryVariableReference variable)
6361 this.variable = variable;
6365 protected override void DoEmit (EmitContext ec)
6367 variable.li.CreateBuilder (ec);
6370 public override void Emit (EmitContext ec)
6372 // Don't create sequence point
6376 protected override void CloneTo (CloneContext clonectx, Statement target)
6384 public TemporaryVariableReference (LocalVariable li, Location loc)
6387 this.type = li.Type;
6391 public override bool IsLockedByStatement {
6399 public LocalVariable LocalInfo {
6405 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6407 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6408 return new TemporaryVariableReference (li, loc);
6411 protected override Expression DoResolve (ResolveContext ec)
6413 eclass = ExprClass.Variable;
6416 // Don't capture temporary variables except when using
6417 // state machine redirection and block yields
6419 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6420 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6421 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6422 storey.CaptureLocalVariable (ec, li);
6428 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6430 return Resolve (ec);
6433 public override void Emit (EmitContext ec)
6435 li.CreateBuilder (ec);
6440 public void EmitAssign (EmitContext ec, Expression source)
6442 li.CreateBuilder (ec);
6444 EmitAssign (ec, source, false, false);
6447 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6449 return li.HoistedVariant;
6452 public override bool IsFixed {
6453 get { return true; }
6456 public override bool IsRef {
6457 get { return false; }
6460 public override string Name {
6461 get { throw new NotImplementedException (); }
6464 public override void SetHasAddressTaken ()
6466 throw new NotImplementedException ();
6469 protected override ILocalVariable Variable {
6473 public override VariableInfo VariableInfo {
6474 get { return null; }
6477 public override void VerifyAssigned (ResolveContext rc)
6483 /// Handles `var' contextual keyword; var becomes a keyword only
6484 /// if no type called var exists in a variable scope
6486 class VarExpr : SimpleName
6488 public VarExpr (Location loc)
6493 public bool InferType (ResolveContext ec, Expression right_side)
6496 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6498 type = right_side.Type;
6499 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6500 ec.Report.Error (815, loc,
6501 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6502 type.GetSignatureForError ());
6506 eclass = ExprClass.Variable;
6510 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6512 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6513 base.Error_TypeOrNamespaceNotFound (ec);
6515 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");