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; }
122 /// Base class for expressions
124 public abstract class Expression {
125 public ExprClass eclass;
126 protected TypeSpec type;
127 protected Location loc;
129 public TypeSpec Type {
131 set { type = value; }
134 public virtual bool IsSideEffectFree {
140 public Location Location {
144 public virtual bool IsNull {
151 // Returns true when the expression during Emit phase breaks stack
152 // by using await expression
154 public virtual bool ContainsEmitWithAwait ()
160 /// Performs semantic analysis on the Expression
164 /// The Resolve method is invoked to perform the semantic analysis
167 /// The return value is an expression (it can be the
168 /// same expression in some cases) or a new
169 /// expression that better represents this node.
171 /// For example, optimizations of Unary (LiteralInt)
172 /// would return a new LiteralInt with a negated
175 /// If there is an error during semantic analysis,
176 /// then an error should be reported (using Report)
177 /// and a null value should be returned.
179 /// There are two side effects expected from calling
180 /// Resolve(): the the field variable "eclass" should
181 /// be set to any value of the enumeration
182 /// `ExprClass' and the type variable should be set
183 /// to a valid type (this is the type of the
186 protected abstract Expression DoResolve (ResolveContext rc);
188 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
194 // This is used if the expression should be resolved as a type or namespace name.
195 // the default implementation fails.
197 public virtual TypeSpec ResolveAsType (IMemberContext mc)
199 ResolveContext ec = new ResolveContext (mc);
200 Expression e = Resolve (ec);
202 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
207 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
209 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
212 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
214 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
217 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
219 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
220 name, TypeManager.CSharpName (type));
223 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
225 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
226 "expressions can be used as a statement");
229 public void Error_InvalidExpressionStatement (BlockContext ec)
231 Error_InvalidExpressionStatement (ec.Report, loc);
234 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
236 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
239 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
241 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
244 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
246 // The error was already reported as CS1660
247 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
250 string from_type = type.GetSignatureForError ();
251 string to_type = target.GetSignatureForError ();
252 if (from_type == to_type) {
253 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
254 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
258 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
263 ec.Report.DisableReporting ();
264 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
265 ec.Report.EnableReporting ();
268 ec.Report.Error (266, loc,
269 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
272 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
277 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
279 // Better message for possible generic expressions
280 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
281 var report = context.Module.Compiler.Report;
282 report.SymbolRelatedToPreviousError (member);
283 if (member is TypeSpec)
284 member = ((TypeSpec) member).GetDefinition ();
286 member = ((MethodSpec) member).GetGenericMethodDefinition ();
288 string name = member.Kind == MemberKind.Method ? "method" : "type";
289 if (member.IsGeneric) {
290 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
291 name, member.GetSignatureForError (), member.Arity.ToString ());
293 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
294 name, member.GetSignatureForError ());
297 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
301 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
303 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
307 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
309 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
312 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
314 ec.Report.SymbolRelatedToPreviousError (type);
315 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
316 TypeManager.CSharpName (type), name);
319 public void Error_ValueAssignment (ResolveContext rc, Expression rhs)
321 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
322 rc.Report.SymbolRelatedToPreviousError (type);
323 if (rc.CurrentInitializerVariable != null) {
324 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
325 type.GetSignatureForError (), GetSignatureForError ());
327 rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
328 GetSignatureForError ());
331 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
335 protected void Error_VoidPointerOperation (ResolveContext rc)
337 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
340 public ResolveFlags ExprClassToResolveFlags {
344 case ExprClass.Namespace:
345 return ResolveFlags.Type;
347 case ExprClass.MethodGroup:
348 return ResolveFlags.MethodGroup;
350 case ExprClass.TypeParameter:
351 return ResolveFlags.TypeParameter;
353 case ExprClass.Value:
354 case ExprClass.Variable:
355 case ExprClass.PropertyAccess:
356 case ExprClass.EventAccess:
357 case ExprClass.IndexerAccess:
358 return ResolveFlags.VariableOrValue;
361 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
366 public virtual string GetSignatureForError ()
368 return type.GetDefinition ().GetSignatureForError ();
372 /// Resolves an expression and performs semantic analysis on it.
376 /// Currently Resolve wraps DoResolve to perform sanity
377 /// checking and assertion checking on what we expect from Resolve.
379 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
381 if (eclass != ExprClass.Unresolved)
391 if ((flags & e.ExprClassToResolveFlags) == 0) {
392 e.Error_UnexpectedKind (ec, flags, loc);
397 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
400 } catch (Exception ex) {
401 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
404 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
405 return ErrorExpression.Instance; // TODO: Add location
410 /// Resolves an expression and performs semantic analysis on it.
412 public Expression Resolve (ResolveContext rc)
414 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
418 /// Resolves an expression for LValue assignment
422 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
423 /// checking and assertion checking on what we expect from Resolve
425 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
427 int errors = ec.Report.Errors;
428 bool out_access = right_side == EmptyExpression.OutAccess;
430 Expression e = DoResolveLValue (ec, right_side);
432 if (e != null && out_access && !(e is IMemoryLocation)) {
433 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
434 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
436 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
437 // e.GetType () + " " + e.GetSignatureForError ());
442 if (errors == ec.Report.Errors) {
444 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
446 Error_ValueAssignment (ec, right_side);
451 if (e.eclass == ExprClass.Unresolved)
452 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
454 if ((e.type == null) && !(e is GenericTypeExpr))
455 throw new Exception ("Expression " + e + " did not set its type after Resolve");
460 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
462 rc.Module.Compiler.Report.Error (182, loc,
463 "An attribute argument must be a constant expression, typeof expression or array creation expression");
467 /// Emits the code for the expression
471 /// The Emit method is invoked to generate the code
472 /// for the expression.
474 public abstract void Emit (EmitContext ec);
477 // Emit code to branch to @target if this expression is equivalent to @on_true.
478 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
479 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
480 // including the use of conditional branches. Note also that a branch MUST be emitted
481 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
484 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
487 // Emit this expression for its side effects, not for its value.
488 // The default implementation is to emit the value, and then throw it away.
489 // Subclasses can provide more efficient implementations, but those MUST be equivalent
490 public virtual void EmitSideEffect (EmitContext ec)
493 ec.Emit (OpCodes.Pop);
497 // Emits the expression into temporary field variable. The method
498 // should be used for await expressions only
500 public virtual Expression EmitToField (EmitContext ec)
503 // This is the await prepare Emit method. When emitting code like
504 // a + b we emit code like
510 // For await a + await b we have to interfere the flow to keep the
511 // stack clean because await yields from the expression. The emit
514 // a = a.EmitToField () // a is changed to temporary field access
515 // b = b.EmitToField ()
521 // The idea is to emit expression and leave the stack empty with
522 // result value still available.
524 // Expressions should override this default implementation when
525 // optimized version can be provided (e.g. FieldExpr)
528 // We can optimize for side-effect free expressions, they can be
529 // emitted out of order
531 if (IsSideEffectFree)
534 bool needs_temporary = ContainsEmitWithAwait ();
535 if (!needs_temporary)
538 // Emit original code
539 EmitToFieldSource (ec);
542 // Store the result to temporary field when we
543 // cannot load `this' directly
545 var field = ec.GetTemporaryField (type);
546 if (needs_temporary) {
548 // Create temporary local (we cannot load `this' before Emit)
550 var temp = ec.GetTemporaryLocal (type);
551 ec.Emit (OpCodes.Stloc, temp);
554 ec.Emit (OpCodes.Ldloc, temp);
555 field.EmitAssignFromStack (ec);
557 ec.FreeTemporaryLocal (temp, type);
559 field.EmitAssignFromStack (ec);
565 protected virtual void EmitToFieldSource (EmitContext ec)
568 // Default implementation calls Emit method
573 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
575 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
576 bool contains_await = false;
578 for (int i = 1; i < expressions.Count; ++i) {
579 if (expressions[i].ContainsEmitWithAwait ()) {
580 contains_await = true;
585 if (contains_await) {
586 for (int i = 0; i < expressions.Count; ++i) {
587 expressions[i] = expressions[i].EmitToField (ec);
592 for (int i = 0; i < expressions.Count; ++i) {
593 expressions[i].Emit (ec);
598 /// Protected constructor. Only derivate types should
599 /// be able to be created
602 protected Expression ()
607 /// Returns a fully formed expression after a MemberLookup
610 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
612 if (spec is EventSpec)
613 return new EventExpr ((EventSpec) spec, loc);
614 if (spec is ConstSpec)
615 return new ConstantExpr ((ConstSpec) spec, loc);
616 if (spec is FieldSpec)
617 return new FieldExpr ((FieldSpec) spec, loc);
618 if (spec is PropertySpec)
619 return new PropertyExpr ((PropertySpec) spec, loc);
620 if (spec is TypeSpec)
621 return new TypeExpression (((TypeSpec) spec), loc);
626 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
628 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
630 rc.Report.SymbolRelatedToPreviousError (type);
632 // Report meaningful error for struct as they always have default ctor in C# context
633 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
635 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
636 type.GetSignatureForError ());
642 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
643 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
644 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
647 return r.ResolveMember<MethodSpec> (rc, ref args);
651 public enum MemberLookupRestrictions
660 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
661 // `qualifier_type' or null to lookup members in the current class.
663 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
665 var members = MemberCache.FindMembers (queried_type, name, false);
669 MemberSpec non_method = null;
670 MemberSpec ambig_non_method = null;
672 for (int i = 0; i < members.Count; ++i) {
673 var member = members[i];
675 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
676 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
679 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
682 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
686 if (!member.IsAccessible (rc))
690 // With runtime binder we can have a situation where queried type is inaccessible
691 // because it came via dynamic object, the check about inconsisted accessibility
692 // had no effect as the type was unknown during compilation
695 // private class N { }
697 // public dynamic Foo ()
703 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
707 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
708 if (member is MethodSpec)
709 return new MethodGroupExpr (members, queried_type, loc);
711 if (!Invocation.IsMemberInvocable (member))
715 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
717 } else if (!errorMode && !member.IsNotCSharpCompatible) {
718 ambig_non_method = member;
722 if (non_method != null) {
723 if (ambig_non_method != null && rc != null) {
724 var report = rc.Module.Compiler.Report;
725 report.SymbolRelatedToPreviousError (non_method);
726 report.SymbolRelatedToPreviousError (ambig_non_method);
727 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
728 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
731 if (non_method is MethodSpec)
732 return new MethodGroupExpr (members, queried_type, loc);
734 return ExprClassFromMemberInfo (non_method, loc);
737 if (members[0].DeclaringType.BaseType == null)
740 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
742 } while (members != null);
747 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
749 throw new NotImplementedException ();
752 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
754 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
755 oper, t.GetSignatureForError ());
758 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
760 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
764 /// Returns an expression that can be used to invoke operator true
765 /// on the expression if it exists.
767 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
769 return GetOperatorTrueOrFalse (ec, e, true, loc);
773 /// Returns an expression that can be used to invoke operator false
774 /// on the expression if it exists.
776 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
778 return GetOperatorTrueOrFalse (ec, e, false, loc);
781 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
783 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
784 var methods = MemberCache.GetUserOperator (e.type, op, false);
788 Arguments arguments = new Arguments (1);
789 arguments.Add (new Argument (e));
791 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
792 var oper = res.ResolveOperator (ec, ref arguments);
797 return new UserOperatorCall (oper, arguments, null, loc);
800 public virtual string ExprClassName
804 case ExprClass.Unresolved:
806 case ExprClass.Value:
808 case ExprClass.Variable:
810 case ExprClass.Namespace:
814 case ExprClass.MethodGroup:
815 return "method group";
816 case ExprClass.PropertyAccess:
817 return "property access";
818 case ExprClass.EventAccess:
819 return "event access";
820 case ExprClass.IndexerAccess:
821 return "indexer access";
822 case ExprClass.Nothing:
824 case ExprClass.TypeParameter:
825 return "type parameter";
827 throw new Exception ("Should not happen");
832 /// Reports that we were expecting `expr' to be of class `expected'
834 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
836 var name = memberExpr.GetSignatureForError ();
838 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
841 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
843 string [] valid = new string [4];
846 if ((flags & ResolveFlags.VariableOrValue) != 0) {
847 valid [count++] = "variable";
848 valid [count++] = "value";
851 if ((flags & ResolveFlags.Type) != 0)
852 valid [count++] = "type";
854 if ((flags & ResolveFlags.MethodGroup) != 0)
855 valid [count++] = "method group";
858 valid [count++] = "unknown";
860 StringBuilder sb = new StringBuilder (valid [0]);
861 for (int i = 1; i < count - 1; i++) {
863 sb.Append (valid [i]);
866 sb.Append ("' or `");
867 sb.Append (valid [count - 1]);
870 ec.Report.Error (119, loc,
871 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
874 public static void UnsafeError (ResolveContext ec, Location loc)
876 UnsafeError (ec.Report, loc);
879 public static void UnsafeError (Report Report, Location loc)
881 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
885 // Converts `source' to an int, uint, long or ulong.
887 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
889 var btypes = ec.BuiltinTypes;
891 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
892 Arguments args = new Arguments (1);
893 args.Add (new Argument (source));
894 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
897 Expression converted;
899 using (ec.Set (ResolveContext.Options.CheckedScope)) {
900 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
901 if (converted == null)
902 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
903 if (converted == null)
904 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
905 if (converted == null)
906 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
908 if (converted == null) {
909 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
915 // Only positive constants are allowed at compile time
917 Constant c = converted as Constant;
918 if (c != null && c.IsNegative)
919 Error_NegativeArrayIndex (ec, source.loc);
921 // No conversion needed to array index
922 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
925 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
929 // Derived classes implement this method by cloning the fields that
930 // could become altered during the Resolve stage
932 // Only expressions that are created for the parser need to implement
935 protected virtual void CloneTo (CloneContext clonectx, Expression target)
937 throw new NotImplementedException (
939 "CloneTo not implemented for expression {0}", this.GetType ()));
943 // Clones an expression created by the parser.
945 // We only support expressions created by the parser so far, not
946 // expressions that have been resolved (many more classes would need
947 // to implement CloneTo).
949 // This infrastructure is here merely for Lambda expressions which
950 // compile the same code using different type values for the same
951 // arguments to find the correct overload
953 public virtual Expression Clone (CloneContext clonectx)
955 Expression cloned = (Expression) MemberwiseClone ();
956 CloneTo (clonectx, cloned);
962 // Implementation of expression to expression tree conversion
964 public abstract Expression CreateExpressionTree (ResolveContext ec);
966 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
968 return CreateExpressionFactoryCall (ec, name, null, args, loc);
971 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
973 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
976 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
978 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
981 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
983 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
987 return new TypeExpression (t, loc);
991 // Implemented by all expressions which support conversion from
992 // compiler expression to invokable runtime expression. Used by
993 // dynamic C# binder.
995 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
997 throw new NotImplementedException ("MakeExpression for " + GetType ());
1000 public virtual object Accept (StructuralVisitor visitor)
1002 return visitor.Visit (this);
1007 /// This is just a base class for expressions that can
1008 /// appear on statements (invocations, object creation,
1009 /// assignments, post/pre increment and decrement). The idea
1010 /// being that they would support an extra Emition interface that
1011 /// does not leave a result on the stack.
1013 public abstract class ExpressionStatement : Expression {
1015 public ExpressionStatement ResolveStatement (BlockContext ec)
1017 Expression e = Resolve (ec);
1021 ExpressionStatement es = e as ExpressionStatement;
1023 Error_InvalidExpressionStatement (ec);
1029 /// Requests the expression to be emitted in a `statement'
1030 /// context. This means that no new value is left on the
1031 /// stack after invoking this method (constrasted with
1032 /// Emit that will always leave a value on the stack).
1034 public abstract void EmitStatement (EmitContext ec);
1036 public override void EmitSideEffect (EmitContext ec)
1043 /// This kind of cast is used to encapsulate the child
1044 /// whose type is child.Type into an expression that is
1045 /// reported to return "return_type". This is used to encapsulate
1046 /// expressions which have compatible types, but need to be dealt
1047 /// at higher levels with.
1049 /// For example, a "byte" expression could be encapsulated in one
1050 /// of these as an "unsigned int". The type for the expression
1051 /// would be "unsigned int".
1054 public abstract class TypeCast : Expression
1056 protected readonly Expression child;
1058 protected TypeCast (Expression child, TypeSpec return_type)
1060 eclass = child.eclass;
1061 loc = child.Location;
1066 public Expression Child {
1072 public override bool ContainsEmitWithAwait ()
1074 return child.ContainsEmitWithAwait ();
1077 public override Expression CreateExpressionTree (ResolveContext ec)
1079 Arguments args = new Arguments (2);
1080 args.Add (new Argument (child.CreateExpressionTree (ec)));
1081 args.Add (new Argument (new TypeOf (type, loc)));
1083 if (type.IsPointer || child.Type.IsPointer)
1084 Error_PointerInsideExpressionTree (ec);
1086 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1089 protected override Expression DoResolve (ResolveContext ec)
1091 // This should never be invoked, we are born in fully
1092 // initialized state.
1097 public override void Emit (EmitContext ec)
1102 public override SLE.Expression MakeExpression (BuilderContext ctx)
1105 return base.MakeExpression (ctx);
1107 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1108 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1109 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1113 protected override void CloneTo (CloneContext clonectx, Expression t)
1118 public override bool IsNull {
1119 get { return child.IsNull; }
1123 public class EmptyCast : TypeCast {
1124 EmptyCast (Expression child, TypeSpec target_type)
1125 : base (child, target_type)
1129 public static Expression Create (Expression child, TypeSpec type)
1131 Constant c = child as Constant;
1133 return new EmptyConstantCast (c, type);
1135 EmptyCast e = child as EmptyCast;
1137 return new EmptyCast (e.child, type);
1139 return new EmptyCast (child, type);
1142 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1144 child.EmitBranchable (ec, label, on_true);
1147 public override void EmitSideEffect (EmitContext ec)
1149 child.EmitSideEffect (ec);
1154 // Used for predefined type user operator (no obsolete check, etc.)
1156 public class OperatorCast : TypeCast
1158 readonly MethodSpec conversion_operator;
1160 public OperatorCast (Expression expr, TypeSpec target_type)
1161 : this (expr, target_type, target_type, false)
1165 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1166 : this (expr, target_type, target_type, find_explicit)
1170 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1171 : base (expr, returnType)
1173 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1174 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1177 foreach (MethodSpec oper in mi) {
1178 if (oper.ReturnType != returnType)
1181 if (oper.Parameters.Types[0] == expr.Type) {
1182 conversion_operator = oper;
1188 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1189 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1192 public override void Emit (EmitContext ec)
1195 ec.Emit (OpCodes.Call, conversion_operator);
1200 // Constant specialization of EmptyCast.
1201 // We need to special case this since an empty cast of
1202 // a constant is still a constant.
1204 public class EmptyConstantCast : Constant
1206 public readonly Constant child;
1208 public EmptyConstantCast (Constant child, TypeSpec type)
1209 : base (child.Location)
1212 throw new ArgumentNullException ("child");
1215 this.eclass = child.eclass;
1219 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1221 if (child.Type == target_type)
1224 // FIXME: check that 'type' can be converted to 'target_type' first
1225 return child.ConvertExplicitly (in_checked_context, target_type);
1228 public override Expression CreateExpressionTree (ResolveContext ec)
1230 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1231 child.CreateExpressionTree (ec),
1232 new TypeOf (type, loc));
1235 Error_PointerInsideExpressionTree (ec);
1237 return CreateExpressionFactoryCall (ec, "Convert", args);
1240 public override bool IsDefaultValue {
1241 get { return child.IsDefaultValue; }
1244 public override bool IsNegative {
1245 get { return child.IsNegative; }
1248 public override bool IsNull {
1249 get { return child.IsNull; }
1252 public override bool IsOneInteger {
1253 get { return child.IsOneInteger; }
1256 public override bool IsSideEffectFree {
1258 return child.IsSideEffectFree;
1262 public override bool IsZeroInteger {
1263 get { return child.IsZeroInteger; }
1266 public override void Emit (EmitContext ec)
1271 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1273 child.EmitBranchable (ec, label, on_true);
1275 // Only to make verifier happy
1276 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1277 ec.Emit (OpCodes.Unbox_Any, type);
1280 public override void EmitSideEffect (EmitContext ec)
1282 child.EmitSideEffect (ec);
1285 public override object GetValue ()
1287 return child.GetValue ();
1290 public override string GetValueAsLiteral ()
1292 return child.GetValueAsLiteral ();
1295 public override long GetValueAsLong ()
1297 return child.GetValueAsLong ();
1300 public override Constant ConvertImplicitly (TypeSpec target_type)
1302 if (type == target_type)
1305 // FIXME: Do we need to check user conversions?
1306 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1309 return child.ConvertImplicitly (target_type);
1314 /// This class is used to wrap literals which belong inside Enums
1316 public class EnumConstant : Constant
1318 public Constant Child;
1320 public EnumConstant (Constant child, TypeSpec enum_type)
1321 : base (child.Location)
1325 this.eclass = ExprClass.Value;
1326 this.type = enum_type;
1329 protected EnumConstant (Location loc)
1334 public override void Emit (EmitContext ec)
1339 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1341 Child.EncodeAttributeValue (rc, enc, Child.Type);
1344 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1346 Child.EmitBranchable (ec, label, on_true);
1349 public override void EmitSideEffect (EmitContext ec)
1351 Child.EmitSideEffect (ec);
1354 public override string GetSignatureForError()
1356 return TypeManager.CSharpName (Type);
1359 public override object GetValue ()
1361 return Child.GetValue ();
1365 public override object GetTypedValue ()
1368 // The method can be used in dynamic context only (on closed types)
1370 // System.Enum.ToObject cannot be called on dynamic types
1371 // EnumBuilder has to be used, but we cannot use EnumBuilder
1372 // because it does not properly support generics
1374 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1378 public override string GetValueAsLiteral ()
1380 return Child.GetValueAsLiteral ();
1383 public override long GetValueAsLong ()
1385 return Child.GetValueAsLong ();
1388 public EnumConstant Increment()
1390 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1393 public override bool IsDefaultValue {
1395 return Child.IsDefaultValue;
1399 public override bool IsSideEffectFree {
1401 return Child.IsSideEffectFree;
1405 public override bool IsZeroInteger {
1406 get { return Child.IsZeroInteger; }
1409 public override bool IsNegative {
1411 return Child.IsNegative;
1415 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1417 if (Child.Type == target_type)
1420 return Child.ConvertExplicitly (in_checked_context, target_type);
1423 public override Constant ConvertImplicitly (TypeSpec type)
1425 if (this.type == type) {
1429 if (!Convert.ImplicitStandardConversionExists (this, type)){
1433 return Child.ConvertImplicitly (type);
1438 /// This kind of cast is used to encapsulate Value Types in objects.
1440 /// The effect of it is to box the value type emitted by the previous
1443 public class BoxedCast : TypeCast {
1445 public BoxedCast (Expression expr, TypeSpec target_type)
1446 : base (expr, target_type)
1448 eclass = ExprClass.Value;
1451 protected override Expression DoResolve (ResolveContext ec)
1453 // This should never be invoked, we are born in fully
1454 // initialized state.
1459 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1461 // Only boxing to object type is supported
1462 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1463 base.EncodeAttributeValue (rc, enc, targetType);
1467 enc.Encode (child.Type);
1468 child.EncodeAttributeValue (rc, enc, child.Type);
1471 public override void Emit (EmitContext ec)
1475 ec.Emit (OpCodes.Box, child.Type);
1478 public override void EmitSideEffect (EmitContext ec)
1480 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1481 // so, we need to emit the box+pop instructions in most cases
1482 if (child.Type.IsStruct &&
1483 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1484 child.EmitSideEffect (ec);
1486 base.EmitSideEffect (ec);
1490 public class UnboxCast : TypeCast {
1491 public UnboxCast (Expression expr, TypeSpec return_type)
1492 : base (expr, return_type)
1496 protected override Expression DoResolve (ResolveContext ec)
1498 // This should never be invoked, we are born in fully
1499 // initialized state.
1504 public override void Emit (EmitContext ec)
1508 ec.Emit (OpCodes.Unbox_Any, type);
1513 /// This is used to perform explicit numeric conversions.
1515 /// Explicit numeric conversions might trigger exceptions in a checked
1516 /// context, so they should generate the conv.ovf opcodes instead of
1519 public class ConvCast : TypeCast {
1520 public enum Mode : byte {
1521 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1523 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1524 U2_I1, U2_U1, U2_I2, U2_CH,
1525 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1526 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1527 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1528 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1529 CH_I1, CH_U1, CH_I2,
1530 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1531 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1537 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1538 : base (child, return_type)
1543 protected override Expression DoResolve (ResolveContext ec)
1545 // This should never be invoked, we are born in fully
1546 // initialized state.
1551 public override string ToString ()
1553 return String.Format ("ConvCast ({0}, {1})", mode, child);
1556 public override void Emit (EmitContext ec)
1560 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1562 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1563 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1564 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1565 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1566 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1568 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1569 case Mode.U1_CH: /* nothing */ break;
1571 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1572 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1573 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1574 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1575 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1576 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1578 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1579 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1580 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1581 case Mode.U2_CH: /* nothing */ break;
1583 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1584 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1585 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1586 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1587 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1588 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1589 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1591 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1592 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1593 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1594 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1595 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1596 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1598 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1599 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1600 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1601 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1602 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1603 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1604 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1605 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1608 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1609 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1610 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1611 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1612 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1613 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1614 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1615 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1616 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1618 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1619 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1620 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1622 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1623 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1624 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1625 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1626 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1627 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1628 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1629 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1630 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1632 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1633 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1634 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1635 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1637 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1638 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1639 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1640 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1641 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1643 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1647 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1648 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1649 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1650 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1651 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1653 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1654 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1656 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1657 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1658 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1659 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1660 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1661 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1663 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1664 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1665 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1666 case Mode.U2_CH: /* nothing */ break;
1668 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1670 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1671 case Mode.I4_U4: /* nothing */ break;
1672 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1673 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1674 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1677 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1678 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1679 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.U4_I4: /* nothing */ break;
1681 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1683 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1684 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1685 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1686 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1687 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1688 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1689 case Mode.I8_U8: /* nothing */ break;
1690 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1693 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1694 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1695 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1697 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1698 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1699 case Mode.U8_I8: /* nothing */ break;
1700 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1701 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1703 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1704 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1705 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1707 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1708 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1709 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1710 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1711 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1712 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1713 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1714 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1715 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1717 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1718 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1719 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1720 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1722 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1723 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1724 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1725 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1726 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1728 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1734 class OpcodeCast : TypeCast
1738 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1739 : base (child, return_type)
1744 protected override Expression DoResolve (ResolveContext ec)
1746 // This should never be invoked, we are born in fully
1747 // initialized state.
1752 public override void Emit (EmitContext ec)
1758 public TypeSpec UnderlyingType {
1759 get { return child.Type; }
1764 // Opcode casts expression with 2 opcodes but only
1765 // single expression tree node
1767 class OpcodeCastDuplex : OpcodeCast
1769 readonly OpCode second;
1771 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1772 : base (child, returnType, first)
1774 this.second = second;
1777 public override void Emit (EmitContext ec)
1785 /// This kind of cast is used to encapsulate a child and cast it
1786 /// to the class requested
1788 public sealed class ClassCast : TypeCast {
1789 readonly bool forced;
1791 public ClassCast (Expression child, TypeSpec return_type)
1792 : base (child, return_type)
1796 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1797 : base (child, return_type)
1799 this.forced = forced;
1802 public override void Emit (EmitContext ec)
1806 bool gen = TypeManager.IsGenericParameter (child.Type);
1808 ec.Emit (OpCodes.Box, child.Type);
1810 if (type.IsGenericParameter) {
1811 ec.Emit (OpCodes.Unbox_Any, type);
1818 ec.Emit (OpCodes.Castclass, type);
1823 // Created during resolving pahse when an expression is wrapped or constantified
1824 // and original expression can be used later (e.g. for expression trees)
1826 public class ReducedExpression : Expression
1828 sealed class ReducedConstantExpression : EmptyConstantCast
1830 readonly Expression orig_expr;
1832 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1833 : base (expr, expr.Type)
1835 this.orig_expr = orig_expr;
1838 public override Constant ConvertImplicitly (TypeSpec target_type)
1840 Constant c = base.ConvertImplicitly (target_type);
1842 c = new ReducedConstantExpression (c, orig_expr);
1847 public override Expression CreateExpressionTree (ResolveContext ec)
1849 return orig_expr.CreateExpressionTree (ec);
1852 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1854 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1856 c = new ReducedConstantExpression (c, orig_expr);
1860 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1863 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1865 if (orig_expr is Conditional)
1866 child.EncodeAttributeValue (rc, enc, targetType);
1868 base.EncodeAttributeValue (rc, enc, targetType);
1872 sealed class ReducedExpressionStatement : ExpressionStatement
1874 readonly Expression orig_expr;
1875 readonly ExpressionStatement stm;
1877 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1879 this.orig_expr = orig;
1881 this.eclass = stm.eclass;
1882 this.type = stm.Type;
1884 this.loc = orig.Location;
1887 public override bool ContainsEmitWithAwait ()
1889 return stm.ContainsEmitWithAwait ();
1892 public override Expression CreateExpressionTree (ResolveContext ec)
1894 return orig_expr.CreateExpressionTree (ec);
1897 protected override Expression DoResolve (ResolveContext ec)
1902 public override void Emit (EmitContext ec)
1907 public override void EmitStatement (EmitContext ec)
1909 stm.EmitStatement (ec);
1913 readonly Expression expr, orig_expr;
1915 private ReducedExpression (Expression expr, Expression orig_expr)
1918 this.eclass = expr.eclass;
1919 this.type = expr.Type;
1920 this.orig_expr = orig_expr;
1921 this.loc = orig_expr.Location;
1926 public Expression OriginalExpression {
1934 public override bool ContainsEmitWithAwait ()
1936 return expr.ContainsEmitWithAwait ();
1940 // Creates fully resolved expression switcher
1942 public static Constant Create (Constant expr, Expression original_expr)
1944 if (expr.eclass == ExprClass.Unresolved)
1945 throw new ArgumentException ("Unresolved expression");
1947 return new ReducedConstantExpression (expr, original_expr);
1950 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1952 return new ReducedExpressionStatement (s, orig);
1955 public static Expression Create (Expression expr, Expression original_expr)
1957 return Create (expr, original_expr, true);
1961 // Creates unresolved reduce expression. The original expression has to be
1962 // already resolved. Created expression is constant based based on `expr'
1963 // value unless canBeConstant is used
1965 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1967 if (canBeConstant) {
1968 Constant c = expr as Constant;
1970 return Create (c, original_expr);
1973 ExpressionStatement s = expr as ExpressionStatement;
1975 return Create (s, original_expr);
1977 if (expr.eclass == ExprClass.Unresolved)
1978 throw new ArgumentException ("Unresolved expression");
1980 return new ReducedExpression (expr, original_expr);
1983 public override Expression CreateExpressionTree (ResolveContext ec)
1985 return orig_expr.CreateExpressionTree (ec);
1988 protected override Expression DoResolve (ResolveContext ec)
1993 public override void Emit (EmitContext ec)
1998 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2000 expr.EmitBranchable (ec, target, on_true);
2003 public override SLE.Expression MakeExpression (BuilderContext ctx)
2005 return orig_expr.MakeExpression (ctx);
2010 // Standard composite pattern
2012 public abstract class CompositeExpression : Expression
2014 protected Expression expr;
2016 protected CompositeExpression (Expression expr)
2019 this.loc = expr.Location;
2022 public override bool ContainsEmitWithAwait ()
2024 return expr.ContainsEmitWithAwait ();
2027 public override Expression CreateExpressionTree (ResolveContext rc)
2029 return expr.CreateExpressionTree (rc);
2032 public Expression Child {
2033 get { return expr; }
2036 protected override Expression DoResolve (ResolveContext rc)
2038 expr = expr.Resolve (rc);
2041 eclass = expr.eclass;
2047 public override void Emit (EmitContext ec)
2052 public override bool IsNull {
2053 get { return expr.IsNull; }
2058 // Base of expressions used only to narrow resolve flow
2060 public abstract class ShimExpression : Expression
2062 protected Expression expr;
2064 protected ShimExpression (Expression expr)
2069 public Expression Expr {
2075 protected override void CloneTo (CloneContext clonectx, Expression t)
2080 ShimExpression target = (ShimExpression) t;
2081 target.expr = expr.Clone (clonectx);
2084 public override bool ContainsEmitWithAwait ()
2086 return expr.ContainsEmitWithAwait ();
2089 public override Expression CreateExpressionTree (ResolveContext ec)
2091 throw new NotSupportedException ("ET");
2094 public override void Emit (EmitContext ec)
2096 throw new InternalErrorException ("Missing Resolve call");
2102 // Unresolved type name expressions
2104 public abstract class ATypeNameExpression : FullNamedExpression
2107 protected TypeArguments targs;
2109 protected ATypeNameExpression (string name, Location l)
2115 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2122 protected ATypeNameExpression (string name, int arity, Location l)
2123 : this (name, new UnboundTypeArguments (arity), l)
2129 protected int Arity {
2131 return targs == null ? 0 : targs.Count;
2135 public bool HasTypeArguments {
2137 return targs != null && !targs.IsEmpty;
2141 public string Name {
2150 public TypeArguments TypeArguments {
2158 public override bool Equals (object obj)
2160 ATypeNameExpression atne = obj as ATypeNameExpression;
2161 return atne != null && atne.Name == Name &&
2162 (targs == null || targs.Equals (atne.targs));
2165 public override int GetHashCode ()
2167 return Name.GetHashCode ();
2170 // TODO: Move it to MemberCore
2171 public static string GetMemberType (MemberCore mc)
2177 if (mc is FieldBase)
2179 if (mc is MethodCore)
2181 if (mc is EnumMember)
2189 public override string GetSignatureForError ()
2191 if (targs != null) {
2192 return Name + "<" + targs.GetSignatureForError () + ">";
2198 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2202 /// SimpleName expressions are formed of a single word and only happen at the beginning
2203 /// of a dotted-name.
2205 public class SimpleName : ATypeNameExpression
2207 public SimpleName (string name, Location l)
2212 public SimpleName (string name, TypeArguments args, Location l)
2213 : base (name, args, l)
2217 public SimpleName (string name, int arity, Location l)
2218 : base (name, arity, l)
2222 public SimpleName GetMethodGroup ()
2224 return new SimpleName (Name, targs, loc);
2227 protected override Expression DoResolve (ResolveContext rc)
2229 var e = SimpleNameResolve (rc, null, false);
2231 var fe = e as FieldExpr;
2233 fe.VerifyAssignedStructField (rc, null);
2239 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2241 return SimpleNameResolve (ec, right_side, false);
2244 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2246 if (ctx.CurrentType != null) {
2247 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2248 if (member != null) {
2249 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2254 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2255 if (retval != null) {
2256 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2257 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2261 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2262 if (retval != null) {
2263 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2267 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2270 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2272 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2275 if (fne.Type != null && Arity > 0) {
2276 if (HasTypeArguments) {
2277 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2278 if (ct.ResolveAsType (ec) == null)
2284 return new GenericOpenTypeExpr (fne.Type, loc);
2288 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2290 if (!(fne is Namespace))
2294 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2295 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2296 ec.Module.Compiler.Report.Error (1980, Location,
2297 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2298 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2301 fne = new DynamicTypeExpr (loc);
2302 fne.ResolveAsType (ec);
2308 Error_TypeOrNamespaceNotFound (ec);
2312 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2314 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2317 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2319 int lookup_arity = Arity;
2320 bool errorMode = false;
2322 Block current_block = rc.CurrentBlock;
2323 INamedBlockVariable variable = null;
2324 bool variable_found = false;
2328 // Stage 1: binding to local variables or parameters
2330 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2332 if (current_block != null && lookup_arity == 0) {
2333 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2334 if (!variable.IsDeclared) {
2335 // We found local name in accessible block but it's not
2336 // initialized yet, maybe the user wanted to bind to something else
2338 variable_found = true;
2340 e = variable.CreateReferenceExpression (rc, loc);
2343 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2352 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2354 TypeSpec member_type = rc.CurrentType;
2355 for (; member_type != null; member_type = member_type.DeclaringType) {
2356 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2360 var me = e as MemberExpr;
2362 // The name matches a type, defer to ResolveAsTypeStep
2370 if (variable != null) {
2371 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2372 rc.Report.Error (844, loc,
2373 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2374 Name, me.GetSignatureForError ());
2378 } else if (me is MethodGroupExpr) {
2379 // Leave it to overload resolution to report correct error
2381 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2382 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2385 // LAMESPEC: again, ignores InvocableOnly
2386 if (variable != null) {
2387 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2388 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2392 // MemberLookup does not check accessors availability, this is actually needed for properties only
2394 var pe = me as PropertyExpr;
2397 // Break as there is no other overload available anyway
2398 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2399 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2402 pe.Getter = pe.PropertyInfo.Get;
2404 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2407 pe.Setter = pe.PropertyInfo.Set;
2412 // TODO: It's used by EventExpr -> FieldExpr transformation only
2413 // TODO: Should go to MemberAccess
2414 me = me.ResolveMemberAccess (rc, null, null);
2418 me.SetTypeArguments (rc, targs);
2425 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2427 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2428 if (IsPossibleTypeOrNamespace (rc)) {
2429 if (variable != null) {
2430 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2431 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2434 return ResolveAsTypeOrNamespace (rc);
2439 if (variable_found) {
2440 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2443 var tparams = rc.CurrentTypeParameters;
2444 if (tparams != null) {
2445 if (tparams.Find (Name) != null) {
2446 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2451 var ct = rc.CurrentType;
2453 if (ct.MemberDefinition.TypeParametersCount > 0) {
2454 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2455 if (ctp.Name == Name) {
2456 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2462 ct = ct.DeclaringType;
2463 } while (ct != null);
2466 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2467 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2469 rc.Report.SymbolRelatedToPreviousError (e.Type);
2470 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2475 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2477 if (e.Type.Arity != Arity) {
2478 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2482 if (e is TypeExpr) {
2483 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2488 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2491 return ErrorExpression.Instance;
2494 if (rc.Module.Evaluator != null) {
2495 var fi = rc.Module.Evaluator.LookupField (Name);
2497 return new FieldExpr (fi.Item1, loc);
2505 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2507 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2512 if (right_side != null) {
2513 if (e is TypeExpr) {
2514 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2518 e = e.ResolveLValue (ec, right_side);
2523 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2527 public override object Accept (StructuralVisitor visitor)
2529 return visitor.Visit (this);
2534 /// Represents a namespace or a type. The name of the class was inspired by
2535 /// section 10.8.1 (Fully Qualified Names).
2537 public abstract class FullNamedExpression : Expression
2539 protected override void CloneTo (CloneContext clonectx, Expression target)
2541 // Do nothing, most unresolved type expressions cannot be
2542 // resolved to different type
2545 public override bool ContainsEmitWithAwait ()
2550 public override Expression CreateExpressionTree (ResolveContext ec)
2552 throw new NotSupportedException ("ET");
2555 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2558 // This is used to resolve the expression as a type, a null
2559 // value will be returned if the expression is not a type
2562 public override TypeSpec ResolveAsType (IMemberContext mc)
2564 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2569 TypeExpr te = fne as TypeExpr;
2571 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2579 var dep = type.GetMissingDependencies ();
2581 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2584 if (type.Kind == MemberKind.Void) {
2585 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2589 // Obsolete checks cannot be done when resolving base context as they
2590 // require type dependencies to be set but we are in process of resolving them
2592 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2593 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2594 if (obsolete_attr != null && !mc.IsObsolete) {
2595 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2603 public override void Emit (EmitContext ec)
2605 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2606 GetSignatureForError ());
2611 /// Expression that evaluates to a type
2613 public abstract class TypeExpr : FullNamedExpression
2615 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2621 protected sealed override Expression DoResolve (ResolveContext ec)
2627 public override bool Equals (object obj)
2629 TypeExpr tobj = obj as TypeExpr;
2633 return Type == tobj.Type;
2636 public override int GetHashCode ()
2638 return Type.GetHashCode ();
2643 /// Fully resolved Expression that already evaluated to a type
2645 public class TypeExpression : TypeExpr
2647 public TypeExpression (TypeSpec t, Location l)
2650 eclass = ExprClass.Type;
2654 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2661 /// This class denotes an expression which evaluates to a member
2662 /// of a struct or a class.
2664 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2667 // An instance expression associated with this member, if it's a
2668 // non-static member
2670 public Expression InstanceExpression;
2673 /// The name of this member.
2675 public abstract string Name {
2680 // When base.member is used
2682 public bool IsBase {
2683 get { return InstanceExpression is BaseThis; }
2687 /// Whether this is an instance member.
2689 public abstract bool IsInstance {
2694 /// Whether this is a static member.
2696 public abstract bool IsStatic {
2700 public abstract string KindName {
2704 protected abstract TypeSpec DeclaringType {
2708 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2710 return InstanceExpression.Type;
2715 // Converts best base candidate for virtual method starting from QueriedBaseType
2717 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2720 // Only when base.member is used and method is virtual
2726 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2727 // means for base.member access we have to find the closest match after we found best candidate
2729 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2731 // The method could already be what we are looking for
2733 TypeSpec[] targs = null;
2734 if (method.DeclaringType != InstanceExpression.Type) {
2735 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2736 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2737 if (base_override.IsGeneric)
2738 targs = method.TypeArguments;
2740 method = base_override;
2744 // TODO: For now we do it for any hoisted call even if it's needed for
2745 // hoisted stories only but that requires a new expression wrapper
2746 if (rc.CurrentAnonymousMethod != null) {
2747 if (targs == null && method.IsGeneric) {
2748 targs = method.TypeArguments;
2749 method = method.GetGenericMethodDefinition ();
2752 if (method.Parameters.HasArglist)
2753 throw new NotImplementedException ("__arglist base call proxy");
2755 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2757 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2758 // get/set member expressions second call would fail to proxy because left expression
2759 // would be of 'this' and not 'base'
2760 if (rc.CurrentType.IsStruct)
2761 InstanceExpression = new This (loc).Resolve (rc);
2765 method = method.MakeGenericMethod (rc, targs);
2769 // Only base will allow this invocation to happen.
2771 if (method.IsAbstract) {
2772 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2778 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2780 if (InstanceExpression == null)
2783 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2784 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2785 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2790 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2792 if (InstanceExpression == null)
2795 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2798 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2800 var ct = rc.CurrentType;
2801 if (ct == qualifier)
2804 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2807 qualifier = qualifier.GetDefinition ();
2808 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2815 public override bool ContainsEmitWithAwait ()
2817 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2820 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2823 type = type.GetDefinition ();
2825 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2828 type = type.DeclaringType;
2829 } while (type != null);
2834 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2836 if (InstanceExpression != null) {
2837 InstanceExpression = InstanceExpression.Resolve (rc);
2838 CheckProtectedMemberAccess (rc, member);
2841 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2842 UnsafeError (rc, loc);
2845 var dep = member.GetMissingDependencies ();
2847 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2850 if (!rc.IsObsolete) {
2851 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2853 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2856 if (!(member is FieldSpec))
2857 member.MemberDefinition.SetIsUsed ();
2860 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2862 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2865 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2867 rc.Report.SymbolRelatedToPreviousError (member);
2868 rc.Report.Error (1540, loc,
2869 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2870 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2874 // Implements identicial simple name and type-name
2876 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2879 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2882 // 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
2883 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2885 if (left is MemberExpr || left is VariableReference) {
2886 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2887 if (identical_type != null && identical_type.Type == left.Type)
2888 return identical_type;
2894 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2897 if (InstanceExpression != null) {
2898 if (InstanceExpression is TypeExpr) {
2899 var t = InstanceExpression.Type;
2901 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2902 if (oa != null && !rc.IsObsolete) {
2903 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2906 t = t.DeclaringType;
2907 } while (t != null);
2909 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2910 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2911 rc.Report.Error (176, loc,
2912 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2913 GetSignatureForError ());
2917 InstanceExpression = null;
2923 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2924 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2925 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2926 rc.Report.Error (236, loc,
2927 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2928 GetSignatureForError ());
2930 rc.Report.Error (120, loc,
2931 "An object reference is required to access non-static member `{0}'",
2932 GetSignatureForError ());
2934 InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
2938 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2939 rc.Report.Error (38, loc,
2940 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2941 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2944 InstanceExpression = new This (loc);
2945 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2946 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2947 InstanceExpression = InstanceExpression.Resolve (rc);
2950 InstanceExpression = InstanceExpression.Resolve (rc);
2956 var me = InstanceExpression as MemberExpr;
2958 me.ResolveInstanceExpression (rc, rhs);
2960 var fe = me as FieldExpr;
2961 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2962 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2963 rc.Report.Warning (1690, 1, loc,
2964 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2965 me.GetSignatureForError ());
2972 // Run member-access postponed check once we know that
2973 // the expression is not field expression which is the only
2974 // expression which can use uninitialized this
2976 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2977 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2981 // Additional checks for l-value member access
2984 if (InstanceExpression is UnboxCast) {
2985 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2992 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2994 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2995 ec.Report.Warning (1720, 1, left.Location,
2996 "Expression will always cause a `{0}'", "System.NullReferenceException");
2999 InstanceExpression = left;
3003 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3005 TypeSpec instance_type = InstanceExpression.Type;
3006 if (TypeSpec.IsValueType (instance_type)) {
3007 if (InstanceExpression is IMemoryLocation) {
3008 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3010 // Cannot release the temporary variable when its address
3011 // is required to be on stack for any parent
3012 LocalTemporary t = new LocalTemporary (instance_type);
3013 InstanceExpression.Emit (ec);
3015 t.AddressOf (ec, AddressOp.Store);
3018 InstanceExpression.Emit (ec);
3020 // Only to make verifier happy
3021 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3022 ec.Emit (OpCodes.Box, instance_type);
3025 if (prepare_for_load)
3026 ec.Emit (OpCodes.Dup);
3029 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3032 public class ExtensionMethodCandidates
3034 readonly NamespaceContainer container;
3035 readonly IList<MethodSpec> methods;
3037 readonly IMemberContext context;
3039 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3041 this.context = context;
3042 this.methods = methods;
3043 this.container = nsContainer;
3044 this.index = lookupIndex;
3047 public NamespaceContainer Container {
3053 public IMemberContext Context {
3059 public int LookupIndex {
3065 public IList<MethodSpec> Methods {
3073 // Represents a group of extension method candidates for whole namespace
3075 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3077 ExtensionMethodCandidates candidates;
3078 public readonly Expression ExtensionExpression;
3080 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3081 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3083 this.candidates = candidates;
3084 this.ExtensionExpression = extensionExpr;
3087 public override bool IsStatic {
3088 get { return true; }
3092 // For extension methodgroup we are not looking for base members but parent
3093 // namespace extension methods
3095 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3097 // TODO: candidates are null only when doing error reporting, that's
3098 // incorrect. We have to discover same extension methods in error mode
3099 if (candidates == null)
3102 int arity = type_arguments == null ? 0 : type_arguments.Count;
3104 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3105 if (candidates == null)
3108 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3111 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3113 // We are already here
3117 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3119 if (arguments == null)
3120 arguments = new Arguments (1);
3122 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3123 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3125 // Store resolved argument and restore original arguments
3127 // Clean-up modified arguments for error reporting
3128 arguments.RemoveAt (0);
3132 var me = ExtensionExpression as MemberExpr;
3134 me.ResolveInstanceExpression (ec, null);
3136 InstanceExpression = null;
3140 #region IErrorHandler Members
3142 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3147 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3149 rc.Report.SymbolRelatedToPreviousError (best);
3150 rc.Report.Error (1928, loc,
3151 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3152 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3155 rc.Report.Error (1929, loc,
3156 "Extension method instance type `{0}' cannot be converted to `{1}'",
3157 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3163 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3168 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3177 /// MethodGroupExpr represents a group of method candidates which
3178 /// can be resolved to the best method overload
3180 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3182 protected IList<MemberSpec> Methods;
3183 MethodSpec best_candidate;
3184 TypeSpec best_candidate_return;
3185 protected TypeArguments type_arguments;
3187 SimpleName simple_name;
3188 protected TypeSpec queried_type;
3190 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3194 this.type = InternalType.MethodGroup;
3196 eclass = ExprClass.MethodGroup;
3197 queried_type = type;
3200 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3201 : this (new MemberSpec[] { m }, type, loc)
3207 public MethodSpec BestCandidate {
3209 return best_candidate;
3213 public TypeSpec BestCandidateReturnType {
3215 return best_candidate_return;
3219 public IList<MemberSpec> Candidates {
3225 protected override TypeSpec DeclaringType {
3227 return queried_type;
3231 public override bool IsInstance {
3233 if (best_candidate != null)
3234 return !best_candidate.IsStatic;
3240 public override bool IsStatic {
3242 if (best_candidate != null)
3243 return best_candidate.IsStatic;
3249 public override string KindName {
3250 get { return "method"; }
3253 public override string Name {
3255 if (best_candidate != null)
3256 return best_candidate.Name;
3259 return Methods.First ().Name;
3266 // When best candidate is already know this factory can be used
3267 // to avoid expensive overload resolution to be called
3269 // NOTE: InstanceExpression has to be set manually
3271 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3273 return new MethodGroupExpr (best, queriedType, loc) {
3274 best_candidate = best,
3275 best_candidate_return = best.ReturnType
3279 public override string GetSignatureForError ()
3281 if (best_candidate != null)
3282 return best_candidate.GetSignatureForError ();
3284 return Methods.First ().GetSignatureForError ();
3287 public override Expression CreateExpressionTree (ResolveContext ec)
3289 if (best_candidate == null) {
3290 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3294 if (best_candidate.IsConditionallyExcluded (ec, loc))
3295 ec.Report.Error (765, loc,
3296 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3298 return new TypeOfMethod (best_candidate, loc);
3301 protected override Expression DoResolve (ResolveContext ec)
3303 this.eclass = ExprClass.MethodGroup;
3305 if (InstanceExpression != null) {
3306 InstanceExpression = InstanceExpression.Resolve (ec);
3307 if (InstanceExpression == null)
3314 public override void Emit (EmitContext ec)
3316 throw new NotSupportedException ();
3319 public void EmitCall (EmitContext ec, Arguments arguments)
3321 var call = new CallEmitter ();
3322 call.InstanceExpression = InstanceExpression;
3323 call.Emit (ec, best_candidate, arguments, loc);
3326 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3328 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3329 Name, TypeManager.CSharpName (target));
3332 public static bool IsExtensionMethodArgument (Expression expr)
3335 // LAMESPEC: No details about which expressions are not allowed
3337 return !(expr is TypeExpr) && !(expr is BaseThis);
3341 /// Find the Applicable Function Members (7.4.2.1)
3343 /// me: Method Group expression with the members to select.
3344 /// it might contain constructors or methods (or anything
3345 /// that maps to a method).
3347 /// Arguments: ArrayList containing resolved Argument objects.
3349 /// loc: The location if we want an error to be reported, or a Null
3350 /// location for "probing" purposes.
3352 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3353 /// that is the best match of me on Arguments.
3356 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3358 // TODO: causes issues with probing mode, remove explicit Kind check
3359 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3362 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3363 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3364 r.BaseMembersProvider = this;
3365 r.InstanceQualifier = this;
3368 if (cerrors != null)
3369 r.CustomErrors = cerrors;
3371 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3372 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3373 if (best_candidate == null)
3374 return r.BestCandidateIsDynamic ? this : null;
3376 // Overload resolver had to create a new method group, all checks bellow have already been executed
3377 if (r.BestCandidateNewMethodGroup != null)
3378 return r.BestCandidateNewMethodGroup;
3380 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3381 if (InstanceExpression != null) {
3382 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3383 InstanceExpression = null;
3385 if (best_candidate.IsStatic && simple_name != null) {
3386 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3389 InstanceExpression.Resolve (ec);
3393 ResolveInstanceExpression (ec, null);
3396 var base_override = CandidateToBaseOverride (ec, best_candidate);
3397 if (base_override == best_candidate) {
3398 best_candidate_return = r.BestCandidateReturnType;
3400 best_candidate = base_override;
3401 best_candidate_return = best_candidate.ReturnType;
3407 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3409 simple_name = original;
3410 return base.ResolveMemberAccess (ec, left, original);
3413 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3415 type_arguments = ta;
3418 #region IBaseMembersProvider Members
3420 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3422 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3425 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3427 if (queried_type == member.DeclaringType)
3430 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3431 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3435 // Extension methods lookup after ordinary methods candidates failed to apply
3437 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3439 if (InstanceExpression == null)
3442 InstanceExpression = InstanceExpression.Resolve (rc);
3443 if (!IsExtensionMethodArgument (InstanceExpression))
3446 int arity = type_arguments == null ? 0 : type_arguments.Count;
3447 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3448 if (methods == null)
3451 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3452 emg.SetTypeArguments (rc, type_arguments);
3459 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3461 public ConstructorInstanceQualifier (TypeSpec type)
3464 InstanceType = type;
3467 public TypeSpec InstanceType { get; private set; }
3469 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3471 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3475 public struct OverloadResolver
3478 public enum Restrictions
3482 ProbingOnly = 1 << 1,
3483 CovariantDelegate = 1 << 2,
3484 NoBaseMembers = 1 << 3,
3485 BaseMembersIncluded = 1 << 4
3488 public interface IBaseMembersProvider
3490 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3491 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3492 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3495 public interface IErrorHandler
3497 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3498 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3499 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3500 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3503 public interface IInstanceQualifier
3505 TypeSpec InstanceType { get; }
3506 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3509 sealed class NoBaseMembers : IBaseMembersProvider
3511 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3513 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3518 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3523 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3529 struct AmbiguousCandidate
3531 public readonly MemberSpec Member;
3532 public readonly bool Expanded;
3533 public readonly AParametersCollection Parameters;
3535 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3538 Parameters = parameters;
3539 Expanded = expanded;
3544 IList<MemberSpec> members;
3545 TypeArguments type_arguments;
3546 IBaseMembersProvider base_provider;
3547 IErrorHandler custom_errors;
3548 IInstanceQualifier instance_qualifier;
3549 Restrictions restrictions;
3550 MethodGroupExpr best_candidate_extension_group;
3551 TypeSpec best_candidate_return_type;
3553 SessionReportPrinter lambda_conv_msgs;
3554 ReportPrinter prev_recorder;
3556 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3557 : this (members, null, restrictions, loc)
3561 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3564 if (members == null || members.Count == 0)
3565 throw new ArgumentException ("empty members set");
3567 this.members = members;
3569 type_arguments = targs;
3570 this.restrictions = restrictions;
3571 if (IsDelegateInvoke)
3572 this.restrictions |= Restrictions.NoBaseMembers;
3574 base_provider = NoBaseMembers.Instance;
3579 public IBaseMembersProvider BaseMembersProvider {
3581 return base_provider;
3584 base_provider = value;
3588 public bool BestCandidateIsDynamic { get; set; }
3591 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3593 public MethodGroupExpr BestCandidateNewMethodGroup {
3595 return best_candidate_extension_group;
3600 // Return type can be different between best candidate and closest override
3602 public TypeSpec BestCandidateReturnType {
3604 return best_candidate_return_type;
3608 public IErrorHandler CustomErrors {
3610 return custom_errors;
3613 custom_errors = value;
3617 TypeSpec DelegateType {
3619 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3620 throw new InternalErrorException ("Not running in delegate mode", loc);
3622 return members [0].DeclaringType;
3626 public IInstanceQualifier InstanceQualifier {
3628 return instance_qualifier;
3631 instance_qualifier = value;
3635 bool IsProbingOnly {
3637 return (restrictions & Restrictions.ProbingOnly) != 0;
3641 bool IsDelegateInvoke {
3643 return (restrictions & Restrictions.DelegateInvoke) != 0;
3650 // 7.4.3.3 Better conversion from expression
3651 // Returns : 1 if a->p is better,
3652 // 2 if a->q is better,
3653 // 0 if neither is better
3655 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3657 TypeSpec argument_type = a.Type;
3660 // If argument is an anonymous function
3662 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3664 // p and q are delegate types or expression tree types
3666 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3667 if (q.MemberDefinition != p.MemberDefinition) {
3672 // Uwrap delegate from Expression<T>
3674 q = TypeManager.GetTypeArguments (q)[0];
3675 p = TypeManager.GetTypeArguments (p)[0];
3678 var p_m = Delegate.GetInvokeMethod (p);
3679 var q_m = Delegate.GetInvokeMethod (q);
3682 // With identical parameter lists
3684 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3691 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3693 if (p.Kind == MemberKind.Void) {
3694 return q.Kind != MemberKind.Void ? 2 : 0;
3698 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3700 if (q.Kind == MemberKind.Void) {
3701 return p.Kind != MemberKind.Void ? 1: 0;
3705 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3706 // better conversion is performed between underlying types Y1 and Y2
3708 if (p.IsGenericTask || q.IsGenericTask) {
3709 var async_am = a.Expr as AnonymousMethodExpression;
3710 if (async_am != null && async_am.Block.IsAsync) {
3712 if (p.IsGenericTask != q.IsGenericTask) {
3716 q = q.TypeArguments[0];
3717 p = p.TypeArguments[0];
3722 // The parameters are identicial and return type is not void, use better type conversion
3723 // on return type to determine better one
3726 if (argument_type == p)
3729 if (argument_type == q)
3733 return BetterTypeConversion (ec, p, q);
3737 // 7.4.3.4 Better conversion from type
3739 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3741 if (p == null || q == null)
3742 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3744 switch (p.BuiltinType) {
3745 case BuiltinTypeSpec.Type.Int:
3746 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3749 case BuiltinTypeSpec.Type.Long:
3750 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3753 case BuiltinTypeSpec.Type.SByte:
3754 switch (q.BuiltinType) {
3755 case BuiltinTypeSpec.Type.Byte:
3756 case BuiltinTypeSpec.Type.UShort:
3757 case BuiltinTypeSpec.Type.UInt:
3758 case BuiltinTypeSpec.Type.ULong:
3762 case BuiltinTypeSpec.Type.Short:
3763 switch (q.BuiltinType) {
3764 case BuiltinTypeSpec.Type.UShort:
3765 case BuiltinTypeSpec.Type.UInt:
3766 case BuiltinTypeSpec.Type.ULong:
3770 case BuiltinTypeSpec.Type.Dynamic:
3771 // Dynamic is never better
3775 switch (q.BuiltinType) {
3776 case BuiltinTypeSpec.Type.Int:
3777 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3780 case BuiltinTypeSpec.Type.Long:
3781 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3784 case BuiltinTypeSpec.Type.SByte:
3785 switch (p.BuiltinType) {
3786 case BuiltinTypeSpec.Type.Byte:
3787 case BuiltinTypeSpec.Type.UShort:
3788 case BuiltinTypeSpec.Type.UInt:
3789 case BuiltinTypeSpec.Type.ULong:
3793 case BuiltinTypeSpec.Type.Short:
3794 switch (p.BuiltinType) {
3795 case BuiltinTypeSpec.Type.UShort:
3796 case BuiltinTypeSpec.Type.UInt:
3797 case BuiltinTypeSpec.Type.ULong:
3801 case BuiltinTypeSpec.Type.Dynamic:
3802 // Dynamic is never better
3806 // FIXME: handle lifted operators
3808 // TODO: this is expensive
3809 Expression p_tmp = new EmptyExpression (p);
3810 Expression q_tmp = new EmptyExpression (q);
3812 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3813 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3815 if (p_to_q && !q_to_p)
3818 if (q_to_p && !p_to_q)
3825 /// Determines "Better function" between candidate
3826 /// and the current best match
3829 /// Returns a boolean indicating :
3830 /// false if candidate ain't better
3831 /// true if candidate is better than the current best match
3833 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3834 MemberSpec best, AParametersCollection bparam, bool best_params)
3836 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3837 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3839 bool better_at_least_one = false;
3841 int args_count = args == null ? 0 : args.Count;
3845 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3848 // Default arguments are ignored for better decision
3849 if (a.IsDefaultArgument)
3853 // When comparing named argument the parameter type index has to be looked up
3854 // in original parameter set (override version for virtual members)
3856 NamedArgument na = a as NamedArgument;
3858 int idx = cparam.GetParameterIndexByName (na.Name);
3859 ct = candidate_pd.Types[idx];
3860 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3861 ct = TypeManager.GetElementType (ct);
3863 idx = bparam.GetParameterIndexByName (na.Name);
3864 bt = best_pd.Types[idx];
3865 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3866 bt = TypeManager.GetElementType (bt);
3868 ct = candidate_pd.Types[c_idx];
3869 bt = best_pd.Types[b_idx];
3871 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3872 ct = TypeManager.GetElementType (ct);
3876 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3877 bt = TypeManager.GetElementType (bt);
3882 if (TypeSpecComparer.IsEqual (ct, bt))
3886 int result = BetterExpressionConversion (ec, a, ct, bt);
3888 // for each argument, the conversion to 'ct' should be no worse than
3889 // the conversion to 'bt'.
3893 // for at least one argument, the conversion to 'ct' should be better than
3894 // the conversion to 'bt'.
3896 better_at_least_one = true;
3899 if (better_at_least_one)
3903 // This handles the case
3905 // Add (float f1, float f2, float f3);
3906 // Add (params decimal [] foo);
3908 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3909 // first candidate would've chosen as better.
3911 if (!same && !a.IsDefaultArgument)
3915 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3919 // This handles the following cases:
3921 // Foo (int i) is better than Foo (int i, long l = 0)
3922 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3924 // Prefer non-optional version
3926 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3928 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3929 if (candidate_pd.Count >= best_pd.Count)
3932 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3939 // One is a non-generic method and second is a generic method, then non-generic is better
3941 if (best.IsGeneric != candidate.IsGeneric)
3942 return best.IsGeneric;
3945 // This handles the following cases:
3947 // Trim () is better than Trim (params char[] chars)
3948 // Concat (string s1, string s2, string s3) is better than
3949 // Concat (string s1, params string [] srest)
3950 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3952 // Prefer non-expanded version
3954 if (candidate_params != best_params)
3957 int candidate_param_count = candidate_pd.Count;
3958 int best_param_count = best_pd.Count;
3960 if (candidate_param_count != best_param_count)
3961 // can only happen if (candidate_params && best_params)
3962 return candidate_param_count > best_param_count && best_pd.HasParams;
3965 // Both methods have the same number of parameters, and the parameters have equal types
3966 // Pick the "more specific" signature using rules over original (non-inflated) types
3968 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3969 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3971 bool specific_at_least_once = false;
3972 for (j = 0; j < args_count; ++j) {
3973 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3975 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3976 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3978 ct = candidate_def_pd.Types[j];
3979 bt = best_def_pd.Types[j];
3984 TypeSpec specific = MoreSpecific (ct, bt);
3988 specific_at_least_once = true;
3991 if (specific_at_least_once)
3997 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3999 rc.Report.Error (1729, loc,
4000 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4001 type.GetSignatureForError (), argCount.ToString ());
4005 // Determines if the candidate method is applicable to the given set of arguments
4006 // There could be two different set of parameters for same candidate where one
4007 // is the closest override for default values and named arguments checks and second
4008 // one being the virtual base for the parameter types and modifiers.
4010 // A return value rates candidate method compatibility,
4011 // 0 = the best, int.MaxValue = the worst
4013 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)
4015 // Parameters of most-derived type used mainly for named and optional parameters
4016 var pd = pm.Parameters;
4018 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4019 // params modifier instead of most-derived type
4020 var cpd = ((IParametersMember) candidate).Parameters;
4021 int param_count = pd.Count;
4022 int optional_count = 0;
4024 Arguments orig_args = arguments;
4026 if (arg_count != param_count) {
4027 for (int i = 0; i < pd.Count; ++i) {
4028 if (pd.FixedParameters[i].HasDefaultValue) {
4029 optional_count = pd.Count - i;
4034 if (optional_count != 0) {
4035 // Readjust expected number when params used
4036 if (cpd.HasParams) {
4038 if (arg_count < param_count)
4040 } else if (arg_count > param_count) {
4041 int args_gap = System.Math.Abs (arg_count - param_count);
4042 return int.MaxValue - 10000 + args_gap;
4044 } else if (arg_count != param_count) {
4045 int args_gap = System.Math.Abs (arg_count - param_count);
4047 return int.MaxValue - 10000 + args_gap;
4048 if (arg_count < param_count - 1)
4049 return int.MaxValue - 10000 + args_gap;
4052 // Resize to fit optional arguments
4053 if (optional_count != 0) {
4054 if (arguments == null) {
4055 arguments = new Arguments (optional_count);
4057 // Have to create a new container, so the next run can do same
4058 var resized = new Arguments (param_count);
4059 resized.AddRange (arguments);
4060 arguments = resized;
4063 for (int i = arg_count; i < param_count; ++i)
4064 arguments.Add (null);
4068 if (arg_count > 0) {
4070 // Shuffle named arguments to the right positions if there are any
4072 if (arguments[arg_count - 1] is NamedArgument) {
4073 arg_count = arguments.Count;
4075 for (int i = 0; i < arg_count; ++i) {
4076 bool arg_moved = false;
4078 NamedArgument na = arguments[i] as NamedArgument;
4082 int index = pd.GetParameterIndexByName (na.Name);
4084 // Named parameter not found
4088 // already reordered
4093 if (index >= param_count) {
4094 // When using parameters which should not be available to the user
4095 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4098 arguments.Add (null);
4102 temp = arguments[index];
4104 // The slot has been taken by positional argument
4105 if (temp != null && !(temp is NamedArgument))
4110 arguments = arguments.MarkOrderedArgument (na);
4114 arguments[index] = arguments[i];
4115 arguments[i] = temp;
4122 arg_count = arguments.Count;
4124 } else if (arguments != null) {
4125 arg_count = arguments.Count;
4129 // 1. Handle generic method using type arguments when specified or type inference
4132 var ms = candidate as MethodSpec;
4133 if (ms != null && ms.IsGeneric) {
4134 // Setup constraint checker for probing only
4135 ConstraintChecker cc = new ConstraintChecker (null);
4137 if (type_arguments != null) {
4138 var g_args_count = ms.Arity;
4139 if (g_args_count != type_arguments.Count)
4140 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4142 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4144 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4145 // for now it simplifies things. I should probably add a callback to ResolveContext
4146 if (lambda_conv_msgs == null) {
4147 lambda_conv_msgs = new SessionReportPrinter ();
4148 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4151 var ti = new TypeInference (arguments);
4152 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4153 lambda_conv_msgs.EndSession ();
4156 return ti.InferenceScore - 20000;
4158 if (i_args.Length != 0) {
4159 ms = ms.MakeGenericMethod (ec, i_args);
4162 cc.IgnoreInferredDynamic = true;
4166 // Type arguments constraints have to match for the method to be applicable
4168 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4170 return int.MaxValue - 25000;
4174 // We have a generic return type and at same time the method is override which
4175 // means we have to also inflate override return type in case the candidate is
4176 // best candidate and override return type is different to base return type.
4178 // virtual Foo<T, object> with override Foo<T, dynamic>
4180 if (candidate != pm) {
4181 MethodSpec override_ms = (MethodSpec) pm;
4182 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4183 returnType = inflator.Inflate (returnType);
4185 returnType = ms.ReturnType;
4189 ptypes = ms.Parameters.Types;
4191 if (type_arguments != null)
4192 return int.MaxValue - 15000;
4198 // 2. Each argument has to be implicitly convertible to method parameter
4200 Parameter.Modifier p_mod = 0;
4203 for (int i = 0; i < arg_count; i++) {
4204 Argument a = arguments[i];
4206 if (!pd.FixedParameters[i].HasDefaultValue) {
4207 arguments = orig_args;
4208 return arg_count * 2 + 2;
4212 // Get the default value expression, we can use the same expression
4213 // if the type matches
4215 Expression e = pd.FixedParameters[i].DefaultValue;
4216 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4218 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4220 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4221 e = new MemberAccess (new MemberAccess (new MemberAccess (
4222 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4224 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4230 arguments[i] = new Argument (e, Argument.AType.Default);
4234 if (p_mod != Parameter.Modifier.PARAMS) {
4235 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4237 } else if (!params_expanded_form) {
4238 params_expanded_form = true;
4239 pt = ((ElementTypeSpec) pt).Element;
4245 if (!params_expanded_form) {
4246 if (a.ArgType == Argument.AType.ExtensionType) {
4248 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4250 // LAMESPEC: or implicit type parameter conversion
4253 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4254 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4255 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4260 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4263 dynamicArgument = true;
4268 // It can be applicable in expanded form (when not doing exact match like for delegates)
4270 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4271 if (!params_expanded_form)
4272 pt = ((ElementTypeSpec) pt).Element;
4275 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4278 params_expanded_form = true;
4279 } else if (score < 0) {
4280 params_expanded_form = true;
4281 dynamicArgument = true;
4286 if (params_expanded_form)
4288 return (arg_count - i) * 2 + score;
4293 // When params parameter has no argument it will be provided later if the method is the best candidate
4295 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4296 params_expanded_form = true;
4299 // Restore original arguments for dynamic binder to keep the intention of original source code
4301 if (dynamicArgument)
4302 arguments = orig_args;
4308 // Tests argument compatibility with the parameter
4309 // The possible return values are
4311 // 1 - modifier mismatch
4312 // 2 - type mismatch
4313 // -1 - dynamic binding required
4315 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4318 // Types have to be identical when ref or out modifer
4319 // is used and argument is not of dynamic type
4321 if ((argument.Modifier | param_mod) != 0) {
4322 if (argument.Type != parameter) {
4324 // Do full equality check after quick path
4326 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4328 // Using dynamic for ref/out parameter can still succeed at runtime
4330 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4337 if (argument.Modifier != param_mod) {
4339 // Using dynamic for ref/out parameter can still succeed at runtime
4341 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4348 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4352 // Deploy custom error reporting for lambda methods. When probing lambda methods
4353 // keep all errors reported in separate set and once we are done and no best
4354 // candidate was found, this set is used to report more details about what was wrong
4357 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4358 if (lambda_conv_msgs == null) {
4359 lambda_conv_msgs = new SessionReportPrinter ();
4360 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4365 // Use implicit conversion in all modes to return same candidates when the expression
4366 // is used as argument or delegate conversion
4368 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4369 if (lambda_conv_msgs != null) {
4370 lambda_conv_msgs.EndSession ();
4380 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4382 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4384 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4387 var ac_p = p as ArrayContainer;
4389 var ac_q = q as ArrayContainer;
4393 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4394 if (specific == ac_p.Element)
4396 if (specific == ac_q.Element)
4398 } else if (TypeManager.IsGenericType (p)) {
4399 var pargs = TypeManager.GetTypeArguments (p);
4400 var qargs = TypeManager.GetTypeArguments (q);
4402 bool p_specific_at_least_once = false;
4403 bool q_specific_at_least_once = false;
4405 for (int i = 0; i < pargs.Length; i++) {
4406 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4407 if (specific == pargs[i])
4408 p_specific_at_least_once = true;
4409 if (specific == qargs[i])
4410 q_specific_at_least_once = true;
4413 if (p_specific_at_least_once && !q_specific_at_least_once)
4415 if (!p_specific_at_least_once && q_specific_at_least_once)
4423 // Find the best method from candidate list
4425 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4427 List<AmbiguousCandidate> ambiguous_candidates = null;
4429 MemberSpec best_candidate;
4430 Arguments best_candidate_args = null;
4431 bool best_candidate_params = false;
4432 bool best_candidate_dynamic = false;
4433 int best_candidate_rate;
4434 IParametersMember best_parameter_member = null;
4436 int args_count = args != null ? args.Count : 0;
4438 Arguments candidate_args = args;
4439 bool error_mode = false;
4440 MemberSpec invocable_member = null;
4442 // Be careful, cannot return until error reporter is restored
4444 best_candidate = null;
4445 best_candidate_rate = int.MaxValue;
4447 var type_members = members;
4451 for (int i = 0; i < type_members.Count; ++i) {
4452 var member = type_members[i];
4455 // Methods in a base class are not candidates if any method in a derived
4456 // class is applicable
4458 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4462 if (!member.IsAccessible (rc))
4465 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4468 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4469 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4474 IParametersMember pm = member as IParametersMember;
4477 // Will use it later to report ambiguity between best method and invocable member
4479 if (Invocation.IsMemberInvocable (member))
4480 invocable_member = member;
4486 // Overload resolution is looking for base member but using parameter names
4487 // and default values from the closest member. That means to do expensive lookup
4488 // for the closest override for virtual or abstract members
4490 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4491 var override_params = base_provider.GetOverrideMemberParameters (member);
4492 if (override_params != null)
4493 pm = override_params;
4497 // Check if the member candidate is applicable
4499 bool params_expanded_form = false;
4500 bool dynamic_argument = false;
4501 TypeSpec rt = pm.MemberType;
4502 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4505 // How does it score compare to others
4507 if (candidate_rate < best_candidate_rate) {
4508 best_candidate_rate = candidate_rate;
4509 best_candidate = member;
4510 best_candidate_args = candidate_args;
4511 best_candidate_params = params_expanded_form;
4512 best_candidate_dynamic = dynamic_argument;
4513 best_parameter_member = pm;
4514 best_candidate_return_type = rt;
4515 } else if (candidate_rate == 0) {
4517 // The member look is done per type for most operations but sometimes
4518 // it's not possible like for binary operators overload because they
4519 // are unioned between 2 sides
4521 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4522 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4527 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4529 // We pack all interface members into top level type which makes the overload resolution
4530 // more complicated for interfaces. We compensate it by removing methods with same
4531 // signature when building the cache hence this path should not really be hit often
4534 // interface IA { void Foo (int arg); }
4535 // interface IB : IA { void Foo (params int[] args); }
4537 // IB::Foo is the best overload when calling IB.Foo (1)
4540 if (ambiguous_candidates != null) {
4541 foreach (var amb_cand in ambiguous_candidates) {
4542 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4551 ambiguous_candidates = null;
4554 // Is the new candidate better
4555 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4559 best_candidate = member;
4560 best_candidate_args = candidate_args;
4561 best_candidate_params = params_expanded_form;
4562 best_candidate_dynamic = dynamic_argument;
4563 best_parameter_member = pm;
4564 best_candidate_return_type = rt;
4566 // It's not better but any other found later could be but we are not sure yet
4567 if (ambiguous_candidates == null)
4568 ambiguous_candidates = new List<AmbiguousCandidate> ();
4570 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4574 // Restore expanded arguments
4575 if (candidate_args != args)
4576 candidate_args = args;
4578 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4580 if (prev_recorder != null)
4581 rc.Report.SetPrinter (prev_recorder);
4585 // We've found exact match
4587 if (best_candidate_rate == 0)
4591 // Try extension methods lookup when no ordinary method match was found and provider enables it
4594 var emg = base_provider.LookupExtensionMethod (rc);
4596 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4598 best_candidate_extension_group = emg;
4599 return (T) (MemberSpec) emg.BestCandidate;
4604 // Don't run expensive error reporting mode for probing
4611 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4614 lambda_conv_msgs = null;
4619 // No best member match found, report an error
4621 if (best_candidate_rate != 0 || error_mode) {
4622 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4626 if (best_candidate_dynamic) {
4627 if (args[0].ArgType == Argument.AType.ExtensionType) {
4628 rc.Report.Error (1973, loc,
4629 "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",
4630 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4633 BestCandidateIsDynamic = true;
4638 // These flags indicates we are running delegate probing conversion. No need to
4639 // do more expensive checks
4641 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4642 return (T) best_candidate;
4644 if (ambiguous_candidates != null) {
4646 // Now check that there are no ambiguities i.e the selected method
4647 // should be better than all the others
4649 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4650 var candidate = ambiguous_candidates [ix];
4652 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4653 var ambiguous = candidate.Member;
4654 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4655 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4656 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4657 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4658 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4661 return (T) best_candidate;
4666 if (invocable_member != null) {
4667 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4668 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4669 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4670 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4674 // And now check if the arguments are all
4675 // compatible, perform conversions if
4676 // necessary etc. and return if everything is
4679 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4682 if (best_candidate == null)
4686 // Check ObsoleteAttribute on the best method
4688 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4689 if (oa != null && !rc.IsObsolete)
4690 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4692 var dep = best_candidate.GetMissingDependencies ();
4694 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4697 best_candidate.MemberDefinition.SetIsUsed ();
4699 args = best_candidate_args;
4700 return (T) best_candidate;
4703 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4705 return ResolveMember<MethodSpec> (rc, ref args);
4708 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4709 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4711 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4714 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4715 ec.Report.SymbolRelatedToPreviousError (method);
4716 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4717 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4718 TypeManager.CSharpSignature (method));
4721 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4722 TypeManager.CSharpSignature (method));
4723 } else if (IsDelegateInvoke) {
4724 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4725 DelegateType.GetSignatureForError ());
4727 ec.Report.SymbolRelatedToPreviousError (method);
4728 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4729 method.GetSignatureForError ());
4732 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4734 string index = (idx + 1).ToString ();
4735 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4736 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4737 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4738 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4739 index, Parameter.GetModifierSignature (a.Modifier));
4741 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4742 index, Parameter.GetModifierSignature (mod));
4743 } else if (a.Expr != ErrorExpression.Instance) {
4744 string p1 = a.GetSignatureForError ();
4745 string p2 = TypeManager.CSharpName (paramType);
4748 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4749 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4752 ec.Report.Error (1503, loc,
4753 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4758 // We have failed to find exact match so we return error info about the closest match
4760 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4762 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4763 int arg_count = args == null ? 0 : args.Count;
4765 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4766 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4767 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4771 if (lambda_conv_msgs != null) {
4772 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4777 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4778 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4779 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4783 // For candidates which match on parameters count report more details about incorrect arguments
4786 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4787 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4788 // Reject any inaccessible member
4789 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4790 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4791 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4795 var ms = best_candidate as MethodSpec;
4796 if (ms != null && ms.IsGeneric) {
4797 bool constr_ok = true;
4798 if (ms.TypeArguments != null)
4799 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4801 if (ta_count == 0) {
4802 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4806 rc.Report.Error (411, loc,
4807 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4808 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4815 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4821 // We failed to find any method with correct argument count, report best candidate
4823 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4826 if (best_candidate.Kind == MemberKind.Constructor) {
4827 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4828 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4829 } else if (IsDelegateInvoke) {
4830 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4831 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4832 DelegateType.GetSignatureForError (), arg_count.ToString ());
4834 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4835 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4836 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4837 name, arg_count.ToString ());
4841 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4843 var pd = pm.Parameters;
4844 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4846 Parameter.Modifier p_mod = 0;
4848 int a_idx = 0, a_pos = 0;
4850 ArrayInitializer params_initializers = null;
4851 bool has_unsafe_arg = pm.MemberType.IsPointer;
4852 int arg_count = args == null ? 0 : args.Count;
4854 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4856 if (p_mod != Parameter.Modifier.PARAMS) {
4857 p_mod = pd.FixedParameters[a_idx].ModFlags;
4859 has_unsafe_arg |= pt.IsPointer;
4861 if (p_mod == Parameter.Modifier.PARAMS) {
4862 if (chose_params_expanded) {
4863 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4864 pt = TypeManager.GetElementType (pt);
4870 // Types have to be identical when ref or out modifer is used
4872 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4873 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4876 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4882 NamedArgument na = a as NamedArgument;
4884 int name_index = pd.GetParameterIndexByName (na.Name);
4885 if (name_index < 0 || name_index >= pd.Count) {
4886 if (IsDelegateInvoke) {
4887 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4888 ec.Report.Error (1746, na.Location,
4889 "The delegate `{0}' does not contain a parameter named `{1}'",
4890 DelegateType.GetSignatureForError (), na.Name);
4892 ec.Report.SymbolRelatedToPreviousError (member);
4893 ec.Report.Error (1739, na.Location,
4894 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4895 TypeManager.CSharpSignature (member), na.Name);
4897 } else if (args[name_index] != a) {
4898 if (IsDelegateInvoke)
4899 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4901 ec.Report.SymbolRelatedToPreviousError (member);
4903 ec.Report.Error (1744, na.Location,
4904 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4909 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4912 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4913 custom_errors.NoArgumentMatch (ec, member);
4917 Expression conv = null;
4918 if (a.ArgType == Argument.AType.ExtensionType) {
4919 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4922 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4924 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4927 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4934 // Convert params arguments to an array initializer
4936 if (params_initializers != null) {
4937 // we choose to use 'a.Expr' rather than 'conv' so that
4938 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4939 params_initializers.Add (a.Expr);
4940 args.RemoveAt (a_idx--);
4945 // Update the argument with the implicit conversion
4949 if (a_idx != arg_count) {
4950 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4955 // Fill not provided arguments required by params modifier
4957 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4959 args = new Arguments (1);
4961 pt = ptypes[pd.Count - 1];
4962 pt = TypeManager.GetElementType (pt);
4963 has_unsafe_arg |= pt.IsPointer;
4964 params_initializers = new ArrayInitializer (0, loc);
4968 // Append an array argument with all params arguments
4970 if (params_initializers != null) {
4971 args.Add (new Argument (
4972 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4976 if (has_unsafe_arg && !ec.IsUnsafe) {
4977 Expression.UnsafeError (ec, loc);
4981 // We could infer inaccesible type arguments
4983 if (type_arguments == null && member.IsGeneric) {
4984 var ms = (MethodSpec) member;
4985 foreach (var ta in ms.TypeArguments) {
4986 if (!ta.IsAccessible (ec)) {
4987 ec.Report.SymbolRelatedToPreviousError (ta);
4988 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4998 public class ConstantExpr : MemberExpr
5000 readonly ConstSpec constant;
5002 public ConstantExpr (ConstSpec constant, Location loc)
5004 this.constant = constant;
5008 public override string Name {
5009 get { throw new NotImplementedException (); }
5012 public override string KindName {
5013 get { return "constant"; }
5016 public override bool IsInstance {
5017 get { return !IsStatic; }
5020 public override bool IsStatic {
5021 get { return true; }
5024 protected override TypeSpec DeclaringType {
5025 get { return constant.DeclaringType; }
5028 public override Expression CreateExpressionTree (ResolveContext ec)
5030 throw new NotSupportedException ("ET");
5033 protected override Expression DoResolve (ResolveContext rc)
5035 ResolveInstanceExpression (rc, null);
5036 DoBestMemberChecks (rc, constant);
5038 var c = constant.GetConstant (rc);
5040 // Creates reference expression to the constant value
5041 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5044 public override void Emit (EmitContext ec)
5046 throw new NotSupportedException ();
5049 public override string GetSignatureForError ()
5051 return constant.GetSignatureForError ();
5054 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5056 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5061 // Fully resolved expression that references a Field
5063 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5065 protected FieldSpec spec;
5066 VariableInfo variable_info;
5068 LocalTemporary temp;
5071 protected FieldExpr (Location l)
5076 public FieldExpr (FieldSpec spec, Location loc)
5081 type = spec.MemberType;
5084 public FieldExpr (FieldBase fi, Location l)
5091 public override string Name {
5097 public bool IsHoisted {
5099 IVariableReference hv = InstanceExpression as IVariableReference;
5100 return hv != null && hv.IsHoisted;
5104 public override bool IsInstance {
5106 return !spec.IsStatic;
5110 public override bool IsStatic {
5112 return spec.IsStatic;
5116 public override string KindName {
5117 get { return "field"; }
5120 public FieldSpec Spec {
5126 protected override TypeSpec DeclaringType {
5128 return spec.DeclaringType;
5132 public VariableInfo VariableInfo {
5134 return variable_info;
5140 public override string GetSignatureForError ()
5142 return spec.GetSignatureForError ();
5145 public bool IsMarshalByRefAccess (ResolveContext rc)
5147 // Checks possible ldflda of field access expression
5148 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5149 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5150 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5153 public void SetHasAddressTaken ()
5155 IVariableReference vr = InstanceExpression as IVariableReference;
5157 vr.SetHasAddressTaken ();
5161 public override Expression CreateExpressionTree (ResolveContext ec)
5163 Expression instance;
5164 if (InstanceExpression == null) {
5165 instance = new NullLiteral (loc);
5167 instance = InstanceExpression.CreateExpressionTree (ec);
5170 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5172 CreateTypeOfExpression ());
5174 return CreateExpressionFactoryCall (ec, "Field", args);
5177 public Expression CreateTypeOfExpression ()
5179 return new TypeOfField (spec, loc);
5182 protected override Expression DoResolve (ResolveContext ec)
5184 return DoResolve (ec, null);
5187 Expression DoResolve (ResolveContext ec, Expression rhs)
5189 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5192 if (ResolveInstanceExpression (ec, rhs)) {
5193 // Resolve the field's instance expression while flow analysis is turned
5194 // off: when accessing a field "a.b", we must check whether the field
5195 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5197 if (lvalue_instance) {
5198 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5199 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5201 Expression right_side =
5202 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5204 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5207 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5208 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5212 if (InstanceExpression == null)
5216 DoBestMemberChecks (ec, spec);
5219 var fb = spec as FixedFieldSpec;
5220 IVariableReference var = InstanceExpression as IVariableReference;
5222 if (lvalue_instance && var != null && var.VariableInfo != null) {
5223 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5227 IFixedExpression fe = InstanceExpression as IFixedExpression;
5228 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5229 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5232 if (InstanceExpression.eclass != ExprClass.Variable) {
5233 ec.Report.SymbolRelatedToPreviousError (spec);
5234 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5235 TypeManager.GetFullNameSignature (spec));
5236 } else if (var != null && var.IsHoisted) {
5237 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5240 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5244 // Set flow-analysis variable info for struct member access. It will be check later
5245 // for precise error reporting
5247 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5248 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5249 if (rhs != null && variable_info != null)
5250 variable_info.SetStructFieldAssigned (ec, Name);
5253 eclass = ExprClass.Variable;
5257 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5262 var var = fe.InstanceExpression as IVariableReference;
5264 var vi = var.VariableInfo;
5266 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5268 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5270 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5277 fe = fe.InstanceExpression as FieldExpr;
5279 } while (fe != null);
5282 static readonly int [] codes = {
5283 191, // instance, write access
5284 192, // instance, out access
5285 198, // static, write access
5286 199, // static, out access
5287 1648, // member of value instance, write access
5288 1649, // member of value instance, out access
5289 1650, // member of value static, write access
5290 1651 // member of value static, out access
5293 static readonly string [] msgs = {
5294 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5295 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5296 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5297 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5298 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5299 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5300 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5301 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5304 // The return value is always null. Returning a value simplifies calling code.
5305 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5308 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5312 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5314 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5319 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5321 Expression e = DoResolve (ec, right_side);
5326 spec.MemberDefinition.SetIsAssigned ();
5328 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5329 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5330 ec.Report.Warning (420, 1, loc,
5331 "`{0}': A volatile field references will not be treated as volatile",
5332 spec.GetSignatureForError ());
5335 if (spec.IsReadOnly) {
5336 // InitOnly fields can only be assigned in constructors or initializers
5337 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5338 return Report_AssignToReadonly (ec, right_side);
5340 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5342 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5343 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5344 return Report_AssignToReadonly (ec, right_side);
5345 // static InitOnly fields cannot be assigned-to in an instance constructor
5346 if (IsStatic && !ec.IsStatic)
5347 return Report_AssignToReadonly (ec, right_side);
5348 // instance constructors can't modify InitOnly fields of other instances of the same type
5349 if (!IsStatic && !(InstanceExpression is This))
5350 return Report_AssignToReadonly (ec, right_side);
5354 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5355 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5356 ec.Report.Warning (197, 1, loc,
5357 "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",
5358 GetSignatureForError ());
5361 eclass = ExprClass.Variable;
5365 public override int GetHashCode ()
5367 return spec.GetHashCode ();
5370 public bool IsFixed {
5373 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5375 IVariableReference variable = InstanceExpression as IVariableReference;
5376 if (variable != null)
5377 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5379 IFixedExpression fe = InstanceExpression as IFixedExpression;
5380 return fe != null && fe.IsFixed;
5384 public override bool Equals (object obj)
5386 FieldExpr fe = obj as FieldExpr;
5390 if (spec != fe.spec)
5393 if (InstanceExpression == null || fe.InstanceExpression == null)
5396 return InstanceExpression.Equals (fe.InstanceExpression);
5399 public void Emit (EmitContext ec, bool leave_copy)
5401 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5403 spec.MemberDefinition.SetIsUsed ();
5407 ec.Emit (OpCodes.Volatile);
5409 ec.Emit (OpCodes.Ldsfld, spec);
5412 EmitInstance (ec, false);
5414 // Optimization for build-in types
5415 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5416 ec.EmitLoadFromPtr (type);
5418 var ff = spec as FixedFieldSpec;
5420 ec.Emit (OpCodes.Ldflda, spec);
5421 ec.Emit (OpCodes.Ldflda, ff.Element);
5424 ec.Emit (OpCodes.Volatile);
5426 ec.Emit (OpCodes.Ldfld, spec);
5432 ec.Emit (OpCodes.Dup);
5434 temp = new LocalTemporary (this.Type);
5440 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5442 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5443 if (isCompound && !(source is DynamicExpressionStatement)) {
5444 if (has_await_source) {
5446 InstanceExpression = InstanceExpression.EmitToField (ec);
5453 if (has_await_source)
5454 source = source.EmitToField (ec);
5456 EmitInstance (ec, prepared);
5462 ec.Emit (OpCodes.Dup);
5464 temp = new LocalTemporary (this.Type);
5469 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5470 ec.Emit (OpCodes.Volatile);
5472 spec.MemberDefinition.SetIsAssigned ();
5475 ec.Emit (OpCodes.Stsfld, spec);
5477 ec.Emit (OpCodes.Stfld, spec);
5487 // Emits store to field with prepared values on stack
5489 public void EmitAssignFromStack (EmitContext ec)
5492 ec.Emit (OpCodes.Stsfld, spec);
5494 ec.Emit (OpCodes.Stfld, spec);
5498 public override void Emit (EmitContext ec)
5503 public override void EmitSideEffect (EmitContext ec)
5505 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5507 if (is_volatile) // || is_marshal_by_ref ())
5508 base.EmitSideEffect (ec);
5511 public void AddressOf (EmitContext ec, AddressOp mode)
5513 if ((mode & AddressOp.Store) != 0)
5514 spec.MemberDefinition.SetIsAssigned ();
5515 if ((mode & AddressOp.Load) != 0)
5516 spec.MemberDefinition.SetIsUsed ();
5519 // Handle initonly fields specially: make a copy and then
5520 // get the address of the copy.
5523 if (spec.IsReadOnly){
5525 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5537 var temp = ec.GetTemporaryLocal (type);
5538 ec.Emit (OpCodes.Stloc, temp);
5539 ec.Emit (OpCodes.Ldloca, temp);
5540 ec.FreeTemporaryLocal (temp, type);
5546 ec.Emit (OpCodes.Ldsflda, spec);
5549 EmitInstance (ec, false);
5550 ec.Emit (OpCodes.Ldflda, spec);
5554 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5556 return MakeExpression (ctx);
5559 public override SLE.Expression MakeExpression (BuilderContext ctx)
5562 return base.MakeExpression (ctx);
5564 return SLE.Expression.Field (
5565 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5566 spec.GetMetaInfo ());
5570 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5572 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5578 // Expression that evaluates to a Property.
5580 // This is not an LValue because we need to re-write the expression. We
5581 // can not take data from the stack and store it.
5583 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5585 public PropertyExpr (PropertySpec spec, Location l)
5588 best_candidate = spec;
5589 type = spec.MemberType;
5594 protected override Arguments Arguments {
5602 protected override TypeSpec DeclaringType {
5604 return best_candidate.DeclaringType;
5608 public override string Name {
5610 return best_candidate.Name;
5614 public override bool IsInstance {
5620 public override bool IsStatic {
5622 return best_candidate.IsStatic;
5626 public override string KindName {
5627 get { return "property"; }
5630 public PropertySpec PropertyInfo {
5632 return best_candidate;
5638 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5640 return new PropertyExpr (spec, loc) {
5646 public override Expression CreateExpressionTree (ResolveContext ec)
5649 if (IsSingleDimensionalArrayLength ()) {
5650 args = new Arguments (1);
5651 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5652 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5655 args = new Arguments (2);
5656 if (InstanceExpression == null)
5657 args.Add (new Argument (new NullLiteral (loc)));
5659 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5660 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5661 return CreateExpressionFactoryCall (ec, "Property", args);
5664 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5666 DoResolveLValue (rc, null);
5667 return new TypeOfMethod (Setter, loc);
5670 public override string GetSignatureForError ()
5672 return best_candidate.GetSignatureForError ();
5675 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5678 return base.MakeExpression (ctx);
5680 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5684 public override SLE.Expression MakeExpression (BuilderContext ctx)
5687 return base.MakeExpression (ctx);
5689 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5693 void Error_PropertyNotValid (ResolveContext ec)
5695 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5696 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5697 GetSignatureForError ());
5700 bool IsSingleDimensionalArrayLength ()
5702 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5705 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5706 return ac != null && ac.Rank == 1;
5709 public override void Emit (EmitContext ec, bool leave_copy)
5712 // Special case: length of single dimension array property is turned into ldlen
5714 if (IsSingleDimensionalArrayLength ()) {
5715 EmitInstance (ec, false);
5716 ec.Emit (OpCodes.Ldlen);
5717 ec.Emit (OpCodes.Conv_I4);
5721 base.Emit (ec, leave_copy);
5724 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5727 LocalTemporary await_source_arg = null;
5729 if (isCompound && !(source is DynamicExpressionStatement)) {
5730 emitting_compound_assignment = true;
5733 if (has_await_arguments) {
5734 await_source_arg = new LocalTemporary (Type);
5735 await_source_arg.Store (ec);
5737 args = new Arguments (1);
5738 args.Add (new Argument (await_source_arg));
5741 temp = await_source_arg;
5744 has_await_arguments = false;
5749 ec.Emit (OpCodes.Dup);
5750 temp = new LocalTemporary (this.Type);
5755 args = new Arguments (1);
5759 temp = new LocalTemporary (this.Type);
5761 args.Add (new Argument (temp));
5763 args.Add (new Argument (source));
5767 emitting_compound_assignment = false;
5769 var call = new CallEmitter ();
5770 call.InstanceExpression = InstanceExpression;
5772 call.InstanceExpressionOnStack = true;
5774 call.Emit (ec, Setter, args, loc);
5781 if (await_source_arg != null) {
5782 await_source_arg.Release (ec);
5786 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5788 eclass = ExprClass.PropertyAccess;
5790 if (best_candidate.IsNotCSharpCompatible) {
5791 Error_PropertyNotValid (rc);
5794 ResolveInstanceExpression (rc, right_side);
5796 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5797 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5798 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5800 type = p.MemberType;
5804 DoBestMemberChecks (rc, best_candidate);
5808 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5810 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5814 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5816 // getter and setter can be different for base calls
5817 MethodSpec getter, setter;
5818 protected T best_candidate;
5820 protected LocalTemporary temp;
5821 protected bool emitting_compound_assignment;
5822 protected bool has_await_arguments;
5824 protected PropertyOrIndexerExpr (Location l)
5831 protected abstract Arguments Arguments { get; set; }
5833 public MethodSpec Getter {
5842 public MethodSpec Setter {
5853 protected override Expression DoResolve (ResolveContext ec)
5855 if (eclass == ExprClass.Unresolved) {
5856 var expr = OverloadResolve (ec, null);
5861 return expr.Resolve (ec);
5864 if (!ResolveGetter (ec))
5870 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5872 if (right_side == EmptyExpression.OutAccess) {
5873 // TODO: best_candidate can be null at this point
5874 INamedBlockVariable variable = null;
5875 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5876 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5877 best_candidate.Name);
5879 right_side.DoResolveLValue (ec, this);
5884 // if the property/indexer returns a value type, and we try to set a field in it
5885 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5886 Error_ValueAssignment (ec, right_side);
5889 if (eclass == ExprClass.Unresolved) {
5890 var expr = OverloadResolve (ec, right_side);
5895 return expr.ResolveLValue (ec, right_side);
5898 if (!ResolveSetter (ec))
5905 // Implements the IAssignMethod interface for assignments
5907 public virtual void Emit (EmitContext ec, bool leave_copy)
5909 var call = new CallEmitter ();
5910 call.InstanceExpression = InstanceExpression;
5911 if (has_await_arguments)
5912 call.HasAwaitArguments = true;
5914 call.DuplicateArguments = emitting_compound_assignment;
5916 call.Emit (ec, Getter, Arguments, loc);
5918 if (call.HasAwaitArguments) {
5919 InstanceExpression = call.InstanceExpression;
5920 Arguments = call.EmittedArguments;
5921 has_await_arguments = true;
5925 ec.Emit (OpCodes.Dup);
5926 temp = new LocalTemporary (Type);
5931 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5933 public override void Emit (EmitContext ec)
5938 protected override void EmitToFieldSource (EmitContext ec)
5940 has_await_arguments = true;
5944 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5946 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5948 bool ResolveGetter (ResolveContext rc)
5950 if (!best_candidate.HasGet) {
5951 if (InstanceExpression != EmptyExpression.Null) {
5952 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5953 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5954 best_candidate.GetSignatureForError ());
5957 } else if (!best_candidate.Get.IsAccessible (rc)) {
5958 if (best_candidate.HasDifferentAccessibility) {
5959 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5960 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5961 TypeManager.CSharpSignature (best_candidate));
5963 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5964 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5968 if (best_candidate.HasDifferentAccessibility) {
5969 CheckProtectedMemberAccess (rc, best_candidate.Get);
5972 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5976 bool ResolveSetter (ResolveContext rc)
5978 if (!best_candidate.HasSet) {
5979 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5980 GetSignatureForError ());
5984 if (!best_candidate.Set.IsAccessible (rc)) {
5985 if (best_candidate.HasDifferentAccessibility) {
5986 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5987 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5988 GetSignatureForError ());
5990 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5991 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5995 if (best_candidate.HasDifferentAccessibility)
5996 CheckProtectedMemberAccess (rc, best_candidate.Set);
5998 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6004 /// Fully resolved expression that evaluates to an Event
6006 public class EventExpr : MemberExpr, IAssignMethod
6008 readonly EventSpec spec;
6011 public EventExpr (EventSpec spec, Location loc)
6019 protected override TypeSpec DeclaringType {
6021 return spec.DeclaringType;
6025 public override string Name {
6031 public override bool IsInstance {
6033 return !spec.IsStatic;
6037 public override bool IsStatic {
6039 return spec.IsStatic;
6043 public override string KindName {
6044 get { return "event"; }
6047 public MethodSpec Operator {
6055 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6058 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6060 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6061 if (spec.BackingField != null &&
6062 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6064 spec.MemberDefinition.SetIsUsed ();
6066 if (!ec.IsObsolete) {
6067 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6069 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6072 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6073 Error_AssignmentEventOnly (ec);
6075 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6077 InstanceExpression = null;
6079 return ml.ResolveMemberAccess (ec, left, original);
6083 return base.ResolveMemberAccess (ec, left, original);
6086 public override Expression CreateExpressionTree (ResolveContext ec)
6088 throw new NotSupportedException ("ET");
6091 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6093 if (right_side == EmptyExpression.EventAddition) {
6094 op = spec.AccessorAdd;
6095 } else if (right_side == EmptyExpression.EventSubtraction) {
6096 op = spec.AccessorRemove;
6100 Error_AssignmentEventOnly (ec);
6104 op = CandidateToBaseOverride (ec, op);
6108 protected override Expression DoResolve (ResolveContext ec)
6110 eclass = ExprClass.EventAccess;
6111 type = spec.MemberType;
6113 ResolveInstanceExpression (ec, null);
6115 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6116 Error_AssignmentEventOnly (ec);
6119 DoBestMemberChecks (ec, spec);
6123 public override void Emit (EmitContext ec)
6125 throw new NotSupportedException ();
6126 //Error_CannotAssign ();
6129 #region IAssignMethod Members
6131 public void Emit (EmitContext ec, bool leave_copy)
6133 throw new NotImplementedException ();
6136 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6138 if (leave_copy || !isCompound)
6139 throw new NotImplementedException ("EventExpr::EmitAssign");
6141 Arguments args = new Arguments (1);
6142 args.Add (new Argument (source));
6144 var call = new CallEmitter ();
6145 call.InstanceExpression = InstanceExpression;
6146 call.Emit (ec, op, args, loc);
6151 void Error_AssignmentEventOnly (ResolveContext ec)
6153 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6154 ec.Report.Error (79, loc,
6155 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6156 GetSignatureForError ());
6158 ec.Report.Error (70, loc,
6159 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6160 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6164 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6166 name = name.Substring (0, name.LastIndexOf ('.'));
6167 base.Error_CannotCallAbstractBase (rc, name);
6170 public override string GetSignatureForError ()
6172 return TypeManager.CSharpSignature (spec);
6175 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6177 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6181 public class TemporaryVariableReference : VariableReference
6183 public class Declarator : Statement
6185 TemporaryVariableReference variable;
6187 public Declarator (TemporaryVariableReference variable)
6189 this.variable = variable;
6193 protected override void DoEmit (EmitContext ec)
6195 variable.li.CreateBuilder (ec);
6198 public override void Emit (EmitContext ec)
6200 // Don't create sequence point
6204 protected override void CloneTo (CloneContext clonectx, Statement target)
6212 public TemporaryVariableReference (LocalVariable li, Location loc)
6215 this.type = li.Type;
6219 public override bool IsLockedByStatement {
6227 public LocalVariable LocalInfo {
6233 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6235 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6236 return new TemporaryVariableReference (li, loc);
6239 protected override Expression DoResolve (ResolveContext ec)
6241 eclass = ExprClass.Variable;
6244 // Don't capture temporary variables except when using
6245 // state machine redirection
6247 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
6248 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6249 storey.CaptureLocalVariable (ec, li);
6255 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6257 return Resolve (ec);
6260 public override void Emit (EmitContext ec)
6262 li.CreateBuilder (ec);
6267 public void EmitAssign (EmitContext ec, Expression source)
6269 li.CreateBuilder (ec);
6271 EmitAssign (ec, source, false, false);
6274 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6276 return li.HoistedVariant;
6279 public override bool IsFixed {
6280 get { return true; }
6283 public override bool IsRef {
6284 get { return false; }
6287 public override string Name {
6288 get { throw new NotImplementedException (); }
6291 public override void SetHasAddressTaken ()
6293 throw new NotImplementedException ();
6296 protected override ILocalVariable Variable {
6300 public override VariableInfo VariableInfo {
6301 get { return null; }
6304 public override void VerifyAssigned (ResolveContext rc)
6310 /// Handles `var' contextual keyword; var becomes a keyword only
6311 /// if no type called var exists in a variable scope
6313 class VarExpr : SimpleName
6315 public VarExpr (Location loc)
6320 public bool InferType (ResolveContext ec, Expression right_side)
6323 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6325 type = right_side.Type;
6326 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6327 ec.Report.Error (815, loc,
6328 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6329 type.GetSignatureForError ());
6333 eclass = ExprClass.Variable;
6337 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6339 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6340 base.Error_TypeOrNamespaceNotFound (ec);
6342 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");