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, Location loc, 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 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, source.loc, 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 retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2281 if (retval != null) {
2282 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2283 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2287 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2288 if (retval != null) {
2289 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2293 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2296 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2298 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2301 if (fne.Type != null && Arity > 0) {
2302 if (HasTypeArguments) {
2303 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2304 if (ct.ResolveAsType (ec) == null)
2310 return new GenericOpenTypeExpr (fne.Type, loc);
2314 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2316 if (!(fne is Namespace))
2320 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2321 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2322 ec.Module.Compiler.Report.Error (1980, Location,
2323 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2324 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2327 fne = new DynamicTypeExpr (loc);
2328 fne.ResolveAsType (ec);
2334 Error_TypeOrNamespaceNotFound (ec);
2338 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2340 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2343 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2345 int lookup_arity = Arity;
2346 bool errorMode = false;
2348 Block current_block = rc.CurrentBlock;
2349 INamedBlockVariable variable = null;
2350 bool variable_found = false;
2354 // Stage 1: binding to local variables or parameters
2356 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2358 if (current_block != null && lookup_arity == 0) {
2359 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2360 if (!variable.IsDeclared) {
2361 // We found local name in accessible block but it's not
2362 // initialized yet, maybe the user wanted to bind to something else
2364 variable_found = true;
2366 e = variable.CreateReferenceExpression (rc, loc);
2369 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2378 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2380 TypeSpec member_type = rc.CurrentType;
2381 for (; member_type != null; member_type = member_type.DeclaringType) {
2382 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2386 var me = e as MemberExpr;
2388 // The name matches a type, defer to ResolveAsTypeStep
2396 if (variable != null) {
2397 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2398 rc.Report.Error (844, loc,
2399 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2400 Name, me.GetSignatureForError ());
2404 } else if (me is MethodGroupExpr) {
2405 // Leave it to overload resolution to report correct error
2407 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2408 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2411 // LAMESPEC: again, ignores InvocableOnly
2412 if (variable != null) {
2413 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2414 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2418 // MemberLookup does not check accessors availability, this is actually needed for properties only
2420 var pe = me as PropertyExpr;
2423 // Break as there is no other overload available anyway
2424 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2425 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2428 pe.Getter = pe.PropertyInfo.Get;
2430 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2433 pe.Setter = pe.PropertyInfo.Set;
2438 // TODO: It's used by EventExpr -> FieldExpr transformation only
2439 // TODO: Should go to MemberAccess
2440 me = me.ResolveMemberAccess (rc, null, null);
2444 me.SetTypeArguments (rc, targs);
2451 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2453 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2454 if (IsPossibleTypeOrNamespace (rc)) {
2455 if (variable != null) {
2456 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2457 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2460 return ResolveAsTypeOrNamespace (rc);
2465 if (variable_found) {
2466 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2469 var tparams = rc.CurrentTypeParameters;
2470 if (tparams != null) {
2471 if (tparams.Find (Name) != null) {
2472 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2477 var ct = rc.CurrentType;
2479 if (ct.MemberDefinition.TypeParametersCount > 0) {
2480 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2481 if (ctp.Name == Name) {
2482 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2488 ct = ct.DeclaringType;
2489 } while (ct != null);
2492 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2493 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2495 rc.Report.SymbolRelatedToPreviousError (e.Type);
2496 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2501 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2503 if (e.Type.Arity != Arity) {
2504 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2508 if (e is TypeExpr) {
2509 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2514 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2517 return ErrorExpression.Instance;
2520 if (rc.Module.Evaluator != null) {
2521 var fi = rc.Module.Evaluator.LookupField (Name);
2523 return new FieldExpr (fi.Item1, loc);
2531 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2533 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2538 if (right_side != null) {
2539 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2540 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2544 e = e.ResolveLValue (ec, right_side);
2552 public override object Accept (StructuralVisitor visitor)
2554 return visitor.Visit (this);
2559 /// Represents a namespace or a type. The name of the class was inspired by
2560 /// section 10.8.1 (Fully Qualified Names).
2562 public abstract class FullNamedExpression : Expression
2564 protected override void CloneTo (CloneContext clonectx, Expression target)
2566 // Do nothing, most unresolved type expressions cannot be
2567 // resolved to different type
2570 public override bool ContainsEmitWithAwait ()
2575 public override Expression CreateExpressionTree (ResolveContext ec)
2577 throw new NotSupportedException ("ET");
2580 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2583 // This is used to resolve the expression as a type, a null
2584 // value will be returned if the expression is not a type
2587 public override TypeSpec ResolveAsType (IMemberContext mc)
2589 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2594 TypeExpr te = fne as TypeExpr;
2596 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2604 var dep = type.GetMissingDependencies ();
2606 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2609 if (type.Kind == MemberKind.Void) {
2610 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2614 // Obsolete checks cannot be done when resolving base context as they
2615 // require type dependencies to be set but we are in process of resolving them
2617 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2618 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2619 if (obsolete_attr != null && !mc.IsObsolete) {
2620 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2628 public override void Emit (EmitContext ec)
2630 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2631 GetSignatureForError ());
2636 /// Expression that evaluates to a type
2638 public abstract class TypeExpr : FullNamedExpression
2640 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2646 protected sealed override Expression DoResolve (ResolveContext ec)
2652 public override bool Equals (object obj)
2654 TypeExpr tobj = obj as TypeExpr;
2658 return Type == tobj.Type;
2661 public override int GetHashCode ()
2663 return Type.GetHashCode ();
2668 /// Fully resolved Expression that already evaluated to a type
2670 public class TypeExpression : TypeExpr
2672 public TypeExpression (TypeSpec t, Location l)
2675 eclass = ExprClass.Type;
2679 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2686 /// This class denotes an expression which evaluates to a member
2687 /// of a struct or a class.
2689 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2692 // An instance expression associated with this member, if it's a
2693 // non-static member
2695 public Expression InstanceExpression;
2698 /// The name of this member.
2700 public abstract string Name {
2705 // When base.member is used
2707 public bool IsBase {
2708 get { return InstanceExpression is BaseThis; }
2712 /// Whether this is an instance member.
2714 public abstract bool IsInstance {
2719 /// Whether this is a static member.
2721 public abstract bool IsStatic {
2725 public abstract string KindName {
2729 protected abstract TypeSpec DeclaringType {
2733 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2735 return InstanceExpression.Type;
2740 // Converts best base candidate for virtual method starting from QueriedBaseType
2742 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2745 // Only when base.member is used and method is virtual
2751 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2752 // means for base.member access we have to find the closest match after we found best candidate
2754 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2756 // The method could already be what we are looking for
2758 TypeSpec[] targs = null;
2759 if (method.DeclaringType != InstanceExpression.Type) {
2760 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2761 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2762 if (base_override.IsGeneric)
2763 targs = method.TypeArguments;
2765 method = base_override;
2769 // TODO: For now we do it for any hoisted call even if it's needed for
2770 // hoisted stories only but that requires a new expression wrapper
2771 if (rc.CurrentAnonymousMethod != null) {
2772 if (targs == null && method.IsGeneric) {
2773 targs = method.TypeArguments;
2774 method = method.GetGenericMethodDefinition ();
2777 if (method.Parameters.HasArglist)
2778 throw new NotImplementedException ("__arglist base call proxy");
2780 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2782 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2783 // get/set member expressions second call would fail to proxy because left expression
2784 // would be of 'this' and not 'base'
2785 if (rc.CurrentType.IsStruct)
2786 InstanceExpression = new This (loc).Resolve (rc);
2790 method = method.MakeGenericMethod (rc, targs);
2794 // Only base will allow this invocation to happen.
2796 if (method.IsAbstract) {
2797 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2803 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2805 if (InstanceExpression == null)
2808 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2809 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2810 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2815 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2817 if (InstanceExpression == null)
2820 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2823 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2825 var ct = rc.CurrentType;
2826 if (ct == qualifier)
2829 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2832 qualifier = qualifier.GetDefinition ();
2833 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2840 public override bool ContainsEmitWithAwait ()
2842 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2845 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2848 type = type.GetDefinition ();
2850 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2853 type = type.DeclaringType;
2854 } while (type != null);
2859 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2861 if (InstanceExpression != null) {
2862 InstanceExpression = InstanceExpression.Resolve (rc);
2863 CheckProtectedMemberAccess (rc, member);
2866 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2867 UnsafeError (rc, loc);
2870 var dep = member.GetMissingDependencies ();
2872 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2875 if (!rc.IsObsolete) {
2876 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2878 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2881 if (!(member is FieldSpec))
2882 member.MemberDefinition.SetIsUsed ();
2885 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2887 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2890 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2892 rc.Report.SymbolRelatedToPreviousError (member);
2893 rc.Report.Error (1540, loc,
2894 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2895 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2899 // Implements identicial simple name and type-name
2901 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2904 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2907 // 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
2908 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2910 if (left is MemberExpr || left is VariableReference) {
2911 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2912 if (identical_type != null && identical_type.Type == left.Type)
2913 return identical_type;
2919 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2922 if (InstanceExpression != null) {
2923 if (InstanceExpression is TypeExpr) {
2924 var t = InstanceExpression.Type;
2926 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2927 if (oa != null && !rc.IsObsolete) {
2928 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2931 t = t.DeclaringType;
2932 } while (t != null);
2934 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2935 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2936 rc.Report.Error (176, loc,
2937 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2938 GetSignatureForError ());
2942 InstanceExpression = null;
2948 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2949 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2950 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2951 rc.Report.Error (236, loc,
2952 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2953 GetSignatureForError ());
2955 rc.Report.Error (120, loc,
2956 "An object reference is required to access non-static member `{0}'",
2957 GetSignatureForError ());
2959 InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
2963 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2964 rc.Report.Error (38, loc,
2965 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2966 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2969 InstanceExpression = new This (loc);
2970 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2971 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2972 InstanceExpression = InstanceExpression.Resolve (rc);
2975 InstanceExpression = InstanceExpression.Resolve (rc);
2981 var me = InstanceExpression as MemberExpr;
2983 me.ResolveInstanceExpression (rc, rhs);
2985 var fe = me as FieldExpr;
2986 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2987 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2988 rc.Report.Warning (1690, 1, loc,
2989 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2990 me.GetSignatureForError ());
2997 // Run member-access postponed check once we know that
2998 // the expression is not field expression which is the only
2999 // expression which can use uninitialized this
3001 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3002 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3006 // Additional checks for l-value member access
3009 if (InstanceExpression is UnboxCast) {
3010 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3017 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3019 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3020 ec.Report.Warning (1720, 1, left.Location,
3021 "Expression will always cause a `{0}'", "System.NullReferenceException");
3024 InstanceExpression = left;
3028 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3030 TypeSpec instance_type = InstanceExpression.Type;
3031 if (TypeSpec.IsValueType (instance_type)) {
3032 if (InstanceExpression is IMemoryLocation) {
3033 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3035 // Cannot release the temporary variable when its address
3036 // is required to be on stack for any parent
3037 LocalTemporary t = new LocalTemporary (instance_type);
3038 InstanceExpression.Emit (ec);
3040 t.AddressOf (ec, AddressOp.Store);
3043 InstanceExpression.Emit (ec);
3045 // Only to make verifier happy
3046 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3047 ec.Emit (OpCodes.Box, instance_type);
3050 if (prepare_for_load)
3051 ec.Emit (OpCodes.Dup);
3054 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3057 public class ExtensionMethodCandidates
3059 readonly NamespaceContainer container;
3060 readonly IList<MethodSpec> methods;
3062 readonly IMemberContext context;
3064 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3066 this.context = context;
3067 this.methods = methods;
3068 this.container = nsContainer;
3069 this.index = lookupIndex;
3072 public NamespaceContainer Container {
3078 public IMemberContext Context {
3084 public int LookupIndex {
3090 public IList<MethodSpec> Methods {
3098 // Represents a group of extension method candidates for whole namespace
3100 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3102 ExtensionMethodCandidates candidates;
3103 public readonly Expression ExtensionExpression;
3105 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3106 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3108 this.candidates = candidates;
3109 this.ExtensionExpression = extensionExpr;
3112 public override bool IsStatic {
3113 get { return true; }
3117 // For extension methodgroup we are not looking for base members but parent
3118 // namespace extension methods
3120 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3122 // TODO: candidates are null only when doing error reporting, that's
3123 // incorrect. We have to discover same extension methods in error mode
3124 if (candidates == null)
3127 int arity = type_arguments == null ? 0 : type_arguments.Count;
3129 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3130 if (candidates == null)
3133 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3136 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3138 // We are already here
3142 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3144 if (arguments == null)
3145 arguments = new Arguments (1);
3147 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3148 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3150 // Store resolved argument and restore original arguments
3152 // Clean-up modified arguments for error reporting
3153 arguments.RemoveAt (0);
3157 var me = ExtensionExpression as MemberExpr;
3159 me.ResolveInstanceExpression (ec, null);
3161 InstanceExpression = null;
3165 #region IErrorHandler Members
3167 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3172 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3174 rc.Report.SymbolRelatedToPreviousError (best);
3175 rc.Report.Error (1928, loc,
3176 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3177 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3180 rc.Report.Error (1929, loc,
3181 "Extension method instance type `{0}' cannot be converted to `{1}'",
3182 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3188 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3193 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3202 /// MethodGroupExpr represents a group of method candidates which
3203 /// can be resolved to the best method overload
3205 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3207 protected IList<MemberSpec> Methods;
3208 MethodSpec best_candidate;
3209 TypeSpec best_candidate_return;
3210 protected TypeArguments type_arguments;
3212 SimpleName simple_name;
3213 protected TypeSpec queried_type;
3215 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3219 this.type = InternalType.MethodGroup;
3221 eclass = ExprClass.MethodGroup;
3222 queried_type = type;
3225 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3226 : this (new MemberSpec[] { m }, type, loc)
3232 public MethodSpec BestCandidate {
3234 return best_candidate;
3238 public TypeSpec BestCandidateReturnType {
3240 return best_candidate_return;
3244 public IList<MemberSpec> Candidates {
3250 protected override TypeSpec DeclaringType {
3252 return queried_type;
3256 public override bool IsInstance {
3258 if (best_candidate != null)
3259 return !best_candidate.IsStatic;
3265 public override bool IsStatic {
3267 if (best_candidate != null)
3268 return best_candidate.IsStatic;
3274 public override string KindName {
3275 get { return "method"; }
3278 public override string Name {
3280 if (best_candidate != null)
3281 return best_candidate.Name;
3284 return Methods.First ().Name;
3291 // When best candidate is already know this factory can be used
3292 // to avoid expensive overload resolution to be called
3294 // NOTE: InstanceExpression has to be set manually
3296 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3298 return new MethodGroupExpr (best, queriedType, loc) {
3299 best_candidate = best,
3300 best_candidate_return = best.ReturnType
3304 public override string GetSignatureForError ()
3306 if (best_candidate != null)
3307 return best_candidate.GetSignatureForError ();
3309 return Methods.First ().GetSignatureForError ();
3312 public override Expression CreateExpressionTree (ResolveContext ec)
3314 if (best_candidate == null) {
3315 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3319 if (best_candidate.IsConditionallyExcluded (ec, loc))
3320 ec.Report.Error (765, loc,
3321 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3323 return new TypeOfMethod (best_candidate, loc);
3326 protected override Expression DoResolve (ResolveContext ec)
3328 this.eclass = ExprClass.MethodGroup;
3330 if (InstanceExpression != null) {
3331 InstanceExpression = InstanceExpression.Resolve (ec);
3332 if (InstanceExpression == null)
3339 public override void Emit (EmitContext ec)
3341 throw new NotSupportedException ();
3344 public void EmitCall (EmitContext ec, Arguments arguments)
3346 var call = new CallEmitter ();
3347 call.InstanceExpression = InstanceExpression;
3348 call.Emit (ec, best_candidate, arguments, loc);
3351 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3353 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3354 Name, TypeManager.CSharpName (target));
3357 public static bool IsExtensionMethodArgument (Expression expr)
3360 // LAMESPEC: No details about which expressions are not allowed
3362 return !(expr is TypeExpr) && !(expr is BaseThis);
3366 /// Find the Applicable Function Members (7.4.2.1)
3368 /// me: Method Group expression with the members to select.
3369 /// it might contain constructors or methods (or anything
3370 /// that maps to a method).
3372 /// Arguments: ArrayList containing resolved Argument objects.
3374 /// loc: The location if we want an error to be reported, or a Null
3375 /// location for "probing" purposes.
3377 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3378 /// that is the best match of me on Arguments.
3381 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3383 // TODO: causes issues with probing mode, remove explicit Kind check
3384 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3387 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3388 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3389 r.BaseMembersProvider = this;
3390 r.InstanceQualifier = this;
3393 if (cerrors != null)
3394 r.CustomErrors = cerrors;
3396 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3397 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3398 if (best_candidate == null)
3399 return r.BestCandidateIsDynamic ? this : null;
3401 // Overload resolver had to create a new method group, all checks bellow have already been executed
3402 if (r.BestCandidateNewMethodGroup != null)
3403 return r.BestCandidateNewMethodGroup;
3405 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3406 if (InstanceExpression != null) {
3407 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3408 InstanceExpression = null;
3410 if (best_candidate.IsStatic && simple_name != null) {
3411 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3414 InstanceExpression.Resolve (ec);
3418 ResolveInstanceExpression (ec, null);
3421 var base_override = CandidateToBaseOverride (ec, best_candidate);
3422 if (base_override == best_candidate) {
3423 best_candidate_return = r.BestCandidateReturnType;
3425 best_candidate = base_override;
3426 best_candidate_return = best_candidate.ReturnType;
3432 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3434 simple_name = original;
3435 return base.ResolveMemberAccess (ec, left, original);
3438 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3440 type_arguments = ta;
3443 #region IBaseMembersProvider Members
3445 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3447 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3450 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3452 if (queried_type == member.DeclaringType)
3455 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3456 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3460 // Extension methods lookup after ordinary methods candidates failed to apply
3462 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3464 if (InstanceExpression == null)
3467 InstanceExpression = InstanceExpression.Resolve (rc);
3468 if (!IsExtensionMethodArgument (InstanceExpression))
3471 int arity = type_arguments == null ? 0 : type_arguments.Count;
3472 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3473 if (methods == null)
3476 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3477 emg.SetTypeArguments (rc, type_arguments);
3484 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3486 public ConstructorInstanceQualifier (TypeSpec type)
3489 InstanceType = type;
3492 public TypeSpec InstanceType { get; private set; }
3494 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3496 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3500 public struct OverloadResolver
3503 public enum Restrictions
3507 ProbingOnly = 1 << 1,
3508 CovariantDelegate = 1 << 2,
3509 NoBaseMembers = 1 << 3,
3510 BaseMembersIncluded = 1 << 4
3513 public interface IBaseMembersProvider
3515 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3516 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3517 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3520 public interface IErrorHandler
3522 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3523 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3524 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3525 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3528 public interface IInstanceQualifier
3530 TypeSpec InstanceType { get; }
3531 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3534 sealed class NoBaseMembers : IBaseMembersProvider
3536 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3538 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3543 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3548 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3554 struct AmbiguousCandidate
3556 public readonly MemberSpec Member;
3557 public readonly bool Expanded;
3558 public readonly AParametersCollection Parameters;
3560 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3563 Parameters = parameters;
3564 Expanded = expanded;
3569 IList<MemberSpec> members;
3570 TypeArguments type_arguments;
3571 IBaseMembersProvider base_provider;
3572 IErrorHandler custom_errors;
3573 IInstanceQualifier instance_qualifier;
3574 Restrictions restrictions;
3575 MethodGroupExpr best_candidate_extension_group;
3576 TypeSpec best_candidate_return_type;
3578 SessionReportPrinter lambda_conv_msgs;
3579 ReportPrinter prev_recorder;
3581 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3582 : this (members, null, restrictions, loc)
3586 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3589 if (members == null || members.Count == 0)
3590 throw new ArgumentException ("empty members set");
3592 this.members = members;
3594 type_arguments = targs;
3595 this.restrictions = restrictions;
3596 if (IsDelegateInvoke)
3597 this.restrictions |= Restrictions.NoBaseMembers;
3599 base_provider = NoBaseMembers.Instance;
3604 public IBaseMembersProvider BaseMembersProvider {
3606 return base_provider;
3609 base_provider = value;
3613 public bool BestCandidateIsDynamic { get; set; }
3616 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3618 public MethodGroupExpr BestCandidateNewMethodGroup {
3620 return best_candidate_extension_group;
3625 // Return type can be different between best candidate and closest override
3627 public TypeSpec BestCandidateReturnType {
3629 return best_candidate_return_type;
3633 public IErrorHandler CustomErrors {
3635 return custom_errors;
3638 custom_errors = value;
3642 TypeSpec DelegateType {
3644 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3645 throw new InternalErrorException ("Not running in delegate mode", loc);
3647 return members [0].DeclaringType;
3651 public IInstanceQualifier InstanceQualifier {
3653 return instance_qualifier;
3656 instance_qualifier = value;
3660 bool IsProbingOnly {
3662 return (restrictions & Restrictions.ProbingOnly) != 0;
3666 bool IsDelegateInvoke {
3668 return (restrictions & Restrictions.DelegateInvoke) != 0;
3675 // 7.4.3.3 Better conversion from expression
3676 // Returns : 1 if a->p is better,
3677 // 2 if a->q is better,
3678 // 0 if neither is better
3680 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3682 TypeSpec argument_type = a.Type;
3685 // If argument is an anonymous function
3687 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3689 // p and q are delegate types or expression tree types
3691 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3692 if (q.MemberDefinition != p.MemberDefinition) {
3697 // Uwrap delegate from Expression<T>
3699 q = TypeManager.GetTypeArguments (q)[0];
3700 p = TypeManager.GetTypeArguments (p)[0];
3703 var p_m = Delegate.GetInvokeMethod (p);
3704 var q_m = Delegate.GetInvokeMethod (q);
3707 // With identical parameter lists
3709 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3716 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3718 if (p.Kind == MemberKind.Void) {
3719 return q.Kind != MemberKind.Void ? 2 : 0;
3723 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3725 if (q.Kind == MemberKind.Void) {
3726 return p.Kind != MemberKind.Void ? 1: 0;
3730 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3731 // better conversion is performed between underlying types Y1 and Y2
3733 if (p.IsGenericTask || q.IsGenericTask) {
3734 var async_am = a.Expr as AnonymousMethodExpression;
3735 if (async_am != null && async_am.Block.IsAsync) {
3737 if (p.IsGenericTask != q.IsGenericTask) {
3741 q = q.TypeArguments[0];
3742 p = p.TypeArguments[0];
3747 // The parameters are identicial and return type is not void, use better type conversion
3748 // on return type to determine better one
3751 if (argument_type == p)
3754 if (argument_type == q)
3758 return BetterTypeConversion (ec, p, q);
3762 // 7.4.3.4 Better conversion from type
3764 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3766 if (p == null || q == null)
3767 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3769 switch (p.BuiltinType) {
3770 case BuiltinTypeSpec.Type.Int:
3771 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3774 case BuiltinTypeSpec.Type.Long:
3775 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3778 case BuiltinTypeSpec.Type.SByte:
3779 switch (q.BuiltinType) {
3780 case BuiltinTypeSpec.Type.Byte:
3781 case BuiltinTypeSpec.Type.UShort:
3782 case BuiltinTypeSpec.Type.UInt:
3783 case BuiltinTypeSpec.Type.ULong:
3787 case BuiltinTypeSpec.Type.Short:
3788 switch (q.BuiltinType) {
3789 case BuiltinTypeSpec.Type.UShort:
3790 case BuiltinTypeSpec.Type.UInt:
3791 case BuiltinTypeSpec.Type.ULong:
3795 case BuiltinTypeSpec.Type.Dynamic:
3796 // Dynamic is never better
3800 switch (q.BuiltinType) {
3801 case BuiltinTypeSpec.Type.Int:
3802 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3805 case BuiltinTypeSpec.Type.Long:
3806 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3809 case BuiltinTypeSpec.Type.SByte:
3810 switch (p.BuiltinType) {
3811 case BuiltinTypeSpec.Type.Byte:
3812 case BuiltinTypeSpec.Type.UShort:
3813 case BuiltinTypeSpec.Type.UInt:
3814 case BuiltinTypeSpec.Type.ULong:
3818 case BuiltinTypeSpec.Type.Short:
3819 switch (p.BuiltinType) {
3820 case BuiltinTypeSpec.Type.UShort:
3821 case BuiltinTypeSpec.Type.UInt:
3822 case BuiltinTypeSpec.Type.ULong:
3826 case BuiltinTypeSpec.Type.Dynamic:
3827 // Dynamic is never better
3831 // FIXME: handle lifted operators
3833 // TODO: this is expensive
3834 Expression p_tmp = new EmptyExpression (p);
3835 Expression q_tmp = new EmptyExpression (q);
3837 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3838 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3840 if (p_to_q && !q_to_p)
3843 if (q_to_p && !p_to_q)
3850 /// Determines "Better function" between candidate
3851 /// and the current best match
3854 /// Returns a boolean indicating :
3855 /// false if candidate ain't better
3856 /// true if candidate is better than the current best match
3858 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3859 MemberSpec best, AParametersCollection bparam, bool best_params)
3861 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3862 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3864 bool better_at_least_one = false;
3866 int args_count = args == null ? 0 : args.Count;
3870 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3873 // Default arguments are ignored for better decision
3874 if (a.IsDefaultArgument)
3878 // When comparing named argument the parameter type index has to be looked up
3879 // in original parameter set (override version for virtual members)
3881 NamedArgument na = a as NamedArgument;
3883 int idx = cparam.GetParameterIndexByName (na.Name);
3884 ct = candidate_pd.Types[idx];
3885 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3886 ct = TypeManager.GetElementType (ct);
3888 idx = bparam.GetParameterIndexByName (na.Name);
3889 bt = best_pd.Types[idx];
3890 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3891 bt = TypeManager.GetElementType (bt);
3893 ct = candidate_pd.Types[c_idx];
3894 bt = best_pd.Types[b_idx];
3896 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3897 ct = TypeManager.GetElementType (ct);
3901 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3902 bt = TypeManager.GetElementType (bt);
3907 if (TypeSpecComparer.IsEqual (ct, bt))
3911 int result = BetterExpressionConversion (ec, a, ct, bt);
3913 // for each argument, the conversion to 'ct' should be no worse than
3914 // the conversion to 'bt'.
3918 // for at least one argument, the conversion to 'ct' should be better than
3919 // the conversion to 'bt'.
3921 better_at_least_one = true;
3924 if (better_at_least_one)
3928 // This handles the case
3930 // Add (float f1, float f2, float f3);
3931 // Add (params decimal [] foo);
3933 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3934 // first candidate would've chosen as better.
3936 if (!same && !a.IsDefaultArgument)
3940 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3944 // This handles the following cases:
3946 // Foo (int i) is better than Foo (int i, long l = 0)
3947 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3949 // Prefer non-optional version
3951 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3953 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3954 if (candidate_pd.Count >= best_pd.Count)
3957 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3964 // One is a non-generic method and second is a generic method, then non-generic is better
3966 if (best.IsGeneric != candidate.IsGeneric)
3967 return best.IsGeneric;
3970 // This handles the following cases:
3972 // Trim () is better than Trim (params char[] chars)
3973 // Concat (string s1, string s2, string s3) is better than
3974 // Concat (string s1, params string [] srest)
3975 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3977 // Prefer non-expanded version
3979 if (candidate_params != best_params)
3982 int candidate_param_count = candidate_pd.Count;
3983 int best_param_count = best_pd.Count;
3985 if (candidate_param_count != best_param_count)
3986 // can only happen if (candidate_params && best_params)
3987 return candidate_param_count > best_param_count && best_pd.HasParams;
3990 // Both methods have the same number of parameters, and the parameters have equal types
3991 // Pick the "more specific" signature using rules over original (non-inflated) types
3993 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3994 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3996 bool specific_at_least_once = false;
3997 for (j = 0; j < args_count; ++j) {
3998 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4000 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4001 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4003 ct = candidate_def_pd.Types[j];
4004 bt = best_def_pd.Types[j];
4009 TypeSpec specific = MoreSpecific (ct, bt);
4013 specific_at_least_once = true;
4016 if (specific_at_least_once)
4022 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4024 rc.Report.Error (1729, loc,
4025 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4026 type.GetSignatureForError (), argCount.ToString ());
4030 // Determines if the candidate method is applicable to the given set of arguments
4031 // There could be two different set of parameters for same candidate where one
4032 // is the closest override for default values and named arguments checks and second
4033 // one being the virtual base for the parameter types and modifiers.
4035 // A return value rates candidate method compatibility,
4036 // 0 = the best, int.MaxValue = the worst
4038 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)
4040 // Parameters of most-derived type used mainly for named and optional parameters
4041 var pd = pm.Parameters;
4043 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4044 // params modifier instead of most-derived type
4045 var cpd = ((IParametersMember) candidate).Parameters;
4046 int param_count = pd.Count;
4047 int optional_count = 0;
4049 Arguments orig_args = arguments;
4051 if (arg_count != param_count) {
4053 // No arguments expansion when doing exact match for delegates
4055 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4056 for (int i = 0; i < pd.Count; ++i) {
4057 if (pd.FixedParameters[i].HasDefaultValue) {
4058 optional_count = pd.Count - i;
4064 if (optional_count != 0) {
4065 // Readjust expected number when params used
4066 if (cpd.HasParams) {
4068 if (arg_count < param_count)
4070 } else if (arg_count > param_count) {
4071 int args_gap = System.Math.Abs (arg_count - param_count);
4072 return int.MaxValue - 10000 + args_gap;
4074 } else if (arg_count != param_count) {
4075 int args_gap = System.Math.Abs (arg_count - param_count);
4077 return int.MaxValue - 10000 + args_gap;
4078 if (arg_count < param_count - 1)
4079 return int.MaxValue - 10000 + args_gap;
4082 // Resize to fit optional arguments
4083 if (optional_count != 0) {
4084 if (arguments == null) {
4085 arguments = new Arguments (optional_count);
4087 // Have to create a new container, so the next run can do same
4088 var resized = new Arguments (param_count);
4089 resized.AddRange (arguments);
4090 arguments = resized;
4093 for (int i = arg_count; i < param_count; ++i)
4094 arguments.Add (null);
4098 if (arg_count > 0) {
4100 // Shuffle named arguments to the right positions if there are any
4102 if (arguments[arg_count - 1] is NamedArgument) {
4103 arg_count = arguments.Count;
4105 for (int i = 0; i < arg_count; ++i) {
4106 bool arg_moved = false;
4108 NamedArgument na = arguments[i] as NamedArgument;
4112 int index = pd.GetParameterIndexByName (na.Name);
4114 // Named parameter not found
4118 // already reordered
4123 if (index >= param_count) {
4124 // When using parameters which should not be available to the user
4125 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4128 arguments.Add (null);
4132 temp = arguments[index];
4134 // The slot has been taken by positional argument
4135 if (temp != null && !(temp is NamedArgument))
4140 arguments = arguments.MarkOrderedArgument (na);
4144 arguments[index] = arguments[i];
4145 arguments[i] = temp;
4152 arg_count = arguments.Count;
4154 } else if (arguments != null) {
4155 arg_count = arguments.Count;
4159 // 1. Handle generic method using type arguments when specified or type inference
4162 var ms = candidate as MethodSpec;
4163 if (ms != null && ms.IsGeneric) {
4164 // Setup constraint checker for probing only
4165 ConstraintChecker cc = new ConstraintChecker (null);
4167 if (type_arguments != null) {
4168 var g_args_count = ms.Arity;
4169 if (g_args_count != type_arguments.Count)
4170 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4172 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4174 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4175 // for now it simplifies things. I should probably add a callback to ResolveContext
4176 if (lambda_conv_msgs == null) {
4177 lambda_conv_msgs = new SessionReportPrinter ();
4178 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4181 var ti = new TypeInference (arguments);
4182 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4183 lambda_conv_msgs.EndSession ();
4186 return ti.InferenceScore - 20000;
4188 if (i_args.Length != 0) {
4189 ms = ms.MakeGenericMethod (ec, i_args);
4192 cc.IgnoreInferredDynamic = true;
4196 // Type arguments constraints have to match for the method to be applicable
4198 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4200 return int.MaxValue - 25000;
4204 // We have a generic return type and at same time the method is override which
4205 // means we have to also inflate override return type in case the candidate is
4206 // best candidate and override return type is different to base return type.
4208 // virtual Foo<T, object> with override Foo<T, dynamic>
4210 if (candidate != pm) {
4211 MethodSpec override_ms = (MethodSpec) pm;
4212 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4213 returnType = inflator.Inflate (returnType);
4215 returnType = ms.ReturnType;
4219 ptypes = ms.Parameters.Types;
4221 if (type_arguments != null)
4222 return int.MaxValue - 15000;
4228 // 2. Each argument has to be implicitly convertible to method parameter
4230 Parameter.Modifier p_mod = 0;
4233 for (int i = 0; i < arg_count; i++) {
4234 Argument a = arguments[i];
4236 var fp = pd.FixedParameters[i];
4237 if (!fp.HasDefaultValue) {
4238 arguments = orig_args;
4239 return arg_count * 2 + 2;
4243 // Get the default value expression, we can use the same expression
4244 // if the type matches
4246 Expression e = fp.DefaultValue;
4247 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4249 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4251 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4252 e = new MemberAccess (new MemberAccess (new MemberAccess (
4253 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4255 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4261 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4263 // LAMESPEC: Attributes can be mixed together with build-in priority
4265 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4266 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4267 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4268 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4269 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4270 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4274 arguments[i] = new Argument (e, Argument.AType.Default);
4278 if (p_mod != Parameter.Modifier.PARAMS) {
4279 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4281 } else if (!params_expanded_form) {
4282 params_expanded_form = true;
4283 pt = ((ElementTypeSpec) pt).Element;
4289 if (!params_expanded_form) {
4290 if (a.ArgType == Argument.AType.ExtensionType) {
4292 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4294 // LAMESPEC: or implicit type parameter conversion
4297 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4298 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4299 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4304 score = IsArgumentCompatible (ec, a, p_mod, pt);
4307 dynamicArgument = true;
4312 // It can be applicable in expanded form (when not doing exact match like for delegates)
4314 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4315 if (!params_expanded_form)
4316 pt = ((ElementTypeSpec) pt).Element;
4319 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4322 params_expanded_form = true;
4323 } else if (score < 0) {
4324 params_expanded_form = true;
4325 dynamicArgument = true;
4330 if (params_expanded_form)
4332 return (arg_count - i) * 2 + score;
4337 // When params parameter has no argument it will be provided later if the method is the best candidate
4339 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4340 params_expanded_form = true;
4343 // Restore original arguments for dynamic binder to keep the intention of original source code
4345 if (dynamicArgument)
4346 arguments = orig_args;
4352 // Tests argument compatibility with the parameter
4353 // The possible return values are
4355 // 1 - modifier mismatch
4356 // 2 - type mismatch
4357 // -1 - dynamic binding required
4359 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4362 // Types have to be identical when ref or out modifer
4363 // is used and argument is not of dynamic type
4365 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4366 if (argument.Type != parameter) {
4368 // Do full equality check after quick path
4370 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4372 // Using dynamic for ref/out parameter can still succeed at runtime
4374 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4381 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4383 // Using dynamic for ref/out parameter can still succeed at runtime
4385 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4392 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4396 // Deploy custom error reporting for lambda methods. When probing lambda methods
4397 // keep all errors reported in separate set and once we are done and no best
4398 // candidate was found, this set is used to report more details about what was wrong
4401 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4402 if (lambda_conv_msgs == null) {
4403 lambda_conv_msgs = new SessionReportPrinter ();
4404 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4409 // Use implicit conversion in all modes to return same candidates when the expression
4410 // is used as argument or delegate conversion
4412 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4413 if (lambda_conv_msgs != null) {
4414 lambda_conv_msgs.EndSession ();
4424 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4426 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4428 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4431 var ac_p = p as ArrayContainer;
4433 var ac_q = q as ArrayContainer;
4437 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4438 if (specific == ac_p.Element)
4440 if (specific == ac_q.Element)
4442 } else if (TypeManager.IsGenericType (p)) {
4443 var pargs = TypeManager.GetTypeArguments (p);
4444 var qargs = TypeManager.GetTypeArguments (q);
4446 bool p_specific_at_least_once = false;
4447 bool q_specific_at_least_once = false;
4449 for (int i = 0; i < pargs.Length; i++) {
4450 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4451 if (specific == pargs[i])
4452 p_specific_at_least_once = true;
4453 if (specific == qargs[i])
4454 q_specific_at_least_once = true;
4457 if (p_specific_at_least_once && !q_specific_at_least_once)
4459 if (!p_specific_at_least_once && q_specific_at_least_once)
4467 // Find the best method from candidate list
4469 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4471 List<AmbiguousCandidate> ambiguous_candidates = null;
4473 MemberSpec best_candidate;
4474 Arguments best_candidate_args = null;
4475 bool best_candidate_params = false;
4476 bool best_candidate_dynamic = false;
4477 int best_candidate_rate;
4478 IParametersMember best_parameter_member = null;
4480 int args_count = args != null ? args.Count : 0;
4482 Arguments candidate_args = args;
4483 bool error_mode = false;
4484 MemberSpec invocable_member = null;
4486 // Be careful, cannot return until error reporter is restored
4488 best_candidate = null;
4489 best_candidate_rate = int.MaxValue;
4491 var type_members = members;
4495 for (int i = 0; i < type_members.Count; ++i) {
4496 var member = type_members[i];
4499 // Methods in a base class are not candidates if any method in a derived
4500 // class is applicable
4502 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4506 if (!member.IsAccessible (rc))
4509 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4512 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4513 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4518 IParametersMember pm = member as IParametersMember;
4521 // Will use it later to report ambiguity between best method and invocable member
4523 if (Invocation.IsMemberInvocable (member))
4524 invocable_member = member;
4530 // Overload resolution is looking for base member but using parameter names
4531 // and default values from the closest member. That means to do expensive lookup
4532 // for the closest override for virtual or abstract members
4534 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4535 var override_params = base_provider.GetOverrideMemberParameters (member);
4536 if (override_params != null)
4537 pm = override_params;
4541 // Check if the member candidate is applicable
4543 bool params_expanded_form = false;
4544 bool dynamic_argument = false;
4545 TypeSpec rt = pm.MemberType;
4546 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4549 // How does it score compare to others
4551 if (candidate_rate < best_candidate_rate) {
4552 best_candidate_rate = candidate_rate;
4553 best_candidate = member;
4554 best_candidate_args = candidate_args;
4555 best_candidate_params = params_expanded_form;
4556 best_candidate_dynamic = dynamic_argument;
4557 best_parameter_member = pm;
4558 best_candidate_return_type = rt;
4559 } else if (candidate_rate == 0) {
4561 // The member look is done per type for most operations but sometimes
4562 // it's not possible like for binary operators overload because they
4563 // are unioned between 2 sides
4565 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4566 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4571 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4573 // We pack all interface members into top level type which makes the overload resolution
4574 // more complicated for interfaces. We compensate it by removing methods with same
4575 // signature when building the cache hence this path should not really be hit often
4578 // interface IA { void Foo (int arg); }
4579 // interface IB : IA { void Foo (params int[] args); }
4581 // IB::Foo is the best overload when calling IB.Foo (1)
4584 if (ambiguous_candidates != null) {
4585 foreach (var amb_cand in ambiguous_candidates) {
4586 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4595 ambiguous_candidates = null;
4598 // Is the new candidate better
4599 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4603 best_candidate = member;
4604 best_candidate_args = candidate_args;
4605 best_candidate_params = params_expanded_form;
4606 best_candidate_dynamic = dynamic_argument;
4607 best_parameter_member = pm;
4608 best_candidate_return_type = rt;
4610 // It's not better but any other found later could be but we are not sure yet
4611 if (ambiguous_candidates == null)
4612 ambiguous_candidates = new List<AmbiguousCandidate> ();
4614 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4618 // Restore expanded arguments
4619 if (candidate_args != args)
4620 candidate_args = args;
4622 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4624 if (prev_recorder != null)
4625 rc.Report.SetPrinter (prev_recorder);
4629 // We've found exact match
4631 if (best_candidate_rate == 0)
4635 // Try extension methods lookup when no ordinary method match was found and provider enables it
4638 var emg = base_provider.LookupExtensionMethod (rc);
4640 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4642 best_candidate_extension_group = emg;
4643 return (T) (MemberSpec) emg.BestCandidate;
4648 // Don't run expensive error reporting mode for probing
4655 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4658 lambda_conv_msgs = null;
4663 // No best member match found, report an error
4665 if (best_candidate_rate != 0 || error_mode) {
4666 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4670 if (best_candidate_dynamic) {
4671 if (args[0].ArgType == Argument.AType.ExtensionType) {
4672 rc.Report.Error (1973, loc,
4673 "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",
4674 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4677 BestCandidateIsDynamic = true;
4682 // These flags indicates we are running delegate probing conversion. No need to
4683 // do more expensive checks
4685 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4686 return (T) best_candidate;
4688 if (ambiguous_candidates != null) {
4690 // Now check that there are no ambiguities i.e the selected method
4691 // should be better than all the others
4693 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4694 var candidate = ambiguous_candidates [ix];
4696 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4697 var ambiguous = candidate.Member;
4698 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4699 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4700 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4701 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4702 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4705 return (T) best_candidate;
4710 if (invocable_member != null) {
4711 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4712 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4713 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4714 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4718 // And now check if the arguments are all
4719 // compatible, perform conversions if
4720 // necessary etc. and return if everything is
4723 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4726 if (best_candidate == null)
4730 // Check ObsoleteAttribute on the best method
4732 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4733 if (oa != null && !rc.IsObsolete)
4734 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4736 var dep = best_candidate.GetMissingDependencies ();
4738 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4741 best_candidate.MemberDefinition.SetIsUsed ();
4743 args = best_candidate_args;
4744 return (T) best_candidate;
4747 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4749 return ResolveMember<MethodSpec> (rc, ref args);
4752 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4753 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4755 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4758 if (a.Type == InternalType.ErrorType)
4761 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4762 ec.Report.SymbolRelatedToPreviousError (method);
4763 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4764 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4765 TypeManager.CSharpSignature (method));
4768 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4769 TypeManager.CSharpSignature (method));
4770 } else if (IsDelegateInvoke) {
4771 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4772 DelegateType.GetSignatureForError ());
4774 ec.Report.SymbolRelatedToPreviousError (method);
4775 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4776 method.GetSignatureForError ());
4779 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4781 string index = (idx + 1).ToString ();
4782 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4783 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4784 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4785 index, Parameter.GetModifierSignature (a.Modifier));
4787 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4788 index, Parameter.GetModifierSignature (mod));
4790 string p1 = a.GetSignatureForError ();
4791 string p2 = TypeManager.CSharpName (paramType);
4794 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4795 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4798 ec.Report.Error (1503, loc,
4799 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4804 // We have failed to find exact match so we return error info about the closest match
4806 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4808 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4809 int arg_count = args == null ? 0 : args.Count;
4811 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4812 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4813 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4817 if (lambda_conv_msgs != null) {
4818 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4823 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4824 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4825 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4829 // For candidates which match on parameters count report more details about incorrect arguments
4832 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4833 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4834 // Reject any inaccessible member
4835 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4836 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4837 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4841 var ms = best_candidate as MethodSpec;
4842 if (ms != null && ms.IsGeneric) {
4843 bool constr_ok = true;
4844 if (ms.TypeArguments != null)
4845 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4847 if (ta_count == 0) {
4848 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4852 rc.Report.Error (411, loc,
4853 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4854 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4861 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4867 // We failed to find any method with correct argument count, report best candidate
4869 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4872 if (best_candidate.Kind == MemberKind.Constructor) {
4873 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4874 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4875 } else if (IsDelegateInvoke) {
4876 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4877 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4878 DelegateType.GetSignatureForError (), arg_count.ToString ());
4880 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4881 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4882 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4883 name, arg_count.ToString ());
4887 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4889 var pd = pm.Parameters;
4890 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4892 Parameter.Modifier p_mod = 0;
4894 int a_idx = 0, a_pos = 0;
4896 ArrayInitializer params_initializers = null;
4897 bool has_unsafe_arg = pm.MemberType.IsPointer;
4898 int arg_count = args == null ? 0 : args.Count;
4900 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4902 if (p_mod != Parameter.Modifier.PARAMS) {
4903 p_mod = pd.FixedParameters[a_idx].ModFlags;
4905 has_unsafe_arg |= pt.IsPointer;
4907 if (p_mod == Parameter.Modifier.PARAMS) {
4908 if (chose_params_expanded) {
4909 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4910 pt = TypeManager.GetElementType (pt);
4916 // Types have to be identical when ref or out modifer is used
4918 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
4919 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
4922 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4928 NamedArgument na = a as NamedArgument;
4930 int name_index = pd.GetParameterIndexByName (na.Name);
4931 if (name_index < 0 || name_index >= pd.Count) {
4932 if (IsDelegateInvoke) {
4933 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4934 ec.Report.Error (1746, na.Location,
4935 "The delegate `{0}' does not contain a parameter named `{1}'",
4936 DelegateType.GetSignatureForError (), na.Name);
4938 ec.Report.SymbolRelatedToPreviousError (member);
4939 ec.Report.Error (1739, na.Location,
4940 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4941 TypeManager.CSharpSignature (member), na.Name);
4943 } else if (args[name_index] != a) {
4944 if (IsDelegateInvoke)
4945 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4947 ec.Report.SymbolRelatedToPreviousError (member);
4949 ec.Report.Error (1744, na.Location,
4950 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4955 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4958 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4959 custom_errors.NoArgumentMatch (ec, member);
4963 Expression conv = null;
4964 if (a.ArgType == Argument.AType.ExtensionType) {
4965 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4968 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4970 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4973 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4980 // Convert params arguments to an array initializer
4982 if (params_initializers != null) {
4983 // we choose to use 'a.Expr' rather than 'conv' so that
4984 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4985 params_initializers.Add (a.Expr);
4986 args.RemoveAt (a_idx--);
4991 // Update the argument with the implicit conversion
4995 if (a_idx != arg_count) {
4996 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5001 // Fill not provided arguments required by params modifier
5003 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5005 args = new Arguments (1);
5007 pt = ptypes[pd.Count - 1];
5008 pt = TypeManager.GetElementType (pt);
5009 has_unsafe_arg |= pt.IsPointer;
5010 params_initializers = new ArrayInitializer (0, loc);
5014 // Append an array argument with all params arguments
5016 if (params_initializers != null) {
5017 args.Add (new Argument (
5018 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5022 if (has_unsafe_arg && !ec.IsUnsafe) {
5023 Expression.UnsafeError (ec, loc);
5027 // We could infer inaccesible type arguments
5029 if (type_arguments == null && member.IsGeneric) {
5030 var ms = (MethodSpec) member;
5031 foreach (var ta in ms.TypeArguments) {
5032 if (!ta.IsAccessible (ec)) {
5033 ec.Report.SymbolRelatedToPreviousError (ta);
5034 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5044 public class ConstantExpr : MemberExpr
5046 readonly ConstSpec constant;
5048 public ConstantExpr (ConstSpec constant, Location loc)
5050 this.constant = constant;
5054 public override string Name {
5055 get { throw new NotImplementedException (); }
5058 public override string KindName {
5059 get { return "constant"; }
5062 public override bool IsInstance {
5063 get { return !IsStatic; }
5066 public override bool IsStatic {
5067 get { return true; }
5070 protected override TypeSpec DeclaringType {
5071 get { return constant.DeclaringType; }
5074 public override Expression CreateExpressionTree (ResolveContext ec)
5076 throw new NotSupportedException ("ET");
5079 protected override Expression DoResolve (ResolveContext rc)
5081 ResolveInstanceExpression (rc, null);
5082 DoBestMemberChecks (rc, constant);
5084 var c = constant.GetConstant (rc);
5086 // Creates reference expression to the constant value
5087 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5090 public override void Emit (EmitContext ec)
5092 throw new NotSupportedException ();
5095 public override string GetSignatureForError ()
5097 return constant.GetSignatureForError ();
5100 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5102 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5107 // Fully resolved expression that references a Field
5109 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5111 protected FieldSpec spec;
5112 VariableInfo variable_info;
5114 LocalTemporary temp;
5117 protected FieldExpr (Location l)
5122 public FieldExpr (FieldSpec spec, Location loc)
5127 type = spec.MemberType;
5130 public FieldExpr (FieldBase fi, Location l)
5137 public override string Name {
5143 public bool IsHoisted {
5145 IVariableReference hv = InstanceExpression as IVariableReference;
5146 return hv != null && hv.IsHoisted;
5150 public override bool IsInstance {
5152 return !spec.IsStatic;
5156 public override bool IsStatic {
5158 return spec.IsStatic;
5162 public override string KindName {
5163 get { return "field"; }
5166 public FieldSpec Spec {
5172 protected override TypeSpec DeclaringType {
5174 return spec.DeclaringType;
5178 public VariableInfo VariableInfo {
5180 return variable_info;
5186 public override string GetSignatureForError ()
5188 return spec.GetSignatureForError ();
5191 public bool IsMarshalByRefAccess (ResolveContext rc)
5193 // Checks possible ldflda of field access expression
5194 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5195 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5196 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5199 public void SetHasAddressTaken ()
5201 IVariableReference vr = InstanceExpression as IVariableReference;
5203 vr.SetHasAddressTaken ();
5207 public override Expression CreateExpressionTree (ResolveContext ec)
5209 Expression instance;
5210 if (InstanceExpression == null) {
5211 instance = new NullLiteral (loc);
5213 instance = InstanceExpression.CreateExpressionTree (ec);
5216 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5218 CreateTypeOfExpression ());
5220 return CreateExpressionFactoryCall (ec, "Field", args);
5223 public Expression CreateTypeOfExpression ()
5225 return new TypeOfField (spec, loc);
5228 protected override Expression DoResolve (ResolveContext ec)
5230 return DoResolve (ec, null);
5233 Expression DoResolve (ResolveContext ec, Expression rhs)
5235 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5238 if (ResolveInstanceExpression (ec, rhs)) {
5239 // Resolve the field's instance expression while flow analysis is turned
5240 // off: when accessing a field "a.b", we must check whether the field
5241 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5243 if (lvalue_instance) {
5244 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5245 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5247 Expression right_side =
5248 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5250 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5253 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5254 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5258 if (InstanceExpression == null)
5262 DoBestMemberChecks (ec, spec);
5265 var fb = spec as FixedFieldSpec;
5266 IVariableReference var = InstanceExpression as IVariableReference;
5268 if (lvalue_instance && var != null && var.VariableInfo != null) {
5269 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5273 IFixedExpression fe = InstanceExpression as IFixedExpression;
5274 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5275 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5278 if (InstanceExpression.eclass != ExprClass.Variable) {
5279 ec.Report.SymbolRelatedToPreviousError (spec);
5280 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5281 TypeManager.GetFullNameSignature (spec));
5282 } else if (var != null && var.IsHoisted) {
5283 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5286 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5290 // Set flow-analysis variable info for struct member access. It will be check later
5291 // for precise error reporting
5293 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5294 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5295 if (rhs != null && variable_info != null)
5296 variable_info.SetStructFieldAssigned (ec, Name);
5299 eclass = ExprClass.Variable;
5303 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5308 var var = fe.InstanceExpression as IVariableReference;
5310 var vi = var.VariableInfo;
5312 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5314 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5316 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5323 fe = fe.InstanceExpression as FieldExpr;
5325 } while (fe != null);
5328 static readonly int [] codes = {
5329 191, // instance, write access
5330 192, // instance, out access
5331 198, // static, write access
5332 199, // static, out access
5333 1648, // member of value instance, write access
5334 1649, // member of value instance, out access
5335 1650, // member of value static, write access
5336 1651 // member of value static, out access
5339 static readonly string [] msgs = {
5340 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5341 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5342 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5343 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5344 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5345 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5346 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5347 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5350 // The return value is always null. Returning a value simplifies calling code.
5351 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5354 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5358 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5360 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5365 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5367 Expression e = DoResolve (ec, right_side);
5372 spec.MemberDefinition.SetIsAssigned ();
5374 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5375 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5376 ec.Report.Warning (420, 1, loc,
5377 "`{0}': A volatile field references will not be treated as volatile",
5378 spec.GetSignatureForError ());
5381 if (spec.IsReadOnly) {
5382 // InitOnly fields can only be assigned in constructors or initializers
5383 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5384 return Report_AssignToReadonly (ec, right_side);
5386 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5388 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5389 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5390 return Report_AssignToReadonly (ec, right_side);
5391 // static InitOnly fields cannot be assigned-to in an instance constructor
5392 if (IsStatic && !ec.IsStatic)
5393 return Report_AssignToReadonly (ec, right_side);
5394 // instance constructors can't modify InitOnly fields of other instances of the same type
5395 if (!IsStatic && !(InstanceExpression is This))
5396 return Report_AssignToReadonly (ec, right_side);
5400 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5401 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5402 ec.Report.Warning (197, 1, loc,
5403 "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",
5404 GetSignatureForError ());
5407 eclass = ExprClass.Variable;
5411 public override int GetHashCode ()
5413 return spec.GetHashCode ();
5416 public bool IsFixed {
5419 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5421 IVariableReference variable = InstanceExpression as IVariableReference;
5422 if (variable != null)
5423 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5425 IFixedExpression fe = InstanceExpression as IFixedExpression;
5426 return fe != null && fe.IsFixed;
5430 public override bool Equals (object obj)
5432 FieldExpr fe = obj as FieldExpr;
5436 if (spec != fe.spec)
5439 if (InstanceExpression == null || fe.InstanceExpression == null)
5442 return InstanceExpression.Equals (fe.InstanceExpression);
5445 public void Emit (EmitContext ec, bool leave_copy)
5447 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5449 spec.MemberDefinition.SetIsUsed ();
5453 ec.Emit (OpCodes.Volatile);
5455 ec.Emit (OpCodes.Ldsfld, spec);
5458 EmitInstance (ec, false);
5460 // Optimization for build-in types
5461 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5462 ec.EmitLoadFromPtr (type);
5464 var ff = spec as FixedFieldSpec;
5466 ec.Emit (OpCodes.Ldflda, spec);
5467 ec.Emit (OpCodes.Ldflda, ff.Element);
5470 ec.Emit (OpCodes.Volatile);
5472 ec.Emit (OpCodes.Ldfld, spec);
5478 ec.Emit (OpCodes.Dup);
5480 temp = new LocalTemporary (this.Type);
5486 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5488 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5489 if (isCompound && !(source is DynamicExpressionStatement)) {
5490 if (has_await_source) {
5492 InstanceExpression = InstanceExpression.EmitToField (ec);
5499 if (has_await_source)
5500 source = source.EmitToField (ec);
5502 EmitInstance (ec, prepared);
5508 ec.Emit (OpCodes.Dup);
5510 temp = new LocalTemporary (this.Type);
5515 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5516 ec.Emit (OpCodes.Volatile);
5518 spec.MemberDefinition.SetIsAssigned ();
5521 ec.Emit (OpCodes.Stsfld, spec);
5523 ec.Emit (OpCodes.Stfld, spec);
5533 // Emits store to field with prepared values on stack
5535 public void EmitAssignFromStack (EmitContext ec)
5538 ec.Emit (OpCodes.Stsfld, spec);
5540 ec.Emit (OpCodes.Stfld, spec);
5544 public override void Emit (EmitContext ec)
5549 public override void EmitSideEffect (EmitContext ec)
5551 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5553 if (is_volatile) // || is_marshal_by_ref ())
5554 base.EmitSideEffect (ec);
5557 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5559 if ((mode & AddressOp.Store) != 0)
5560 spec.MemberDefinition.SetIsAssigned ();
5561 if ((mode & AddressOp.Load) != 0)
5562 spec.MemberDefinition.SetIsUsed ();
5565 // Handle initonly fields specially: make a copy and then
5566 // get the address of the copy.
5569 if (spec.IsReadOnly){
5571 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5583 var temp = ec.GetTemporaryLocal (type);
5584 ec.Emit (OpCodes.Stloc, temp);
5585 ec.Emit (OpCodes.Ldloca, temp);
5586 ec.FreeTemporaryLocal (temp, type);
5592 ec.Emit (OpCodes.Ldsflda, spec);
5595 EmitInstance (ec, false);
5596 ec.Emit (OpCodes.Ldflda, spec);
5600 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5602 return MakeExpression (ctx);
5605 public override SLE.Expression MakeExpression (BuilderContext ctx)
5608 return base.MakeExpression (ctx);
5610 return SLE.Expression.Field (
5611 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5612 spec.GetMetaInfo ());
5616 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5618 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5624 // Expression that evaluates to a Property.
5626 // This is not an LValue because we need to re-write the expression. We
5627 // can not take data from the stack and store it.
5629 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5631 public PropertyExpr (PropertySpec spec, Location l)
5634 best_candidate = spec;
5635 type = spec.MemberType;
5640 protected override Arguments Arguments {
5648 protected override TypeSpec DeclaringType {
5650 return best_candidate.DeclaringType;
5654 public override string Name {
5656 return best_candidate.Name;
5660 public override bool IsInstance {
5666 public override bool IsStatic {
5668 return best_candidate.IsStatic;
5672 public override string KindName {
5673 get { return "property"; }
5676 public PropertySpec PropertyInfo {
5678 return best_candidate;
5684 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5686 return new PropertyExpr (spec, loc) {
5692 public override Expression CreateExpressionTree (ResolveContext ec)
5695 if (IsSingleDimensionalArrayLength ()) {
5696 args = new Arguments (1);
5697 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5698 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5701 args = new Arguments (2);
5702 if (InstanceExpression == null)
5703 args.Add (new Argument (new NullLiteral (loc)));
5705 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5706 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5707 return CreateExpressionFactoryCall (ec, "Property", args);
5710 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5712 DoResolveLValue (rc, null);
5713 return new TypeOfMethod (Setter, loc);
5716 public override string GetSignatureForError ()
5718 return best_candidate.GetSignatureForError ();
5721 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5724 return base.MakeExpression (ctx);
5726 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5730 public override SLE.Expression MakeExpression (BuilderContext ctx)
5733 return base.MakeExpression (ctx);
5735 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5739 void Error_PropertyNotValid (ResolveContext ec)
5741 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5742 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5743 GetSignatureForError ());
5746 bool IsSingleDimensionalArrayLength ()
5748 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5751 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5752 return ac != null && ac.Rank == 1;
5755 public override void Emit (EmitContext ec, bool leave_copy)
5758 // Special case: length of single dimension array property is turned into ldlen
5760 if (IsSingleDimensionalArrayLength ()) {
5761 EmitInstance (ec, false);
5762 ec.Emit (OpCodes.Ldlen);
5763 ec.Emit (OpCodes.Conv_I4);
5767 base.Emit (ec, leave_copy);
5770 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5773 LocalTemporary await_source_arg = null;
5775 if (isCompound && !(source is DynamicExpressionStatement)) {
5776 emitting_compound_assignment = true;
5779 if (has_await_arguments) {
5780 await_source_arg = new LocalTemporary (Type);
5781 await_source_arg.Store (ec);
5783 args = new Arguments (1);
5784 args.Add (new Argument (await_source_arg));
5787 temp = await_source_arg;
5790 has_await_arguments = false;
5795 ec.Emit (OpCodes.Dup);
5796 temp = new LocalTemporary (this.Type);
5801 args = new Arguments (1);
5805 temp = new LocalTemporary (this.Type);
5807 args.Add (new Argument (temp));
5809 args.Add (new Argument (source));
5813 emitting_compound_assignment = false;
5815 var call = new CallEmitter ();
5816 call.InstanceExpression = InstanceExpression;
5818 call.InstanceExpressionOnStack = true;
5820 call.Emit (ec, Setter, args, loc);
5827 if (await_source_arg != null) {
5828 await_source_arg.Release (ec);
5832 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5834 eclass = ExprClass.PropertyAccess;
5836 if (best_candidate.IsNotCSharpCompatible) {
5837 Error_PropertyNotValid (rc);
5840 ResolveInstanceExpression (rc, right_side);
5842 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5843 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5844 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5846 type = p.MemberType;
5850 DoBestMemberChecks (rc, best_candidate);
5854 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5856 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5860 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5862 // getter and setter can be different for base calls
5863 MethodSpec getter, setter;
5864 protected T best_candidate;
5866 protected LocalTemporary temp;
5867 protected bool emitting_compound_assignment;
5868 protected bool has_await_arguments;
5870 protected PropertyOrIndexerExpr (Location l)
5877 protected abstract Arguments Arguments { get; set; }
5879 public MethodSpec Getter {
5888 public MethodSpec Setter {
5899 protected override Expression DoResolve (ResolveContext ec)
5901 if (eclass == ExprClass.Unresolved) {
5902 var expr = OverloadResolve (ec, null);
5907 return expr.Resolve (ec);
5910 if (!ResolveGetter (ec))
5916 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5918 if (right_side == EmptyExpression.OutAccess) {
5919 // TODO: best_candidate can be null at this point
5920 INamedBlockVariable variable = null;
5921 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5922 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5923 best_candidate.Name);
5925 right_side.DoResolveLValue (ec, this);
5930 // if the property/indexer returns a value type, and we try to set a field in it
5931 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5932 Error_ValueAssignment (ec, right_side);
5935 if (eclass == ExprClass.Unresolved) {
5936 var expr = OverloadResolve (ec, right_side);
5941 return expr.ResolveLValue (ec, right_side);
5944 if (!ResolveSetter (ec))
5951 // Implements the IAssignMethod interface for assignments
5953 public virtual void Emit (EmitContext ec, bool leave_copy)
5955 var call = new CallEmitter ();
5956 call.InstanceExpression = InstanceExpression;
5957 if (has_await_arguments)
5958 call.HasAwaitArguments = true;
5960 call.DuplicateArguments = emitting_compound_assignment;
5962 call.Emit (ec, Getter, Arguments, loc);
5964 if (call.HasAwaitArguments) {
5965 InstanceExpression = call.InstanceExpression;
5966 Arguments = call.EmittedArguments;
5967 has_await_arguments = true;
5971 ec.Emit (OpCodes.Dup);
5972 temp = new LocalTemporary (Type);
5977 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5979 public override void Emit (EmitContext ec)
5984 protected override FieldExpr EmitToFieldSource (EmitContext ec)
5986 has_await_arguments = true;
5991 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5993 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5995 bool ResolveGetter (ResolveContext rc)
5997 if (!best_candidate.HasGet) {
5998 if (InstanceExpression != EmptyExpression.Null) {
5999 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6000 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6001 best_candidate.GetSignatureForError ());
6004 } else if (!best_candidate.Get.IsAccessible (rc)) {
6005 if (best_candidate.HasDifferentAccessibility) {
6006 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6007 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6008 TypeManager.CSharpSignature (best_candidate));
6010 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6011 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6015 if (best_candidate.HasDifferentAccessibility) {
6016 CheckProtectedMemberAccess (rc, best_candidate.Get);
6019 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6023 bool ResolveSetter (ResolveContext rc)
6025 if (!best_candidate.HasSet) {
6026 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6027 GetSignatureForError ());
6031 if (!best_candidate.Set.IsAccessible (rc)) {
6032 if (best_candidate.HasDifferentAccessibility) {
6033 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6034 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6035 GetSignatureForError ());
6037 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6038 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
6042 if (best_candidate.HasDifferentAccessibility)
6043 CheckProtectedMemberAccess (rc, best_candidate.Set);
6045 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6051 /// Fully resolved expression that evaluates to an Event
6053 public class EventExpr : MemberExpr, IAssignMethod
6055 readonly EventSpec spec;
6058 public EventExpr (EventSpec spec, Location loc)
6066 protected override TypeSpec DeclaringType {
6068 return spec.DeclaringType;
6072 public override string Name {
6078 public override bool IsInstance {
6080 return !spec.IsStatic;
6084 public override bool IsStatic {
6086 return spec.IsStatic;
6090 public override string KindName {
6091 get { return "event"; }
6094 public MethodSpec Operator {
6102 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6105 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6107 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6108 if (spec.BackingField != null &&
6109 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6111 spec.MemberDefinition.SetIsUsed ();
6113 if (!ec.IsObsolete) {
6114 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6116 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6119 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6120 Error_AssignmentEventOnly (ec);
6122 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6124 InstanceExpression = null;
6126 return ml.ResolveMemberAccess (ec, left, original);
6130 return base.ResolveMemberAccess (ec, left, original);
6133 public override Expression CreateExpressionTree (ResolveContext ec)
6135 throw new NotSupportedException ("ET");
6138 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6140 if (right_side == EmptyExpression.EventAddition) {
6141 op = spec.AccessorAdd;
6142 } else if (right_side == EmptyExpression.EventSubtraction) {
6143 op = spec.AccessorRemove;
6147 Error_AssignmentEventOnly (ec);
6151 op = CandidateToBaseOverride (ec, op);
6155 protected override Expression DoResolve (ResolveContext ec)
6157 eclass = ExprClass.EventAccess;
6158 type = spec.MemberType;
6160 ResolveInstanceExpression (ec, null);
6162 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6163 Error_AssignmentEventOnly (ec);
6166 DoBestMemberChecks (ec, spec);
6170 public override void Emit (EmitContext ec)
6172 throw new NotSupportedException ();
6173 //Error_CannotAssign ();
6176 #region IAssignMethod Members
6178 public void Emit (EmitContext ec, bool leave_copy)
6180 throw new NotImplementedException ();
6183 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6185 if (leave_copy || !isCompound)
6186 throw new NotImplementedException ("EventExpr::EmitAssign");
6188 Arguments args = new Arguments (1);
6189 args.Add (new Argument (source));
6191 var call = new CallEmitter ();
6192 call.InstanceExpression = InstanceExpression;
6193 call.Emit (ec, op, args, loc);
6198 void Error_AssignmentEventOnly (ResolveContext ec)
6200 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6201 ec.Report.Error (79, loc,
6202 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6203 GetSignatureForError ());
6205 ec.Report.Error (70, loc,
6206 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6207 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6211 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6213 name = name.Substring (0, name.LastIndexOf ('.'));
6214 base.Error_CannotCallAbstractBase (rc, name);
6217 public override string GetSignatureForError ()
6219 return TypeManager.CSharpSignature (spec);
6222 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6224 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6228 public class TemporaryVariableReference : VariableReference
6230 public class Declarator : Statement
6232 TemporaryVariableReference variable;
6234 public Declarator (TemporaryVariableReference variable)
6236 this.variable = variable;
6240 protected override void DoEmit (EmitContext ec)
6242 variable.li.CreateBuilder (ec);
6245 public override void Emit (EmitContext ec)
6247 // Don't create sequence point
6251 protected override void CloneTo (CloneContext clonectx, Statement target)
6259 public TemporaryVariableReference (LocalVariable li, Location loc)
6262 this.type = li.Type;
6266 public override bool IsLockedByStatement {
6274 public LocalVariable LocalInfo {
6280 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6282 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6283 return new TemporaryVariableReference (li, loc);
6286 protected override Expression DoResolve (ResolveContext ec)
6288 eclass = ExprClass.Variable;
6291 // Don't capture temporary variables except when using
6292 // state machine redirection and block yields
6294 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6295 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6296 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6297 storey.CaptureLocalVariable (ec, li);
6303 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6305 return Resolve (ec);
6308 public override void Emit (EmitContext ec)
6310 li.CreateBuilder (ec);
6315 public void EmitAssign (EmitContext ec, Expression source)
6317 li.CreateBuilder (ec);
6319 EmitAssign (ec, source, false, false);
6322 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6324 return li.HoistedVariant;
6327 public override bool IsFixed {
6328 get { return true; }
6331 public override bool IsRef {
6332 get { return false; }
6335 public override string Name {
6336 get { throw new NotImplementedException (); }
6339 public override void SetHasAddressTaken ()
6341 throw new NotImplementedException ();
6344 protected override ILocalVariable Variable {
6348 public override VariableInfo VariableInfo {
6349 get { return null; }
6352 public override void VerifyAssigned (ResolveContext rc)
6358 /// Handles `var' contextual keyword; var becomes a keyword only
6359 /// if no type called var exists in a variable scope
6361 class VarExpr : SimpleName
6363 public VarExpr (Location loc)
6368 public bool InferType (ResolveContext ec, Expression right_side)
6371 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6373 type = right_side.Type;
6374 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6375 ec.Report.Error (815, loc,
6376 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6377 type.GetSignatureForError ());
6381 eclass = ExprClass.Variable;
6385 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6387 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6388 base.Error_TypeOrNamespaceNotFound (ec);
6390 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");