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)
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 (Report r, MemberCore mc, string expected, Location loc)
836 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
839 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
843 name = mc.GetSignatureForError ();
845 name = GetSignatureForError ();
847 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
848 name, was, expected);
851 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
853 string [] valid = new string [4];
856 if ((flags & ResolveFlags.VariableOrValue) != 0) {
857 valid [count++] = "variable";
858 valid [count++] = "value";
861 if ((flags & ResolveFlags.Type) != 0)
862 valid [count++] = "type";
864 if ((flags & ResolveFlags.MethodGroup) != 0)
865 valid [count++] = "method group";
868 valid [count++] = "unknown";
870 StringBuilder sb = new StringBuilder (valid [0]);
871 for (int i = 1; i < count - 1; i++) {
873 sb.Append (valid [i]);
876 sb.Append ("' or `");
877 sb.Append (valid [count - 1]);
880 ec.Report.Error (119, loc,
881 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
884 public static void UnsafeError (ResolveContext ec, Location loc)
886 UnsafeError (ec.Report, loc);
889 public static void UnsafeError (Report Report, Location loc)
891 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
895 // Converts `source' to an int, uint, long or ulong.
897 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
899 var btypes = ec.BuiltinTypes;
901 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
902 Arguments args = new Arguments (1);
903 args.Add (new Argument (source));
904 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
907 Expression converted;
909 using (ec.Set (ResolveContext.Options.CheckedScope)) {
910 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
911 if (converted == null)
912 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
913 if (converted == null)
914 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
915 if (converted == null)
916 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
918 if (converted == null) {
919 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
925 // Only positive constants are allowed at compile time
927 Constant c = converted as Constant;
928 if (c != null && c.IsNegative)
929 Error_NegativeArrayIndex (ec, source.loc);
931 // No conversion needed to array index
932 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
935 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
939 // Derived classes implement this method by cloning the fields that
940 // could become altered during the Resolve stage
942 // Only expressions that are created for the parser need to implement
945 protected virtual void CloneTo (CloneContext clonectx, Expression target)
947 throw new NotImplementedException (
949 "CloneTo not implemented for expression {0}", this.GetType ()));
953 // Clones an expression created by the parser.
955 // We only support expressions created by the parser so far, not
956 // expressions that have been resolved (many more classes would need
957 // to implement CloneTo).
959 // This infrastructure is here merely for Lambda expressions which
960 // compile the same code using different type values for the same
961 // arguments to find the correct overload
963 public virtual Expression Clone (CloneContext clonectx)
965 Expression cloned = (Expression) MemberwiseClone ();
966 CloneTo (clonectx, cloned);
972 // Implementation of expression to expression tree conversion
974 public abstract Expression CreateExpressionTree (ResolveContext ec);
976 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
978 return CreateExpressionFactoryCall (ec, name, null, args, loc);
981 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
983 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
986 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
988 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
991 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
993 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
997 return new TypeExpression (t, loc);
1001 // Implemented by all expressions which support conversion from
1002 // compiler expression to invokable runtime expression. Used by
1003 // dynamic C# binder.
1005 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1007 throw new NotImplementedException ("MakeExpression for " + GetType ());
1010 public virtual object Accept (StructuralVisitor visitor)
1012 return visitor.Visit (this);
1017 /// This is just a base class for expressions that can
1018 /// appear on statements (invocations, object creation,
1019 /// assignments, post/pre increment and decrement). The idea
1020 /// being that they would support an extra Emition interface that
1021 /// does not leave a result on the stack.
1023 public abstract class ExpressionStatement : Expression {
1025 public ExpressionStatement ResolveStatement (BlockContext ec)
1027 Expression e = Resolve (ec);
1031 ExpressionStatement es = e as ExpressionStatement;
1033 Error_InvalidExpressionStatement (ec);
1039 /// Requests the expression to be emitted in a `statement'
1040 /// context. This means that no new value is left on the
1041 /// stack after invoking this method (constrasted with
1042 /// Emit that will always leave a value on the stack).
1044 public abstract void EmitStatement (EmitContext ec);
1046 public override void EmitSideEffect (EmitContext ec)
1053 /// This kind of cast is used to encapsulate the child
1054 /// whose type is child.Type into an expression that is
1055 /// reported to return "return_type". This is used to encapsulate
1056 /// expressions which have compatible types, but need to be dealt
1057 /// at higher levels with.
1059 /// For example, a "byte" expression could be encapsulated in one
1060 /// of these as an "unsigned int". The type for the expression
1061 /// would be "unsigned int".
1064 public abstract class TypeCast : Expression
1066 protected readonly Expression child;
1068 protected TypeCast (Expression child, TypeSpec return_type)
1070 eclass = child.eclass;
1071 loc = child.Location;
1076 public Expression Child {
1082 public override bool ContainsEmitWithAwait ()
1084 return child.ContainsEmitWithAwait ();
1087 public override Expression CreateExpressionTree (ResolveContext ec)
1089 Arguments args = new Arguments (2);
1090 args.Add (new Argument (child.CreateExpressionTree (ec)));
1091 args.Add (new Argument (new TypeOf (type, loc)));
1093 if (type.IsPointer || child.Type.IsPointer)
1094 Error_PointerInsideExpressionTree (ec);
1096 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1099 protected override Expression DoResolve (ResolveContext ec)
1101 // This should never be invoked, we are born in fully
1102 // initialized state.
1107 public override void Emit (EmitContext ec)
1112 public override SLE.Expression MakeExpression (BuilderContext ctx)
1115 return base.MakeExpression (ctx);
1117 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1118 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1119 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1123 protected override void CloneTo (CloneContext clonectx, Expression t)
1128 public override bool IsNull {
1129 get { return child.IsNull; }
1133 public class EmptyCast : TypeCast {
1134 EmptyCast (Expression child, TypeSpec target_type)
1135 : base (child, target_type)
1139 public static Expression Create (Expression child, TypeSpec type)
1141 Constant c = child as Constant;
1143 return new EmptyConstantCast (c, type);
1145 EmptyCast e = child as EmptyCast;
1147 return new EmptyCast (e.child, type);
1149 return new EmptyCast (child, type);
1152 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1154 child.EmitBranchable (ec, label, on_true);
1157 public override void EmitSideEffect (EmitContext ec)
1159 child.EmitSideEffect (ec);
1164 // Used for predefined type user operator (no obsolete check, etc.)
1166 public class OperatorCast : TypeCast
1168 readonly MethodSpec conversion_operator;
1170 public OperatorCast (Expression expr, TypeSpec target_type)
1171 : this (expr, target_type, target_type, false)
1175 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1176 : this (expr, target_type, target_type, find_explicit)
1180 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1181 : base (expr, returnType)
1183 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1184 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1187 foreach (MethodSpec oper in mi) {
1188 if (oper.ReturnType != returnType)
1191 if (oper.Parameters.Types[0] == expr.Type) {
1192 conversion_operator = oper;
1198 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1199 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1202 public override void Emit (EmitContext ec)
1205 ec.Emit (OpCodes.Call, conversion_operator);
1210 // Constant specialization of EmptyCast.
1211 // We need to special case this since an empty cast of
1212 // a constant is still a constant.
1214 public class EmptyConstantCast : Constant
1216 public readonly Constant child;
1218 public EmptyConstantCast (Constant child, TypeSpec type)
1219 : base (child.Location)
1222 throw new ArgumentNullException ("child");
1225 this.eclass = child.eclass;
1229 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1231 if (child.Type == target_type)
1234 // FIXME: check that 'type' can be converted to 'target_type' first
1235 return child.ConvertExplicitly (in_checked_context, target_type);
1238 public override Expression CreateExpressionTree (ResolveContext ec)
1240 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1241 child.CreateExpressionTree (ec),
1242 new TypeOf (type, loc));
1245 Error_PointerInsideExpressionTree (ec);
1247 return CreateExpressionFactoryCall (ec, "Convert", args);
1250 public override bool IsDefaultValue {
1251 get { return child.IsDefaultValue; }
1254 public override bool IsNegative {
1255 get { return child.IsNegative; }
1258 public override bool IsNull {
1259 get { return child.IsNull; }
1262 public override bool IsOneInteger {
1263 get { return child.IsOneInteger; }
1266 public override bool IsSideEffectFree {
1268 return child.IsSideEffectFree;
1272 public override bool IsZeroInteger {
1273 get { return child.IsZeroInteger; }
1276 public override void Emit (EmitContext ec)
1281 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1283 child.EmitBranchable (ec, label, on_true);
1285 // Only to make verifier happy
1286 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1287 ec.Emit (OpCodes.Unbox_Any, type);
1290 public override void EmitSideEffect (EmitContext ec)
1292 child.EmitSideEffect (ec);
1295 public override object GetValue ()
1297 return child.GetValue ();
1300 public override string GetValueAsLiteral ()
1302 return child.GetValueAsLiteral ();
1305 public override long GetValueAsLong ()
1307 return child.GetValueAsLong ();
1310 public override Constant ConvertImplicitly (TypeSpec target_type)
1312 if (type == target_type)
1315 // FIXME: Do we need to check user conversions?
1316 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1319 return child.ConvertImplicitly (target_type);
1324 /// This class is used to wrap literals which belong inside Enums
1326 public class EnumConstant : Constant
1328 public Constant Child;
1330 public EnumConstant (Constant child, TypeSpec enum_type)
1331 : base (child.Location)
1335 this.eclass = ExprClass.Value;
1336 this.type = enum_type;
1339 protected EnumConstant (Location loc)
1344 public override void Emit (EmitContext ec)
1349 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1351 Child.EncodeAttributeValue (rc, enc, Child.Type);
1354 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1356 Child.EmitBranchable (ec, label, on_true);
1359 public override void EmitSideEffect (EmitContext ec)
1361 Child.EmitSideEffect (ec);
1364 public override string GetSignatureForError()
1366 return TypeManager.CSharpName (Type);
1369 public override object GetValue ()
1371 return Child.GetValue ();
1375 public override object GetTypedValue ()
1378 // The method can be used in dynamic context only (on closed types)
1380 // System.Enum.ToObject cannot be called on dynamic types
1381 // EnumBuilder has to be used, but we cannot use EnumBuilder
1382 // because it does not properly support generics
1384 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1388 public override string GetValueAsLiteral ()
1390 return Child.GetValueAsLiteral ();
1393 public override long GetValueAsLong ()
1395 return Child.GetValueAsLong ();
1398 public EnumConstant Increment()
1400 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1403 public override bool IsDefaultValue {
1405 return Child.IsDefaultValue;
1409 public override bool IsSideEffectFree {
1411 return Child.IsSideEffectFree;
1415 public override bool IsZeroInteger {
1416 get { return Child.IsZeroInteger; }
1419 public override bool IsNegative {
1421 return Child.IsNegative;
1425 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1427 if (Child.Type == target_type)
1430 return Child.ConvertExplicitly (in_checked_context, target_type);
1433 public override Constant ConvertImplicitly (TypeSpec type)
1435 if (this.type == type) {
1439 if (!Convert.ImplicitStandardConversionExists (this, type)){
1443 return Child.ConvertImplicitly (type);
1448 /// This kind of cast is used to encapsulate Value Types in objects.
1450 /// The effect of it is to box the value type emitted by the previous
1453 public class BoxedCast : TypeCast {
1455 public BoxedCast (Expression expr, TypeSpec target_type)
1456 : base (expr, target_type)
1458 eclass = ExprClass.Value;
1461 protected override Expression DoResolve (ResolveContext ec)
1463 // This should never be invoked, we are born in fully
1464 // initialized state.
1469 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1471 // Only boxing to object type is supported
1472 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1473 base.EncodeAttributeValue (rc, enc, targetType);
1477 enc.Encode (child.Type);
1478 child.EncodeAttributeValue (rc, enc, child.Type);
1481 public override void Emit (EmitContext ec)
1485 ec.Emit (OpCodes.Box, child.Type);
1488 public override void EmitSideEffect (EmitContext ec)
1490 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1491 // so, we need to emit the box+pop instructions in most cases
1492 if (child.Type.IsStruct &&
1493 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1494 child.EmitSideEffect (ec);
1496 base.EmitSideEffect (ec);
1500 public class UnboxCast : TypeCast {
1501 public UnboxCast (Expression expr, TypeSpec return_type)
1502 : base (expr, return_type)
1506 protected override Expression DoResolve (ResolveContext ec)
1508 // This should never be invoked, we are born in fully
1509 // initialized state.
1514 public override void Emit (EmitContext ec)
1518 ec.Emit (OpCodes.Unbox_Any, type);
1523 /// This is used to perform explicit numeric conversions.
1525 /// Explicit numeric conversions might trigger exceptions in a checked
1526 /// context, so they should generate the conv.ovf opcodes instead of
1529 public class ConvCast : TypeCast {
1530 public enum Mode : byte {
1531 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1533 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1534 U2_I1, U2_U1, U2_I2, U2_CH,
1535 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1536 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1537 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1538 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1539 CH_I1, CH_U1, CH_I2,
1540 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1541 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1547 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1548 : base (child, return_type)
1553 protected override Expression DoResolve (ResolveContext ec)
1555 // This should never be invoked, we are born in fully
1556 // initialized state.
1561 public override string ToString ()
1563 return String.Format ("ConvCast ({0}, {1})", mode, child);
1566 public override void Emit (EmitContext ec)
1570 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1572 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1573 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1574 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1575 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1576 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1578 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1579 case Mode.U1_CH: /* nothing */ break;
1581 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1582 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1583 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1584 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1585 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1586 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1588 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1589 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1590 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1591 case Mode.U2_CH: /* nothing */ break;
1593 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1594 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1595 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1596 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1597 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1598 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1599 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1601 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1602 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1603 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1604 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1605 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1606 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1608 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1609 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1610 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1611 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1612 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1613 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1614 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1615 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1616 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1618 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1619 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1620 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1621 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1622 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1623 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1624 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1625 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1626 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1628 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1629 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1630 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1632 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1633 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1634 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1635 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1637 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1638 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1639 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1640 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1642 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1643 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1644 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1645 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1646 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1647 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1648 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1649 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1650 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1651 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1653 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1657 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1658 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1659 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1660 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1661 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1663 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1664 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1666 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1667 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1668 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1670 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1671 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1673 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1674 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1675 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1676 case Mode.U2_CH: /* nothing */ break;
1678 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.I4_U4: /* nothing */ break;
1682 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1683 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1684 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1687 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1688 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1689 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U4_I4: /* nothing */ break;
1691 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1693 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1694 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1695 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1696 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1697 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1698 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1699 case Mode.I8_U8: /* nothing */ break;
1700 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1701 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1703 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1704 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1705 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1706 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1707 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1708 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1709 case Mode.U8_I8: /* nothing */ break;
1710 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1711 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1713 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1714 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1715 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1717 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1718 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1719 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1720 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1722 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1723 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1724 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1725 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1727 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1728 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1729 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1730 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1731 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1732 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1733 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1734 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1735 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1736 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1738 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1744 class OpcodeCast : TypeCast
1748 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1749 : base (child, return_type)
1754 protected override Expression DoResolve (ResolveContext ec)
1756 // This should never be invoked, we are born in fully
1757 // initialized state.
1762 public override void Emit (EmitContext ec)
1768 public TypeSpec UnderlyingType {
1769 get { return child.Type; }
1774 // Opcode casts expression with 2 opcodes but only
1775 // single expression tree node
1777 class OpcodeCastDuplex : OpcodeCast
1779 readonly OpCode second;
1781 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1782 : base (child, returnType, first)
1784 this.second = second;
1787 public override void Emit (EmitContext ec)
1795 /// This kind of cast is used to encapsulate a child and cast it
1796 /// to the class requested
1798 public sealed class ClassCast : TypeCast {
1799 readonly bool forced;
1801 public ClassCast (Expression child, TypeSpec return_type)
1802 : base (child, return_type)
1806 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1807 : base (child, return_type)
1809 this.forced = forced;
1812 public override void Emit (EmitContext ec)
1816 bool gen = TypeManager.IsGenericParameter (child.Type);
1818 ec.Emit (OpCodes.Box, child.Type);
1820 if (type.IsGenericParameter) {
1821 ec.Emit (OpCodes.Unbox_Any, type);
1828 ec.Emit (OpCodes.Castclass, type);
1833 // Created during resolving pahse when an expression is wrapped or constantified
1834 // and original expression can be used later (e.g. for expression trees)
1836 public class ReducedExpression : Expression
1838 sealed class ReducedConstantExpression : EmptyConstantCast
1840 readonly Expression orig_expr;
1842 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1843 : base (expr, expr.Type)
1845 this.orig_expr = orig_expr;
1848 public override Constant ConvertImplicitly (TypeSpec target_type)
1850 Constant c = base.ConvertImplicitly (target_type);
1852 c = new ReducedConstantExpression (c, orig_expr);
1857 public override Expression CreateExpressionTree (ResolveContext ec)
1859 return orig_expr.CreateExpressionTree (ec);
1862 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1864 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1866 c = new ReducedConstantExpression (c, orig_expr);
1870 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1873 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1875 if (orig_expr is Conditional)
1876 child.EncodeAttributeValue (rc, enc, targetType);
1878 base.EncodeAttributeValue (rc, enc, targetType);
1882 sealed class ReducedExpressionStatement : ExpressionStatement
1884 readonly Expression orig_expr;
1885 readonly ExpressionStatement stm;
1887 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1889 this.orig_expr = orig;
1891 this.eclass = stm.eclass;
1892 this.type = stm.Type;
1894 this.loc = orig.Location;
1897 public override bool ContainsEmitWithAwait ()
1899 return stm.ContainsEmitWithAwait ();
1902 public override Expression CreateExpressionTree (ResolveContext ec)
1904 return orig_expr.CreateExpressionTree (ec);
1907 protected override Expression DoResolve (ResolveContext ec)
1912 public override void Emit (EmitContext ec)
1917 public override void EmitStatement (EmitContext ec)
1919 stm.EmitStatement (ec);
1923 readonly Expression expr, orig_expr;
1925 private ReducedExpression (Expression expr, Expression orig_expr)
1928 this.eclass = expr.eclass;
1929 this.type = expr.Type;
1930 this.orig_expr = orig_expr;
1931 this.loc = orig_expr.Location;
1936 public Expression OriginalExpression {
1944 public override bool ContainsEmitWithAwait ()
1946 return expr.ContainsEmitWithAwait ();
1950 // Creates fully resolved expression switcher
1952 public static Constant Create (Constant expr, Expression original_expr)
1954 if (expr.eclass == ExprClass.Unresolved)
1955 throw new ArgumentException ("Unresolved expression");
1957 return new ReducedConstantExpression (expr, original_expr);
1960 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1962 return new ReducedExpressionStatement (s, orig);
1965 public static Expression Create (Expression expr, Expression original_expr)
1967 return Create (expr, original_expr, true);
1971 // Creates unresolved reduce expression. The original expression has to be
1972 // already resolved. Created expression is constant based based on `expr'
1973 // value unless canBeConstant is used
1975 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1977 if (canBeConstant) {
1978 Constant c = expr as Constant;
1980 return Create (c, original_expr);
1983 ExpressionStatement s = expr as ExpressionStatement;
1985 return Create (s, original_expr);
1987 if (expr.eclass == ExprClass.Unresolved)
1988 throw new ArgumentException ("Unresolved expression");
1990 return new ReducedExpression (expr, original_expr);
1993 public override Expression CreateExpressionTree (ResolveContext ec)
1995 return orig_expr.CreateExpressionTree (ec);
1998 protected override Expression DoResolve (ResolveContext ec)
2003 public override void Emit (EmitContext ec)
2008 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2010 expr.EmitBranchable (ec, target, on_true);
2013 public override SLE.Expression MakeExpression (BuilderContext ctx)
2015 return orig_expr.MakeExpression (ctx);
2020 // Standard composite pattern
2022 public abstract class CompositeExpression : Expression
2024 protected Expression expr;
2026 protected CompositeExpression (Expression expr)
2029 this.loc = expr.Location;
2032 public override bool ContainsEmitWithAwait ()
2034 return expr.ContainsEmitWithAwait ();
2037 public override Expression CreateExpressionTree (ResolveContext rc)
2039 return expr.CreateExpressionTree (rc);
2042 public Expression Child {
2043 get { return expr; }
2046 protected override Expression DoResolve (ResolveContext rc)
2048 expr = expr.Resolve (rc);
2051 eclass = expr.eclass;
2057 public override void Emit (EmitContext ec)
2062 public override bool IsNull {
2063 get { return expr.IsNull; }
2068 // Base of expressions used only to narrow resolve flow
2070 public abstract class ShimExpression : Expression
2072 protected Expression expr;
2074 protected ShimExpression (Expression expr)
2079 public Expression Expr {
2085 protected override void CloneTo (CloneContext clonectx, Expression t)
2090 ShimExpression target = (ShimExpression) t;
2091 target.expr = expr.Clone (clonectx);
2094 public override bool ContainsEmitWithAwait ()
2096 return expr.ContainsEmitWithAwait ();
2099 public override Expression CreateExpressionTree (ResolveContext ec)
2101 throw new NotSupportedException ("ET");
2104 public override void Emit (EmitContext ec)
2106 throw new InternalErrorException ("Missing Resolve call");
2112 // Unresolved type name expressions
2114 public abstract class ATypeNameExpression : FullNamedExpression
2117 protected TypeArguments targs;
2119 protected ATypeNameExpression (string name, Location l)
2125 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2132 protected ATypeNameExpression (string name, int arity, Location l)
2133 : this (name, new UnboundTypeArguments (arity), l)
2139 protected int Arity {
2141 return targs == null ? 0 : targs.Count;
2145 public bool HasTypeArguments {
2147 return targs != null && !targs.IsEmpty;
2151 public string Name {
2160 public TypeArguments TypeArguments {
2168 public override bool Equals (object obj)
2170 ATypeNameExpression atne = obj as ATypeNameExpression;
2171 return atne != null && atne.Name == Name &&
2172 (targs == null || targs.Equals (atne.targs));
2175 public override int GetHashCode ()
2177 return Name.GetHashCode ();
2180 // TODO: Move it to MemberCore
2181 public static string GetMemberType (MemberCore mc)
2187 if (mc is FieldBase)
2189 if (mc is MethodCore)
2191 if (mc is EnumMember)
2199 public override string GetSignatureForError ()
2201 if (targs != null) {
2202 return Name + "<" + targs.GetSignatureForError () + ">";
2208 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2212 /// SimpleName expressions are formed of a single word and only happen at the beginning
2213 /// of a dotted-name.
2215 public class SimpleName : ATypeNameExpression
2217 public SimpleName (string name, Location l)
2222 public SimpleName (string name, TypeArguments args, Location l)
2223 : base (name, args, l)
2227 public SimpleName (string name, int arity, Location l)
2228 : base (name, arity, l)
2232 public SimpleName GetMethodGroup ()
2234 return new SimpleName (Name, targs, loc);
2237 protected override Expression DoResolve (ResolveContext rc)
2239 var e = SimpleNameResolve (rc, null, false);
2241 var fe = e as FieldExpr;
2243 fe.VerifyAssignedStructField (rc, null);
2249 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2251 return SimpleNameResolve (ec, right_side, false);
2254 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2256 if (ctx.CurrentType != null) {
2257 if (ctx.CurrentMemberDefinition != null) {
2258 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2260 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2266 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2267 if (retval != null) {
2268 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2269 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2273 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2274 if (retval != null) {
2275 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2279 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2282 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2284 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2287 if (fne.Type != null && Arity > 0) {
2288 if (HasTypeArguments) {
2289 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2290 if (ct.ResolveAsType (ec) == null)
2296 return new GenericOpenTypeExpr (fne.Type, loc);
2300 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2302 if (!(fne is Namespace))
2306 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2307 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2308 ec.Module.Compiler.Report.Error (1980, Location,
2309 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2310 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2313 fne = new DynamicTypeExpr (loc);
2314 fne.ResolveAsType (ec);
2320 Error_TypeOrNamespaceNotFound (ec);
2324 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2326 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2329 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2331 int lookup_arity = Arity;
2332 bool errorMode = false;
2334 Block current_block = rc.CurrentBlock;
2335 INamedBlockVariable variable = null;
2336 bool variable_found = false;
2340 // Stage 1: binding to local variables or parameters
2342 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2344 if (current_block != null && lookup_arity == 0) {
2345 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2346 if (!variable.IsDeclared) {
2347 // We found local name in accessible block but it's not
2348 // initialized yet, maybe the user wanted to bind to something else
2350 variable_found = true;
2352 e = variable.CreateReferenceExpression (rc, loc);
2355 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2364 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2366 TypeSpec member_type = rc.CurrentType;
2367 for (; member_type != null; member_type = member_type.DeclaringType) {
2368 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2372 var me = e as MemberExpr;
2374 // The name matches a type, defer to ResolveAsTypeStep
2382 if (variable != null) {
2383 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2384 rc.Report.Error (844, loc,
2385 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2386 Name, me.GetSignatureForError ());
2390 } else if (me is MethodGroupExpr) {
2391 // Leave it to overload resolution to report correct error
2393 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2394 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2397 // LAMESPEC: again, ignores InvocableOnly
2398 if (variable != null) {
2399 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2400 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2404 // MemberLookup does not check accessors availability, this is actually needed for properties only
2406 var pe = me as PropertyExpr;
2409 // Break as there is no other overload available anyway
2410 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2411 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2414 pe.Getter = pe.PropertyInfo.Get;
2416 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2419 pe.Setter = pe.PropertyInfo.Set;
2424 // TODO: It's used by EventExpr -> FieldExpr transformation only
2425 // TODO: Should go to MemberAccess
2426 me = me.ResolveMemberAccess (rc, null, null);
2430 me.SetTypeArguments (rc, targs);
2437 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2439 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2440 if (IsPossibleTypeOrNamespace (rc)) {
2441 if (variable != null) {
2442 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2443 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2446 return ResolveAsTypeOrNamespace (rc);
2451 if (variable_found) {
2452 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2455 TypeParameter[] tparams = rc.CurrentTypeParameters;
2456 if (tparams != null) {
2457 foreach (var ctp in tparams) {
2458 if (ctp.Name == Name) {
2459 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2465 var ct = rc.CurrentType;
2467 if (ct.MemberDefinition.TypeParametersCount > 0) {
2468 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2469 if (ctp.Name == Name) {
2470 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2476 ct = ct.DeclaringType;
2477 } while (ct != null);
2480 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2481 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2483 rc.Report.SymbolRelatedToPreviousError (e.Type);
2484 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2489 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2491 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2492 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2497 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2500 return ErrorExpression.Instance;
2503 if (rc.Module.Evaluator != null) {
2504 var fi = rc.Module.Evaluator.LookupField (Name);
2506 return new FieldExpr (fi.Item1, loc);
2514 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2516 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2521 if (right_side != null) {
2522 if (e is TypeExpr) {
2523 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2527 e = e.ResolveLValue (ec, right_side);
2532 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2536 public override object Accept (StructuralVisitor visitor)
2538 return visitor.Visit (this);
2543 /// Represents a namespace or a type. The name of the class was inspired by
2544 /// section 10.8.1 (Fully Qualified Names).
2546 public abstract class FullNamedExpression : Expression
2548 protected override void CloneTo (CloneContext clonectx, Expression target)
2550 // Do nothing, most unresolved type expressions cannot be
2551 // resolved to different type
2554 public override bool ContainsEmitWithAwait ()
2559 public override Expression CreateExpressionTree (ResolveContext ec)
2561 throw new NotSupportedException ("ET");
2564 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2567 // This is used to resolve the expression as a type, a null
2568 // value will be returned if the expression is not a type
2571 public override TypeSpec ResolveAsType (IMemberContext mc)
2573 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2578 TypeExpr te = fne as TypeExpr;
2580 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2588 var dep = type.GetMissingDependencies ();
2590 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2594 // Obsolete checks cannot be done when resolving base context as they
2595 // require type dependencies to be set but we are in process of resolving them
2597 if (!(mc is TypeContainer.BaseContext)) {
2598 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2599 if (obsolete_attr != null && !mc.IsObsolete) {
2600 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2608 public override void Emit (EmitContext ec)
2610 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2611 GetSignatureForError ());
2616 /// Expression that evaluates to a type
2618 public abstract class TypeExpr : FullNamedExpression
2620 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2626 protected sealed override Expression DoResolve (ResolveContext ec)
2632 public override bool Equals (object obj)
2634 TypeExpr tobj = obj as TypeExpr;
2638 return Type == tobj.Type;
2641 public override int GetHashCode ()
2643 return Type.GetHashCode ();
2648 /// Fully resolved Expression that already evaluated to a type
2650 public class TypeExpression : TypeExpr
2652 public TypeExpression (TypeSpec t, Location l)
2655 eclass = ExprClass.Type;
2659 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2666 /// This class denotes an expression which evaluates to a member
2667 /// of a struct or a class.
2669 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2672 // An instance expression associated with this member, if it's a
2673 // non-static member
2675 public Expression InstanceExpression;
2678 /// The name of this member.
2680 public abstract string Name {
2685 // When base.member is used
2687 public bool IsBase {
2688 get { return InstanceExpression is BaseThis; }
2692 /// Whether this is an instance member.
2694 public abstract bool IsInstance {
2699 /// Whether this is a static member.
2701 public abstract bool IsStatic {
2705 protected abstract TypeSpec DeclaringType {
2709 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2711 return InstanceExpression.Type;
2716 // Converts best base candidate for virtual method starting from QueriedBaseType
2718 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2721 // Only when base.member is used and method is virtual
2727 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2728 // means for base.member access we have to find the closest match after we found best candidate
2730 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2732 // The method could already be what we are looking for
2734 TypeSpec[] targs = null;
2735 if (method.DeclaringType != InstanceExpression.Type) {
2736 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2737 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2738 if (base_override.IsGeneric)
2739 targs = method.TypeArguments;
2741 method = base_override;
2745 // TODO: For now we do it for any hoisted call even if it's needed for
2746 // hoisted stories only but that requires a new expression wrapper
2747 if (rc.CurrentAnonymousMethod != null) {
2748 if (targs == null && method.IsGeneric) {
2749 targs = method.TypeArguments;
2750 method = method.GetGenericMethodDefinition ();
2753 if (method.Parameters.HasArglist)
2754 throw new NotImplementedException ("__arglist base call proxy");
2756 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2758 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2759 // get/set member expressions second call would fail to proxy because left expression
2760 // would be of 'this' and not 'base'
2761 if (rc.CurrentType.IsStruct)
2762 InstanceExpression = new This (loc).Resolve (rc);
2766 method = method.MakeGenericMethod (rc, targs);
2770 // Only base will allow this invocation to happen.
2772 if (method.IsAbstract) {
2773 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2779 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2781 if (InstanceExpression == null)
2784 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2785 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2786 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2791 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2793 if (InstanceExpression == null)
2796 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2799 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2801 var ct = rc.CurrentType;
2802 if (ct == qualifier)
2805 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2808 qualifier = qualifier.GetDefinition ();
2809 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2816 public override bool ContainsEmitWithAwait ()
2818 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2821 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2824 type = type.GetDefinition ();
2826 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2829 type = type.DeclaringType;
2830 } while (type != null);
2835 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2837 if (InstanceExpression != null) {
2838 InstanceExpression = InstanceExpression.Resolve (rc);
2839 CheckProtectedMemberAccess (rc, member);
2842 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2843 UnsafeError (rc, loc);
2846 var dep = member.GetMissingDependencies ();
2848 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2851 if (!rc.IsObsolete) {
2852 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2854 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2857 if (!(member is FieldSpec))
2858 member.MemberDefinition.SetIsUsed ();
2861 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2863 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2866 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2868 rc.Report.SymbolRelatedToPreviousError (member);
2869 rc.Report.Error (1540, loc,
2870 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2871 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2875 // Implements identicial simple name and type-name
2877 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2880 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2883 // 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
2884 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2886 if (left is MemberExpr || left is VariableReference) {
2887 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2888 if (identical_type != null && identical_type.Type == left.Type)
2889 return identical_type;
2895 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2898 if (InstanceExpression != null) {
2899 if (InstanceExpression is TypeExpr) {
2900 var t = InstanceExpression.Type;
2902 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2903 if (oa != null && !rc.IsObsolete) {
2904 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2907 t = t.DeclaringType;
2908 } while (t != null);
2910 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2911 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2912 rc.Report.Error (176, loc,
2913 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2914 GetSignatureForError ());
2918 InstanceExpression = null;
2924 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2925 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2926 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2927 rc.Report.Error (236, loc,
2928 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2929 GetSignatureForError ());
2931 rc.Report.Error (120, loc,
2932 "An object reference is required to access non-static member `{0}'",
2933 GetSignatureForError ());
2935 InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
2939 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2940 rc.Report.Error (38, loc,
2941 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2942 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2945 InstanceExpression = new This (loc);
2946 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2947 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2948 InstanceExpression = InstanceExpression.Resolve (rc);
2951 InstanceExpression = InstanceExpression.Resolve (rc);
2957 var me = InstanceExpression as MemberExpr;
2959 me.ResolveInstanceExpression (rc, rhs);
2961 var fe = me as FieldExpr;
2962 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2963 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2964 rc.Report.Warning (1690, 1, loc,
2965 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2966 me.GetSignatureForError ());
2973 // Run member-access postponed check once we know that
2974 // the expression is not field expression which is the only
2975 // expression which can use uninitialized this
2977 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2978 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2982 // Additional checks for l-value member access
2985 if (InstanceExpression is UnboxCast) {
2986 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2993 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2995 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2996 ec.Report.Warning (1720, 1, left.Location,
2997 "Expression will always cause a `{0}'", "System.NullReferenceException");
3000 InstanceExpression = left;
3004 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3006 TypeSpec instance_type = InstanceExpression.Type;
3007 if (TypeSpec.IsValueType (instance_type)) {
3008 if (InstanceExpression is IMemoryLocation) {
3009 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3011 // Cannot release the temporary variable when its address
3012 // is required to be on stack for any parent
3013 LocalTemporary t = new LocalTemporary (instance_type);
3014 InstanceExpression.Emit (ec);
3016 t.AddressOf (ec, AddressOp.Store);
3019 InstanceExpression.Emit (ec);
3021 // Only to make verifier happy
3022 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3023 ec.Emit (OpCodes.Box, instance_type);
3026 if (prepare_for_load)
3027 ec.Emit (OpCodes.Dup);
3030 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3033 public class ExtensionMethodCandidates
3035 NamespaceContainer container;
3037 IList<MethodSpec> methods;
3039 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
3040 : this (methods, nsContainer, null)
3044 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
3046 this.methods = methods;
3047 this.container = nsContainer;
3051 public NamespaceContainer Container {
3057 public bool HasUninspectedMembers { get; set; }
3059 public Namespace Namespace {
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;
3105 // Here we try to resume the search for extension method at the point
3106 // where the last bunch of candidates was found. It's more tricky than
3107 // it seems as we have to check both namespace containers and namespace
3108 // in correct order.
3114 // namespace B.C.D {
3115 // <our first search found candidates in A.B.C.D
3119 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3120 // checked before we hit A.N1 using
3122 if (candidates.Namespace == null) {
3124 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3125 if (methods != null) {
3126 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3127 return methods.Cast<MemberSpec> ().ToList ();
3131 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3132 if (ns_container == null)
3135 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3136 if (candidates == null)
3139 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3142 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3144 // We are already here
3148 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3150 if (arguments == null)
3151 arguments = new Arguments (1);
3153 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3154 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3156 // Store resolved argument and restore original arguments
3158 // Clean-up modified arguments for error reporting
3159 arguments.RemoveAt (0);
3163 var me = ExtensionExpression as MemberExpr;
3165 me.ResolveInstanceExpression (ec, null);
3167 InstanceExpression = null;
3171 #region IErrorHandler Members
3173 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3178 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3180 rc.Report.SymbolRelatedToPreviousError (best);
3181 rc.Report.Error (1928, loc,
3182 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3183 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3186 rc.Report.Error (1929, loc,
3187 "Extension method instance type `{0}' cannot be converted to `{1}'",
3188 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3194 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3199 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3208 /// MethodGroupExpr represents a group of method candidates which
3209 /// can be resolved to the best method overload
3211 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3213 protected IList<MemberSpec> Methods;
3214 MethodSpec best_candidate;
3215 TypeSpec best_candidate_return;
3216 protected TypeArguments type_arguments;
3218 SimpleName simple_name;
3219 protected TypeSpec queried_type;
3221 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3225 this.type = InternalType.MethodGroup;
3227 eclass = ExprClass.MethodGroup;
3228 queried_type = type;
3231 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3232 : this (new MemberSpec[] { m }, type, loc)
3238 public MethodSpec BestCandidate {
3240 return best_candidate;
3244 public TypeSpec BestCandidateReturnType {
3246 return best_candidate_return;
3250 public IList<MemberSpec> Candidates {
3256 protected override TypeSpec DeclaringType {
3258 return queried_type;
3262 public override bool IsInstance {
3264 if (best_candidate != null)
3265 return !best_candidate.IsStatic;
3271 public override bool IsStatic {
3273 if (best_candidate != null)
3274 return best_candidate.IsStatic;
3280 public override string Name {
3282 if (best_candidate != null)
3283 return best_candidate.Name;
3286 return Methods.First ().Name;
3293 // When best candidate is already know this factory can be used
3294 // to avoid expensive overload resolution to be called
3296 // NOTE: InstanceExpression has to be set manually
3298 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3300 return new MethodGroupExpr (best, queriedType, loc) {
3301 best_candidate = best,
3302 best_candidate_return = best.ReturnType
3306 public override string GetSignatureForError ()
3308 if (best_candidate != null)
3309 return best_candidate.GetSignatureForError ();
3311 return Methods.First ().GetSignatureForError ();
3314 public override Expression CreateExpressionTree (ResolveContext ec)
3316 if (best_candidate == null) {
3317 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3321 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3322 ec.Report.Error (765, loc,
3323 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3325 return new TypeOfMethod (best_candidate, loc);
3328 protected override Expression DoResolve (ResolveContext ec)
3330 this.eclass = ExprClass.MethodGroup;
3332 if (InstanceExpression != null) {
3333 InstanceExpression = InstanceExpression.Resolve (ec);
3334 if (InstanceExpression == null)
3341 public override void Emit (EmitContext ec)
3343 throw new NotSupportedException ();
3346 public void EmitCall (EmitContext ec, Arguments arguments)
3348 var call = new CallEmitter ();
3349 call.InstanceExpression = InstanceExpression;
3350 call.Emit (ec, best_candidate, arguments, loc);
3353 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3355 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3356 Name, TypeManager.CSharpName (target));
3359 public static bool IsExtensionMethodArgument (Expression expr)
3362 // LAMESPEC: No details about which expressions are not allowed
3364 return !(expr is TypeExpr) && !(expr is BaseThis);
3368 /// Find the Applicable Function Members (7.4.2.1)
3370 /// me: Method Group expression with the members to select.
3371 /// it might contain constructors or methods (or anything
3372 /// that maps to a method).
3374 /// Arguments: ArrayList containing resolved Argument objects.
3376 /// loc: The location if we want an error to be reported, or a Null
3377 /// location for "probing" purposes.
3379 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3380 /// that is the best match of me on Arguments.
3383 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3385 // TODO: causes issues with probing mode, remove explicit Kind check
3386 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3389 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3390 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3391 r.BaseMembersProvider = this;
3392 r.InstanceQualifier = this;
3395 if (cerrors != null)
3396 r.CustomErrors = cerrors;
3398 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3399 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3400 if (best_candidate == null)
3401 return r.BestCandidateIsDynamic ? this : null;
3403 // Overload resolver had to create a new method group, all checks bellow have already been executed
3404 if (r.BestCandidateNewMethodGroup != null)
3405 return r.BestCandidateNewMethodGroup;
3407 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3408 if (InstanceExpression != null) {
3409 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3410 InstanceExpression = null;
3412 if (best_candidate.IsStatic && simple_name != null) {
3413 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3416 InstanceExpression.Resolve (ec);
3420 ResolveInstanceExpression (ec, null);
3423 var base_override = CandidateToBaseOverride (ec, best_candidate);
3424 if (base_override == best_candidate) {
3425 best_candidate_return = r.BestCandidateReturnType;
3427 best_candidate = base_override;
3428 best_candidate_return = best_candidate.ReturnType;
3434 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3436 simple_name = original;
3437 return base.ResolveMemberAccess (ec, left, original);
3440 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3442 type_arguments = ta;
3445 #region IBaseMembersProvider Members
3447 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3449 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3452 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3454 if (queried_type == member.DeclaringType)
3457 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3458 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3462 // Extension methods lookup after ordinary methods candidates failed to apply
3464 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3466 if (InstanceExpression == null)
3469 InstanceExpression = InstanceExpression.Resolve (rc);
3470 if (!IsExtensionMethodArgument (InstanceExpression))
3473 int arity = type_arguments == null ? 0 : type_arguments.Count;
3474 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3475 if (methods == null)
3478 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3479 emg.SetTypeArguments (rc, type_arguments);
3486 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3488 public ConstructorInstanceQualifier (TypeSpec type)
3491 InstanceType = type;
3494 public TypeSpec InstanceType { get; private set; }
3496 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3498 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3502 public struct OverloadResolver
3505 public enum Restrictions
3509 ProbingOnly = 1 << 1,
3510 CovariantDelegate = 1 << 2,
3511 NoBaseMembers = 1 << 3,
3512 BaseMembersIncluded = 1 << 4
3515 public interface IBaseMembersProvider
3517 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3518 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3519 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3522 public interface IErrorHandler
3524 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3525 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3526 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3527 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3530 public interface IInstanceQualifier
3532 TypeSpec InstanceType { get; }
3533 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3536 sealed class NoBaseMembers : IBaseMembersProvider
3538 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3540 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3545 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3550 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3556 struct AmbiguousCandidate
3558 public readonly MemberSpec Member;
3559 public readonly bool Expanded;
3560 public readonly AParametersCollection Parameters;
3562 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3565 Parameters = parameters;
3566 Expanded = expanded;
3571 IList<MemberSpec> members;
3572 TypeArguments type_arguments;
3573 IBaseMembersProvider base_provider;
3574 IErrorHandler custom_errors;
3575 IInstanceQualifier instance_qualifier;
3576 Restrictions restrictions;
3577 MethodGroupExpr best_candidate_extension_group;
3578 TypeSpec best_candidate_return_type;
3580 SessionReportPrinter lambda_conv_msgs;
3581 ReportPrinter prev_recorder;
3583 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3584 : this (members, null, restrictions, loc)
3588 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3591 if (members == null || members.Count == 0)
3592 throw new ArgumentException ("empty members set");
3594 this.members = members;
3596 type_arguments = targs;
3597 this.restrictions = restrictions;
3598 if (IsDelegateInvoke)
3599 this.restrictions |= Restrictions.NoBaseMembers;
3601 base_provider = NoBaseMembers.Instance;
3606 public IBaseMembersProvider BaseMembersProvider {
3608 return base_provider;
3611 base_provider = value;
3615 public bool BestCandidateIsDynamic { get; set; }
3618 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3620 public MethodGroupExpr BestCandidateNewMethodGroup {
3622 return best_candidate_extension_group;
3627 // Return type can be different between best candidate and closest override
3629 public TypeSpec BestCandidateReturnType {
3631 return best_candidate_return_type;
3635 public IErrorHandler CustomErrors {
3637 return custom_errors;
3640 custom_errors = value;
3644 TypeSpec DelegateType {
3646 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3647 throw new InternalErrorException ("Not running in delegate mode", loc);
3649 return members [0].DeclaringType;
3653 public IInstanceQualifier InstanceQualifier {
3655 return instance_qualifier;
3658 instance_qualifier = value;
3662 bool IsProbingOnly {
3664 return (restrictions & Restrictions.ProbingOnly) != 0;
3668 bool IsDelegateInvoke {
3670 return (restrictions & Restrictions.DelegateInvoke) != 0;
3677 // 7.4.3.3 Better conversion from expression
3678 // Returns : 1 if a->p is better,
3679 // 2 if a->q is better,
3680 // 0 if neither is better
3682 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3684 TypeSpec argument_type = a.Type;
3687 // If argument is an anonymous function
3689 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3691 // p and q are delegate types or expression tree types
3693 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3694 if (q.MemberDefinition != p.MemberDefinition) {
3699 // Uwrap delegate from Expression<T>
3701 q = TypeManager.GetTypeArguments (q)[0];
3702 p = TypeManager.GetTypeArguments (p)[0];
3705 var p_m = Delegate.GetInvokeMethod (p);
3706 var q_m = Delegate.GetInvokeMethod (q);
3709 // With identical parameter lists
3711 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3718 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3720 if (p.Kind == MemberKind.Void) {
3721 return q.Kind != MemberKind.Void ? 2 : 0;
3725 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3727 if (q.Kind == MemberKind.Void) {
3728 return p.Kind != MemberKind.Void ? 1: 0;
3732 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3733 // better conversion is performed between underlying types Y1 and Y2
3735 if (p.IsGenericTask || q.IsGenericTask) {
3736 var async_am = a.Expr as AnonymousMethodExpression;
3737 if (async_am != null && async_am.Block.IsAsync) {
3739 if (p.IsGenericTask != q.IsGenericTask) {
3743 q = q.TypeArguments[0];
3744 p = p.TypeArguments[0];
3749 // The parameters are identicial and return type is not void, use better type conversion
3750 // on return type to determine better one
3753 if (argument_type == p)
3756 if (argument_type == q)
3760 return BetterTypeConversion (ec, p, q);
3764 // 7.4.3.4 Better conversion from type
3766 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3768 if (p == null || q == null)
3769 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3771 switch (p.BuiltinType) {
3772 case BuiltinTypeSpec.Type.Int:
3773 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3776 case BuiltinTypeSpec.Type.Long:
3777 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3780 case BuiltinTypeSpec.Type.SByte:
3781 switch (q.BuiltinType) {
3782 case BuiltinTypeSpec.Type.Byte:
3783 case BuiltinTypeSpec.Type.UShort:
3784 case BuiltinTypeSpec.Type.UInt:
3785 case BuiltinTypeSpec.Type.ULong:
3789 case BuiltinTypeSpec.Type.Short:
3790 switch (q.BuiltinType) {
3791 case BuiltinTypeSpec.Type.UShort:
3792 case BuiltinTypeSpec.Type.UInt:
3793 case BuiltinTypeSpec.Type.ULong:
3797 case BuiltinTypeSpec.Type.Dynamic:
3798 // Dynamic is never better
3802 switch (q.BuiltinType) {
3803 case BuiltinTypeSpec.Type.Int:
3804 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3807 case BuiltinTypeSpec.Type.Long:
3808 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3811 case BuiltinTypeSpec.Type.SByte:
3812 switch (p.BuiltinType) {
3813 case BuiltinTypeSpec.Type.Byte:
3814 case BuiltinTypeSpec.Type.UShort:
3815 case BuiltinTypeSpec.Type.UInt:
3816 case BuiltinTypeSpec.Type.ULong:
3820 case BuiltinTypeSpec.Type.Short:
3821 switch (p.BuiltinType) {
3822 case BuiltinTypeSpec.Type.UShort:
3823 case BuiltinTypeSpec.Type.UInt:
3824 case BuiltinTypeSpec.Type.ULong:
3828 case BuiltinTypeSpec.Type.Dynamic:
3829 // Dynamic is never better
3833 // FIXME: handle lifted operators
3835 // TODO: this is expensive
3836 Expression p_tmp = new EmptyExpression (p);
3837 Expression q_tmp = new EmptyExpression (q);
3839 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3840 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3842 if (p_to_q && !q_to_p)
3845 if (q_to_p && !p_to_q)
3852 /// Determines "Better function" between candidate
3853 /// and the current best match
3856 /// Returns a boolean indicating :
3857 /// false if candidate ain't better
3858 /// true if candidate is better than the current best match
3860 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3861 MemberSpec best, AParametersCollection bparam, bool best_params)
3863 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3864 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3866 bool better_at_least_one = false;
3868 int args_count = args == null ? 0 : args.Count;
3872 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3875 // Default arguments are ignored for better decision
3876 if (a.IsDefaultArgument)
3880 // When comparing named argument the parameter type index has to be looked up
3881 // in original parameter set (override version for virtual members)
3883 NamedArgument na = a as NamedArgument;
3885 int idx = cparam.GetParameterIndexByName (na.Name);
3886 ct = candidate_pd.Types[idx];
3887 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3888 ct = TypeManager.GetElementType (ct);
3890 idx = bparam.GetParameterIndexByName (na.Name);
3891 bt = best_pd.Types[idx];
3892 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3893 bt = TypeManager.GetElementType (bt);
3895 ct = candidate_pd.Types[c_idx];
3896 bt = best_pd.Types[b_idx];
3898 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3899 ct = TypeManager.GetElementType (ct);
3903 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3904 bt = TypeManager.GetElementType (bt);
3909 if (TypeSpecComparer.IsEqual (ct, bt))
3913 int result = BetterExpressionConversion (ec, a, ct, bt);
3915 // for each argument, the conversion to 'ct' should be no worse than
3916 // the conversion to 'bt'.
3920 // for at least one argument, the conversion to 'ct' should be better than
3921 // the conversion to 'bt'.
3923 better_at_least_one = true;
3926 if (better_at_least_one)
3930 // This handles the case
3932 // Add (float f1, float f2, float f3);
3933 // Add (params decimal [] foo);
3935 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3936 // first candidate would've chosen as better.
3938 if (!same && !a.IsDefaultArgument)
3942 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3946 // This handles the following cases:
3948 // Foo (int i) is better than Foo (int i, long l = 0)
3949 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3951 // Prefer non-optional version
3953 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3955 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3956 if (candidate_pd.Count >= best_pd.Count)
3959 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3966 // One is a non-generic method and second is a generic method, then non-generic is better
3968 if (best.IsGeneric != candidate.IsGeneric)
3969 return best.IsGeneric;
3972 // This handles the following cases:
3974 // Trim () is better than Trim (params char[] chars)
3975 // Concat (string s1, string s2, string s3) is better than
3976 // Concat (string s1, params string [] srest)
3977 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3979 // Prefer non-expanded version
3981 if (candidate_params != best_params)
3984 int candidate_param_count = candidate_pd.Count;
3985 int best_param_count = best_pd.Count;
3987 if (candidate_param_count != best_param_count)
3988 // can only happen if (candidate_params && best_params)
3989 return candidate_param_count > best_param_count && best_pd.HasParams;
3992 // Both methods have the same number of parameters, and the parameters have equal types
3993 // Pick the "more specific" signature using rules over original (non-inflated) types
3995 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3996 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3998 bool specific_at_least_once = false;
3999 for (j = 0; j < args_count; ++j) {
4000 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4002 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4003 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4005 ct = candidate_def_pd.Types[j];
4006 bt = best_def_pd.Types[j];
4011 TypeSpec specific = MoreSpecific (ct, bt);
4015 specific_at_least_once = true;
4018 if (specific_at_least_once)
4024 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4026 rc.Report.Error (1729, loc,
4027 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4028 type.GetSignatureForError (), argCount.ToString ());
4032 // Determines if the candidate method is applicable to the given set of arguments
4033 // There could be two different set of parameters for same candidate where one
4034 // is the closest override for default values and named arguments checks and second
4035 // one being the virtual base for the parameter types and modifiers.
4037 // A return value rates candidate method compatibility,
4038 // 0 = the best, int.MaxValue = the worst
4040 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)
4042 // Parameters of most-derived type used mainly for named and optional parameters
4043 var pd = pm.Parameters;
4045 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4046 // params modifier instead of most-derived type
4047 var cpd = ((IParametersMember) candidate).Parameters;
4048 int param_count = pd.Count;
4049 int optional_count = 0;
4051 Arguments orig_args = arguments;
4053 if (arg_count != param_count) {
4054 for (int i = 0; i < pd.Count; ++i) {
4055 if (pd.FixedParameters[i].HasDefaultValue) {
4056 optional_count = pd.Count - i;
4061 if (optional_count != 0) {
4062 // Readjust expected number when params used
4063 if (cpd.HasParams) {
4065 if (arg_count < param_count)
4067 } else if (arg_count > param_count) {
4068 int args_gap = System.Math.Abs (arg_count - param_count);
4069 return int.MaxValue - 10000 + args_gap;
4071 } else if (arg_count != param_count) {
4072 int args_gap = System.Math.Abs (arg_count - param_count);
4074 return int.MaxValue - 10000 + args_gap;
4075 if (arg_count < param_count - 1)
4076 return int.MaxValue - 10000 + args_gap;
4079 // Resize to fit optional arguments
4080 if (optional_count != 0) {
4081 if (arguments == null) {
4082 arguments = new Arguments (optional_count);
4084 // Have to create a new container, so the next run can do same
4085 var resized = new Arguments (param_count);
4086 resized.AddRange (arguments);
4087 arguments = resized;
4090 for (int i = arg_count; i < param_count; ++i)
4091 arguments.Add (null);
4095 if (arg_count > 0) {
4097 // Shuffle named arguments to the right positions if there are any
4099 if (arguments[arg_count - 1] is NamedArgument) {
4100 arg_count = arguments.Count;
4102 for (int i = 0; i < arg_count; ++i) {
4103 bool arg_moved = false;
4105 NamedArgument na = arguments[i] as NamedArgument;
4109 int index = pd.GetParameterIndexByName (na.Name);
4111 // Named parameter not found
4115 // already reordered
4120 if (index >= param_count) {
4121 // When using parameters which should not be available to the user
4122 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4125 arguments.Add (null);
4129 temp = arguments[index];
4131 // The slot has been taken by positional argument
4132 if (temp != null && !(temp is NamedArgument))
4137 arguments = arguments.MarkOrderedArgument (na);
4141 arguments[index] = arguments[i];
4142 arguments[i] = temp;
4149 arg_count = arguments.Count;
4151 } else if (arguments != null) {
4152 arg_count = arguments.Count;
4156 // 1. Handle generic method using type arguments when specified or type inference
4159 var ms = candidate as MethodSpec;
4160 if (ms != null && ms.IsGeneric) {
4161 // Setup constraint checker for probing only
4162 ConstraintChecker cc = new ConstraintChecker (null);
4164 if (type_arguments != null) {
4165 var g_args_count = ms.Arity;
4166 if (g_args_count != type_arguments.Count)
4167 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4169 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4171 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4172 // for now it simplifies things. I should probably add a callback to ResolveContext
4173 if (lambda_conv_msgs == null) {
4174 lambda_conv_msgs = new SessionReportPrinter ();
4175 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4178 var ti = new TypeInference (arguments);
4179 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4180 lambda_conv_msgs.EndSession ();
4183 return ti.InferenceScore - 20000;
4185 if (i_args.Length != 0) {
4186 ms = ms.MakeGenericMethod (ec, i_args);
4189 cc.IgnoreInferredDynamic = true;
4193 // Type arguments constraints have to match for the method to be applicable
4195 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4197 return int.MaxValue - 25000;
4201 // We have a generic return type and at same time the method is override which
4202 // means we have to also inflate override return type in case the candidate is
4203 // best candidate and override return type is different to base return type.
4205 // virtual Foo<T, object> with override Foo<T, dynamic>
4207 if (candidate != pm) {
4208 MethodSpec override_ms = (MethodSpec) pm;
4209 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4210 returnType = inflator.Inflate (returnType);
4212 returnType = ms.ReturnType;
4216 ptypes = ms.Parameters.Types;
4218 if (type_arguments != null)
4219 return int.MaxValue - 15000;
4225 // 2. Each argument has to be implicitly convertible to method parameter
4227 Parameter.Modifier p_mod = 0;
4230 for (int i = 0; i < arg_count; i++) {
4231 Argument a = arguments[i];
4233 if (!pd.FixedParameters[i].HasDefaultValue) {
4234 arguments = orig_args;
4235 return arg_count * 2 + 2;
4239 // Get the default value expression, we can use the same expression
4240 // if the type matches
4242 Expression e = pd.FixedParameters[i].DefaultValue;
4243 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4245 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4247 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4248 e = new MemberAccess (new MemberAccess (new MemberAccess (
4249 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4251 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4257 arguments[i] = new Argument (e, Argument.AType.Default);
4261 if (p_mod != Parameter.Modifier.PARAMS) {
4262 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4264 } else if (!params_expanded_form) {
4265 params_expanded_form = true;
4266 pt = ((ElementTypeSpec) pt).Element;
4272 if (!params_expanded_form) {
4273 if (a.ArgType == Argument.AType.ExtensionType) {
4275 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4277 // LAMESPEC: or implicit type parameter conversion
4280 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4281 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4282 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4287 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4290 dynamicArgument = true;
4295 // It can be applicable in expanded form (when not doing exact match like for delegates)
4297 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4298 if (!params_expanded_form)
4299 pt = ((ElementTypeSpec) pt).Element;
4302 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4305 params_expanded_form = true;
4306 } else if (score < 0) {
4307 params_expanded_form = true;
4308 dynamicArgument = true;
4313 if (params_expanded_form)
4315 return (arg_count - i) * 2 + score;
4320 // When params parameter has no argument it will be provided later if the method is the best candidate
4322 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4323 params_expanded_form = true;
4326 // Restore original arguments for dynamic binder to keep the intention of original source code
4328 if (dynamicArgument)
4329 arguments = orig_args;
4335 // Tests argument compatibility with the parameter
4336 // The possible return values are
4338 // 1 - modifier mismatch
4339 // 2 - type mismatch
4340 // -1 - dynamic binding required
4342 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4345 // Types have to be identical when ref or out modifer
4346 // is used and argument is not of dynamic type
4348 if ((argument.Modifier | param_mod) != 0) {
4349 if (argument.Type != parameter) {
4351 // Do full equality check after quick path
4353 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4355 // Using dynamic for ref/out parameter can still succeed at runtime
4357 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4364 if (argument.Modifier != param_mod) {
4366 // Using dynamic for ref/out parameter can still succeed at runtime
4368 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4375 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4379 // Deploy custom error reporting for lambda methods. When probing lambda methods
4380 // keep all errors reported in separate set and once we are done and no best
4381 // candidate was found, this set is used to report more details about what was wrong
4384 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4385 if (lambda_conv_msgs == null) {
4386 lambda_conv_msgs = new SessionReportPrinter ();
4387 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4392 // Use implicit conversion in all modes to return same candidates when the expression
4393 // is used as argument or delegate conversion
4395 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4396 if (lambda_conv_msgs != null) {
4397 lambda_conv_msgs.EndSession ();
4407 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4409 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4411 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4414 var ac_p = p as ArrayContainer;
4416 var ac_q = q as ArrayContainer;
4420 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4421 if (specific == ac_p.Element)
4423 if (specific == ac_q.Element)
4425 } else if (TypeManager.IsGenericType (p)) {
4426 var pargs = TypeManager.GetTypeArguments (p);
4427 var qargs = TypeManager.GetTypeArguments (q);
4429 bool p_specific_at_least_once = false;
4430 bool q_specific_at_least_once = false;
4432 for (int i = 0; i < pargs.Length; i++) {
4433 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4434 if (specific == pargs[i])
4435 p_specific_at_least_once = true;
4436 if (specific == qargs[i])
4437 q_specific_at_least_once = true;
4440 if (p_specific_at_least_once && !q_specific_at_least_once)
4442 if (!p_specific_at_least_once && q_specific_at_least_once)
4450 // Find the best method from candidate list
4452 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4454 List<AmbiguousCandidate> ambiguous_candidates = null;
4456 MemberSpec best_candidate;
4457 Arguments best_candidate_args = null;
4458 bool best_candidate_params = false;
4459 bool best_candidate_dynamic = false;
4460 int best_candidate_rate;
4461 IParametersMember best_parameter_member = null;
4463 int args_count = args != null ? args.Count : 0;
4465 Arguments candidate_args = args;
4466 bool error_mode = false;
4467 MemberSpec invocable_member = null;
4469 // Be careful, cannot return until error reporter is restored
4471 best_candidate = null;
4472 best_candidate_rate = int.MaxValue;
4474 var type_members = members;
4478 for (int i = 0; i < type_members.Count; ++i) {
4479 var member = type_members[i];
4482 // Methods in a base class are not candidates if any method in a derived
4483 // class is applicable
4485 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4489 if (!member.IsAccessible (rc))
4492 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4495 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4496 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4501 IParametersMember pm = member as IParametersMember;
4504 // Will use it later to report ambiguity between best method and invocable member
4506 if (Invocation.IsMemberInvocable (member))
4507 invocable_member = member;
4513 // Overload resolution is looking for base member but using parameter names
4514 // and default values from the closest member. That means to do expensive lookup
4515 // for the closest override for virtual or abstract members
4517 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4518 var override_params = base_provider.GetOverrideMemberParameters (member);
4519 if (override_params != null)
4520 pm = override_params;
4524 // Check if the member candidate is applicable
4526 bool params_expanded_form = false;
4527 bool dynamic_argument = false;
4528 TypeSpec rt = pm.MemberType;
4529 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4532 // How does it score compare to others
4534 if (candidate_rate < best_candidate_rate) {
4535 best_candidate_rate = candidate_rate;
4536 best_candidate = member;
4537 best_candidate_args = candidate_args;
4538 best_candidate_params = params_expanded_form;
4539 best_candidate_dynamic = dynamic_argument;
4540 best_parameter_member = pm;
4541 best_candidate_return_type = rt;
4542 } else if (candidate_rate == 0) {
4544 // The member look is done per type for most operations but sometimes
4545 // it's not possible like for binary operators overload because they
4546 // are unioned between 2 sides
4548 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4549 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4554 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4556 // We pack all interface members into top level type which makes the overload resolution
4557 // more complicated for interfaces. We compensate it by removing methods with same
4558 // signature when building the cache hence this path should not really be hit often
4561 // interface IA { void Foo (int arg); }
4562 // interface IB : IA { void Foo (params int[] args); }
4564 // IB::Foo is the best overload when calling IB.Foo (1)
4567 if (ambiguous_candidates != null) {
4568 foreach (var amb_cand in ambiguous_candidates) {
4569 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4578 ambiguous_candidates = null;
4581 // Is the new candidate better
4582 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4586 best_candidate = member;
4587 best_candidate_args = candidate_args;
4588 best_candidate_params = params_expanded_form;
4589 best_candidate_dynamic = dynamic_argument;
4590 best_parameter_member = pm;
4591 best_candidate_return_type = rt;
4593 // It's not better but any other found later could be but we are not sure yet
4594 if (ambiguous_candidates == null)
4595 ambiguous_candidates = new List<AmbiguousCandidate> ();
4597 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4601 // Restore expanded arguments
4602 if (candidate_args != args)
4603 candidate_args = args;
4605 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4607 if (prev_recorder != null)
4608 rc.Report.SetPrinter (prev_recorder);
4612 // We've found exact match
4614 if (best_candidate_rate == 0)
4618 // Try extension methods lookup when no ordinary method match was found and provider enables it
4621 var emg = base_provider.LookupExtensionMethod (rc);
4623 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4625 best_candidate_extension_group = emg;
4626 return (T) (MemberSpec) emg.BestCandidate;
4631 // Don't run expensive error reporting mode for probing
4638 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4641 lambda_conv_msgs = null;
4646 // No best member match found, report an error
4648 if (best_candidate_rate != 0 || error_mode) {
4649 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4653 if (best_candidate_dynamic) {
4654 if (args[0].ArgType == Argument.AType.ExtensionType) {
4655 rc.Report.Error (1973, loc,
4656 "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",
4657 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4660 BestCandidateIsDynamic = true;
4665 // These flags indicates we are running delegate probing conversion. No need to
4666 // do more expensive checks
4668 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4669 return (T) best_candidate;
4671 if (ambiguous_candidates != null) {
4673 // Now check that there are no ambiguities i.e the selected method
4674 // should be better than all the others
4676 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4677 var candidate = ambiguous_candidates [ix];
4679 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4680 var ambiguous = candidate.Member;
4681 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4682 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4683 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4684 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4685 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4688 return (T) best_candidate;
4693 if (invocable_member != null) {
4694 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4695 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4696 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4697 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4701 // And now check if the arguments are all
4702 // compatible, perform conversions if
4703 // necessary etc. and return if everything is
4706 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4709 if (best_candidate == null)
4713 // Check ObsoleteAttribute on the best method
4715 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4716 if (oa != null && !rc.IsObsolete)
4717 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4719 var dep = best_candidate.GetMissingDependencies ();
4721 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4724 best_candidate.MemberDefinition.SetIsUsed ();
4726 args = best_candidate_args;
4727 return (T) best_candidate;
4730 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4732 return ResolveMember<MethodSpec> (rc, ref args);
4735 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4736 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4738 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4741 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4742 ec.Report.SymbolRelatedToPreviousError (method);
4743 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4744 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4745 TypeManager.CSharpSignature (method));
4748 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4749 TypeManager.CSharpSignature (method));
4750 } else if (IsDelegateInvoke) {
4751 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4752 DelegateType.GetSignatureForError ());
4754 ec.Report.SymbolRelatedToPreviousError (method);
4755 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4756 method.GetSignatureForError ());
4759 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4761 string index = (idx + 1).ToString ();
4762 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4763 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4764 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4765 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4766 index, Parameter.GetModifierSignature (a.Modifier));
4768 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4769 index, Parameter.GetModifierSignature (mod));
4770 } else if (a.Expr != ErrorExpression.Instance) {
4771 string p1 = a.GetSignatureForError ();
4772 string p2 = TypeManager.CSharpName (paramType);
4775 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4776 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4779 ec.Report.Error (1503, loc,
4780 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4785 // We have failed to find exact match so we return error info about the closest match
4787 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4789 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4790 int arg_count = args == null ? 0 : args.Count;
4792 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4793 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4794 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4798 if (lambda_conv_msgs != null) {
4799 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4804 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4805 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4806 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4810 // For candidates which match on parameters count report more details about incorrect arguments
4813 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4814 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4815 // Reject any inaccessible member
4816 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4817 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4818 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4822 var ms = best_candidate as MethodSpec;
4823 if (ms != null && ms.IsGeneric) {
4824 bool constr_ok = true;
4825 if (ms.TypeArguments != null)
4826 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4828 if (ta_count == 0) {
4829 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4833 rc.Report.Error (411, loc,
4834 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4835 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4842 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4848 // We failed to find any method with correct argument count, report best candidate
4850 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4853 if (best_candidate.Kind == MemberKind.Constructor) {
4854 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4855 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4856 } else if (IsDelegateInvoke) {
4857 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4858 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4859 DelegateType.GetSignatureForError (), arg_count.ToString ());
4861 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4862 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4863 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4864 name, arg_count.ToString ());
4868 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4870 var pd = pm.Parameters;
4871 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4873 Parameter.Modifier p_mod = 0;
4875 int a_idx = 0, a_pos = 0;
4877 ArrayInitializer params_initializers = null;
4878 bool has_unsafe_arg = pm.MemberType.IsPointer;
4879 int arg_count = args == null ? 0 : args.Count;
4881 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4883 if (p_mod != Parameter.Modifier.PARAMS) {
4884 p_mod = pd.FixedParameters[a_idx].ModFlags;
4886 has_unsafe_arg |= pt.IsPointer;
4888 if (p_mod == Parameter.Modifier.PARAMS) {
4889 if (chose_params_expanded) {
4890 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4891 pt = TypeManager.GetElementType (pt);
4897 // Types have to be identical when ref or out modifer is used
4899 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4900 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4903 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4909 NamedArgument na = a as NamedArgument;
4911 int name_index = pd.GetParameterIndexByName (na.Name);
4912 if (name_index < 0 || name_index >= pd.Count) {
4913 if (IsDelegateInvoke) {
4914 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4915 ec.Report.Error (1746, na.Location,
4916 "The delegate `{0}' does not contain a parameter named `{1}'",
4917 DelegateType.GetSignatureForError (), na.Name);
4919 ec.Report.SymbolRelatedToPreviousError (member);
4920 ec.Report.Error (1739, na.Location,
4921 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4922 TypeManager.CSharpSignature (member), na.Name);
4924 } else if (args[name_index] != a) {
4925 if (IsDelegateInvoke)
4926 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4928 ec.Report.SymbolRelatedToPreviousError (member);
4930 ec.Report.Error (1744, na.Location,
4931 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4936 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4939 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4940 custom_errors.NoArgumentMatch (ec, member);
4944 Expression conv = null;
4945 if (a.ArgType == Argument.AType.ExtensionType) {
4946 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4949 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4951 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4954 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4961 // Convert params arguments to an array initializer
4963 if (params_initializers != null) {
4964 // we choose to use 'a.Expr' rather than 'conv' so that
4965 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4966 params_initializers.Add (a.Expr);
4967 args.RemoveAt (a_idx--);
4972 // Update the argument with the implicit conversion
4976 if (a_idx != arg_count) {
4977 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4982 // Fill not provided arguments required by params modifier
4984 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4986 args = new Arguments (1);
4988 pt = ptypes[pd.Count - 1];
4989 pt = TypeManager.GetElementType (pt);
4990 has_unsafe_arg |= pt.IsPointer;
4991 params_initializers = new ArrayInitializer (0, loc);
4995 // Append an array argument with all params arguments
4997 if (params_initializers != null) {
4998 args.Add (new Argument (
4999 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5003 if (has_unsafe_arg && !ec.IsUnsafe) {
5004 Expression.UnsafeError (ec, loc);
5008 // We could infer inaccesible type arguments
5010 if (type_arguments == null && member.IsGeneric) {
5011 var ms = (MethodSpec) member;
5012 foreach (var ta in ms.TypeArguments) {
5013 if (!ta.IsAccessible (ec)) {
5014 ec.Report.SymbolRelatedToPreviousError (ta);
5015 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5025 public class ConstantExpr : MemberExpr
5027 readonly ConstSpec constant;
5029 public ConstantExpr (ConstSpec constant, Location loc)
5031 this.constant = constant;
5035 public override string Name {
5036 get { throw new NotImplementedException (); }
5039 public override bool IsInstance {
5040 get { return !IsStatic; }
5043 public override bool IsStatic {
5044 get { return true; }
5047 protected override TypeSpec DeclaringType {
5048 get { return constant.DeclaringType; }
5051 public override Expression CreateExpressionTree (ResolveContext ec)
5053 throw new NotSupportedException ("ET");
5056 protected override Expression DoResolve (ResolveContext rc)
5058 ResolveInstanceExpression (rc, null);
5059 DoBestMemberChecks (rc, constant);
5061 var c = constant.GetConstant (rc);
5063 // Creates reference expression to the constant value
5064 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5067 public override void Emit (EmitContext ec)
5069 throw new NotSupportedException ();
5072 public override string GetSignatureForError ()
5074 return constant.GetSignatureForError ();
5077 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5079 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5084 // Fully resolved expression that references a Field
5086 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5088 protected FieldSpec spec;
5089 VariableInfo variable_info;
5091 LocalTemporary temp;
5094 protected FieldExpr (Location l)
5099 public FieldExpr (FieldSpec spec, Location loc)
5104 type = spec.MemberType;
5107 public FieldExpr (FieldBase fi, Location l)
5114 public override string Name {
5120 public bool IsHoisted {
5122 IVariableReference hv = InstanceExpression as IVariableReference;
5123 return hv != null && hv.IsHoisted;
5127 public override bool IsInstance {
5129 return !spec.IsStatic;
5133 public override bool IsStatic {
5135 return spec.IsStatic;
5139 public FieldSpec Spec {
5145 protected override TypeSpec DeclaringType {
5147 return spec.DeclaringType;
5151 public VariableInfo VariableInfo {
5153 return variable_info;
5159 public override string GetSignatureForError ()
5161 return spec.GetSignatureForError ();
5164 public bool IsMarshalByRefAccess (ResolveContext rc)
5166 // Checks possible ldflda of field access expression
5167 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5168 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5169 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5172 public void SetHasAddressTaken ()
5174 IVariableReference vr = InstanceExpression as IVariableReference;
5176 vr.SetHasAddressTaken ();
5180 public override Expression CreateExpressionTree (ResolveContext ec)
5182 Expression instance;
5183 if (InstanceExpression == null) {
5184 instance = new NullLiteral (loc);
5186 instance = InstanceExpression.CreateExpressionTree (ec);
5189 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5191 CreateTypeOfExpression ());
5193 return CreateExpressionFactoryCall (ec, "Field", args);
5196 public Expression CreateTypeOfExpression ()
5198 return new TypeOfField (spec, loc);
5201 protected override Expression DoResolve (ResolveContext ec)
5203 return DoResolve (ec, null);
5206 Expression DoResolve (ResolveContext ec, Expression rhs)
5208 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5211 if (ResolveInstanceExpression (ec, rhs)) {
5212 // Resolve the field's instance expression while flow analysis is turned
5213 // off: when accessing a field "a.b", we must check whether the field
5214 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5216 if (lvalue_instance) {
5217 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5218 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5220 Expression right_side =
5221 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5223 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5226 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5227 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5231 if (InstanceExpression == null)
5235 DoBestMemberChecks (ec, spec);
5238 var fb = spec as FixedFieldSpec;
5239 IVariableReference var = InstanceExpression as IVariableReference;
5241 if (lvalue_instance && var != null && var.VariableInfo != null) {
5242 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5246 IFixedExpression fe = InstanceExpression as IFixedExpression;
5247 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5248 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5251 if (InstanceExpression.eclass != ExprClass.Variable) {
5252 ec.Report.SymbolRelatedToPreviousError (spec);
5253 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5254 TypeManager.GetFullNameSignature (spec));
5255 } else if (var != null && var.IsHoisted) {
5256 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5259 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5263 // Set flow-analysis variable info for struct member access. It will be check later
5264 // for precise error reporting
5266 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5267 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5268 if (rhs != null && variable_info != null)
5269 variable_info.SetStructFieldAssigned (ec, Name);
5272 eclass = ExprClass.Variable;
5276 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5281 var var = fe.InstanceExpression as IVariableReference;
5283 var vi = var.VariableInfo;
5285 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5287 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5289 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5296 fe = fe.InstanceExpression as FieldExpr;
5298 } while (fe != null);
5301 static readonly int [] codes = {
5302 191, // instance, write access
5303 192, // instance, out access
5304 198, // static, write access
5305 199, // static, out access
5306 1648, // member of value instance, write access
5307 1649, // member of value instance, out access
5308 1650, // member of value static, write access
5309 1651 // member of value static, out access
5312 static readonly string [] msgs = {
5313 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5314 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5315 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5316 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5317 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5318 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5319 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5320 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5323 // The return value is always null. Returning a value simplifies calling code.
5324 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5327 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5331 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5333 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5338 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5340 Expression e = DoResolve (ec, right_side);
5345 spec.MemberDefinition.SetIsAssigned ();
5347 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5348 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5349 ec.Report.Warning (420, 1, loc,
5350 "`{0}': A volatile field references will not be treated as volatile",
5351 spec.GetSignatureForError ());
5354 if (spec.IsReadOnly) {
5355 // InitOnly fields can only be assigned in constructors or initializers
5356 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5357 return Report_AssignToReadonly (ec, right_side);
5359 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5361 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5362 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5363 return Report_AssignToReadonly (ec, right_side);
5364 // static InitOnly fields cannot be assigned-to in an instance constructor
5365 if (IsStatic && !ec.IsStatic)
5366 return Report_AssignToReadonly (ec, right_side);
5367 // instance constructors can't modify InitOnly fields of other instances of the same type
5368 if (!IsStatic && !(InstanceExpression is This))
5369 return Report_AssignToReadonly (ec, right_side);
5373 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5374 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5375 ec.Report.Warning (197, 1, loc,
5376 "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",
5377 GetSignatureForError ());
5380 eclass = ExprClass.Variable;
5384 public override int GetHashCode ()
5386 return spec.GetHashCode ();
5389 public bool IsFixed {
5392 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5394 IVariableReference variable = InstanceExpression as IVariableReference;
5395 if (variable != null)
5396 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5398 IFixedExpression fe = InstanceExpression as IFixedExpression;
5399 return fe != null && fe.IsFixed;
5403 public override bool Equals (object obj)
5405 FieldExpr fe = obj as FieldExpr;
5409 if (spec != fe.spec)
5412 if (InstanceExpression == null || fe.InstanceExpression == null)
5415 return InstanceExpression.Equals (fe.InstanceExpression);
5418 public void Emit (EmitContext ec, bool leave_copy)
5420 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5422 spec.MemberDefinition.SetIsUsed ();
5426 ec.Emit (OpCodes.Volatile);
5428 ec.Emit (OpCodes.Ldsfld, spec);
5431 EmitInstance (ec, false);
5433 // Optimization for build-in types
5434 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5435 ec.EmitLoadFromPtr (type);
5437 var ff = spec as FixedFieldSpec;
5439 ec.Emit (OpCodes.Ldflda, spec);
5440 ec.Emit (OpCodes.Ldflda, ff.Element);
5443 ec.Emit (OpCodes.Volatile);
5445 ec.Emit (OpCodes.Ldfld, spec);
5451 ec.Emit (OpCodes.Dup);
5453 temp = new LocalTemporary (this.Type);
5459 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5461 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5462 if (isCompound && !(source is DynamicExpressionStatement)) {
5463 if (has_await_source) {
5465 InstanceExpression = InstanceExpression.EmitToField (ec);
5472 if (has_await_source)
5473 source = source.EmitToField (ec);
5475 EmitInstance (ec, prepared);
5481 ec.Emit (OpCodes.Dup);
5483 temp = new LocalTemporary (this.Type);
5488 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5489 ec.Emit (OpCodes.Volatile);
5491 spec.MemberDefinition.SetIsAssigned ();
5494 ec.Emit (OpCodes.Stsfld, spec);
5496 ec.Emit (OpCodes.Stfld, spec);
5506 // Emits store to field with prepared values on stack
5508 public void EmitAssignFromStack (EmitContext ec)
5511 ec.Emit (OpCodes.Stsfld, spec);
5513 ec.Emit (OpCodes.Stfld, spec);
5517 public override void Emit (EmitContext ec)
5522 public override void EmitSideEffect (EmitContext ec)
5524 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5526 if (is_volatile) // || is_marshal_by_ref ())
5527 base.EmitSideEffect (ec);
5530 public void AddressOf (EmitContext ec, AddressOp mode)
5532 if ((mode & AddressOp.Store) != 0)
5533 spec.MemberDefinition.SetIsAssigned ();
5534 if ((mode & AddressOp.Load) != 0)
5535 spec.MemberDefinition.SetIsUsed ();
5538 // Handle initonly fields specially: make a copy and then
5539 // get the address of the copy.
5542 if (spec.IsReadOnly){
5544 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5556 var temp = ec.GetTemporaryLocal (type);
5557 ec.Emit (OpCodes.Stloc, temp);
5558 ec.Emit (OpCodes.Ldloca, temp);
5559 ec.FreeTemporaryLocal (temp, type);
5565 ec.Emit (OpCodes.Ldsflda, spec);
5568 EmitInstance (ec, false);
5569 ec.Emit (OpCodes.Ldflda, spec);
5573 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5575 return MakeExpression (ctx);
5578 public override SLE.Expression MakeExpression (BuilderContext ctx)
5581 return base.MakeExpression (ctx);
5583 return SLE.Expression.Field (
5584 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5585 spec.GetMetaInfo ());
5589 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5591 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5597 // Expression that evaluates to a Property.
5599 // This is not an LValue because we need to re-write the expression. We
5600 // can not take data from the stack and store it.
5602 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5604 public PropertyExpr (PropertySpec spec, Location l)
5607 best_candidate = spec;
5608 type = spec.MemberType;
5613 protected override Arguments Arguments {
5621 protected override TypeSpec DeclaringType {
5623 return best_candidate.DeclaringType;
5627 public override string Name {
5629 return best_candidate.Name;
5633 public override bool IsInstance {
5639 public override bool IsStatic {
5641 return best_candidate.IsStatic;
5645 public PropertySpec PropertyInfo {
5647 return best_candidate;
5653 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5655 return new PropertyExpr (spec, loc) {
5661 public override Expression CreateExpressionTree (ResolveContext ec)
5664 if (IsSingleDimensionalArrayLength ()) {
5665 args = new Arguments (1);
5666 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5667 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5670 args = new Arguments (2);
5671 if (InstanceExpression == null)
5672 args.Add (new Argument (new NullLiteral (loc)));
5674 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5675 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5676 return CreateExpressionFactoryCall (ec, "Property", args);
5679 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5681 DoResolveLValue (rc, null);
5682 return new TypeOfMethod (Setter, loc);
5685 public override string GetSignatureForError ()
5687 return best_candidate.GetSignatureForError ();
5690 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5693 return base.MakeExpression (ctx);
5695 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5699 public override SLE.Expression MakeExpression (BuilderContext ctx)
5702 return base.MakeExpression (ctx);
5704 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5708 void Error_PropertyNotValid (ResolveContext ec)
5710 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5711 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5712 GetSignatureForError ());
5715 bool IsSingleDimensionalArrayLength ()
5717 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5720 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5721 return ac != null && ac.Rank == 1;
5724 public override void Emit (EmitContext ec, bool leave_copy)
5727 // Special case: length of single dimension array property is turned into ldlen
5729 if (IsSingleDimensionalArrayLength ()) {
5730 EmitInstance (ec, false);
5731 ec.Emit (OpCodes.Ldlen);
5732 ec.Emit (OpCodes.Conv_I4);
5736 base.Emit (ec, leave_copy);
5739 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5742 LocalTemporary await_source_arg = null;
5744 if (isCompound && !(source is DynamicExpressionStatement)) {
5745 emitting_compound_assignment = true;
5748 if (has_await_arguments) {
5749 await_source_arg = new LocalTemporary (Type);
5750 await_source_arg.Store (ec);
5752 args = new Arguments (1);
5753 args.Add (new Argument (await_source_arg));
5756 temp = await_source_arg;
5759 has_await_arguments = false;
5764 ec.Emit (OpCodes.Dup);
5765 temp = new LocalTemporary (this.Type);
5770 args = new Arguments (1);
5774 temp = new LocalTemporary (this.Type);
5776 args.Add (new Argument (temp));
5778 args.Add (new Argument (source));
5782 emitting_compound_assignment = false;
5784 var call = new CallEmitter ();
5785 call.InstanceExpression = InstanceExpression;
5787 call.InstanceExpressionOnStack = true;
5789 call.Emit (ec, Setter, args, loc);
5796 if (await_source_arg != null) {
5797 await_source_arg.Release (ec);
5801 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5803 eclass = ExprClass.PropertyAccess;
5805 if (best_candidate.IsNotCSharpCompatible) {
5806 Error_PropertyNotValid (rc);
5809 ResolveInstanceExpression (rc, right_side);
5811 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5812 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5813 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5815 type = p.MemberType;
5819 DoBestMemberChecks (rc, best_candidate);
5823 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5825 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5829 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5831 // getter and setter can be different for base calls
5832 MethodSpec getter, setter;
5833 protected T best_candidate;
5835 protected LocalTemporary temp;
5836 protected bool emitting_compound_assignment;
5837 protected bool has_await_arguments;
5839 protected PropertyOrIndexerExpr (Location l)
5846 protected abstract Arguments Arguments { get; set; }
5848 public MethodSpec Getter {
5857 public MethodSpec Setter {
5868 protected override Expression DoResolve (ResolveContext ec)
5870 if (eclass == ExprClass.Unresolved) {
5871 var expr = OverloadResolve (ec, null);
5876 return expr.Resolve (ec);
5879 if (!ResolveGetter (ec))
5885 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5887 if (right_side == EmptyExpression.OutAccess) {
5888 // TODO: best_candidate can be null at this point
5889 INamedBlockVariable variable = null;
5890 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5891 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5892 best_candidate.Name);
5894 right_side.DoResolveLValue (ec, this);
5899 // if the property/indexer returns a value type, and we try to set a field in it
5900 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5901 Error_ValueAssignment (ec, right_side);
5904 if (eclass == ExprClass.Unresolved) {
5905 var expr = OverloadResolve (ec, right_side);
5910 return expr.ResolveLValue (ec, right_side);
5913 if (!ResolveSetter (ec))
5920 // Implements the IAssignMethod interface for assignments
5922 public virtual void Emit (EmitContext ec, bool leave_copy)
5924 var call = new CallEmitter ();
5925 call.InstanceExpression = InstanceExpression;
5926 if (has_await_arguments)
5927 call.HasAwaitArguments = true;
5929 call.DuplicateArguments = emitting_compound_assignment;
5931 call.Emit (ec, Getter, Arguments, loc);
5933 if (call.HasAwaitArguments) {
5934 InstanceExpression = call.InstanceExpression;
5935 Arguments = call.EmittedArguments;
5936 has_await_arguments = true;
5940 ec.Emit (OpCodes.Dup);
5941 temp = new LocalTemporary (Type);
5946 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5948 public override void Emit (EmitContext ec)
5953 protected override void EmitToFieldSource (EmitContext ec)
5955 has_await_arguments = true;
5959 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5961 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5963 bool ResolveGetter (ResolveContext rc)
5965 if (!best_candidate.HasGet) {
5966 if (InstanceExpression != EmptyExpression.Null) {
5967 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5968 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5969 best_candidate.GetSignatureForError ());
5972 } else if (!best_candidate.Get.IsAccessible (rc)) {
5973 if (best_candidate.HasDifferentAccessibility) {
5974 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5975 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5976 TypeManager.CSharpSignature (best_candidate));
5978 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5979 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5983 if (best_candidate.HasDifferentAccessibility) {
5984 CheckProtectedMemberAccess (rc, best_candidate.Get);
5987 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5991 bool ResolveSetter (ResolveContext rc)
5993 if (!best_candidate.HasSet) {
5994 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5995 GetSignatureForError ());
5999 if (!best_candidate.Set.IsAccessible (rc)) {
6000 if (best_candidate.HasDifferentAccessibility) {
6001 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6002 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6003 GetSignatureForError ());
6005 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6006 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
6010 if (best_candidate.HasDifferentAccessibility)
6011 CheckProtectedMemberAccess (rc, best_candidate.Set);
6013 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6019 /// Fully resolved expression that evaluates to an Event
6021 public class EventExpr : MemberExpr, IAssignMethod
6023 readonly EventSpec spec;
6026 public EventExpr (EventSpec spec, Location loc)
6034 protected override TypeSpec DeclaringType {
6036 return spec.DeclaringType;
6040 public override string Name {
6046 public override bool IsInstance {
6048 return !spec.IsStatic;
6052 public override bool IsStatic {
6054 return spec.IsStatic;
6058 public MethodSpec Operator {
6066 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6069 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6071 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6072 if (spec.BackingField != null &&
6073 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6075 spec.MemberDefinition.SetIsUsed ();
6077 if (!ec.IsObsolete) {
6078 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6080 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6083 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6084 Error_AssignmentEventOnly (ec);
6086 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6088 InstanceExpression = null;
6090 return ml.ResolveMemberAccess (ec, left, original);
6094 return base.ResolveMemberAccess (ec, left, original);
6097 public override Expression CreateExpressionTree (ResolveContext ec)
6099 throw new NotSupportedException ("ET");
6102 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6104 if (right_side == EmptyExpression.EventAddition) {
6105 op = spec.AccessorAdd;
6106 } else if (right_side == EmptyExpression.EventSubtraction) {
6107 op = spec.AccessorRemove;
6111 Error_AssignmentEventOnly (ec);
6115 op = CandidateToBaseOverride (ec, op);
6119 protected override Expression DoResolve (ResolveContext ec)
6121 eclass = ExprClass.EventAccess;
6122 type = spec.MemberType;
6124 ResolveInstanceExpression (ec, null);
6126 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6127 Error_AssignmentEventOnly (ec);
6130 DoBestMemberChecks (ec, spec);
6134 public override void Emit (EmitContext ec)
6136 throw new NotSupportedException ();
6137 //Error_CannotAssign ();
6140 #region IAssignMethod Members
6142 public void Emit (EmitContext ec, bool leave_copy)
6144 throw new NotImplementedException ();
6147 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6149 if (leave_copy || !isCompound)
6150 throw new NotImplementedException ("EventExpr::EmitAssign");
6152 Arguments args = new Arguments (1);
6153 args.Add (new Argument (source));
6155 var call = new CallEmitter ();
6156 call.InstanceExpression = InstanceExpression;
6157 call.Emit (ec, op, args, loc);
6162 void Error_AssignmentEventOnly (ResolveContext ec)
6164 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6165 ec.Report.Error (79, loc,
6166 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6167 GetSignatureForError ());
6169 ec.Report.Error (70, loc,
6170 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6171 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6175 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6177 name = name.Substring (0, name.LastIndexOf ('.'));
6178 base.Error_CannotCallAbstractBase (rc, name);
6181 public override string GetSignatureForError ()
6183 return TypeManager.CSharpSignature (spec);
6186 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6188 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6192 public class TemporaryVariableReference : VariableReference
6194 public class Declarator : Statement
6196 TemporaryVariableReference variable;
6198 public Declarator (TemporaryVariableReference variable)
6200 this.variable = variable;
6204 protected override void DoEmit (EmitContext ec)
6206 variable.li.CreateBuilder (ec);
6209 protected override void CloneTo (CloneContext clonectx, Statement target)
6217 public TemporaryVariableReference (LocalVariable li, Location loc)
6220 this.type = li.Type;
6224 public override bool IsLockedByStatement {
6232 public LocalVariable LocalInfo {
6238 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6240 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6241 return new TemporaryVariableReference (li, loc);
6244 protected override Expression DoResolve (ResolveContext ec)
6246 eclass = ExprClass.Variable;
6249 // Don't capture temporary variables except when using
6250 // state machine redirection
6252 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
6253 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6254 storey.CaptureLocalVariable (ec, li);
6260 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6262 return Resolve (ec);
6265 public override void Emit (EmitContext ec)
6267 li.CreateBuilder (ec);
6272 public void EmitAssign (EmitContext ec, Expression source)
6274 li.CreateBuilder (ec);
6276 EmitAssign (ec, source, false, false);
6279 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6281 return li.HoistedVariant;
6284 public override bool IsFixed {
6285 get { return true; }
6288 public override bool IsRef {
6289 get { return false; }
6292 public override string Name {
6293 get { throw new NotImplementedException (); }
6296 public override void SetHasAddressTaken ()
6298 throw new NotImplementedException ();
6301 protected override ILocalVariable Variable {
6305 public override VariableInfo VariableInfo {
6306 get { return null; }
6309 public override void VerifyAssigned (ResolveContext rc)
6315 /// Handles `var' contextual keyword; var becomes a keyword only
6316 /// if no type called var exists in a variable scope
6318 class VarExpr : SimpleName
6320 public VarExpr (Location loc)
6325 public bool InferType (ResolveContext ec, Expression right_side)
6328 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6330 type = right_side.Type;
6331 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6332 ec.Report.Error (815, loc,
6333 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6334 type.GetSignatureForError ());
6338 eclass = ExprClass.Variable;
6342 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6344 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6345 base.Error_TypeOrNamespaceNotFound (ec);
6347 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");