2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Returns true when the expression during Emit phase breaks stack
157 // by using await expression
159 public virtual bool ContainsEmitWithAwait ()
165 /// Performs semantic analysis on the Expression
169 /// The Resolve method is invoked to perform the semantic analysis
172 /// The return value is an expression (it can be the
173 /// same expression in some cases) or a new
174 /// expression that better represents this node.
176 /// For example, optimizations of Unary (LiteralInt)
177 /// would return a new LiteralInt with a negated
180 /// If there is an error during semantic analysis,
181 /// then an error should be reported (using Report)
182 /// and a null value should be returned.
184 /// There are two side effects expected from calling
185 /// Resolve(): the the field variable "eclass" should
186 /// be set to any value of the enumeration
187 /// `ExprClass' and the type variable should be set
188 /// to a valid type (this is the type of the
191 protected abstract Expression DoResolve (ResolveContext rc);
193 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
199 // This is used if the expression should be resolved as a type or namespace name.
200 // the default implementation fails.
202 public virtual TypeSpec ResolveAsType (IMemberContext mc)
204 ResolveContext ec = new ResolveContext (mc);
205 Expression e = Resolve (ec);
207 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
212 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
214 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
217 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
219 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
222 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
224 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
225 name, TypeManager.CSharpName (type));
228 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
230 Report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
233 public void Error_InvalidExpressionStatement (BlockContext ec)
235 Error_InvalidExpressionStatement (ec.Report, loc);
238 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
240 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
243 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
245 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
248 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
250 // The error was already reported as CS1660
251 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
254 string from_type = type.GetSignatureForError ();
255 string to_type = target.GetSignatureForError ();
256 if (from_type == to_type) {
257 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
258 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
262 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
267 ec.Report.DisableReporting ();
268 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
269 ec.Report.EnableReporting ();
272 ec.Report.Error (266, loc,
273 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
276 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
281 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
283 // Better message for possible generic expressions
284 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
285 var report = context.Module.Compiler.Report;
286 report.SymbolRelatedToPreviousError (member);
287 if (member is TypeSpec)
288 member = ((TypeSpec) member).GetDefinition ();
290 member = ((MethodSpec) member).GetGenericMethodDefinition ();
292 string name = member.Kind == MemberKind.Method ? "method" : "type";
293 if (member.IsGeneric) {
294 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
295 name, member.GetSignatureForError (), member.Arity.ToString ());
297 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
298 name, member.GetSignatureForError ());
301 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
305 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
307 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
311 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
313 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
316 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
318 ec.Report.SymbolRelatedToPreviousError (type);
319 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
320 TypeManager.CSharpName (type), name);
323 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
325 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
326 rc.Report.SymbolRelatedToPreviousError (type);
327 if (rc.CurrentInitializerVariable != null) {
328 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
329 type.GetSignatureForError (), GetSignatureForError ());
331 rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
332 GetSignatureForError ());
335 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
339 protected void Error_VoidPointerOperation (ResolveContext rc)
341 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
344 public ResolveFlags ExprClassToResolveFlags {
348 case ExprClass.Namespace:
349 return ResolveFlags.Type;
351 case ExprClass.MethodGroup:
352 return ResolveFlags.MethodGroup;
354 case ExprClass.TypeParameter:
355 return ResolveFlags.TypeParameter;
357 case ExprClass.Value:
358 case ExprClass.Variable:
359 case ExprClass.PropertyAccess:
360 case ExprClass.EventAccess:
361 case ExprClass.IndexerAccess:
362 return ResolveFlags.VariableOrValue;
365 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
370 public virtual string GetSignatureForError ()
372 return type.GetDefinition ().GetSignatureForError ();
376 /// Resolves an expression and performs semantic analysis on it.
380 /// Currently Resolve wraps DoResolve to perform sanity
381 /// checking and assertion checking on what we expect from Resolve.
383 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
385 if (eclass != ExprClass.Unresolved)
395 if ((flags & e.ExprClassToResolveFlags) == 0) {
396 e.Error_UnexpectedKind (ec, flags, loc);
401 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
404 } catch (Exception ex) {
405 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
408 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
409 return ErrorExpression.Instance; // TODO: Add location
414 /// Resolves an expression and performs semantic analysis on it.
416 public Expression Resolve (ResolveContext rc)
418 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
422 /// Resolves an expression for LValue assignment
426 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
427 /// checking and assertion checking on what we expect from Resolve
429 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
431 int errors = ec.Report.Errors;
432 bool out_access = right_side == EmptyExpression.OutAccess;
434 Expression e = DoResolveLValue (ec, right_side);
436 if (e != null && out_access && !(e is IMemoryLocation)) {
437 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
438 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
440 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
441 // e.GetType () + " " + e.GetSignatureForError ());
446 if (errors == ec.Report.Errors) {
448 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
450 Error_ValueAssignment (ec, right_side);
455 if (e.eclass == ExprClass.Unresolved)
456 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
458 if ((e.type == null) && !(e is GenericTypeExpr))
459 throw new Exception ("Expression " + e + " did not set its type after Resolve");
464 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
466 rc.Module.Compiler.Report.Error (182, loc,
467 "An attribute argument must be a constant expression, typeof expression or array creation expression");
471 /// Emits the code for the expression
475 /// The Emit method is invoked to generate the code
476 /// for the expression.
478 public abstract void Emit (EmitContext ec);
481 // Emit code to branch to @target if this expression is equivalent to @on_true.
482 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
483 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
484 // including the use of conditional branches. Note also that a branch MUST be emitted
485 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
488 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
491 // Emit this expression for its side effects, not for its value.
492 // The default implementation is to emit the value, and then throw it away.
493 // Subclasses can provide more efficient implementations, but those MUST be equivalent
494 public virtual void EmitSideEffect (EmitContext ec)
497 ec.Emit (OpCodes.Pop);
501 // Emits the expression into temporary field variable. The method
502 // should be used for await expressions only
504 public virtual Expression EmitToField (EmitContext ec)
507 // This is the await prepare Emit method. When emitting code like
508 // a + b we emit code like
514 // For await a + await b we have to interfere the flow to keep the
515 // stack clean because await yields from the expression. The emit
518 // a = a.EmitToField () // a is changed to temporary field access
519 // b = b.EmitToField ()
525 // The idea is to emit expression and leave the stack empty with
526 // result value still available.
528 // Expressions should override this default implementation when
529 // optimized version can be provided (e.g. FieldExpr)
532 // We can optimize for side-effect free expressions, they can be
533 // emitted out of order
535 if (IsSideEffectFree)
538 bool needs_temporary = ContainsEmitWithAwait ();
539 if (!needs_temporary)
542 // Emit original code
543 var field = EmitToFieldSource (ec);
546 // Store the result to temporary field when we
547 // cannot load `this' directly
549 field = ec.GetTemporaryField (type);
550 if (needs_temporary) {
552 // Create temporary local (we cannot load `this' before Emit)
554 var temp = ec.GetTemporaryLocal (type);
555 ec.Emit (OpCodes.Stloc, temp);
558 ec.Emit (OpCodes.Ldloc, temp);
559 field.EmitAssignFromStack (ec);
561 ec.FreeTemporaryLocal (temp, type);
563 field.EmitAssignFromStack (ec);
570 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
573 // Default implementation calls Emit method
579 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
581 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
582 bool contains_await = false;
584 for (int i = 1; i < expressions.Count; ++i) {
585 if (expressions[i].ContainsEmitWithAwait ()) {
586 contains_await = true;
591 if (contains_await) {
592 for (int i = 0; i < expressions.Count; ++i) {
593 expressions[i] = expressions[i].EmitToField (ec);
598 for (int i = 0; i < expressions.Count; ++i) {
599 expressions[i].Emit (ec);
604 /// Protected constructor. Only derivate types should
605 /// be able to be created
608 protected Expression ()
613 /// Returns a fully formed expression after a MemberLookup
616 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
618 if (spec is EventSpec)
619 return new EventExpr ((EventSpec) spec, loc);
620 if (spec is ConstSpec)
621 return new ConstantExpr ((ConstSpec) spec, loc);
622 if (spec is FieldSpec)
623 return new FieldExpr ((FieldSpec) spec, loc);
624 if (spec is PropertySpec)
625 return new PropertyExpr ((PropertySpec) spec, loc);
626 if (spec is TypeSpec)
627 return new TypeExpression (((TypeSpec) spec), loc);
632 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
634 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
636 rc.Report.SymbolRelatedToPreviousError (type);
638 // Report meaningful error for struct as they always have default ctor in C# context
639 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
641 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
642 type.GetSignatureForError ());
648 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
649 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
650 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
653 return r.ResolveMember<MethodSpec> (rc, ref args);
657 public enum MemberLookupRestrictions
666 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
667 // `qualifier_type' or null to lookup members in the current class.
669 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
671 var members = MemberCache.FindMembers (queried_type, name, false);
675 MemberSpec non_method = null;
676 MemberSpec ambig_non_method = null;
678 for (int i = 0; i < members.Count; ++i) {
679 var member = members[i];
681 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
682 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
685 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
688 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
692 if (!member.IsAccessible (rc))
696 // With runtime binder we can have a situation where queried type is inaccessible
697 // because it came via dynamic object, the check about inconsisted accessibility
698 // had no effect as the type was unknown during compilation
701 // private class N { }
703 // public dynamic Foo ()
709 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
713 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
714 if (member is MethodSpec)
715 return new MethodGroupExpr (members, queried_type, loc);
717 if (!Invocation.IsMemberInvocable (member))
721 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
723 } else if (!errorMode && !member.IsNotCSharpCompatible) {
724 ambig_non_method = member;
728 if (non_method != null) {
729 if (ambig_non_method != null && rc != null) {
730 var report = rc.Module.Compiler.Report;
731 report.SymbolRelatedToPreviousError (non_method);
732 report.SymbolRelatedToPreviousError (ambig_non_method);
733 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
734 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
737 if (non_method is MethodSpec)
738 return new MethodGroupExpr (members, queried_type, loc);
740 return ExprClassFromMemberInfo (non_method, loc);
743 if (members[0].DeclaringType.BaseType == null)
746 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
748 } while (members != null);
753 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
755 throw new NotImplementedException ();
758 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
760 if (t == InternalType.ErrorType)
763 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
764 oper, t.GetSignatureForError ());
767 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
769 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
773 /// Returns an expression that can be used to invoke operator true
774 /// on the expression if it exists.
776 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
778 return GetOperatorTrueOrFalse (ec, e, true, loc);
782 /// Returns an expression that can be used to invoke operator false
783 /// on the expression if it exists.
785 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
787 return GetOperatorTrueOrFalse (ec, e, false, loc);
790 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
792 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
793 var methods = MemberCache.GetUserOperator (e.type, op, false);
797 Arguments arguments = new Arguments (1);
798 arguments.Add (new Argument (e));
800 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
801 var oper = res.ResolveOperator (ec, ref arguments);
806 return new UserOperatorCall (oper, arguments, null, loc);
809 public virtual string ExprClassName
813 case ExprClass.Unresolved:
815 case ExprClass.Value:
817 case ExprClass.Variable:
819 case ExprClass.Namespace:
823 case ExprClass.MethodGroup:
824 return "method group";
825 case ExprClass.PropertyAccess:
826 return "property access";
827 case ExprClass.EventAccess:
828 return "event access";
829 case ExprClass.IndexerAccess:
830 return "indexer access";
831 case ExprClass.Nothing:
833 case ExprClass.TypeParameter:
834 return "type parameter";
836 throw new Exception ("Should not happen");
841 /// Reports that we were expecting `expr' to be of class `expected'
843 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
845 var name = memberExpr.GetSignatureForError ();
847 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
850 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
852 string [] valid = new string [4];
855 if ((flags & ResolveFlags.VariableOrValue) != 0) {
856 valid [count++] = "variable";
857 valid [count++] = "value";
860 if ((flags & ResolveFlags.Type) != 0)
861 valid [count++] = "type";
863 if ((flags & ResolveFlags.MethodGroup) != 0)
864 valid [count++] = "method group";
867 valid [count++] = "unknown";
869 StringBuilder sb = new StringBuilder (valid [0]);
870 for (int i = 1; i < count - 1; i++) {
872 sb.Append (valid [i]);
875 sb.Append ("' or `");
876 sb.Append (valid [count - 1]);
879 ec.Report.Error (119, loc,
880 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
883 public static void UnsafeError (ResolveContext ec, Location loc)
885 UnsafeError (ec.Report, loc);
888 public static void UnsafeError (Report Report, Location loc)
890 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
894 // Converts `source' to an int, uint, long or ulong.
896 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
898 var btypes = ec.BuiltinTypes;
900 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
901 Arguments args = new Arguments (1);
902 args.Add (new Argument (source));
903 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
906 Expression converted;
908 using (ec.Set (ResolveContext.Options.CheckedScope)) {
909 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
910 if (converted == null)
911 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
912 if (converted == null)
913 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
914 if (converted == null)
915 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
917 if (converted == null) {
918 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
924 // Only positive constants are allowed at compile time
926 Constant c = converted as Constant;
927 if (c != null && c.IsNegative)
928 Error_NegativeArrayIndex (ec, source.loc);
930 // No conversion needed to array index
931 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
934 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
938 // Derived classes implement this method by cloning the fields that
939 // could become altered during the Resolve stage
941 // Only expressions that are created for the parser need to implement
944 protected virtual void CloneTo (CloneContext clonectx, Expression target)
946 throw new NotImplementedException (
948 "CloneTo not implemented for expression {0}", this.GetType ()));
952 // Clones an expression created by the parser.
954 // We only support expressions created by the parser so far, not
955 // expressions that have been resolved (many more classes would need
956 // to implement CloneTo).
958 // This infrastructure is here merely for Lambda expressions which
959 // compile the same code using different type values for the same
960 // arguments to find the correct overload
962 public virtual Expression Clone (CloneContext clonectx)
964 Expression cloned = (Expression) MemberwiseClone ();
965 CloneTo (clonectx, cloned);
971 // Implementation of expression to expression tree conversion
973 public abstract Expression CreateExpressionTree (ResolveContext ec);
975 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
977 return CreateExpressionFactoryCall (ec, name, null, args, loc);
980 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
982 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
985 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
987 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
990 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
992 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
996 return new TypeExpression (t, loc);
1000 // Implemented by all expressions which support conversion from
1001 // compiler expression to invokable runtime expression. Used by
1002 // dynamic C# binder.
1004 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1006 throw new NotImplementedException ("MakeExpression for " + GetType ());
1009 public virtual object Accept (StructuralVisitor visitor)
1011 return visitor.Visit (this);
1016 /// This is just a base class for expressions that can
1017 /// appear on statements (invocations, object creation,
1018 /// assignments, post/pre increment and decrement). The idea
1019 /// being that they would support an extra Emition interface that
1020 /// does not leave a result on the stack.
1022 public abstract class ExpressionStatement : Expression {
1024 public ExpressionStatement ResolveStatement (BlockContext ec)
1026 Expression e = Resolve (ec);
1030 ExpressionStatement es = e as ExpressionStatement;
1032 Error_InvalidExpressionStatement (ec);
1034 if (ec.CurrentAnonymousMethod is AsyncInitializer && !(e is Assign) &&
1035 (e.Type.IsGenericTask || e.Type == ec.Module.PredefinedTypes.Task.TypeSpec)) {
1036 ec.Report.Warning (4014, 1, e.Location,
1037 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1044 /// Requests the expression to be emitted in a `statement'
1045 /// context. This means that no new value is left on the
1046 /// stack after invoking this method (constrasted with
1047 /// Emit that will always leave a value on the stack).
1049 public abstract void EmitStatement (EmitContext ec);
1051 public override void EmitSideEffect (EmitContext ec)
1058 /// This kind of cast is used to encapsulate the child
1059 /// whose type is child.Type into an expression that is
1060 /// reported to return "return_type". This is used to encapsulate
1061 /// expressions which have compatible types, but need to be dealt
1062 /// at higher levels with.
1064 /// For example, a "byte" expression could be encapsulated in one
1065 /// of these as an "unsigned int". The type for the expression
1066 /// would be "unsigned int".
1069 public abstract class TypeCast : Expression
1071 protected readonly Expression child;
1073 protected TypeCast (Expression child, TypeSpec return_type)
1075 eclass = child.eclass;
1076 loc = child.Location;
1081 public Expression Child {
1087 public override bool ContainsEmitWithAwait ()
1089 return child.ContainsEmitWithAwait ();
1092 public override Expression CreateExpressionTree (ResolveContext ec)
1094 Arguments args = new Arguments (2);
1095 args.Add (new Argument (child.CreateExpressionTree (ec)));
1096 args.Add (new Argument (new TypeOf (type, loc)));
1098 if (type.IsPointer || child.Type.IsPointer)
1099 Error_PointerInsideExpressionTree (ec);
1101 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1104 protected override Expression DoResolve (ResolveContext ec)
1106 // This should never be invoked, we are born in fully
1107 // initialized state.
1112 public override void Emit (EmitContext ec)
1117 public override SLE.Expression MakeExpression (BuilderContext ctx)
1120 return base.MakeExpression (ctx);
1122 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1123 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1124 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1128 protected override void CloneTo (CloneContext clonectx, Expression t)
1133 public override bool IsNull {
1134 get { return child.IsNull; }
1138 public class EmptyCast : TypeCast {
1139 EmptyCast (Expression child, TypeSpec target_type)
1140 : base (child, target_type)
1144 public static Expression Create (Expression child, TypeSpec type)
1146 Constant c = child as Constant;
1148 return new EmptyConstantCast (c, type);
1150 EmptyCast e = child as EmptyCast;
1152 return new EmptyCast (e.child, type);
1154 return new EmptyCast (child, type);
1157 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1159 child.EmitBranchable (ec, label, on_true);
1162 public override void EmitSideEffect (EmitContext ec)
1164 child.EmitSideEffect (ec);
1169 // Used for predefined type user operator (no obsolete check, etc.)
1171 public class OperatorCast : TypeCast
1173 readonly MethodSpec conversion_operator;
1175 public OperatorCast (Expression expr, TypeSpec target_type)
1176 : this (expr, target_type, target_type, false)
1180 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1181 : this (expr, target_type, target_type, find_explicit)
1185 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1186 : base (expr, returnType)
1188 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1189 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1192 foreach (MethodSpec oper in mi) {
1193 if (oper.ReturnType != returnType)
1196 if (oper.Parameters.Types[0] == expr.Type) {
1197 conversion_operator = oper;
1203 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1204 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1207 public override void Emit (EmitContext ec)
1210 ec.Emit (OpCodes.Call, conversion_operator);
1215 // Constant specialization of EmptyCast.
1216 // We need to special case this since an empty cast of
1217 // a constant is still a constant.
1219 public class EmptyConstantCast : Constant
1221 public readonly Constant child;
1223 public EmptyConstantCast (Constant child, TypeSpec type)
1224 : base (child.Location)
1227 throw new ArgumentNullException ("child");
1230 this.eclass = child.eclass;
1234 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1236 if (child.Type == target_type)
1239 // FIXME: check that 'type' can be converted to 'target_type' first
1240 return child.ConvertExplicitly (in_checked_context, target_type);
1243 public override Expression CreateExpressionTree (ResolveContext ec)
1245 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1246 child.CreateExpressionTree (ec),
1247 new TypeOf (type, loc));
1250 Error_PointerInsideExpressionTree (ec);
1252 return CreateExpressionFactoryCall (ec, "Convert", args);
1255 public override bool IsDefaultValue {
1256 get { return child.IsDefaultValue; }
1259 public override bool IsNegative {
1260 get { return child.IsNegative; }
1263 public override bool IsNull {
1264 get { return child.IsNull; }
1267 public override bool IsOneInteger {
1268 get { return child.IsOneInteger; }
1271 public override bool IsSideEffectFree {
1273 return child.IsSideEffectFree;
1277 public override bool IsZeroInteger {
1278 get { return child.IsZeroInteger; }
1281 public override void Emit (EmitContext ec)
1286 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1288 child.EmitBranchable (ec, label, on_true);
1290 // Only to make verifier happy
1291 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1292 ec.Emit (OpCodes.Unbox_Any, type);
1295 public override void EmitSideEffect (EmitContext ec)
1297 child.EmitSideEffect (ec);
1300 public override object GetValue ()
1302 return child.GetValue ();
1305 public override string GetValueAsLiteral ()
1307 return child.GetValueAsLiteral ();
1310 public override long GetValueAsLong ()
1312 return child.GetValueAsLong ();
1315 public override Constant ConvertImplicitly (TypeSpec target_type)
1317 if (type == target_type)
1320 // FIXME: Do we need to check user conversions?
1321 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1324 return child.ConvertImplicitly (target_type);
1329 /// This class is used to wrap literals which belong inside Enums
1331 public class EnumConstant : Constant
1333 public Constant Child;
1335 public EnumConstant (Constant child, TypeSpec enum_type)
1336 : base (child.Location)
1340 this.eclass = ExprClass.Value;
1341 this.type = enum_type;
1344 protected EnumConstant (Location loc)
1349 public override void Emit (EmitContext ec)
1354 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1356 Child.EncodeAttributeValue (rc, enc, Child.Type);
1359 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1361 Child.EmitBranchable (ec, label, on_true);
1364 public override void EmitSideEffect (EmitContext ec)
1366 Child.EmitSideEffect (ec);
1369 public override string GetSignatureForError()
1371 return TypeManager.CSharpName (Type);
1374 public override object GetValue ()
1376 return Child.GetValue ();
1380 public override object GetTypedValue ()
1383 // The method can be used in dynamic context only (on closed types)
1385 // System.Enum.ToObject cannot be called on dynamic types
1386 // EnumBuilder has to be used, but we cannot use EnumBuilder
1387 // because it does not properly support generics
1389 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1393 public override string GetValueAsLiteral ()
1395 return Child.GetValueAsLiteral ();
1398 public override long GetValueAsLong ()
1400 return Child.GetValueAsLong ();
1403 public EnumConstant Increment()
1405 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1408 public override bool IsDefaultValue {
1410 return Child.IsDefaultValue;
1414 public override bool IsSideEffectFree {
1416 return Child.IsSideEffectFree;
1420 public override bool IsZeroInteger {
1421 get { return Child.IsZeroInteger; }
1424 public override bool IsNegative {
1426 return Child.IsNegative;
1430 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1432 if (Child.Type == target_type)
1435 return Child.ConvertExplicitly (in_checked_context, target_type);
1438 public override Constant ConvertImplicitly (TypeSpec type)
1440 if (this.type == type) {
1444 if (!Convert.ImplicitStandardConversionExists (this, type)){
1448 return Child.ConvertImplicitly (type);
1453 /// This kind of cast is used to encapsulate Value Types in objects.
1455 /// The effect of it is to box the value type emitted by the previous
1458 public class BoxedCast : TypeCast {
1460 public BoxedCast (Expression expr, TypeSpec target_type)
1461 : base (expr, target_type)
1463 eclass = ExprClass.Value;
1466 protected override Expression DoResolve (ResolveContext ec)
1468 // This should never be invoked, we are born in fully
1469 // initialized state.
1474 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1476 // Only boxing to object type is supported
1477 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1478 base.EncodeAttributeValue (rc, enc, targetType);
1482 enc.Encode (child.Type);
1483 child.EncodeAttributeValue (rc, enc, child.Type);
1486 public override void Emit (EmitContext ec)
1490 ec.Emit (OpCodes.Box, child.Type);
1493 public override void EmitSideEffect (EmitContext ec)
1495 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1496 // so, we need to emit the box+pop instructions in most cases
1497 if (child.Type.IsStruct &&
1498 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1499 child.EmitSideEffect (ec);
1501 base.EmitSideEffect (ec);
1505 public class UnboxCast : TypeCast {
1506 public UnboxCast (Expression expr, TypeSpec return_type)
1507 : base (expr, return_type)
1511 protected override Expression DoResolve (ResolveContext ec)
1513 // This should never be invoked, we are born in fully
1514 // initialized state.
1519 public override void Emit (EmitContext ec)
1523 ec.Emit (OpCodes.Unbox_Any, type);
1528 /// This is used to perform explicit numeric conversions.
1530 /// Explicit numeric conversions might trigger exceptions in a checked
1531 /// context, so they should generate the conv.ovf opcodes instead of
1534 public class ConvCast : TypeCast {
1535 public enum Mode : byte {
1536 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1538 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1539 U2_I1, U2_U1, U2_I2, U2_CH,
1540 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1541 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1542 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1543 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1544 CH_I1, CH_U1, CH_I2,
1545 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1546 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1552 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1553 : base (child, return_type)
1558 protected override Expression DoResolve (ResolveContext ec)
1560 // This should never be invoked, we are born in fully
1561 // initialized state.
1566 public override string ToString ()
1568 return String.Format ("ConvCast ({0}, {1})", mode, child);
1571 public override void Emit (EmitContext ec)
1575 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1577 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1578 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1579 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1580 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1581 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1584 case Mode.U1_CH: /* nothing */ break;
1586 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1587 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1588 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1589 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1590 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1591 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1593 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1594 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1595 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1596 case Mode.U2_CH: /* nothing */ break;
1598 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1599 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1600 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1601 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1602 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1603 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1604 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1607 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1608 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1609 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1610 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1611 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1613 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1614 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1615 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1616 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1618 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1619 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1620 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1623 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1624 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1625 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1626 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1627 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1628 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1629 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1630 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1631 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1633 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1634 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1635 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1637 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1638 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1639 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1640 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1641 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1642 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1643 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1644 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1645 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1647 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1648 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1649 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1650 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1651 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1652 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1653 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1654 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1655 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1656 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1658 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1662 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1663 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1665 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1666 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1672 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1673 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1675 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1676 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.U2_CH: /* nothing */ break;
1683 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1684 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1685 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1686 case Mode.I4_U4: /* nothing */ break;
1687 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1689 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1692 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1693 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1694 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1695 case Mode.U4_I4: /* nothing */ break;
1696 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1698 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.I8_U8: /* nothing */ break;
1705 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1708 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1709 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1710 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1711 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1713 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1714 case Mode.U8_I8: /* nothing */ break;
1715 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1716 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1718 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1719 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1720 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1722 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1723 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1724 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1725 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1726 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1727 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1728 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1729 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1730 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1732 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1733 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1734 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1735 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1736 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1737 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1738 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1739 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1740 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1741 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1743 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1749 class OpcodeCast : TypeCast
1753 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1754 : base (child, return_type)
1759 protected override Expression DoResolve (ResolveContext ec)
1761 // This should never be invoked, we are born in fully
1762 // initialized state.
1767 public override void Emit (EmitContext ec)
1773 public TypeSpec UnderlyingType {
1774 get { return child.Type; }
1779 // Opcode casts expression with 2 opcodes but only
1780 // single expression tree node
1782 class OpcodeCastDuplex : OpcodeCast
1784 readonly OpCode second;
1786 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1787 : base (child, returnType, first)
1789 this.second = second;
1792 public override void Emit (EmitContext ec)
1800 /// This kind of cast is used to encapsulate a child and cast it
1801 /// to the class requested
1803 public sealed class ClassCast : TypeCast {
1804 readonly bool forced;
1806 public ClassCast (Expression child, TypeSpec return_type)
1807 : base (child, return_type)
1811 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1812 : base (child, return_type)
1814 this.forced = forced;
1817 public override void Emit (EmitContext ec)
1821 bool gen = TypeManager.IsGenericParameter (child.Type);
1823 ec.Emit (OpCodes.Box, child.Type);
1825 if (type.IsGenericParameter) {
1826 ec.Emit (OpCodes.Unbox_Any, type);
1833 ec.Emit (OpCodes.Castclass, type);
1838 // Created during resolving pahse when an expression is wrapped or constantified
1839 // and original expression can be used later (e.g. for expression trees)
1841 public class ReducedExpression : Expression
1843 sealed class ReducedConstantExpression : EmptyConstantCast
1845 readonly Expression orig_expr;
1847 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1848 : base (expr, expr.Type)
1850 this.orig_expr = orig_expr;
1853 public override Constant ConvertImplicitly (TypeSpec target_type)
1855 Constant c = base.ConvertImplicitly (target_type);
1857 c = new ReducedConstantExpression (c, orig_expr);
1862 public override Expression CreateExpressionTree (ResolveContext ec)
1864 return orig_expr.CreateExpressionTree (ec);
1867 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1869 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1871 c = new ReducedConstantExpression (c, orig_expr);
1875 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1878 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1880 if (orig_expr is Conditional)
1881 child.EncodeAttributeValue (rc, enc, targetType);
1883 base.EncodeAttributeValue (rc, enc, targetType);
1887 sealed class ReducedExpressionStatement : ExpressionStatement
1889 readonly Expression orig_expr;
1890 readonly ExpressionStatement stm;
1892 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1894 this.orig_expr = orig;
1896 this.eclass = stm.eclass;
1897 this.type = stm.Type;
1899 this.loc = orig.Location;
1902 public override bool ContainsEmitWithAwait ()
1904 return stm.ContainsEmitWithAwait ();
1907 public override Expression CreateExpressionTree (ResolveContext ec)
1909 return orig_expr.CreateExpressionTree (ec);
1912 protected override Expression DoResolve (ResolveContext ec)
1917 public override void Emit (EmitContext ec)
1922 public override void EmitStatement (EmitContext ec)
1924 stm.EmitStatement (ec);
1928 readonly Expression expr, orig_expr;
1930 private ReducedExpression (Expression expr, Expression orig_expr)
1933 this.eclass = expr.eclass;
1934 this.type = expr.Type;
1935 this.orig_expr = orig_expr;
1936 this.loc = orig_expr.Location;
1941 public override bool IsSideEffectFree {
1943 return expr.IsSideEffectFree;
1947 public Expression OriginalExpression {
1955 public override bool ContainsEmitWithAwait ()
1957 return expr.ContainsEmitWithAwait ();
1961 // Creates fully resolved expression switcher
1963 public static Constant Create (Constant expr, Expression original_expr)
1965 if (expr.eclass == ExprClass.Unresolved)
1966 throw new ArgumentException ("Unresolved expression");
1968 return new ReducedConstantExpression (expr, original_expr);
1971 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1973 return new ReducedExpressionStatement (s, orig);
1976 public static Expression Create (Expression expr, Expression original_expr)
1978 return Create (expr, original_expr, true);
1982 // Creates unresolved reduce expression. The original expression has to be
1983 // already resolved. Created expression is constant based based on `expr'
1984 // value unless canBeConstant is used
1986 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1988 if (canBeConstant) {
1989 Constant c = expr as Constant;
1991 return Create (c, original_expr);
1994 ExpressionStatement s = expr as ExpressionStatement;
1996 return Create (s, original_expr);
1998 if (expr.eclass == ExprClass.Unresolved)
1999 throw new ArgumentException ("Unresolved expression");
2001 return new ReducedExpression (expr, original_expr);
2004 public override Expression CreateExpressionTree (ResolveContext ec)
2006 return orig_expr.CreateExpressionTree (ec);
2009 protected override Expression DoResolve (ResolveContext ec)
2014 public override void Emit (EmitContext ec)
2019 public override Expression EmitToField (EmitContext ec)
2021 return expr.EmitToField(ec);
2024 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2026 expr.EmitBranchable (ec, target, on_true);
2029 public override SLE.Expression MakeExpression (BuilderContext ctx)
2031 return orig_expr.MakeExpression (ctx);
2036 // Standard composite pattern
2038 public abstract class CompositeExpression : Expression
2040 protected Expression expr;
2042 protected CompositeExpression (Expression expr)
2045 this.loc = expr.Location;
2048 public override bool ContainsEmitWithAwait ()
2050 return expr.ContainsEmitWithAwait ();
2053 public override Expression CreateExpressionTree (ResolveContext rc)
2055 return expr.CreateExpressionTree (rc);
2058 public Expression Child {
2059 get { return expr; }
2062 protected override Expression DoResolve (ResolveContext rc)
2064 expr = expr.Resolve (rc);
2067 eclass = expr.eclass;
2073 public override void Emit (EmitContext ec)
2078 public override bool IsNull {
2079 get { return expr.IsNull; }
2084 // Base of expressions used only to narrow resolve flow
2086 public abstract class ShimExpression : Expression
2088 protected Expression expr;
2090 protected ShimExpression (Expression expr)
2095 public Expression Expr {
2101 protected override void CloneTo (CloneContext clonectx, Expression t)
2106 ShimExpression target = (ShimExpression) t;
2107 target.expr = expr.Clone (clonectx);
2110 public override bool ContainsEmitWithAwait ()
2112 return expr.ContainsEmitWithAwait ();
2115 public override Expression CreateExpressionTree (ResolveContext ec)
2117 throw new NotSupportedException ("ET");
2120 public override void Emit (EmitContext ec)
2122 throw new InternalErrorException ("Missing Resolve call");
2128 // Unresolved type name expressions
2130 public abstract class ATypeNameExpression : FullNamedExpression
2133 protected TypeArguments targs;
2135 protected ATypeNameExpression (string name, Location l)
2141 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2148 protected ATypeNameExpression (string name, int arity, Location l)
2149 : this (name, new UnboundTypeArguments (arity), l)
2155 protected int Arity {
2157 return targs == null ? 0 : targs.Count;
2161 public bool HasTypeArguments {
2163 return targs != null && !targs.IsEmpty;
2167 public string Name {
2176 public TypeArguments TypeArguments {
2184 public override bool Equals (object obj)
2186 ATypeNameExpression atne = obj as ATypeNameExpression;
2187 return atne != null && atne.Name == Name &&
2188 (targs == null || targs.Equals (atne.targs));
2191 public override int GetHashCode ()
2193 return Name.GetHashCode ();
2196 // TODO: Move it to MemberCore
2197 public static string GetMemberType (MemberCore mc)
2203 if (mc is FieldBase)
2205 if (mc is MethodCore)
2207 if (mc is EnumMember)
2215 public override string GetSignatureForError ()
2217 if (targs != null) {
2218 return Name + "<" + targs.GetSignatureForError () + ">";
2224 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2228 /// SimpleName expressions are formed of a single word and only happen at the beginning
2229 /// of a dotted-name.
2231 public class SimpleName : ATypeNameExpression
2233 public SimpleName (string name, Location l)
2238 public SimpleName (string name, TypeArguments args, Location l)
2239 : base (name, args, l)
2243 public SimpleName (string name, int arity, Location l)
2244 : base (name, arity, l)
2248 public SimpleName GetMethodGroup ()
2250 return new SimpleName (Name, targs, loc);
2253 protected override Expression DoResolve (ResolveContext rc)
2255 var e = SimpleNameResolve (rc, null, false);
2257 var fe = e as FieldExpr;
2259 fe.VerifyAssignedStructField (rc, null);
2265 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2267 return SimpleNameResolve (ec, right_side, false);
2270 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2272 if (ctx.CurrentType != null) {
2273 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2274 if (member != null) {
2275 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2280 var 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 || me is PropertyExpr || me is IndexerExpr) {
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);
2500 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2502 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2503 return ErrorExpression.Instance;
2507 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2509 if (e.Type.Arity != Arity) {
2510 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2514 if (e is TypeExpr) {
2515 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2520 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2523 return ErrorExpression.Instance;
2526 if (rc.Module.Evaluator != null) {
2527 var fi = rc.Module.Evaluator.LookupField (Name);
2529 return new FieldExpr (fi.Item1, loc);
2537 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2539 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2544 if (right_side != null) {
2545 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2546 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2550 e = e.ResolveLValue (ec, right_side);
2558 public override object Accept (StructuralVisitor visitor)
2560 return visitor.Visit (this);
2565 /// Represents a namespace or a type. The name of the class was inspired by
2566 /// section 10.8.1 (Fully Qualified Names).
2568 public abstract class FullNamedExpression : Expression
2570 protected override void CloneTo (CloneContext clonectx, Expression target)
2572 // Do nothing, most unresolved type expressions cannot be
2573 // resolved to different type
2576 public override bool ContainsEmitWithAwait ()
2581 public override Expression CreateExpressionTree (ResolveContext ec)
2583 throw new NotSupportedException ("ET");
2586 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2589 // This is used to resolve the expression as a type, a null
2590 // value will be returned if the expression is not a type
2593 public override TypeSpec ResolveAsType (IMemberContext mc)
2595 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2600 TypeExpr te = fne as TypeExpr;
2602 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2610 var dep = type.GetMissingDependencies ();
2612 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2615 if (type.Kind == MemberKind.Void) {
2616 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2620 // Obsolete checks cannot be done when resolving base context as they
2621 // require type dependencies to be set but we are in process of resolving them
2623 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2624 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2625 if (obsolete_attr != null && !mc.IsObsolete) {
2626 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2634 public override void Emit (EmitContext ec)
2636 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2637 GetSignatureForError ());
2642 /// Expression that evaluates to a type
2644 public abstract class TypeExpr : FullNamedExpression
2646 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2652 protected sealed override Expression DoResolve (ResolveContext ec)
2658 public override bool Equals (object obj)
2660 TypeExpr tobj = obj as TypeExpr;
2664 return Type == tobj.Type;
2667 public override int GetHashCode ()
2669 return Type.GetHashCode ();
2674 /// Fully resolved Expression that already evaluated to a type
2676 public class TypeExpression : TypeExpr
2678 public TypeExpression (TypeSpec t, Location l)
2681 eclass = ExprClass.Type;
2685 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2692 /// This class denotes an expression which evaluates to a member
2693 /// of a struct or a class.
2695 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2698 // An instance expression associated with this member, if it's a
2699 // non-static member
2701 public Expression InstanceExpression;
2704 /// The name of this member.
2706 public abstract string Name {
2711 // When base.member is used
2713 public bool IsBase {
2714 get { return InstanceExpression is BaseThis; }
2718 /// Whether this is an instance member.
2720 public abstract bool IsInstance {
2725 /// Whether this is a static member.
2727 public abstract bool IsStatic {
2731 public abstract string KindName {
2735 protected abstract TypeSpec DeclaringType {
2739 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2741 return InstanceExpression.Type;
2746 // Converts best base candidate for virtual method starting from QueriedBaseType
2748 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2751 // Only when base.member is used and method is virtual
2757 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2758 // means for base.member access we have to find the closest match after we found best candidate
2760 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2762 // The method could already be what we are looking for
2764 TypeSpec[] targs = null;
2765 if (method.DeclaringType != InstanceExpression.Type) {
2766 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2767 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2768 if (base_override.IsGeneric)
2769 targs = method.TypeArguments;
2771 method = base_override;
2776 // When base access is used inside anonymous method/iterator/etc we need to
2777 // get back to the context of original type. We do it by emiting proxy
2778 // method in original class and rewriting base call to this compiler
2779 // generated method call which does the actual base invocation. This may
2780 // introduce redundant storey but with `this' only but it's tricky to avoid
2781 // at this stage as we don't know what expressions follow base
2783 if (rc.CurrentAnonymousMethod != null) {
2784 if (targs == null && method.IsGeneric) {
2785 targs = method.TypeArguments;
2786 method = method.GetGenericMethodDefinition ();
2789 if (method.Parameters.HasArglist)
2790 throw new NotImplementedException ("__arglist base call proxy");
2792 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2794 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2795 // get/set member expressions second call would fail to proxy because left expression
2796 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2797 // FIXME: The async check is another hack but will probably fail with mutators
2798 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2799 InstanceExpression = new This (loc).Resolve (rc);
2803 method = method.MakeGenericMethod (rc, targs);
2807 // Only base will allow this invocation to happen.
2809 if (method.IsAbstract) {
2810 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2816 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2818 if (InstanceExpression == null)
2821 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2822 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2823 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2828 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2830 if (InstanceExpression == null)
2833 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2836 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2838 var ct = rc.CurrentType;
2839 if (ct == qualifier)
2842 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2845 qualifier = qualifier.GetDefinition ();
2846 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2853 public override bool ContainsEmitWithAwait ()
2855 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2858 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2861 type = type.GetDefinition ();
2863 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2866 type = type.DeclaringType;
2867 } while (type != null);
2872 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2874 if (InstanceExpression != null) {
2875 InstanceExpression = InstanceExpression.Resolve (rc);
2876 CheckProtectedMemberAccess (rc, member);
2879 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2880 UnsafeError (rc, loc);
2883 var dep = member.GetMissingDependencies ();
2885 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2888 if (!rc.IsObsolete) {
2889 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2891 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2894 if (!(member is FieldSpec))
2895 member.MemberDefinition.SetIsUsed ();
2898 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2900 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2903 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2905 rc.Report.SymbolRelatedToPreviousError (member);
2906 rc.Report.Error (1540, loc,
2907 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2908 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2912 // Implements identicial simple name and type-name
2914 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2917 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2920 // 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
2921 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2923 if (left is MemberExpr || left is VariableReference) {
2924 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2925 if (identical_type != null && identical_type.Type == left.Type)
2926 return identical_type;
2932 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2935 if (InstanceExpression != null) {
2936 if (InstanceExpression is TypeExpr) {
2937 var t = InstanceExpression.Type;
2939 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2940 if (oa != null && !rc.IsObsolete) {
2941 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2944 t = t.DeclaringType;
2945 } while (t != null);
2947 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2948 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2949 rc.Report.Error (176, loc,
2950 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2951 GetSignatureForError ());
2955 InstanceExpression = null;
2961 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2962 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2963 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2964 rc.Report.Error (236, loc,
2965 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2966 GetSignatureForError ());
2968 rc.Report.Error (120, loc,
2969 "An object reference is required to access non-static member `{0}'",
2970 GetSignatureForError ());
2972 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
2976 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2977 rc.Report.Error (38, loc,
2978 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2979 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2982 InstanceExpression = new This (loc);
2983 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2984 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2985 InstanceExpression = InstanceExpression.Resolve (rc);
2988 InstanceExpression = InstanceExpression.Resolve (rc);
2994 var me = InstanceExpression as MemberExpr;
2996 me.ResolveInstanceExpression (rc, rhs);
2998 // Using this check to detect probing instance expression resolve
2999 if (!rc.OmitStructFlowAnalysis) {
3000 var fe = me as FieldExpr;
3001 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3002 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3003 rc.Report.Warning (1690, 1, loc,
3004 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3005 me.GetSignatureForError ());
3013 // Run member-access postponed check once we know that
3014 // the expression is not field expression which is the only
3015 // expression which can use uninitialized this
3017 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3018 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3022 // Additional checks for l-value member access
3025 if (InstanceExpression is UnboxCast) {
3026 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3033 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3035 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3036 ec.Report.Warning (1720, 1, left.Location,
3037 "Expression will always cause a `{0}'", "System.NullReferenceException");
3040 InstanceExpression = left;
3044 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3046 TypeSpec instance_type = InstanceExpression.Type;
3047 if (TypeSpec.IsValueType (instance_type)) {
3048 if (InstanceExpression is IMemoryLocation) {
3049 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3051 // Cannot release the temporary variable when its address
3052 // is required to be on stack for any parent
3053 LocalTemporary t = new LocalTemporary (instance_type);
3054 InstanceExpression.Emit (ec);
3056 t.AddressOf (ec, AddressOp.Store);
3059 InstanceExpression.Emit (ec);
3061 // Only to make verifier happy
3062 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3063 ec.Emit (OpCodes.Box, instance_type);
3066 if (prepare_for_load)
3067 ec.Emit (OpCodes.Dup);
3070 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3073 public class ExtensionMethodCandidates
3075 readonly NamespaceContainer container;
3076 readonly IList<MethodSpec> methods;
3078 readonly IMemberContext context;
3080 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3082 this.context = context;
3083 this.methods = methods;
3084 this.container = nsContainer;
3085 this.index = lookupIndex;
3088 public NamespaceContainer Container {
3094 public IMemberContext Context {
3100 public int LookupIndex {
3106 public IList<MethodSpec> Methods {
3114 // Represents a group of extension method candidates for whole namespace
3116 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3118 ExtensionMethodCandidates candidates;
3119 public readonly Expression ExtensionExpression;
3121 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3122 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3124 this.candidates = candidates;
3125 this.ExtensionExpression = extensionExpr;
3128 public override bool IsStatic {
3129 get { return true; }
3133 // For extension methodgroup we are not looking for base members but parent
3134 // namespace extension methods
3136 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3138 // TODO: candidates are null only when doing error reporting, that's
3139 // incorrect. We have to discover same extension methods in error mode
3140 if (candidates == null)
3143 int arity = type_arguments == null ? 0 : type_arguments.Count;
3145 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3146 if (candidates == null)
3149 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3152 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3154 // We are already here
3158 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3160 if (arguments == null)
3161 arguments = new Arguments (1);
3163 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3164 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3166 // Store resolved argument and restore original arguments
3168 // Clean-up modified arguments for error reporting
3169 arguments.RemoveAt (0);
3173 var me = ExtensionExpression as MemberExpr;
3175 me.ResolveInstanceExpression (ec, null);
3177 InstanceExpression = null;
3181 #region IErrorHandler Members
3183 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3188 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3190 rc.Report.SymbolRelatedToPreviousError (best);
3191 rc.Report.Error (1928, loc,
3192 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3193 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3196 rc.Report.Error (1929, loc,
3197 "Extension method instance type `{0}' cannot be converted to `{1}'",
3198 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3204 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3209 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3218 /// MethodGroupExpr represents a group of method candidates which
3219 /// can be resolved to the best method overload
3221 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3223 protected IList<MemberSpec> Methods;
3224 MethodSpec best_candidate;
3225 TypeSpec best_candidate_return;
3226 protected TypeArguments type_arguments;
3228 SimpleName simple_name;
3229 protected TypeSpec queried_type;
3231 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3235 this.type = InternalType.MethodGroup;
3237 eclass = ExprClass.MethodGroup;
3238 queried_type = type;
3241 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3242 : this (new MemberSpec[] { m }, type, loc)
3248 public MethodSpec BestCandidate {
3250 return best_candidate;
3254 public TypeSpec BestCandidateReturnType {
3256 return best_candidate_return;
3260 public IList<MemberSpec> Candidates {
3266 protected override TypeSpec DeclaringType {
3268 return queried_type;
3272 public override bool IsInstance {
3274 if (best_candidate != null)
3275 return !best_candidate.IsStatic;
3281 public override bool IsStatic {
3283 if (best_candidate != null)
3284 return best_candidate.IsStatic;
3290 public override string KindName {
3291 get { return "method"; }
3294 public override string Name {
3296 if (best_candidate != null)
3297 return best_candidate.Name;
3300 return Methods.First ().Name;
3307 // When best candidate is already know this factory can be used
3308 // to avoid expensive overload resolution to be called
3310 // NOTE: InstanceExpression has to be set manually
3312 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3314 return new MethodGroupExpr (best, queriedType, loc) {
3315 best_candidate = best,
3316 best_candidate_return = best.ReturnType
3320 public override string GetSignatureForError ()
3322 if (best_candidate != null)
3323 return best_candidate.GetSignatureForError ();
3325 return Methods.First ().GetSignatureForError ();
3328 public override Expression CreateExpressionTree (ResolveContext ec)
3330 if (best_candidate == null) {
3331 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3335 if (best_candidate.IsConditionallyExcluded (ec, loc))
3336 ec.Report.Error (765, loc,
3337 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3339 return new TypeOfMethod (best_candidate, loc);
3342 protected override Expression DoResolve (ResolveContext ec)
3344 this.eclass = ExprClass.MethodGroup;
3346 if (InstanceExpression != null) {
3347 InstanceExpression = InstanceExpression.Resolve (ec);
3348 if (InstanceExpression == null)
3355 public override void Emit (EmitContext ec)
3357 throw new NotSupportedException ();
3360 public void EmitCall (EmitContext ec, Arguments arguments)
3362 var call = new CallEmitter ();
3363 call.InstanceExpression = InstanceExpression;
3364 call.Emit (ec, best_candidate, arguments, loc);
3367 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3369 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3370 Name, TypeManager.CSharpName (target));
3373 public static bool IsExtensionMethodArgument (Expression expr)
3376 // LAMESPEC: No details about which expressions are not allowed
3378 return !(expr is TypeExpr) && !(expr is BaseThis);
3382 /// Find the Applicable Function Members (7.4.2.1)
3384 /// me: Method Group expression with the members to select.
3385 /// it might contain constructors or methods (or anything
3386 /// that maps to a method).
3388 /// Arguments: ArrayList containing resolved Argument objects.
3390 /// loc: The location if we want an error to be reported, or a Null
3391 /// location for "probing" purposes.
3393 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3394 /// that is the best match of me on Arguments.
3397 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3399 // TODO: causes issues with probing mode, remove explicit Kind check
3400 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3403 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3404 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3405 r.BaseMembersProvider = this;
3406 r.InstanceQualifier = this;
3409 if (cerrors != null)
3410 r.CustomErrors = cerrors;
3412 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3413 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3414 if (best_candidate == null)
3415 return r.BestCandidateIsDynamic ? this : null;
3417 // Overload resolver had to create a new method group, all checks bellow have already been executed
3418 if (r.BestCandidateNewMethodGroup != null)
3419 return r.BestCandidateNewMethodGroup;
3421 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3422 if (InstanceExpression != null) {
3423 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3424 InstanceExpression = null;
3426 if (best_candidate.IsStatic && simple_name != null) {
3427 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3430 InstanceExpression.Resolve (ec);
3434 ResolveInstanceExpression (ec, null);
3437 var base_override = CandidateToBaseOverride (ec, best_candidate);
3438 if (base_override == best_candidate) {
3439 best_candidate_return = r.BestCandidateReturnType;
3441 best_candidate = base_override;
3442 best_candidate_return = best_candidate.ReturnType;
3446 // Additional check for possible imported base override method which
3447 // could not be done during IsOverrideMethodBaseTypeAccessible
3449 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3450 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3451 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3452 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3458 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3460 var fe = left as FieldExpr;
3463 // Using method-group on struct fields makes the struct assigned. I am not sure
3464 // why but that's what .net does
3466 fe.Spec.MemberDefinition.SetIsAssigned ();
3469 simple_name = original;
3470 return base.ResolveMemberAccess (ec, left, original);
3473 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3475 type_arguments = ta;
3478 #region IBaseMembersProvider Members
3480 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3482 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3485 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3487 if (queried_type == member.DeclaringType)
3490 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3491 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3495 // Extension methods lookup after ordinary methods candidates failed to apply
3497 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3499 if (InstanceExpression == null)
3502 InstanceExpression = InstanceExpression.Resolve (rc);
3503 if (!IsExtensionMethodArgument (InstanceExpression))
3506 int arity = type_arguments == null ? 0 : type_arguments.Count;
3507 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3508 if (methods == null)
3511 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3512 emg.SetTypeArguments (rc, type_arguments);
3519 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3521 public ConstructorInstanceQualifier (TypeSpec type)
3524 InstanceType = type;
3527 public TypeSpec InstanceType { get; private set; }
3529 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3531 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3535 public struct OverloadResolver
3538 public enum Restrictions
3542 ProbingOnly = 1 << 1,
3543 CovariantDelegate = 1 << 2,
3544 NoBaseMembers = 1 << 3,
3545 BaseMembersIncluded = 1 << 4
3548 public interface IBaseMembersProvider
3550 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3551 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3552 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3555 public interface IErrorHandler
3557 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3558 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3559 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3560 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3563 public interface IInstanceQualifier
3565 TypeSpec InstanceType { get; }
3566 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3569 sealed class NoBaseMembers : IBaseMembersProvider
3571 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3573 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3578 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3583 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3589 struct AmbiguousCandidate
3591 public readonly MemberSpec Member;
3592 public readonly bool Expanded;
3593 public readonly AParametersCollection Parameters;
3595 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3598 Parameters = parameters;
3599 Expanded = expanded;
3604 IList<MemberSpec> members;
3605 TypeArguments type_arguments;
3606 IBaseMembersProvider base_provider;
3607 IErrorHandler custom_errors;
3608 IInstanceQualifier instance_qualifier;
3609 Restrictions restrictions;
3610 MethodGroupExpr best_candidate_extension_group;
3611 TypeSpec best_candidate_return_type;
3613 SessionReportPrinter lambda_conv_msgs;
3615 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3616 : this (members, null, restrictions, loc)
3620 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3623 if (members == null || members.Count == 0)
3624 throw new ArgumentException ("empty members set");
3626 this.members = members;
3628 type_arguments = targs;
3629 this.restrictions = restrictions;
3630 if (IsDelegateInvoke)
3631 this.restrictions |= Restrictions.NoBaseMembers;
3633 base_provider = NoBaseMembers.Instance;
3638 public IBaseMembersProvider BaseMembersProvider {
3640 return base_provider;
3643 base_provider = value;
3647 public bool BestCandidateIsDynamic { get; set; }
3650 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3652 public MethodGroupExpr BestCandidateNewMethodGroup {
3654 return best_candidate_extension_group;
3659 // Return type can be different between best candidate and closest override
3661 public TypeSpec BestCandidateReturnType {
3663 return best_candidate_return_type;
3667 public IErrorHandler CustomErrors {
3669 return custom_errors;
3672 custom_errors = value;
3676 TypeSpec DelegateType {
3678 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3679 throw new InternalErrorException ("Not running in delegate mode", loc);
3681 return members [0].DeclaringType;
3685 public IInstanceQualifier InstanceQualifier {
3687 return instance_qualifier;
3690 instance_qualifier = value;
3694 bool IsProbingOnly {
3696 return (restrictions & Restrictions.ProbingOnly) != 0;
3700 bool IsDelegateInvoke {
3702 return (restrictions & Restrictions.DelegateInvoke) != 0;
3709 // 7.4.3.3 Better conversion from expression
3710 // Returns : 1 if a->p is better,
3711 // 2 if a->q is better,
3712 // 0 if neither is better
3714 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3716 TypeSpec argument_type = a.Type;
3719 // If argument is an anonymous function
3721 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3723 // p and q are delegate types or expression tree types
3725 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3726 if (q.MemberDefinition != p.MemberDefinition) {
3731 // Uwrap delegate from Expression<T>
3733 q = TypeManager.GetTypeArguments (q)[0];
3734 p = TypeManager.GetTypeArguments (p)[0];
3737 var p_m = Delegate.GetInvokeMethod (p);
3738 var q_m = Delegate.GetInvokeMethod (q);
3741 // With identical parameter lists
3743 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3750 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3752 if (p.Kind == MemberKind.Void) {
3753 return q.Kind != MemberKind.Void ? 2 : 0;
3757 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3759 if (q.Kind == MemberKind.Void) {
3760 return p.Kind != MemberKind.Void ? 1: 0;
3764 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3765 // better conversion is performed between underlying types Y1 and Y2
3767 if (p.IsGenericTask || q.IsGenericTask) {
3768 var async_am = a.Expr as AnonymousMethodExpression;
3769 if (async_am != null && async_am.Block.IsAsync) {
3771 if (p.IsGenericTask != q.IsGenericTask) {
3775 q = q.TypeArguments[0];
3776 p = p.TypeArguments[0];
3781 // The parameters are identicial and return type is not void, use better type conversion
3782 // on return type to determine better one
3785 if (argument_type == p)
3788 if (argument_type == q)
3792 return BetterTypeConversion (ec, p, q);
3796 // 7.4.3.4 Better conversion from type
3798 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3800 if (p == null || q == null)
3801 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3803 switch (p.BuiltinType) {
3804 case BuiltinTypeSpec.Type.Int:
3805 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3808 case BuiltinTypeSpec.Type.Long:
3809 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3812 case BuiltinTypeSpec.Type.SByte:
3813 switch (q.BuiltinType) {
3814 case BuiltinTypeSpec.Type.Byte:
3815 case BuiltinTypeSpec.Type.UShort:
3816 case BuiltinTypeSpec.Type.UInt:
3817 case BuiltinTypeSpec.Type.ULong:
3821 case BuiltinTypeSpec.Type.Short:
3822 switch (q.BuiltinType) {
3823 case BuiltinTypeSpec.Type.UShort:
3824 case BuiltinTypeSpec.Type.UInt:
3825 case BuiltinTypeSpec.Type.ULong:
3829 case BuiltinTypeSpec.Type.Dynamic:
3830 // Dynamic is never better
3834 switch (q.BuiltinType) {
3835 case BuiltinTypeSpec.Type.Int:
3836 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3839 case BuiltinTypeSpec.Type.Long:
3840 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3843 case BuiltinTypeSpec.Type.SByte:
3844 switch (p.BuiltinType) {
3845 case BuiltinTypeSpec.Type.Byte:
3846 case BuiltinTypeSpec.Type.UShort:
3847 case BuiltinTypeSpec.Type.UInt:
3848 case BuiltinTypeSpec.Type.ULong:
3852 case BuiltinTypeSpec.Type.Short:
3853 switch (p.BuiltinType) {
3854 case BuiltinTypeSpec.Type.UShort:
3855 case BuiltinTypeSpec.Type.UInt:
3856 case BuiltinTypeSpec.Type.ULong:
3860 case BuiltinTypeSpec.Type.Dynamic:
3861 // Dynamic is never better
3865 // FIXME: handle lifted operators
3867 // TODO: this is expensive
3868 Expression p_tmp = new EmptyExpression (p);
3869 Expression q_tmp = new EmptyExpression (q);
3871 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3872 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3874 if (p_to_q && !q_to_p)
3877 if (q_to_p && !p_to_q)
3884 /// Determines "Better function" between candidate
3885 /// and the current best match
3888 /// Returns a boolean indicating :
3889 /// false if candidate ain't better
3890 /// true if candidate is better than the current best match
3892 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3893 MemberSpec best, AParametersCollection bparam, bool best_params)
3895 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3896 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3898 bool better_at_least_one = false;
3900 int args_count = args == null ? 0 : args.Count;
3904 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3907 // Default arguments are ignored for better decision
3908 if (a.IsDefaultArgument)
3912 // When comparing named argument the parameter type index has to be looked up
3913 // in original parameter set (override version for virtual members)
3915 NamedArgument na = a as NamedArgument;
3917 int idx = cparam.GetParameterIndexByName (na.Name);
3918 ct = candidate_pd.Types[idx];
3919 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3920 ct = TypeManager.GetElementType (ct);
3922 idx = bparam.GetParameterIndexByName (na.Name);
3923 bt = best_pd.Types[idx];
3924 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3925 bt = TypeManager.GetElementType (bt);
3927 ct = candidate_pd.Types[c_idx];
3928 bt = best_pd.Types[b_idx];
3930 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3931 ct = TypeManager.GetElementType (ct);
3935 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3936 bt = TypeManager.GetElementType (bt);
3941 if (TypeSpecComparer.IsEqual (ct, bt))
3945 int result = BetterExpressionConversion (ec, a, ct, bt);
3947 // for each argument, the conversion to 'ct' should be no worse than
3948 // the conversion to 'bt'.
3952 // for at least one argument, the conversion to 'ct' should be better than
3953 // the conversion to 'bt'.
3955 better_at_least_one = true;
3958 if (better_at_least_one)
3962 // This handles the case
3964 // Add (float f1, float f2, float f3);
3965 // Add (params decimal [] foo);
3967 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3968 // first candidate would've chosen as better.
3970 if (!same && !a.IsDefaultArgument)
3974 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3978 // This handles the following cases:
3980 // Foo (int i) is better than Foo (int i, long l = 0)
3981 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3983 // Prefer non-optional version
3985 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3987 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3988 if (candidate_pd.Count >= best_pd.Count)
3991 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3998 // One is a non-generic method and second is a generic method, then non-generic is better
4000 if (best.IsGeneric != candidate.IsGeneric)
4001 return best.IsGeneric;
4004 // This handles the following cases:
4006 // Trim () is better than Trim (params char[] chars)
4007 // Concat (string s1, string s2, string s3) is better than
4008 // Concat (string s1, params string [] srest)
4009 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4011 // Prefer non-expanded version
4013 if (candidate_params != best_params)
4016 int candidate_param_count = candidate_pd.Count;
4017 int best_param_count = best_pd.Count;
4019 if (candidate_param_count != best_param_count)
4020 // can only happen if (candidate_params && best_params)
4021 return candidate_param_count > best_param_count && best_pd.HasParams;
4024 // Both methods have the same number of parameters, and the parameters have equal types
4025 // Pick the "more specific" signature using rules over original (non-inflated) types
4027 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4028 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4030 bool specific_at_least_once = false;
4031 for (j = 0; j < args_count; ++j) {
4032 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4034 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4035 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4037 ct = candidate_def_pd.Types[j];
4038 bt = best_def_pd.Types[j];
4043 TypeSpec specific = MoreSpecific (ct, bt);
4047 specific_at_least_once = true;
4050 if (specific_at_least_once)
4056 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4058 rc.Report.Error (1729, loc,
4059 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4060 type.GetSignatureForError (), argCount.ToString ());
4064 // Determines if the candidate method is applicable to the given set of arguments
4065 // There could be two different set of parameters for same candidate where one
4066 // is the closest override for default values and named arguments checks and second
4067 // one being the virtual base for the parameter types and modifiers.
4069 // A return value rates candidate method compatibility,
4070 // 0 = the best, int.MaxValue = the worst
4073 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)
4075 // Parameters of most-derived type used mainly for named and optional parameters
4076 var pd = pm.Parameters;
4078 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4079 // params modifier instead of most-derived type
4080 var cpd = ((IParametersMember) candidate).Parameters;
4081 int param_count = pd.Count;
4082 int optional_count = 0;
4084 Arguments orig_args = arguments;
4086 if (arg_count != param_count) {
4088 // No arguments expansion when doing exact match for delegates
4090 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4091 for (int i = 0; i < pd.Count; ++i) {
4092 if (pd.FixedParameters[i].HasDefaultValue) {
4093 optional_count = pd.Count - i;
4099 if (optional_count != 0) {
4100 // Readjust expected number when params used
4101 if (cpd.HasParams) {
4103 if (arg_count < param_count)
4105 } else if (arg_count > param_count) {
4106 int args_gap = System.Math.Abs (arg_count - param_count);
4107 return int.MaxValue - 10000 + args_gap;
4109 } else if (arg_count != param_count) {
4110 int args_gap = System.Math.Abs (arg_count - param_count);
4112 return int.MaxValue - 10000 + args_gap;
4113 if (arg_count < param_count - 1)
4114 return int.MaxValue - 10000 + args_gap;
4117 // Resize to fit optional arguments
4118 if (optional_count != 0) {
4119 if (arguments == null) {
4120 arguments = new Arguments (optional_count);
4122 // Have to create a new container, so the next run can do same
4123 var resized = new Arguments (param_count);
4124 resized.AddRange (arguments);
4125 arguments = resized;
4128 for (int i = arg_count; i < param_count; ++i)
4129 arguments.Add (null);
4133 if (arg_count > 0) {
4135 // Shuffle named arguments to the right positions if there are any
4137 if (arguments[arg_count - 1] is NamedArgument) {
4138 arg_count = arguments.Count;
4140 for (int i = 0; i < arg_count; ++i) {
4141 bool arg_moved = false;
4143 NamedArgument na = arguments[i] as NamedArgument;
4147 int index = pd.GetParameterIndexByName (na.Name);
4149 // Named parameter not found
4153 // already reordered
4158 if (index >= param_count) {
4159 // When using parameters which should not be available to the user
4160 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4163 arguments.Add (null);
4167 temp = arguments[index];
4169 // The slot has been taken by positional argument
4170 if (temp != null && !(temp is NamedArgument))
4175 arguments = arguments.MarkOrderedArgument (na);
4179 arguments[index] = arguments[i];
4180 arguments[i] = temp;
4187 arg_count = arguments.Count;
4189 } else if (arguments != null) {
4190 arg_count = arguments.Count;
4194 // Don't do any expensive checks when the candidate cannot succeed
4196 if (arg_count != param_count && !cpd.HasParams)
4197 return (param_count - arg_count) * 2 + 1;
4199 var dep = candidate.GetMissingDependencies ();
4201 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4206 // 1. Handle generic method using type arguments when specified or type inference
4209 var ms = candidate as MethodSpec;
4210 if (ms != null && ms.IsGeneric) {
4211 // Setup constraint checker for probing only
4212 ConstraintChecker cc = new ConstraintChecker (null);
4214 if (type_arguments != null) {
4215 var g_args_count = ms.Arity;
4216 if (g_args_count != type_arguments.Count)
4217 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4219 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4222 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4223 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4224 // candidate was found use the set to report more details about what was wrong with lambda body.
4225 // The general idea is to distinguish between code errors and errors caused by
4226 // trial-and-error type inference
4228 if (lambda_conv_msgs == null) {
4229 for (int i = 0; i < arg_count; i++) {
4230 Argument a = arguments[i];
4234 var am = a.Expr as AnonymousMethodExpression;
4236 if (lambda_conv_msgs == null)
4237 lambda_conv_msgs = new SessionReportPrinter ();
4239 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4244 var ti = new TypeInference (arguments);
4245 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4248 return ti.InferenceScore - 20000;
4251 // Clear any error messages when the result was success
4253 if (lambda_conv_msgs != null)
4254 lambda_conv_msgs.ClearSession ();
4256 if (i_args.Length != 0) {
4257 ms = ms.MakeGenericMethod (ec, i_args);
4260 cc.IgnoreInferredDynamic = true;
4264 // Type arguments constraints have to match for the method to be applicable
4266 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4268 return int.MaxValue - 25000;
4272 // We have a generic return type and at same time the method is override which
4273 // means we have to also inflate override return type in case the candidate is
4274 // best candidate and override return type is different to base return type.
4276 // virtual Foo<T, object> with override Foo<T, dynamic>
4278 if (candidate != pm) {
4279 MethodSpec override_ms = (MethodSpec) pm;
4280 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4281 returnType = inflator.Inflate (returnType);
4283 returnType = ms.ReturnType;
4287 ptypes = ms.Parameters.Types;
4289 if (type_arguments != null)
4290 return int.MaxValue - 15000;
4296 // 2. Each argument has to be implicitly convertible to method parameter
4298 Parameter.Modifier p_mod = 0;
4301 for (int i = 0; i < arg_count; i++) {
4302 Argument a = arguments[i];
4304 var fp = pd.FixedParameters[i];
4305 if (!fp.HasDefaultValue) {
4306 arguments = orig_args;
4307 return arg_count * 2 + 2;
4311 // Get the default value expression, we can use the same expression
4312 // if the type matches
4314 Expression e = fp.DefaultValue;
4315 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4317 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4319 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4320 e = new MemberAccess (new MemberAccess (new MemberAccess (
4321 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4323 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4329 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4331 // LAMESPEC: Attributes can be mixed together with build-in priority
4333 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4334 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4335 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4336 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4337 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4338 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4342 arguments[i] = new Argument (e, Argument.AType.Default);
4346 if (p_mod != Parameter.Modifier.PARAMS) {
4347 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4349 } else if (!params_expanded_form) {
4350 params_expanded_form = true;
4351 pt = ((ElementTypeSpec) pt).Element;
4357 if (!params_expanded_form) {
4358 if (a.ArgType == Argument.AType.ExtensionType) {
4360 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4362 // LAMESPEC: or implicit type parameter conversion
4365 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4366 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4367 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4372 score = IsArgumentCompatible (ec, a, p_mod, pt);
4375 dynamicArgument = true;
4380 // It can be applicable in expanded form (when not doing exact match like for delegates)
4382 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4383 if (!params_expanded_form)
4384 pt = ((ElementTypeSpec) pt).Element;
4387 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4390 params_expanded_form = true;
4391 } else if (score < 0) {
4392 params_expanded_form = true;
4393 dynamicArgument = true;
4398 if (params_expanded_form)
4400 return (arg_count - i) * 2 + score;
4405 // When params parameter has no argument it will be provided later if the method is the best candidate
4407 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4408 params_expanded_form = true;
4411 // Restore original arguments for dynamic binder to keep the intention of original source code
4413 if (dynamicArgument)
4414 arguments = orig_args;
4420 // Tests argument compatibility with the parameter
4421 // The possible return values are
4423 // 1 - modifier mismatch
4424 // 2 - type mismatch
4425 // -1 - dynamic binding required
4427 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4430 // Types have to be identical when ref or out modifer
4431 // is used and argument is not of dynamic type
4433 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4434 if (argument.Type != parameter) {
4436 // Do full equality check after quick path
4438 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4440 // Using dynamic for ref/out parameter can still succeed at runtime
4442 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4449 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4451 // Using dynamic for ref/out parameter can still succeed at runtime
4453 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4460 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4464 // Use implicit conversion in all modes to return same candidates when the expression
4465 // is used as argument or delegate conversion
4467 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4475 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4477 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4479 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4482 var ac_p = p as ArrayContainer;
4484 var ac_q = q as ArrayContainer;
4488 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4489 if (specific == ac_p.Element)
4491 if (specific == ac_q.Element)
4493 } else if (TypeManager.IsGenericType (p)) {
4494 var pargs = TypeManager.GetTypeArguments (p);
4495 var qargs = TypeManager.GetTypeArguments (q);
4497 bool p_specific_at_least_once = false;
4498 bool q_specific_at_least_once = false;
4500 for (int i = 0; i < pargs.Length; i++) {
4501 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4502 if (specific == pargs[i])
4503 p_specific_at_least_once = true;
4504 if (specific == qargs[i])
4505 q_specific_at_least_once = true;
4508 if (p_specific_at_least_once && !q_specific_at_least_once)
4510 if (!p_specific_at_least_once && q_specific_at_least_once)
4518 // Find the best method from candidate list
4520 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4522 List<AmbiguousCandidate> ambiguous_candidates = null;
4524 MemberSpec best_candidate;
4525 Arguments best_candidate_args = null;
4526 bool best_candidate_params = false;
4527 bool best_candidate_dynamic = false;
4528 int best_candidate_rate;
4529 IParametersMember best_parameter_member = null;
4531 int args_count = args != null ? args.Count : 0;
4533 Arguments candidate_args = args;
4534 bool error_mode = false;
4535 MemberSpec invocable_member = null;
4538 best_candidate = null;
4539 best_candidate_rate = int.MaxValue;
4541 var type_members = members;
4543 for (int i = 0; i < type_members.Count; ++i) {
4544 var member = type_members[i];
4547 // Methods in a base class are not candidates if any method in a derived
4548 // class is applicable
4550 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4554 if (!member.IsAccessible (rc))
4557 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4560 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4561 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4566 IParametersMember pm = member as IParametersMember;
4569 // Will use it later to report ambiguity between best method and invocable member
4571 if (Invocation.IsMemberInvocable (member))
4572 invocable_member = member;
4578 // Overload resolution is looking for base member but using parameter names
4579 // and default values from the closest member. That means to do expensive lookup
4580 // for the closest override for virtual or abstract members
4582 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4583 var override_params = base_provider.GetOverrideMemberParameters (member);
4584 if (override_params != null)
4585 pm = override_params;
4589 // Check if the member candidate is applicable
4591 bool params_expanded_form = false;
4592 bool dynamic_argument = false;
4593 TypeSpec rt = pm.MemberType;
4594 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4596 if (lambda_conv_msgs != null)
4597 lambda_conv_msgs.EndSession ();
4600 // How does it score compare to others
4602 if (candidate_rate < best_candidate_rate) {
4604 // Fatal error (missing dependency), cannot continue
4605 if (candidate_rate < 0)
4608 best_candidate_rate = candidate_rate;
4609 best_candidate = member;
4610 best_candidate_args = candidate_args;
4611 best_candidate_params = params_expanded_form;
4612 best_candidate_dynamic = dynamic_argument;
4613 best_parameter_member = pm;
4614 best_candidate_return_type = rt;
4615 } else if (candidate_rate == 0) {
4617 // The member look is done per type for most operations but sometimes
4618 // it's not possible like for binary operators overload because they
4619 // are unioned between 2 sides
4621 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4622 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4627 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4629 // We pack all interface members into top level type which makes the overload resolution
4630 // more complicated for interfaces. We compensate it by removing methods with same
4631 // signature when building the cache hence this path should not really be hit often
4634 // interface IA { void Foo (int arg); }
4635 // interface IB : IA { void Foo (params int[] args); }
4637 // IB::Foo is the best overload when calling IB.Foo (1)
4640 if (ambiguous_candidates != null) {
4641 foreach (var amb_cand in ambiguous_candidates) {
4642 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4651 ambiguous_candidates = null;
4654 // Is the new candidate better
4655 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4659 best_candidate = member;
4660 best_candidate_args = candidate_args;
4661 best_candidate_params = params_expanded_form;
4662 best_candidate_dynamic = dynamic_argument;
4663 best_parameter_member = pm;
4664 best_candidate_return_type = rt;
4666 // It's not better but any other found later could be but we are not sure yet
4667 if (ambiguous_candidates == null)
4668 ambiguous_candidates = new List<AmbiguousCandidate> ();
4670 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4674 // Restore expanded arguments
4675 if (candidate_args != args)
4676 candidate_args = args;
4678 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4681 // We've found exact match
4683 if (best_candidate_rate == 0)
4687 // Try extension methods lookup when no ordinary method match was found and provider enables it
4690 var emg = base_provider.LookupExtensionMethod (rc);
4692 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4694 best_candidate_extension_group = emg;
4695 return (T) (MemberSpec) emg.BestCandidate;
4700 // Don't run expensive error reporting mode for probing
4707 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4710 lambda_conv_msgs = null;
4715 // No best member match found, report an error
4717 if (best_candidate_rate != 0 || error_mode) {
4718 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4722 if (best_candidate_dynamic) {
4723 if (args[0].ArgType == Argument.AType.ExtensionType) {
4724 rc.Report.Error (1973, loc,
4725 "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",
4726 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4729 BestCandidateIsDynamic = true;
4734 // These flags indicates we are running delegate probing conversion. No need to
4735 // do more expensive checks
4737 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4738 return (T) best_candidate;
4740 if (ambiguous_candidates != null) {
4742 // Now check that there are no ambiguities i.e the selected method
4743 // should be better than all the others
4745 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4746 var candidate = ambiguous_candidates [ix];
4748 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4749 var ambiguous = candidate.Member;
4750 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4751 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4752 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4753 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4754 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4757 return (T) best_candidate;
4762 if (invocable_member != null) {
4763 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4764 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4765 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4766 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4770 // And now check if the arguments are all
4771 // compatible, perform conversions if
4772 // necessary etc. and return if everything is
4775 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4778 if (best_candidate == null)
4782 // Check ObsoleteAttribute on the best method
4784 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4785 if (oa != null && !rc.IsObsolete)
4786 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4788 best_candidate.MemberDefinition.SetIsUsed ();
4790 args = best_candidate_args;
4791 return (T) best_candidate;
4794 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4796 return ResolveMember<MethodSpec> (rc, ref args);
4799 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4800 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4802 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4805 if (a.Type == InternalType.ErrorType)
4808 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4809 ec.Report.SymbolRelatedToPreviousError (method);
4810 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4811 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4812 TypeManager.CSharpSignature (method));
4815 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4816 TypeManager.CSharpSignature (method));
4817 } else if (IsDelegateInvoke) {
4818 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4819 DelegateType.GetSignatureForError ());
4821 ec.Report.SymbolRelatedToPreviousError (method);
4822 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4823 method.GetSignatureForError ());
4826 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4828 string index = (idx + 1).ToString ();
4829 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4830 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4831 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4832 index, Parameter.GetModifierSignature (a.Modifier));
4834 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4835 index, Parameter.GetModifierSignature (mod));
4837 string p1 = a.GetSignatureForError ();
4838 string p2 = TypeManager.CSharpName (paramType);
4841 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4842 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4845 ec.Report.Error (1503, loc,
4846 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4851 // We have failed to find exact match so we return error info about the closest match
4853 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4855 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4856 int arg_count = args == null ? 0 : args.Count;
4858 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4859 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4860 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4864 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
4869 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4870 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4871 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4875 // For candidates which match on parameters count report more details about incorrect arguments
4878 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4879 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4880 // Reject any inaccessible member
4881 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4882 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4883 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4887 var ms = best_candidate as MethodSpec;
4888 if (ms != null && ms.IsGeneric) {
4889 bool constr_ok = true;
4890 if (ms.TypeArguments != null)
4891 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4893 if (ta_count == 0) {
4894 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4898 rc.Report.Error (411, loc,
4899 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4900 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4907 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4913 // We failed to find any method with correct argument count, report best candidate
4915 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4918 if (best_candidate.Kind == MemberKind.Constructor) {
4919 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4920 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4921 } else if (IsDelegateInvoke) {
4922 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4923 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4924 DelegateType.GetSignatureForError (), arg_count.ToString ());
4926 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4927 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4928 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4929 name, arg_count.ToString ());
4933 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4935 var pd = pm.Parameters;
4936 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4938 Parameter.Modifier p_mod = 0;
4940 int a_idx = 0, a_pos = 0;
4942 ArrayInitializer params_initializers = null;
4943 bool has_unsafe_arg = pm.MemberType.IsPointer;
4944 int arg_count = args == null ? 0 : args.Count;
4946 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4948 if (p_mod != Parameter.Modifier.PARAMS) {
4949 p_mod = pd.FixedParameters[a_idx].ModFlags;
4951 has_unsafe_arg |= pt.IsPointer;
4953 if (p_mod == Parameter.Modifier.PARAMS) {
4954 if (chose_params_expanded) {
4955 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4956 pt = TypeManager.GetElementType (pt);
4962 // Types have to be identical when ref or out modifer is used
4964 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
4965 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
4968 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4974 NamedArgument na = a as NamedArgument;
4976 int name_index = pd.GetParameterIndexByName (na.Name);
4977 if (name_index < 0 || name_index >= pd.Count) {
4978 if (IsDelegateInvoke) {
4979 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4980 ec.Report.Error (1746, na.Location,
4981 "The delegate `{0}' does not contain a parameter named `{1}'",
4982 DelegateType.GetSignatureForError (), na.Name);
4984 ec.Report.SymbolRelatedToPreviousError (member);
4985 ec.Report.Error (1739, na.Location,
4986 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4987 TypeManager.CSharpSignature (member), na.Name);
4989 } else if (args[name_index] != a) {
4990 if (IsDelegateInvoke)
4991 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4993 ec.Report.SymbolRelatedToPreviousError (member);
4995 ec.Report.Error (1744, na.Location,
4996 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5001 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5004 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5005 custom_errors.NoArgumentMatch (ec, member);
5009 Expression conv = null;
5010 if (a.ArgType == Argument.AType.ExtensionType) {
5011 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5014 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5016 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5019 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5026 // Convert params arguments to an array initializer
5028 if (params_initializers != null) {
5029 // we choose to use 'a.Expr' rather than 'conv' so that
5030 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5031 params_initializers.Add (a.Expr);
5032 args.RemoveAt (a_idx--);
5037 // Update the argument with the implicit conversion
5041 if (a_idx != arg_count) {
5042 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5047 // Fill not provided arguments required by params modifier
5049 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5051 args = new Arguments (1);
5053 pt = ptypes[pd.Count - 1];
5054 pt = TypeManager.GetElementType (pt);
5055 has_unsafe_arg |= pt.IsPointer;
5056 params_initializers = new ArrayInitializer (0, loc);
5060 // Append an array argument with all params arguments
5062 if (params_initializers != null) {
5063 args.Add (new Argument (
5064 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5068 if (has_unsafe_arg && !ec.IsUnsafe) {
5069 Expression.UnsafeError (ec, loc);
5073 // We could infer inaccesible type arguments
5075 if (type_arguments == null && member.IsGeneric) {
5076 var ms = (MethodSpec) member;
5077 foreach (var ta in ms.TypeArguments) {
5078 if (!ta.IsAccessible (ec)) {
5079 ec.Report.SymbolRelatedToPreviousError (ta);
5080 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5090 public class ConstantExpr : MemberExpr
5092 readonly ConstSpec constant;
5094 public ConstantExpr (ConstSpec constant, Location loc)
5096 this.constant = constant;
5100 public override string Name {
5101 get { throw new NotImplementedException (); }
5104 public override string KindName {
5105 get { return "constant"; }
5108 public override bool IsInstance {
5109 get { return !IsStatic; }
5112 public override bool IsStatic {
5113 get { return true; }
5116 protected override TypeSpec DeclaringType {
5117 get { return constant.DeclaringType; }
5120 public override Expression CreateExpressionTree (ResolveContext ec)
5122 throw new NotSupportedException ("ET");
5125 protected override Expression DoResolve (ResolveContext rc)
5127 ResolveInstanceExpression (rc, null);
5128 DoBestMemberChecks (rc, constant);
5130 var c = constant.GetConstant (rc);
5132 // Creates reference expression to the constant value
5133 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5136 public override void Emit (EmitContext ec)
5138 throw new NotSupportedException ();
5141 public override string GetSignatureForError ()
5143 return constant.GetSignatureForError ();
5146 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5148 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5153 // Fully resolved expression that references a Field
5155 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5157 protected FieldSpec spec;
5158 VariableInfo variable_info;
5160 LocalTemporary temp;
5163 protected FieldExpr (Location l)
5168 public FieldExpr (FieldSpec spec, Location loc)
5173 type = spec.MemberType;
5176 public FieldExpr (FieldBase fi, Location l)
5183 public override string Name {
5189 public bool IsHoisted {
5191 IVariableReference hv = InstanceExpression as IVariableReference;
5192 return hv != null && hv.IsHoisted;
5196 public override bool IsInstance {
5198 return !spec.IsStatic;
5202 public override bool IsStatic {
5204 return spec.IsStatic;
5208 public override string KindName {
5209 get { return "field"; }
5212 public FieldSpec Spec {
5218 protected override TypeSpec DeclaringType {
5220 return spec.DeclaringType;
5224 public VariableInfo VariableInfo {
5226 return variable_info;
5232 public override string GetSignatureForError ()
5234 return spec.GetSignatureForError ();
5237 public bool IsMarshalByRefAccess (ResolveContext rc)
5239 // Checks possible ldflda of field access expression
5240 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5241 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5242 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5245 public void SetHasAddressTaken ()
5247 IVariableReference vr = InstanceExpression as IVariableReference;
5249 vr.SetHasAddressTaken ();
5253 public override Expression CreateExpressionTree (ResolveContext ec)
5255 return CreateExpressionTree (ec, true);
5258 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5261 Expression instance;
5263 if (InstanceExpression == null) {
5264 instance = new NullLiteral (loc);
5265 } else if (convertInstance) {
5266 instance = InstanceExpression.CreateExpressionTree (ec);
5268 args = new Arguments (1);
5269 args.Add (new Argument (InstanceExpression));
5270 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5273 args = Arguments.CreateForExpressionTree (ec, null,
5275 CreateTypeOfExpression ());
5277 return CreateExpressionFactoryCall (ec, "Field", args);
5280 public Expression CreateTypeOfExpression ()
5282 return new TypeOfField (spec, loc);
5285 protected override Expression DoResolve (ResolveContext ec)
5287 return DoResolve (ec, null);
5290 Expression DoResolve (ResolveContext ec, Expression rhs)
5292 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5295 if (ResolveInstanceExpression (ec, rhs)) {
5296 // Resolve the field's instance expression while flow analysis is turned
5297 // off: when accessing a field "a.b", we must check whether the field
5298 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5300 if (lvalue_instance) {
5301 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5302 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5304 Expression right_side =
5305 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5307 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5310 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5311 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5315 if (InstanceExpression == null)
5319 DoBestMemberChecks (ec, spec);
5322 var fb = spec as FixedFieldSpec;
5323 IVariableReference var = InstanceExpression as IVariableReference;
5325 if (lvalue_instance && var != null && var.VariableInfo != null) {
5326 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5330 IFixedExpression fe = InstanceExpression as IFixedExpression;
5331 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5332 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5335 if (InstanceExpression.eclass != ExprClass.Variable) {
5336 ec.Report.SymbolRelatedToPreviousError (spec);
5337 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5338 TypeManager.GetFullNameSignature (spec));
5339 } else if (var != null && var.IsHoisted) {
5340 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5343 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5347 // Set flow-analysis variable info for struct member access. It will be check later
5348 // for precise error reporting
5350 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5351 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5352 if (rhs != null && variable_info != null)
5353 variable_info.SetStructFieldAssigned (ec, Name);
5356 eclass = ExprClass.Variable;
5360 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5365 var var = fe.InstanceExpression as IVariableReference;
5367 var vi = var.VariableInfo;
5369 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5371 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5373 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5380 fe = fe.InstanceExpression as FieldExpr;
5382 } while (fe != null);
5385 static readonly int [] codes = {
5386 191, // instance, write access
5387 192, // instance, out access
5388 198, // static, write access
5389 199, // static, out access
5390 1648, // member of value instance, write access
5391 1649, // member of value instance, out access
5392 1650, // member of value static, write access
5393 1651 // member of value static, out access
5396 static readonly string [] msgs = {
5397 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5398 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5399 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5400 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5401 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5402 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5403 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5404 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5407 // The return value is always null. Returning a value simplifies calling code.
5408 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5411 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5415 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5417 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5422 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5424 Expression e = DoResolve (ec, right_side);
5429 spec.MemberDefinition.SetIsAssigned ();
5431 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5432 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5433 ec.Report.Warning (420, 1, loc,
5434 "`{0}': A volatile field references will not be treated as volatile",
5435 spec.GetSignatureForError ());
5438 if (spec.IsReadOnly) {
5439 // InitOnly fields can only be assigned in constructors or initializers
5440 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5441 return Report_AssignToReadonly (ec, right_side);
5443 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5445 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5446 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5447 return Report_AssignToReadonly (ec, right_side);
5448 // static InitOnly fields cannot be assigned-to in an instance constructor
5449 if (IsStatic && !ec.IsStatic)
5450 return Report_AssignToReadonly (ec, right_side);
5451 // instance constructors can't modify InitOnly fields of other instances of the same type
5452 if (!IsStatic && !(InstanceExpression is This))
5453 return Report_AssignToReadonly (ec, right_side);
5457 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5458 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5459 ec.Report.Warning (197, 1, loc,
5460 "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",
5461 GetSignatureForError ());
5464 eclass = ExprClass.Variable;
5468 public override int GetHashCode ()
5470 return spec.GetHashCode ();
5473 public bool IsFixed {
5476 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5478 IVariableReference variable = InstanceExpression as IVariableReference;
5479 if (variable != null)
5480 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5482 IFixedExpression fe = InstanceExpression as IFixedExpression;
5483 return fe != null && fe.IsFixed;
5487 public override bool Equals (object obj)
5489 FieldExpr fe = obj as FieldExpr;
5493 if (spec != fe.spec)
5496 if (InstanceExpression == null || fe.InstanceExpression == null)
5499 return InstanceExpression.Equals (fe.InstanceExpression);
5502 public void Emit (EmitContext ec, bool leave_copy)
5504 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5506 spec.MemberDefinition.SetIsUsed ();
5510 ec.Emit (OpCodes.Volatile);
5512 ec.Emit (OpCodes.Ldsfld, spec);
5515 EmitInstance (ec, false);
5517 // Optimization for build-in types
5518 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5519 ec.EmitLoadFromPtr (type);
5521 var ff = spec as FixedFieldSpec;
5523 ec.Emit (OpCodes.Ldflda, spec);
5524 ec.Emit (OpCodes.Ldflda, ff.Element);
5527 ec.Emit (OpCodes.Volatile);
5529 ec.Emit (OpCodes.Ldfld, spec);
5535 ec.Emit (OpCodes.Dup);
5537 temp = new LocalTemporary (this.Type);
5543 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5545 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5546 if (isCompound && !(source is DynamicExpressionStatement)) {
5547 if (has_await_source) {
5549 InstanceExpression = InstanceExpression.EmitToField (ec);
5556 if (has_await_source)
5557 source = source.EmitToField (ec);
5559 EmitInstance (ec, prepared);
5565 ec.Emit (OpCodes.Dup);
5567 temp = new LocalTemporary (this.Type);
5572 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5573 ec.Emit (OpCodes.Volatile);
5575 spec.MemberDefinition.SetIsAssigned ();
5578 ec.Emit (OpCodes.Stsfld, spec);
5580 ec.Emit (OpCodes.Stfld, spec);
5590 // Emits store to field with prepared values on stack
5592 public void EmitAssignFromStack (EmitContext ec)
5595 ec.Emit (OpCodes.Stsfld, spec);
5597 ec.Emit (OpCodes.Stfld, spec);
5601 public override void Emit (EmitContext ec)
5606 public override void EmitSideEffect (EmitContext ec)
5608 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5610 if (is_volatile) // || is_marshal_by_ref ())
5611 base.EmitSideEffect (ec);
5614 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5616 if ((mode & AddressOp.Store) != 0)
5617 spec.MemberDefinition.SetIsAssigned ();
5618 if ((mode & AddressOp.Load) != 0)
5619 spec.MemberDefinition.SetIsUsed ();
5622 // Handle initonly fields specially: make a copy and then
5623 // get the address of the copy.
5626 if (spec.IsReadOnly){
5628 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5640 var temp = ec.GetTemporaryLocal (type);
5641 ec.Emit (OpCodes.Stloc, temp);
5642 ec.Emit (OpCodes.Ldloca, temp);
5643 ec.FreeTemporaryLocal (temp, type);
5649 ec.Emit (OpCodes.Ldsflda, spec);
5652 EmitInstance (ec, false);
5653 ec.Emit (OpCodes.Ldflda, spec);
5657 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5659 return MakeExpression (ctx);
5662 public override SLE.Expression MakeExpression (BuilderContext ctx)
5665 return base.MakeExpression (ctx);
5667 return SLE.Expression.Field (
5668 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5669 spec.GetMetaInfo ());
5673 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5675 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5681 // Expression that evaluates to a Property.
5683 // This is not an LValue because we need to re-write the expression. We
5684 // can not take data from the stack and store it.
5686 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5688 public PropertyExpr (PropertySpec spec, Location l)
5691 best_candidate = spec;
5692 type = spec.MemberType;
5697 protected override Arguments Arguments {
5705 protected override TypeSpec DeclaringType {
5707 return best_candidate.DeclaringType;
5711 public override string Name {
5713 return best_candidate.Name;
5717 public override bool IsInstance {
5723 public override bool IsStatic {
5725 return best_candidate.IsStatic;
5729 public override string KindName {
5730 get { return "property"; }
5733 public PropertySpec PropertyInfo {
5735 return best_candidate;
5741 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5743 return new PropertyExpr (spec, loc) {
5749 public override Expression CreateExpressionTree (ResolveContext ec)
5752 if (IsSingleDimensionalArrayLength ()) {
5753 args = new Arguments (1);
5754 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5755 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5758 args = new Arguments (2);
5759 if (InstanceExpression == null)
5760 args.Add (new Argument (new NullLiteral (loc)));
5762 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5763 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5764 return CreateExpressionFactoryCall (ec, "Property", args);
5767 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5769 DoResolveLValue (rc, null);
5770 return new TypeOfMethod (Setter, loc);
5773 public override string GetSignatureForError ()
5775 return best_candidate.GetSignatureForError ();
5778 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5781 return base.MakeExpression (ctx);
5783 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5787 public override SLE.Expression MakeExpression (BuilderContext ctx)
5790 return base.MakeExpression (ctx);
5792 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5796 void Error_PropertyNotValid (ResolveContext ec)
5798 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5799 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5800 GetSignatureForError ());
5803 bool IsSingleDimensionalArrayLength ()
5805 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5808 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5809 return ac != null && ac.Rank == 1;
5812 public override void Emit (EmitContext ec, bool leave_copy)
5815 // Special case: length of single dimension array property is turned into ldlen
5817 if (IsSingleDimensionalArrayLength ()) {
5818 EmitInstance (ec, false);
5819 ec.Emit (OpCodes.Ldlen);
5820 ec.Emit (OpCodes.Conv_I4);
5824 base.Emit (ec, leave_copy);
5827 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5830 LocalTemporary await_source_arg = null;
5832 if (isCompound && !(source is DynamicExpressionStatement)) {
5833 emitting_compound_assignment = true;
5836 if (has_await_arguments) {
5837 await_source_arg = new LocalTemporary (Type);
5838 await_source_arg.Store (ec);
5840 args = new Arguments (1);
5841 args.Add (new Argument (await_source_arg));
5844 temp = await_source_arg;
5847 has_await_arguments = false;
5852 ec.Emit (OpCodes.Dup);
5853 temp = new LocalTemporary (this.Type);
5858 args = new Arguments (1);
5862 temp = new LocalTemporary (this.Type);
5864 args.Add (new Argument (temp));
5866 args.Add (new Argument (source));
5870 emitting_compound_assignment = false;
5872 var call = new CallEmitter ();
5873 call.InstanceExpression = InstanceExpression;
5875 call.InstanceExpressionOnStack = true;
5877 call.Emit (ec, Setter, args, loc);
5884 if (await_source_arg != null) {
5885 await_source_arg.Release (ec);
5889 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5891 eclass = ExprClass.PropertyAccess;
5893 if (best_candidate.IsNotCSharpCompatible) {
5894 Error_PropertyNotValid (rc);
5897 ResolveInstanceExpression (rc, right_side);
5899 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5900 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5901 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5903 type = p.MemberType;
5907 DoBestMemberChecks (rc, best_candidate);
5911 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5913 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5917 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5919 // getter and setter can be different for base calls
5920 MethodSpec getter, setter;
5921 protected T best_candidate;
5923 protected LocalTemporary temp;
5924 protected bool emitting_compound_assignment;
5925 protected bool has_await_arguments;
5927 protected PropertyOrIndexerExpr (Location l)
5934 protected abstract Arguments Arguments { get; set; }
5936 public MethodSpec Getter {
5945 public MethodSpec Setter {
5956 protected override Expression DoResolve (ResolveContext ec)
5958 if (eclass == ExprClass.Unresolved) {
5959 var expr = OverloadResolve (ec, null);
5964 return expr.Resolve (ec);
5967 if (!ResolveGetter (ec))
5973 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5975 if (right_side == EmptyExpression.OutAccess) {
5976 // TODO: best_candidate can be null at this point
5977 INamedBlockVariable variable = null;
5978 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5979 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5980 best_candidate.Name);
5982 right_side.DoResolveLValue (ec, this);
5987 // if the property/indexer returns a value type, and we try to set a field in it
5988 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5989 Error_ValueAssignment (ec, right_side);
5992 if (eclass == ExprClass.Unresolved) {
5993 var expr = OverloadResolve (ec, right_side);
5998 return expr.ResolveLValue (ec, right_side);
6001 if (!ResolveSetter (ec))
6008 // Implements the IAssignMethod interface for assignments
6010 public virtual void Emit (EmitContext ec, bool leave_copy)
6012 var call = new CallEmitter ();
6013 call.InstanceExpression = InstanceExpression;
6014 if (has_await_arguments)
6015 call.HasAwaitArguments = true;
6017 call.DuplicateArguments = emitting_compound_assignment;
6019 call.Emit (ec, Getter, Arguments, loc);
6021 if (call.HasAwaitArguments) {
6022 InstanceExpression = call.InstanceExpression;
6023 Arguments = call.EmittedArguments;
6024 has_await_arguments = true;
6028 ec.Emit (OpCodes.Dup);
6029 temp = new LocalTemporary (Type);
6034 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6036 public override void Emit (EmitContext ec)
6041 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6043 has_await_arguments = true;
6048 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6050 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6052 bool ResolveGetter (ResolveContext rc)
6054 if (!best_candidate.HasGet) {
6055 if (InstanceExpression != EmptyExpression.Null) {
6056 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6057 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6058 best_candidate.GetSignatureForError ());
6061 } else if (!best_candidate.Get.IsAccessible (rc)) {
6062 if (best_candidate.HasDifferentAccessibility) {
6063 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6064 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6065 TypeManager.CSharpSignature (best_candidate));
6067 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6068 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6072 if (best_candidate.HasDifferentAccessibility) {
6073 CheckProtectedMemberAccess (rc, best_candidate.Get);
6076 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6080 bool ResolveSetter (ResolveContext rc)
6082 if (!best_candidate.HasSet) {
6083 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6084 GetSignatureForError ());
6088 if (!best_candidate.Set.IsAccessible (rc)) {
6089 if (best_candidate.HasDifferentAccessibility) {
6090 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6091 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6092 GetSignatureForError ());
6094 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6095 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6099 if (best_candidate.HasDifferentAccessibility)
6100 CheckProtectedMemberAccess (rc, best_candidate.Set);
6102 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6108 /// Fully resolved expression that evaluates to an Event
6110 public class EventExpr : MemberExpr, IAssignMethod
6112 readonly EventSpec spec;
6115 public EventExpr (EventSpec spec, Location loc)
6123 protected override TypeSpec DeclaringType {
6125 return spec.DeclaringType;
6129 public override string Name {
6135 public override bool IsInstance {
6137 return !spec.IsStatic;
6141 public override bool IsStatic {
6143 return spec.IsStatic;
6147 public override string KindName {
6148 get { return "event"; }
6151 public MethodSpec Operator {
6159 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6162 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6164 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6165 if (spec.BackingField != null &&
6166 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6168 spec.MemberDefinition.SetIsUsed ();
6170 if (!ec.IsObsolete) {
6171 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6173 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6176 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6177 Error_AssignmentEventOnly (ec);
6179 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6181 InstanceExpression = null;
6183 return ml.ResolveMemberAccess (ec, left, original);
6187 return base.ResolveMemberAccess (ec, left, original);
6190 public override Expression CreateExpressionTree (ResolveContext ec)
6192 throw new NotSupportedException ("ET");
6195 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6197 if (right_side == EmptyExpression.EventAddition) {
6198 op = spec.AccessorAdd;
6199 } else if (right_side == EmptyExpression.EventSubtraction) {
6200 op = spec.AccessorRemove;
6204 Error_AssignmentEventOnly (ec);
6208 op = CandidateToBaseOverride (ec, op);
6212 protected override Expression DoResolve (ResolveContext ec)
6214 eclass = ExprClass.EventAccess;
6215 type = spec.MemberType;
6217 ResolveInstanceExpression (ec, null);
6219 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6220 Error_AssignmentEventOnly (ec);
6223 DoBestMemberChecks (ec, spec);
6227 public override void Emit (EmitContext ec)
6229 throw new NotSupportedException ();
6230 //Error_CannotAssign ();
6233 #region IAssignMethod Members
6235 public void Emit (EmitContext ec, bool leave_copy)
6237 throw new NotImplementedException ();
6240 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6242 if (leave_copy || !isCompound)
6243 throw new NotImplementedException ("EventExpr::EmitAssign");
6245 Arguments args = new Arguments (1);
6246 args.Add (new Argument (source));
6248 var call = new CallEmitter ();
6249 call.InstanceExpression = InstanceExpression;
6250 call.Emit (ec, op, args, loc);
6255 void Error_AssignmentEventOnly (ResolveContext ec)
6257 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6258 ec.Report.Error (79, loc,
6259 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6260 GetSignatureForError ());
6262 ec.Report.Error (70, loc,
6263 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6264 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6268 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6270 name = name.Substring (0, name.LastIndexOf ('.'));
6271 base.Error_CannotCallAbstractBase (rc, name);
6274 public override string GetSignatureForError ()
6276 return TypeManager.CSharpSignature (spec);
6279 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6281 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6285 public class TemporaryVariableReference : VariableReference
6287 public class Declarator : Statement
6289 TemporaryVariableReference variable;
6291 public Declarator (TemporaryVariableReference variable)
6293 this.variable = variable;
6297 protected override void DoEmit (EmitContext ec)
6299 variable.li.CreateBuilder (ec);
6302 public override void Emit (EmitContext ec)
6304 // Don't create sequence point
6308 protected override void CloneTo (CloneContext clonectx, Statement target)
6316 public TemporaryVariableReference (LocalVariable li, Location loc)
6319 this.type = li.Type;
6323 public override bool IsLockedByStatement {
6331 public LocalVariable LocalInfo {
6337 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6339 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6340 return new TemporaryVariableReference (li, loc);
6343 protected override Expression DoResolve (ResolveContext ec)
6345 eclass = ExprClass.Variable;
6348 // Don't capture temporary variables except when using
6349 // state machine redirection and block yields
6351 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6352 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6353 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6354 storey.CaptureLocalVariable (ec, li);
6360 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6362 return Resolve (ec);
6365 public override void Emit (EmitContext ec)
6367 li.CreateBuilder (ec);
6372 public void EmitAssign (EmitContext ec, Expression source)
6374 li.CreateBuilder (ec);
6376 EmitAssign (ec, source, false, false);
6379 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6381 return li.HoistedVariant;
6384 public override bool IsFixed {
6385 get { return true; }
6388 public override bool IsRef {
6389 get { return false; }
6392 public override string Name {
6393 get { throw new NotImplementedException (); }
6396 public override void SetHasAddressTaken ()
6398 throw new NotImplementedException ();
6401 protected override ILocalVariable Variable {
6405 public override VariableInfo VariableInfo {
6406 get { return null; }
6409 public override void VerifyAssigned (ResolveContext rc)
6415 /// Handles `var' contextual keyword; var becomes a keyword only
6416 /// if no type called var exists in a variable scope
6418 class VarExpr : SimpleName
6420 public VarExpr (Location loc)
6425 public bool InferType (ResolveContext ec, Expression right_side)
6428 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6430 type = right_side.Type;
6431 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6432 ec.Report.Error (815, loc,
6433 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6434 type.GetSignatureForError ());
6438 eclass = ExprClass.Variable;
6442 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6444 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6445 base.Error_TypeOrNamespaceNotFound (ec);
6447 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");