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 (type, 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;
3448 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3450 simple_name = original;
3451 return base.ResolveMemberAccess (ec, left, original);
3454 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3456 type_arguments = ta;
3459 #region IBaseMembersProvider Members
3461 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3463 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3466 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3468 if (queried_type == member.DeclaringType)
3471 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3472 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3476 // Extension methods lookup after ordinary methods candidates failed to apply
3478 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3480 if (InstanceExpression == null)
3483 InstanceExpression = InstanceExpression.Resolve (rc);
3484 if (!IsExtensionMethodArgument (InstanceExpression))
3487 int arity = type_arguments == null ? 0 : type_arguments.Count;
3488 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3489 if (methods == null)
3492 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3493 emg.SetTypeArguments (rc, type_arguments);
3500 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3502 public ConstructorInstanceQualifier (TypeSpec type)
3505 InstanceType = type;
3508 public TypeSpec InstanceType { get; private set; }
3510 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3512 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3516 public struct OverloadResolver
3519 public enum Restrictions
3523 ProbingOnly = 1 << 1,
3524 CovariantDelegate = 1 << 2,
3525 NoBaseMembers = 1 << 3,
3526 BaseMembersIncluded = 1 << 4
3529 public interface IBaseMembersProvider
3531 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3532 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3533 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3536 public interface IErrorHandler
3538 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3539 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3540 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3541 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3544 public interface IInstanceQualifier
3546 TypeSpec InstanceType { get; }
3547 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3550 sealed class NoBaseMembers : IBaseMembersProvider
3552 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3554 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3559 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3564 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3570 struct AmbiguousCandidate
3572 public readonly MemberSpec Member;
3573 public readonly bool Expanded;
3574 public readonly AParametersCollection Parameters;
3576 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3579 Parameters = parameters;
3580 Expanded = expanded;
3585 IList<MemberSpec> members;
3586 TypeArguments type_arguments;
3587 IBaseMembersProvider base_provider;
3588 IErrorHandler custom_errors;
3589 IInstanceQualifier instance_qualifier;
3590 Restrictions restrictions;
3591 MethodGroupExpr best_candidate_extension_group;
3592 TypeSpec best_candidate_return_type;
3594 SessionReportPrinter lambda_conv_msgs;
3596 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3597 : this (members, null, restrictions, loc)
3601 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3604 if (members == null || members.Count == 0)
3605 throw new ArgumentException ("empty members set");
3607 this.members = members;
3609 type_arguments = targs;
3610 this.restrictions = restrictions;
3611 if (IsDelegateInvoke)
3612 this.restrictions |= Restrictions.NoBaseMembers;
3614 base_provider = NoBaseMembers.Instance;
3619 public IBaseMembersProvider BaseMembersProvider {
3621 return base_provider;
3624 base_provider = value;
3628 public bool BestCandidateIsDynamic { get; set; }
3631 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3633 public MethodGroupExpr BestCandidateNewMethodGroup {
3635 return best_candidate_extension_group;
3640 // Return type can be different between best candidate and closest override
3642 public TypeSpec BestCandidateReturnType {
3644 return best_candidate_return_type;
3648 public IErrorHandler CustomErrors {
3650 return custom_errors;
3653 custom_errors = value;
3657 TypeSpec DelegateType {
3659 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3660 throw new InternalErrorException ("Not running in delegate mode", loc);
3662 return members [0].DeclaringType;
3666 public IInstanceQualifier InstanceQualifier {
3668 return instance_qualifier;
3671 instance_qualifier = value;
3675 bool IsProbingOnly {
3677 return (restrictions & Restrictions.ProbingOnly) != 0;
3681 bool IsDelegateInvoke {
3683 return (restrictions & Restrictions.DelegateInvoke) != 0;
3690 // 7.4.3.3 Better conversion from expression
3691 // Returns : 1 if a->p is better,
3692 // 2 if a->q is better,
3693 // 0 if neither is better
3695 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3697 TypeSpec argument_type = a.Type;
3700 // If argument is an anonymous function
3702 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3704 // p and q are delegate types or expression tree types
3706 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3707 if (q.MemberDefinition != p.MemberDefinition) {
3712 // Uwrap delegate from Expression<T>
3714 q = TypeManager.GetTypeArguments (q)[0];
3715 p = TypeManager.GetTypeArguments (p)[0];
3718 var p_m = Delegate.GetInvokeMethod (p);
3719 var q_m = Delegate.GetInvokeMethod (q);
3722 // With identical parameter lists
3724 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3731 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3733 if (p.Kind == MemberKind.Void) {
3734 return q.Kind != MemberKind.Void ? 2 : 0;
3738 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3740 if (q.Kind == MemberKind.Void) {
3741 return p.Kind != MemberKind.Void ? 1: 0;
3745 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3746 // better conversion is performed between underlying types Y1 and Y2
3748 if (p.IsGenericTask || q.IsGenericTask) {
3749 var async_am = a.Expr as AnonymousMethodExpression;
3750 if (async_am != null && async_am.Block.IsAsync) {
3752 if (p.IsGenericTask != q.IsGenericTask) {
3756 q = q.TypeArguments[0];
3757 p = p.TypeArguments[0];
3762 // The parameters are identicial and return type is not void, use better type conversion
3763 // on return type to determine better one
3766 if (argument_type == p)
3769 if (argument_type == q)
3773 return BetterTypeConversion (ec, p, q);
3777 // 7.4.3.4 Better conversion from type
3779 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3781 if (p == null || q == null)
3782 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3784 switch (p.BuiltinType) {
3785 case BuiltinTypeSpec.Type.Int:
3786 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3789 case BuiltinTypeSpec.Type.Long:
3790 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3793 case BuiltinTypeSpec.Type.SByte:
3794 switch (q.BuiltinType) {
3795 case BuiltinTypeSpec.Type.Byte:
3796 case BuiltinTypeSpec.Type.UShort:
3797 case BuiltinTypeSpec.Type.UInt:
3798 case BuiltinTypeSpec.Type.ULong:
3802 case BuiltinTypeSpec.Type.Short:
3803 switch (q.BuiltinType) {
3804 case BuiltinTypeSpec.Type.UShort:
3805 case BuiltinTypeSpec.Type.UInt:
3806 case BuiltinTypeSpec.Type.ULong:
3810 case BuiltinTypeSpec.Type.Dynamic:
3811 // Dynamic is never better
3815 switch (q.BuiltinType) {
3816 case BuiltinTypeSpec.Type.Int:
3817 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3820 case BuiltinTypeSpec.Type.Long:
3821 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3824 case BuiltinTypeSpec.Type.SByte:
3825 switch (p.BuiltinType) {
3826 case BuiltinTypeSpec.Type.Byte:
3827 case BuiltinTypeSpec.Type.UShort:
3828 case BuiltinTypeSpec.Type.UInt:
3829 case BuiltinTypeSpec.Type.ULong:
3833 case BuiltinTypeSpec.Type.Short:
3834 switch (p.BuiltinType) {
3835 case BuiltinTypeSpec.Type.UShort:
3836 case BuiltinTypeSpec.Type.UInt:
3837 case BuiltinTypeSpec.Type.ULong:
3841 case BuiltinTypeSpec.Type.Dynamic:
3842 // Dynamic is never better
3846 // FIXME: handle lifted operators
3848 // TODO: this is expensive
3849 Expression p_tmp = new EmptyExpression (p);
3850 Expression q_tmp = new EmptyExpression (q);
3852 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3853 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3855 if (p_to_q && !q_to_p)
3858 if (q_to_p && !p_to_q)
3865 /// Determines "Better function" between candidate
3866 /// and the current best match
3869 /// Returns a boolean indicating :
3870 /// false if candidate ain't better
3871 /// true if candidate is better than the current best match
3873 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3874 MemberSpec best, AParametersCollection bparam, bool best_params)
3876 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3877 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3879 bool better_at_least_one = false;
3881 int args_count = args == null ? 0 : args.Count;
3885 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3888 // Default arguments are ignored for better decision
3889 if (a.IsDefaultArgument)
3893 // When comparing named argument the parameter type index has to be looked up
3894 // in original parameter set (override version for virtual members)
3896 NamedArgument na = a as NamedArgument;
3898 int idx = cparam.GetParameterIndexByName (na.Name);
3899 ct = candidate_pd.Types[idx];
3900 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3901 ct = TypeManager.GetElementType (ct);
3903 idx = bparam.GetParameterIndexByName (na.Name);
3904 bt = best_pd.Types[idx];
3905 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3906 bt = TypeManager.GetElementType (bt);
3908 ct = candidate_pd.Types[c_idx];
3909 bt = best_pd.Types[b_idx];
3911 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3912 ct = TypeManager.GetElementType (ct);
3916 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3917 bt = TypeManager.GetElementType (bt);
3922 if (TypeSpecComparer.IsEqual (ct, bt))
3926 int result = BetterExpressionConversion (ec, a, ct, bt);
3928 // for each argument, the conversion to 'ct' should be no worse than
3929 // the conversion to 'bt'.
3933 // for at least one argument, the conversion to 'ct' should be better than
3934 // the conversion to 'bt'.
3936 better_at_least_one = true;
3939 if (better_at_least_one)
3943 // This handles the case
3945 // Add (float f1, float f2, float f3);
3946 // Add (params decimal [] foo);
3948 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3949 // first candidate would've chosen as better.
3951 if (!same && !a.IsDefaultArgument)
3955 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3959 // This handles the following cases:
3961 // Foo (int i) is better than Foo (int i, long l = 0)
3962 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3964 // Prefer non-optional version
3966 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3968 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3969 if (candidate_pd.Count >= best_pd.Count)
3972 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3979 // One is a non-generic method and second is a generic method, then non-generic is better
3981 if (best.IsGeneric != candidate.IsGeneric)
3982 return best.IsGeneric;
3985 // This handles the following cases:
3987 // Trim () is better than Trim (params char[] chars)
3988 // Concat (string s1, string s2, string s3) is better than
3989 // Concat (string s1, params string [] srest)
3990 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3992 // Prefer non-expanded version
3994 if (candidate_params != best_params)
3997 int candidate_param_count = candidate_pd.Count;
3998 int best_param_count = best_pd.Count;
4000 if (candidate_param_count != best_param_count)
4001 // can only happen if (candidate_params && best_params)
4002 return candidate_param_count > best_param_count && best_pd.HasParams;
4005 // Both methods have the same number of parameters, and the parameters have equal types
4006 // Pick the "more specific" signature using rules over original (non-inflated) types
4008 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4009 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4011 bool specific_at_least_once = false;
4012 for (j = 0; j < args_count; ++j) {
4013 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4015 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4016 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4018 ct = candidate_def_pd.Types[j];
4019 bt = best_def_pd.Types[j];
4024 TypeSpec specific = MoreSpecific (ct, bt);
4028 specific_at_least_once = true;
4031 if (specific_at_least_once)
4037 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4039 rc.Report.Error (1729, loc,
4040 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4041 type.GetSignatureForError (), argCount.ToString ());
4045 // Determines if the candidate method is applicable to the given set of arguments
4046 // There could be two different set of parameters for same candidate where one
4047 // is the closest override for default values and named arguments checks and second
4048 // one being the virtual base for the parameter types and modifiers.
4050 // A return value rates candidate method compatibility,
4051 // 0 = the best, int.MaxValue = the worst
4054 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)
4056 // Parameters of most-derived type used mainly for named and optional parameters
4057 var pd = pm.Parameters;
4059 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4060 // params modifier instead of most-derived type
4061 var cpd = ((IParametersMember) candidate).Parameters;
4062 int param_count = pd.Count;
4063 int optional_count = 0;
4065 Arguments orig_args = arguments;
4067 if (arg_count != param_count) {
4069 // No arguments expansion when doing exact match for delegates
4071 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4072 for (int i = 0; i < pd.Count; ++i) {
4073 if (pd.FixedParameters[i].HasDefaultValue) {
4074 optional_count = pd.Count - i;
4080 if (optional_count != 0) {
4081 // Readjust expected number when params used
4082 if (cpd.HasParams) {
4084 if (arg_count < param_count)
4086 } else if (arg_count > param_count) {
4087 int args_gap = System.Math.Abs (arg_count - param_count);
4088 return int.MaxValue - 10000 + args_gap;
4090 } else if (arg_count != param_count) {
4091 int args_gap = System.Math.Abs (arg_count - param_count);
4093 return int.MaxValue - 10000 + args_gap;
4094 if (arg_count < param_count - 1)
4095 return int.MaxValue - 10000 + args_gap;
4098 // Resize to fit optional arguments
4099 if (optional_count != 0) {
4100 if (arguments == null) {
4101 arguments = new Arguments (optional_count);
4103 // Have to create a new container, so the next run can do same
4104 var resized = new Arguments (param_count);
4105 resized.AddRange (arguments);
4106 arguments = resized;
4109 for (int i = arg_count; i < param_count; ++i)
4110 arguments.Add (null);
4114 if (arg_count > 0) {
4116 // Shuffle named arguments to the right positions if there are any
4118 if (arguments[arg_count - 1] is NamedArgument) {
4119 arg_count = arguments.Count;
4121 for (int i = 0; i < arg_count; ++i) {
4122 bool arg_moved = false;
4124 NamedArgument na = arguments[i] as NamedArgument;
4128 int index = pd.GetParameterIndexByName (na.Name);
4130 // Named parameter not found
4134 // already reordered
4139 if (index >= param_count) {
4140 // When using parameters which should not be available to the user
4141 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4144 arguments.Add (null);
4148 temp = arguments[index];
4150 // The slot has been taken by positional argument
4151 if (temp != null && !(temp is NamedArgument))
4156 arguments = arguments.MarkOrderedArgument (na);
4160 arguments[index] = arguments[i];
4161 arguments[i] = temp;
4168 arg_count = arguments.Count;
4170 } else if (arguments != null) {
4171 arg_count = arguments.Count;
4175 // Don't do any expensive checks when the candidate cannot succeed
4177 if (arg_count != param_count && !cpd.HasParams)
4178 return (param_count - arg_count) * 2 + 1;
4180 var dep = candidate.GetMissingDependencies ();
4182 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4187 // 1. Handle generic method using type arguments when specified or type inference
4190 var ms = candidate as MethodSpec;
4191 if (ms != null && ms.IsGeneric) {
4192 // Setup constraint checker for probing only
4193 ConstraintChecker cc = new ConstraintChecker (null);
4195 if (type_arguments != null) {
4196 var g_args_count = ms.Arity;
4197 if (g_args_count != type_arguments.Count)
4198 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4200 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4203 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4204 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4205 // candidate was found use the set to report more details about what was wrong with lambda body.
4206 // The general idea is to distinguish between code errors and errors caused by
4207 // trial-and-error type inference
4209 if (lambda_conv_msgs == null) {
4210 for (int i = 0; i < arg_count; i++) {
4211 Argument a = arguments[i];
4215 var am = a.Expr as AnonymousMethodExpression;
4217 if (lambda_conv_msgs == null)
4218 lambda_conv_msgs = new SessionReportPrinter ();
4220 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4225 var ti = new TypeInference (arguments);
4226 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4229 return ti.InferenceScore - 20000;
4232 // Clear any error messages when the result was success
4234 if (lambda_conv_msgs != null)
4235 lambda_conv_msgs.ClearSession ();
4237 if (i_args.Length != 0) {
4238 ms = ms.MakeGenericMethod (ec, i_args);
4241 cc.IgnoreInferredDynamic = true;
4245 // Type arguments constraints have to match for the method to be applicable
4247 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4249 return int.MaxValue - 25000;
4253 // We have a generic return type and at same time the method is override which
4254 // means we have to also inflate override return type in case the candidate is
4255 // best candidate and override return type is different to base return type.
4257 // virtual Foo<T, object> with override Foo<T, dynamic>
4259 if (candidate != pm) {
4260 MethodSpec override_ms = (MethodSpec) pm;
4261 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4262 returnType = inflator.Inflate (returnType);
4264 returnType = ms.ReturnType;
4268 ptypes = ms.Parameters.Types;
4270 if (type_arguments != null)
4271 return int.MaxValue - 15000;
4277 // 2. Each argument has to be implicitly convertible to method parameter
4279 Parameter.Modifier p_mod = 0;
4282 for (int i = 0; i < arg_count; i++) {
4283 Argument a = arguments[i];
4285 var fp = pd.FixedParameters[i];
4286 if (!fp.HasDefaultValue) {
4287 arguments = orig_args;
4288 return arg_count * 2 + 2;
4292 // Get the default value expression, we can use the same expression
4293 // if the type matches
4295 Expression e = fp.DefaultValue;
4296 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4298 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4300 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4301 e = new MemberAccess (new MemberAccess (new MemberAccess (
4302 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4304 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4310 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4312 // LAMESPEC: Attributes can be mixed together with build-in priority
4314 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4315 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4316 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4317 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4318 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4319 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4323 arguments[i] = new Argument (e, Argument.AType.Default);
4327 if (p_mod != Parameter.Modifier.PARAMS) {
4328 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4330 } else if (!params_expanded_form) {
4331 params_expanded_form = true;
4332 pt = ((ElementTypeSpec) pt).Element;
4338 if (!params_expanded_form) {
4339 if (a.ArgType == Argument.AType.ExtensionType) {
4341 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4343 // LAMESPEC: or implicit type parameter conversion
4346 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4347 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4348 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4353 score = IsArgumentCompatible (ec, a, p_mod, pt);
4356 dynamicArgument = true;
4361 // It can be applicable in expanded form (when not doing exact match like for delegates)
4363 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4364 if (!params_expanded_form)
4365 pt = ((ElementTypeSpec) pt).Element;
4368 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4371 params_expanded_form = true;
4372 } else if (score < 0) {
4373 params_expanded_form = true;
4374 dynamicArgument = true;
4379 if (params_expanded_form)
4381 return (arg_count - i) * 2 + score;
4386 // When params parameter has no argument it will be provided later if the method is the best candidate
4388 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4389 params_expanded_form = true;
4392 // Restore original arguments for dynamic binder to keep the intention of original source code
4394 if (dynamicArgument)
4395 arguments = orig_args;
4401 // Tests argument compatibility with the parameter
4402 // The possible return values are
4404 // 1 - modifier mismatch
4405 // 2 - type mismatch
4406 // -1 - dynamic binding required
4408 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4411 // Types have to be identical when ref or out modifer
4412 // is used and argument is not of dynamic type
4414 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4415 if (argument.Type != parameter) {
4417 // Do full equality check after quick path
4419 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4421 // Using dynamic for ref/out parameter can still succeed at runtime
4423 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4430 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4432 // Using dynamic for ref/out parameter can still succeed at runtime
4434 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4441 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4445 // Use implicit conversion in all modes to return same candidates when the expression
4446 // is used as argument or delegate conversion
4448 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4456 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4458 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4460 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4463 var ac_p = p as ArrayContainer;
4465 var ac_q = q as ArrayContainer;
4469 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4470 if (specific == ac_p.Element)
4472 if (specific == ac_q.Element)
4474 } else if (TypeManager.IsGenericType (p)) {
4475 var pargs = TypeManager.GetTypeArguments (p);
4476 var qargs = TypeManager.GetTypeArguments (q);
4478 bool p_specific_at_least_once = false;
4479 bool q_specific_at_least_once = false;
4481 for (int i = 0; i < pargs.Length; i++) {
4482 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4483 if (specific == pargs[i])
4484 p_specific_at_least_once = true;
4485 if (specific == qargs[i])
4486 q_specific_at_least_once = true;
4489 if (p_specific_at_least_once && !q_specific_at_least_once)
4491 if (!p_specific_at_least_once && q_specific_at_least_once)
4499 // Find the best method from candidate list
4501 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4503 List<AmbiguousCandidate> ambiguous_candidates = null;
4505 MemberSpec best_candidate;
4506 Arguments best_candidate_args = null;
4507 bool best_candidate_params = false;
4508 bool best_candidate_dynamic = false;
4509 int best_candidate_rate;
4510 IParametersMember best_parameter_member = null;
4512 int args_count = args != null ? args.Count : 0;
4514 Arguments candidate_args = args;
4515 bool error_mode = false;
4516 MemberSpec invocable_member = null;
4519 best_candidate = null;
4520 best_candidate_rate = int.MaxValue;
4522 var type_members = members;
4524 for (int i = 0; i < type_members.Count; ++i) {
4525 var member = type_members[i];
4528 // Methods in a base class are not candidates if any method in a derived
4529 // class is applicable
4531 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4535 if (!member.IsAccessible (rc))
4538 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4541 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4542 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4547 IParametersMember pm = member as IParametersMember;
4550 // Will use it later to report ambiguity between best method and invocable member
4552 if (Invocation.IsMemberInvocable (member))
4553 invocable_member = member;
4559 // Overload resolution is looking for base member but using parameter names
4560 // and default values from the closest member. That means to do expensive lookup
4561 // for the closest override for virtual or abstract members
4563 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4564 var override_params = base_provider.GetOverrideMemberParameters (member);
4565 if (override_params != null)
4566 pm = override_params;
4570 // Check if the member candidate is applicable
4572 bool params_expanded_form = false;
4573 bool dynamic_argument = false;
4574 TypeSpec rt = pm.MemberType;
4575 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4577 if (lambda_conv_msgs != null)
4578 lambda_conv_msgs.EndSession ();
4581 // How does it score compare to others
4583 if (candidate_rate < best_candidate_rate) {
4585 // Fatal error (missing dependency), cannot continue
4586 if (candidate_rate < 0)
4589 best_candidate_rate = candidate_rate;
4590 best_candidate = member;
4591 best_candidate_args = candidate_args;
4592 best_candidate_params = params_expanded_form;
4593 best_candidate_dynamic = dynamic_argument;
4594 best_parameter_member = pm;
4595 best_candidate_return_type = rt;
4596 } else if (candidate_rate == 0) {
4598 // The member look is done per type for most operations but sometimes
4599 // it's not possible like for binary operators overload because they
4600 // are unioned between 2 sides
4602 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4603 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4608 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4610 // We pack all interface members into top level type which makes the overload resolution
4611 // more complicated for interfaces. We compensate it by removing methods with same
4612 // signature when building the cache hence this path should not really be hit often
4615 // interface IA { void Foo (int arg); }
4616 // interface IB : IA { void Foo (params int[] args); }
4618 // IB::Foo is the best overload when calling IB.Foo (1)
4621 if (ambiguous_candidates != null) {
4622 foreach (var amb_cand in ambiguous_candidates) {
4623 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4632 ambiguous_candidates = null;
4635 // Is the new candidate better
4636 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4640 best_candidate = member;
4641 best_candidate_args = candidate_args;
4642 best_candidate_params = params_expanded_form;
4643 best_candidate_dynamic = dynamic_argument;
4644 best_parameter_member = pm;
4645 best_candidate_return_type = rt;
4647 // It's not better but any other found later could be but we are not sure yet
4648 if (ambiguous_candidates == null)
4649 ambiguous_candidates = new List<AmbiguousCandidate> ();
4651 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4655 // Restore expanded arguments
4656 if (candidate_args != args)
4657 candidate_args = args;
4659 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4662 // We've found exact match
4664 if (best_candidate_rate == 0)
4668 // Try extension methods lookup when no ordinary method match was found and provider enables it
4671 var emg = base_provider.LookupExtensionMethod (rc);
4673 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4675 best_candidate_extension_group = emg;
4676 return (T) (MemberSpec) emg.BestCandidate;
4681 // Don't run expensive error reporting mode for probing
4688 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4691 lambda_conv_msgs = null;
4696 // No best member match found, report an error
4698 if (best_candidate_rate != 0 || error_mode) {
4699 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4703 if (best_candidate_dynamic) {
4704 if (args[0].ArgType == Argument.AType.ExtensionType) {
4705 rc.Report.Error (1973, loc,
4706 "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",
4707 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4710 BestCandidateIsDynamic = true;
4715 // These flags indicates we are running delegate probing conversion. No need to
4716 // do more expensive checks
4718 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4719 return (T) best_candidate;
4721 if (ambiguous_candidates != null) {
4723 // Now check that there are no ambiguities i.e the selected method
4724 // should be better than all the others
4726 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4727 var candidate = ambiguous_candidates [ix];
4729 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4730 var ambiguous = candidate.Member;
4731 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4732 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4733 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4734 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4735 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4738 return (T) best_candidate;
4743 if (invocable_member != null) {
4744 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4745 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4746 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4747 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4751 // And now check if the arguments are all
4752 // compatible, perform conversions if
4753 // necessary etc. and return if everything is
4756 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4759 if (best_candidate == null)
4763 // Check ObsoleteAttribute on the best method
4765 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4766 if (oa != null && !rc.IsObsolete)
4767 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4769 best_candidate.MemberDefinition.SetIsUsed ();
4771 args = best_candidate_args;
4772 return (T) best_candidate;
4775 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4777 return ResolveMember<MethodSpec> (rc, ref args);
4780 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4781 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4783 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4786 if (a.Type == InternalType.ErrorType)
4789 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4790 ec.Report.SymbolRelatedToPreviousError (method);
4791 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
4792 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4793 TypeManager.CSharpSignature (method));
4796 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4797 TypeManager.CSharpSignature (method));
4798 } else if (IsDelegateInvoke) {
4799 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4800 DelegateType.GetSignatureForError ());
4802 ec.Report.SymbolRelatedToPreviousError (method);
4803 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4804 method.GetSignatureForError ());
4807 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4809 string index = (idx + 1).ToString ();
4810 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
4811 if ((mod & Parameter.Modifier.RefOutMask) == 0)
4812 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4813 index, Parameter.GetModifierSignature (a.Modifier));
4815 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4816 index, Parameter.GetModifierSignature (mod));
4818 string p1 = a.GetSignatureForError ();
4819 string p2 = TypeManager.CSharpName (paramType);
4822 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4823 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4826 ec.Report.Error (1503, loc,
4827 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4832 // We have failed to find exact match so we return error info about the closest match
4834 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4836 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4837 int arg_count = args == null ? 0 : args.Count;
4839 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4840 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4841 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4845 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
4850 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4851 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4852 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4856 // For candidates which match on parameters count report more details about incorrect arguments
4859 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4860 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4861 // Reject any inaccessible member
4862 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4863 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4864 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4868 var ms = best_candidate as MethodSpec;
4869 if (ms != null && ms.IsGeneric) {
4870 bool constr_ok = true;
4871 if (ms.TypeArguments != null)
4872 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4874 if (ta_count == 0) {
4875 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4879 rc.Report.Error (411, loc,
4880 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4881 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4888 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4894 // We failed to find any method with correct argument count, report best candidate
4896 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4899 if (best_candidate.Kind == MemberKind.Constructor) {
4900 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4901 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4902 } else if (IsDelegateInvoke) {
4903 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4904 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4905 DelegateType.GetSignatureForError (), arg_count.ToString ());
4907 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4908 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4909 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4910 name, arg_count.ToString ());
4914 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4916 var pd = pm.Parameters;
4917 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4919 Parameter.Modifier p_mod = 0;
4921 int a_idx = 0, a_pos = 0;
4923 ArrayInitializer params_initializers = null;
4924 bool has_unsafe_arg = pm.MemberType.IsPointer;
4925 int arg_count = args == null ? 0 : args.Count;
4927 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4929 if (p_mod != Parameter.Modifier.PARAMS) {
4930 p_mod = pd.FixedParameters[a_idx].ModFlags;
4932 has_unsafe_arg |= pt.IsPointer;
4934 if (p_mod == Parameter.Modifier.PARAMS) {
4935 if (chose_params_expanded) {
4936 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4937 pt = TypeManager.GetElementType (pt);
4943 // Types have to be identical when ref or out modifer is used
4945 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
4946 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
4949 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4955 NamedArgument na = a as NamedArgument;
4957 int name_index = pd.GetParameterIndexByName (na.Name);
4958 if (name_index < 0 || name_index >= pd.Count) {
4959 if (IsDelegateInvoke) {
4960 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4961 ec.Report.Error (1746, na.Location,
4962 "The delegate `{0}' does not contain a parameter named `{1}'",
4963 DelegateType.GetSignatureForError (), na.Name);
4965 ec.Report.SymbolRelatedToPreviousError (member);
4966 ec.Report.Error (1739, na.Location,
4967 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4968 TypeManager.CSharpSignature (member), na.Name);
4970 } else if (args[name_index] != a) {
4971 if (IsDelegateInvoke)
4972 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4974 ec.Report.SymbolRelatedToPreviousError (member);
4976 ec.Report.Error (1744, na.Location,
4977 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4982 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4985 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4986 custom_errors.NoArgumentMatch (ec, member);
4990 Expression conv = null;
4991 if (a.ArgType == Argument.AType.ExtensionType) {
4992 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4995 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4997 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5000 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5007 // Convert params arguments to an array initializer
5009 if (params_initializers != null) {
5010 // we choose to use 'a.Expr' rather than 'conv' so that
5011 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5012 params_initializers.Add (a.Expr);
5013 args.RemoveAt (a_idx--);
5018 // Update the argument with the implicit conversion
5022 if (a_idx != arg_count) {
5023 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5028 // Fill not provided arguments required by params modifier
5030 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5032 args = new Arguments (1);
5034 pt = ptypes[pd.Count - 1];
5035 pt = TypeManager.GetElementType (pt);
5036 has_unsafe_arg |= pt.IsPointer;
5037 params_initializers = new ArrayInitializer (0, loc);
5041 // Append an array argument with all params arguments
5043 if (params_initializers != null) {
5044 args.Add (new Argument (
5045 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5049 if (has_unsafe_arg && !ec.IsUnsafe) {
5050 Expression.UnsafeError (ec, loc);
5054 // We could infer inaccesible type arguments
5056 if (type_arguments == null && member.IsGeneric) {
5057 var ms = (MethodSpec) member;
5058 foreach (var ta in ms.TypeArguments) {
5059 if (!ta.IsAccessible (ec)) {
5060 ec.Report.SymbolRelatedToPreviousError (ta);
5061 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5071 public class ConstantExpr : MemberExpr
5073 readonly ConstSpec constant;
5075 public ConstantExpr (ConstSpec constant, Location loc)
5077 this.constant = constant;
5081 public override string Name {
5082 get { throw new NotImplementedException (); }
5085 public override string KindName {
5086 get { return "constant"; }
5089 public override bool IsInstance {
5090 get { return !IsStatic; }
5093 public override bool IsStatic {
5094 get { return true; }
5097 protected override TypeSpec DeclaringType {
5098 get { return constant.DeclaringType; }
5101 public override Expression CreateExpressionTree (ResolveContext ec)
5103 throw new NotSupportedException ("ET");
5106 protected override Expression DoResolve (ResolveContext rc)
5108 ResolveInstanceExpression (rc, null);
5109 DoBestMemberChecks (rc, constant);
5111 var c = constant.GetConstant (rc);
5113 // Creates reference expression to the constant value
5114 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5117 public override void Emit (EmitContext ec)
5119 throw new NotSupportedException ();
5122 public override string GetSignatureForError ()
5124 return constant.GetSignatureForError ();
5127 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5129 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5134 // Fully resolved expression that references a Field
5136 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5138 protected FieldSpec spec;
5139 VariableInfo variable_info;
5141 LocalTemporary temp;
5144 protected FieldExpr (Location l)
5149 public FieldExpr (FieldSpec spec, Location loc)
5154 type = spec.MemberType;
5157 public FieldExpr (FieldBase fi, Location l)
5164 public override string Name {
5170 public bool IsHoisted {
5172 IVariableReference hv = InstanceExpression as IVariableReference;
5173 return hv != null && hv.IsHoisted;
5177 public override bool IsInstance {
5179 return !spec.IsStatic;
5183 public override bool IsStatic {
5185 return spec.IsStatic;
5189 public override string KindName {
5190 get { return "field"; }
5193 public FieldSpec Spec {
5199 protected override TypeSpec DeclaringType {
5201 return spec.DeclaringType;
5205 public VariableInfo VariableInfo {
5207 return variable_info;
5213 public override string GetSignatureForError ()
5215 return spec.GetSignatureForError ();
5218 public bool IsMarshalByRefAccess (ResolveContext rc)
5220 // Checks possible ldflda of field access expression
5221 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5222 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5223 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5226 public void SetHasAddressTaken ()
5228 IVariableReference vr = InstanceExpression as IVariableReference;
5230 vr.SetHasAddressTaken ();
5234 public override Expression CreateExpressionTree (ResolveContext ec)
5236 return CreateExpressionTree (ec, true);
5239 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5242 Expression instance;
5244 if (InstanceExpression == null) {
5245 instance = new NullLiteral (loc);
5246 } else if (convertInstance) {
5247 instance = InstanceExpression.CreateExpressionTree (ec);
5249 args = new Arguments (1);
5250 args.Add (new Argument (InstanceExpression));
5251 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5254 args = Arguments.CreateForExpressionTree (ec, null,
5256 CreateTypeOfExpression ());
5258 return CreateExpressionFactoryCall (ec, "Field", args);
5261 public Expression CreateTypeOfExpression ()
5263 return new TypeOfField (spec, loc);
5266 protected override Expression DoResolve (ResolveContext ec)
5268 return DoResolve (ec, null);
5271 Expression DoResolve (ResolveContext ec, Expression rhs)
5273 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5276 if (ResolveInstanceExpression (ec, rhs)) {
5277 // Resolve the field's instance expression while flow analysis is turned
5278 // off: when accessing a field "a.b", we must check whether the field
5279 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5281 if (lvalue_instance) {
5282 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5283 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5285 Expression right_side =
5286 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5288 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5291 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5292 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5296 if (InstanceExpression == null)
5300 DoBestMemberChecks (ec, spec);
5303 var fb = spec as FixedFieldSpec;
5304 IVariableReference var = InstanceExpression as IVariableReference;
5306 if (lvalue_instance && var != null && var.VariableInfo != null) {
5307 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5311 IFixedExpression fe = InstanceExpression as IFixedExpression;
5312 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5313 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5316 if (InstanceExpression.eclass != ExprClass.Variable) {
5317 ec.Report.SymbolRelatedToPreviousError (spec);
5318 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5319 TypeManager.GetFullNameSignature (spec));
5320 } else if (var != null && var.IsHoisted) {
5321 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5324 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5328 // Set flow-analysis variable info for struct member access. It will be check later
5329 // for precise error reporting
5331 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5332 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5333 if (rhs != null && variable_info != null)
5334 variable_info.SetStructFieldAssigned (ec, Name);
5337 eclass = ExprClass.Variable;
5341 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5346 var var = fe.InstanceExpression as IVariableReference;
5348 var vi = var.VariableInfo;
5350 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5352 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5354 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5361 fe = fe.InstanceExpression as FieldExpr;
5363 } while (fe != null);
5366 static readonly int [] codes = {
5367 191, // instance, write access
5368 192, // instance, out access
5369 198, // static, write access
5370 199, // static, out access
5371 1648, // member of value instance, write access
5372 1649, // member of value instance, out access
5373 1650, // member of value static, write access
5374 1651 // member of value static, out access
5377 static readonly string [] msgs = {
5378 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5379 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5380 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5381 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5382 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5383 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5384 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5385 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5388 // The return value is always null. Returning a value simplifies calling code.
5389 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5392 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5396 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5398 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5403 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5405 Expression e = DoResolve (ec, right_side);
5410 spec.MemberDefinition.SetIsAssigned ();
5412 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5413 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5414 ec.Report.Warning (420, 1, loc,
5415 "`{0}': A volatile field references will not be treated as volatile",
5416 spec.GetSignatureForError ());
5419 if (spec.IsReadOnly) {
5420 // InitOnly fields can only be assigned in constructors or initializers
5421 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5422 return Report_AssignToReadonly (ec, right_side);
5424 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5426 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5427 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5428 return Report_AssignToReadonly (ec, right_side);
5429 // static InitOnly fields cannot be assigned-to in an instance constructor
5430 if (IsStatic && !ec.IsStatic)
5431 return Report_AssignToReadonly (ec, right_side);
5432 // instance constructors can't modify InitOnly fields of other instances of the same type
5433 if (!IsStatic && !(InstanceExpression is This))
5434 return Report_AssignToReadonly (ec, right_side);
5438 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5439 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5440 ec.Report.Warning (197, 1, loc,
5441 "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",
5442 GetSignatureForError ());
5445 eclass = ExprClass.Variable;
5449 public override int GetHashCode ()
5451 return spec.GetHashCode ();
5454 public bool IsFixed {
5457 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5459 IVariableReference variable = InstanceExpression as IVariableReference;
5460 if (variable != null)
5461 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5463 IFixedExpression fe = InstanceExpression as IFixedExpression;
5464 return fe != null && fe.IsFixed;
5468 public override bool Equals (object obj)
5470 FieldExpr fe = obj as FieldExpr;
5474 if (spec != fe.spec)
5477 if (InstanceExpression == null || fe.InstanceExpression == null)
5480 return InstanceExpression.Equals (fe.InstanceExpression);
5483 public void Emit (EmitContext ec, bool leave_copy)
5485 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5487 spec.MemberDefinition.SetIsUsed ();
5491 ec.Emit (OpCodes.Volatile);
5493 ec.Emit (OpCodes.Ldsfld, spec);
5496 EmitInstance (ec, false);
5498 // Optimization for build-in types
5499 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5500 ec.EmitLoadFromPtr (type);
5502 var ff = spec as FixedFieldSpec;
5504 ec.Emit (OpCodes.Ldflda, spec);
5505 ec.Emit (OpCodes.Ldflda, ff.Element);
5508 ec.Emit (OpCodes.Volatile);
5510 ec.Emit (OpCodes.Ldfld, spec);
5516 ec.Emit (OpCodes.Dup);
5518 temp = new LocalTemporary (this.Type);
5524 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5526 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5527 if (isCompound && !(source is DynamicExpressionStatement)) {
5528 if (has_await_source) {
5530 InstanceExpression = InstanceExpression.EmitToField (ec);
5537 if (has_await_source)
5538 source = source.EmitToField (ec);
5540 EmitInstance (ec, prepared);
5546 ec.Emit (OpCodes.Dup);
5548 temp = new LocalTemporary (this.Type);
5553 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5554 ec.Emit (OpCodes.Volatile);
5556 spec.MemberDefinition.SetIsAssigned ();
5559 ec.Emit (OpCodes.Stsfld, spec);
5561 ec.Emit (OpCodes.Stfld, spec);
5571 // Emits store to field with prepared values on stack
5573 public void EmitAssignFromStack (EmitContext ec)
5576 ec.Emit (OpCodes.Stsfld, spec);
5578 ec.Emit (OpCodes.Stfld, spec);
5582 public override void Emit (EmitContext ec)
5587 public override void EmitSideEffect (EmitContext ec)
5589 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5591 if (is_volatile) // || is_marshal_by_ref ())
5592 base.EmitSideEffect (ec);
5595 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5597 if ((mode & AddressOp.Store) != 0)
5598 spec.MemberDefinition.SetIsAssigned ();
5599 if ((mode & AddressOp.Load) != 0)
5600 spec.MemberDefinition.SetIsUsed ();
5603 // Handle initonly fields specially: make a copy and then
5604 // get the address of the copy.
5607 if (spec.IsReadOnly){
5609 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5621 var temp = ec.GetTemporaryLocal (type);
5622 ec.Emit (OpCodes.Stloc, temp);
5623 ec.Emit (OpCodes.Ldloca, temp);
5624 ec.FreeTemporaryLocal (temp, type);
5630 ec.Emit (OpCodes.Ldsflda, spec);
5633 EmitInstance (ec, false);
5634 ec.Emit (OpCodes.Ldflda, spec);
5638 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5640 return MakeExpression (ctx);
5643 public override SLE.Expression MakeExpression (BuilderContext ctx)
5646 return base.MakeExpression (ctx);
5648 return SLE.Expression.Field (
5649 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5650 spec.GetMetaInfo ());
5654 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5656 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5662 // Expression that evaluates to a Property.
5664 // This is not an LValue because we need to re-write the expression. We
5665 // can not take data from the stack and store it.
5667 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5669 public PropertyExpr (PropertySpec spec, Location l)
5672 best_candidate = spec;
5673 type = spec.MemberType;
5678 protected override Arguments Arguments {
5686 protected override TypeSpec DeclaringType {
5688 return best_candidate.DeclaringType;
5692 public override string Name {
5694 return best_candidate.Name;
5698 public override bool IsInstance {
5704 public override bool IsStatic {
5706 return best_candidate.IsStatic;
5710 public override string KindName {
5711 get { return "property"; }
5714 public PropertySpec PropertyInfo {
5716 return best_candidate;
5722 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5724 return new PropertyExpr (spec, loc) {
5730 public override Expression CreateExpressionTree (ResolveContext ec)
5733 if (IsSingleDimensionalArrayLength ()) {
5734 args = new Arguments (1);
5735 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5736 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5739 args = new Arguments (2);
5740 if (InstanceExpression == null)
5741 args.Add (new Argument (new NullLiteral (loc)));
5743 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5744 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5745 return CreateExpressionFactoryCall (ec, "Property", args);
5748 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5750 DoResolveLValue (rc, null);
5751 return new TypeOfMethod (Setter, loc);
5754 public override string GetSignatureForError ()
5756 return best_candidate.GetSignatureForError ();
5759 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5762 return base.MakeExpression (ctx);
5764 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5768 public override SLE.Expression MakeExpression (BuilderContext ctx)
5771 return base.MakeExpression (ctx);
5773 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5777 void Error_PropertyNotValid (ResolveContext ec)
5779 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5780 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5781 GetSignatureForError ());
5784 bool IsSingleDimensionalArrayLength ()
5786 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5789 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5790 return ac != null && ac.Rank == 1;
5793 public override void Emit (EmitContext ec, bool leave_copy)
5796 // Special case: length of single dimension array property is turned into ldlen
5798 if (IsSingleDimensionalArrayLength ()) {
5799 EmitInstance (ec, false);
5800 ec.Emit (OpCodes.Ldlen);
5801 ec.Emit (OpCodes.Conv_I4);
5805 base.Emit (ec, leave_copy);
5808 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5811 LocalTemporary await_source_arg = null;
5813 if (isCompound && !(source is DynamicExpressionStatement)) {
5814 emitting_compound_assignment = true;
5817 if (has_await_arguments) {
5818 await_source_arg = new LocalTemporary (Type);
5819 await_source_arg.Store (ec);
5821 args = new Arguments (1);
5822 args.Add (new Argument (await_source_arg));
5825 temp = await_source_arg;
5828 has_await_arguments = false;
5833 ec.Emit (OpCodes.Dup);
5834 temp = new LocalTemporary (this.Type);
5839 args = new Arguments (1);
5843 temp = new LocalTemporary (this.Type);
5845 args.Add (new Argument (temp));
5847 args.Add (new Argument (source));
5851 emitting_compound_assignment = false;
5853 var call = new CallEmitter ();
5854 call.InstanceExpression = InstanceExpression;
5856 call.InstanceExpressionOnStack = true;
5858 call.Emit (ec, Setter, args, loc);
5865 if (await_source_arg != null) {
5866 await_source_arg.Release (ec);
5870 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5872 eclass = ExprClass.PropertyAccess;
5874 if (best_candidate.IsNotCSharpCompatible) {
5875 Error_PropertyNotValid (rc);
5878 ResolveInstanceExpression (rc, right_side);
5880 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5881 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5882 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5884 type = p.MemberType;
5888 DoBestMemberChecks (rc, best_candidate);
5892 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5894 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5898 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5900 // getter and setter can be different for base calls
5901 MethodSpec getter, setter;
5902 protected T best_candidate;
5904 protected LocalTemporary temp;
5905 protected bool emitting_compound_assignment;
5906 protected bool has_await_arguments;
5908 protected PropertyOrIndexerExpr (Location l)
5915 protected abstract Arguments Arguments { get; set; }
5917 public MethodSpec Getter {
5926 public MethodSpec Setter {
5937 protected override Expression DoResolve (ResolveContext ec)
5939 if (eclass == ExprClass.Unresolved) {
5940 var expr = OverloadResolve (ec, null);
5945 return expr.Resolve (ec);
5948 if (!ResolveGetter (ec))
5954 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5956 if (right_side == EmptyExpression.OutAccess) {
5957 // TODO: best_candidate can be null at this point
5958 INamedBlockVariable variable = null;
5959 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5960 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5961 best_candidate.Name);
5963 right_side.DoResolveLValue (ec, this);
5968 // if the property/indexer returns a value type, and we try to set a field in it
5969 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5970 Error_ValueAssignment (ec, right_side);
5973 if (eclass == ExprClass.Unresolved) {
5974 var expr = OverloadResolve (ec, right_side);
5979 return expr.ResolveLValue (ec, right_side);
5982 if (!ResolveSetter (ec))
5989 // Implements the IAssignMethod interface for assignments
5991 public virtual void Emit (EmitContext ec, bool leave_copy)
5993 var call = new CallEmitter ();
5994 call.InstanceExpression = InstanceExpression;
5995 if (has_await_arguments)
5996 call.HasAwaitArguments = true;
5998 call.DuplicateArguments = emitting_compound_assignment;
6000 call.Emit (ec, Getter, Arguments, loc);
6002 if (call.HasAwaitArguments) {
6003 InstanceExpression = call.InstanceExpression;
6004 Arguments = call.EmittedArguments;
6005 has_await_arguments = true;
6009 ec.Emit (OpCodes.Dup);
6010 temp = new LocalTemporary (Type);
6015 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6017 public override void Emit (EmitContext ec)
6022 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6024 has_await_arguments = true;
6029 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6031 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6033 bool ResolveGetter (ResolveContext rc)
6035 if (!best_candidate.HasGet) {
6036 if (InstanceExpression != EmptyExpression.Null) {
6037 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6038 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6039 best_candidate.GetSignatureForError ());
6042 } else if (!best_candidate.Get.IsAccessible (rc)) {
6043 if (best_candidate.HasDifferentAccessibility) {
6044 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6045 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6046 TypeManager.CSharpSignature (best_candidate));
6048 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6049 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6053 if (best_candidate.HasDifferentAccessibility) {
6054 CheckProtectedMemberAccess (rc, best_candidate.Get);
6057 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6061 bool ResolveSetter (ResolveContext rc)
6063 if (!best_candidate.HasSet) {
6064 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6065 GetSignatureForError ());
6069 if (!best_candidate.Set.IsAccessible (rc)) {
6070 if (best_candidate.HasDifferentAccessibility) {
6071 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6072 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6073 GetSignatureForError ());
6075 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6076 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6080 if (best_candidate.HasDifferentAccessibility)
6081 CheckProtectedMemberAccess (rc, best_candidate.Set);
6083 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6089 /// Fully resolved expression that evaluates to an Event
6091 public class EventExpr : MemberExpr, IAssignMethod
6093 readonly EventSpec spec;
6096 public EventExpr (EventSpec spec, Location loc)
6104 protected override TypeSpec DeclaringType {
6106 return spec.DeclaringType;
6110 public override string Name {
6116 public override bool IsInstance {
6118 return !spec.IsStatic;
6122 public override bool IsStatic {
6124 return spec.IsStatic;
6128 public override string KindName {
6129 get { return "event"; }
6132 public MethodSpec Operator {
6140 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6143 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6145 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6146 if (spec.BackingField != null &&
6147 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6149 spec.MemberDefinition.SetIsUsed ();
6151 if (!ec.IsObsolete) {
6152 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6154 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6157 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6158 Error_AssignmentEventOnly (ec);
6160 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6162 InstanceExpression = null;
6164 return ml.ResolveMemberAccess (ec, left, original);
6168 return base.ResolveMemberAccess (ec, left, original);
6171 public override Expression CreateExpressionTree (ResolveContext ec)
6173 throw new NotSupportedException ("ET");
6176 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6178 if (right_side == EmptyExpression.EventAddition) {
6179 op = spec.AccessorAdd;
6180 } else if (right_side == EmptyExpression.EventSubtraction) {
6181 op = spec.AccessorRemove;
6185 Error_AssignmentEventOnly (ec);
6189 op = CandidateToBaseOverride (ec, op);
6193 protected override Expression DoResolve (ResolveContext ec)
6195 eclass = ExprClass.EventAccess;
6196 type = spec.MemberType;
6198 ResolveInstanceExpression (ec, null);
6200 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6201 Error_AssignmentEventOnly (ec);
6204 DoBestMemberChecks (ec, spec);
6208 public override void Emit (EmitContext ec)
6210 throw new NotSupportedException ();
6211 //Error_CannotAssign ();
6214 #region IAssignMethod Members
6216 public void Emit (EmitContext ec, bool leave_copy)
6218 throw new NotImplementedException ();
6221 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6223 if (leave_copy || !isCompound)
6224 throw new NotImplementedException ("EventExpr::EmitAssign");
6226 Arguments args = new Arguments (1);
6227 args.Add (new Argument (source));
6229 var call = new CallEmitter ();
6230 call.InstanceExpression = InstanceExpression;
6231 call.Emit (ec, op, args, loc);
6236 void Error_AssignmentEventOnly (ResolveContext ec)
6238 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6239 ec.Report.Error (79, loc,
6240 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6241 GetSignatureForError ());
6243 ec.Report.Error (70, loc,
6244 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6245 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6249 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6251 name = name.Substring (0, name.LastIndexOf ('.'));
6252 base.Error_CannotCallAbstractBase (rc, name);
6255 public override string GetSignatureForError ()
6257 return TypeManager.CSharpSignature (spec);
6260 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6262 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6266 public class TemporaryVariableReference : VariableReference
6268 public class Declarator : Statement
6270 TemporaryVariableReference variable;
6272 public Declarator (TemporaryVariableReference variable)
6274 this.variable = variable;
6278 protected override void DoEmit (EmitContext ec)
6280 variable.li.CreateBuilder (ec);
6283 public override void Emit (EmitContext ec)
6285 // Don't create sequence point
6289 protected override void CloneTo (CloneContext clonectx, Statement target)
6297 public TemporaryVariableReference (LocalVariable li, Location loc)
6300 this.type = li.Type;
6304 public override bool IsLockedByStatement {
6312 public LocalVariable LocalInfo {
6318 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6320 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6321 return new TemporaryVariableReference (li, loc);
6324 protected override Expression DoResolve (ResolveContext ec)
6326 eclass = ExprClass.Variable;
6329 // Don't capture temporary variables except when using
6330 // state machine redirection and block yields
6332 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator &&
6333 ec.CurrentBlock.Explicit.HasYield && ec.IsVariableCapturingRequired) {
6334 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6335 storey.CaptureLocalVariable (ec, li);
6341 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6343 return Resolve (ec);
6346 public override void Emit (EmitContext ec)
6348 li.CreateBuilder (ec);
6353 public void EmitAssign (EmitContext ec, Expression source)
6355 li.CreateBuilder (ec);
6357 EmitAssign (ec, source, false, false);
6360 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6362 return li.HoistedVariant;
6365 public override bool IsFixed {
6366 get { return true; }
6369 public override bool IsRef {
6370 get { return false; }
6373 public override string Name {
6374 get { throw new NotImplementedException (); }
6377 public override void SetHasAddressTaken ()
6379 throw new NotImplementedException ();
6382 protected override ILocalVariable Variable {
6386 public override VariableInfo VariableInfo {
6387 get { return null; }
6390 public override void VerifyAssigned (ResolveContext rc)
6396 /// Handles `var' contextual keyword; var becomes a keyword only
6397 /// if no type called var exists in a variable scope
6399 class VarExpr : SimpleName
6401 public VarExpr (Location loc)
6406 public bool InferType (ResolveContext ec, Expression right_side)
6409 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6411 type = right_side.Type;
6412 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6413 ec.Report.Error (815, loc,
6414 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6415 type.GetSignatureForError ());
6419 eclass = ExprClass.Variable;
6423 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6425 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6426 base.Error_TypeOrNamespaceNotFound (ec);
6428 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");