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.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
67 // This is just as a hint to AddressOf of what will be done with the
70 public enum AddressOp {
77 /// This interface is implemented by variables
79 public interface IMemoryLocation {
81 /// The AddressOf method should generate code that loads
82 /// the address of the object and leaves it on the stack.
84 /// The `mode' argument is used to notify the expression
85 /// of whether this will be used to read from the address or
86 /// write to the address.
88 /// This is just a hint that can be used to provide good error
89 /// reporting, and should have no other side effects.
91 void AddressOf (EmitContext ec, AddressOp mode);
95 // An expressions resolved as a direct variable reference
97 public interface IVariableReference : IFixedExpression
99 bool IsHoisted { get; }
101 VariableInfo VariableInfo { get; }
103 void SetHasAddressTaken ();
107 // Implemented by an expression which could be or is always
110 public interface IFixedExpression
112 bool IsFixed { get; }
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
120 protected TypeSpec type;
121 protected Location loc;
123 public TypeSpec Type {
125 set { type = value; }
128 public Location Location {
132 // Not nice but we have broken hierarchy.
133 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public virtual bool IsNull {
149 /// Performs semantic analysis on the Expression
153 /// The Resolve method is invoked to perform the semantic analysis
156 /// The return value is an expression (it can be the
157 /// same expression in some cases) or a new
158 /// expression that better represents this node.
160 /// For example, optimizations of Unary (LiteralInt)
161 /// would return a new LiteralInt with a negated
164 /// If there is an error during semantic analysis,
165 /// then an error should be reported (using Report)
166 /// and a null value should be returned.
168 /// There are two side effects expected from calling
169 /// Resolve(): the the field variable "eclass" should
170 /// be set to any value of the enumeration
171 /// `ExprClass' and the type variable should be set
172 /// to a valid type (this is the type of the
175 protected abstract Expression DoResolve (ResolveContext rc);
177 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
183 // This is used if the expression should be resolved as a type or namespace name.
184 // the default implementation fails.
186 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
189 ResolveContext ec = new ResolveContext (rc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
199 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
200 // same name exists or as a keyword when no type was found
202 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
204 return ResolveAsTypeTerminal (rc, silent);
208 // This is used to resolve the expression as a type, a null
209 // value will be returned if the expression is not a type
212 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
214 int errors = ec.Compiler.Report.Errors;
216 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
221 TypeExpr te = fne as TypeExpr;
223 if (!silent && errors == ec.Compiler.Report.Errors)
224 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
228 if (!te.CheckAccessLevel (ec)) {
229 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
230 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
236 // Obsolete checks cannot be done when resolving base context as they
237 // require type dependecies to be set but we are just resolving them
239 if (!silent && !(ec is TypeContainer.BaseContext)) {
240 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
241 if (obsolete_attr != null && !ec.IsObsolete) {
242 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
249 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
251 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
254 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
256 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
259 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
261 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
262 name, TypeManager.CSharpName (type));
265 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
267 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
268 "expressions can be used as a statement");
271 public void Error_InvalidExpressionStatement (BlockContext ec)
273 Error_InvalidExpressionStatement (ec.Report, loc);
276 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
278 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
281 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
283 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
286 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
288 // The error was already reported as CS1660
289 if (type == InternalType.AnonymousMethod)
293 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
294 string sig1 = type.DeclaringMethod == null ?
295 TypeManager.CSharpName (type.DeclaringType) :
296 TypeManager.CSharpSignature (type.DeclaringMethod);
297 string sig2 = target.DeclaringMethod == null ?
298 TypeManager.CSharpName (target.DeclaringType) :
299 TypeManager.CSharpSignature (target.DeclaringMethod);
300 ec.Report.ExtraInformation (loc,
302 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
303 Type.Name, sig1, sig2));
304 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
305 ec.Report.ExtraInformation (loc,
307 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
308 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
312 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
313 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
317 ec.Report.DisableReporting ();
318 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
319 ec.Report.EnableReporting ();
322 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
323 "An explicit conversion exists (are you missing a cast?)",
324 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
328 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
329 type.GetSignatureForError (), target.GetSignatureForError ());
332 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
334 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
337 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
339 // Better message for possible generic expressions
340 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
341 report.SymbolRelatedToPreviousError (member);
342 if (member is TypeSpec)
343 member = ((TypeSpec) member).GetDefinition ();
345 member = ((MethodSpec) member).GetGenericMethodDefinition ();
347 string name = member.Kind == MemberKind.Method ? "method" : "type";
348 if (member.IsGeneric) {
349 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
350 name, member.GetSignatureForError (), member.Arity.ToString ());
352 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
353 name, member.GetSignatureForError ());
356 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
360 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
362 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
366 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
368 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
371 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
373 ec.Report.SymbolRelatedToPreviousError (type);
374 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
375 TypeManager.CSharpName (type), name);
378 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
380 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
383 public ResolveFlags ExprClassToResolveFlags {
387 case ExprClass.Namespace:
388 return ResolveFlags.Type;
390 case ExprClass.MethodGroup:
391 return ResolveFlags.MethodGroup;
393 case ExprClass.TypeParameter:
394 return ResolveFlags.TypeParameter;
396 case ExprClass.Value:
397 case ExprClass.Variable:
398 case ExprClass.PropertyAccess:
399 case ExprClass.EventAccess:
400 case ExprClass.IndexerAccess:
401 return ResolveFlags.VariableOrValue;
404 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
410 /// Resolves an expression and performs semantic analysis on it.
414 /// Currently Resolve wraps DoResolve to perform sanity
415 /// checking and assertion checking on what we expect from Resolve.
417 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
419 if (eclass != ExprClass.Unresolved)
429 if ((flags & e.ExprClassToResolveFlags) == 0) {
430 e.Error_UnexpectedKind (ec, flags, loc);
435 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
438 } catch (Exception ex) {
439 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
442 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
443 return EmptyExpression.Null;
448 /// Resolves an expression and performs semantic analysis on it.
450 public Expression Resolve (ResolveContext rc)
452 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
456 /// Resolves an expression for LValue assignment
460 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
461 /// checking and assertion checking on what we expect from Resolve
463 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
465 int errors = ec.Report.Errors;
466 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
468 Expression e = DoResolveLValue (ec, right_side);
470 if (e != null && out_access && !(e is IMemoryLocation)) {
471 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
472 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
474 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
475 // e.GetType () + " " + e.GetSignatureForError ());
480 if (errors == ec.Report.Errors) {
482 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
484 Error_ValueAssignment (ec, loc);
489 if (e.eclass == ExprClass.Unresolved)
490 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
492 if ((e.type == null) && !(e is GenericTypeExpr))
493 throw new Exception ("Expression " + e + " did not set its type after Resolve");
498 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
500 rc.Compiler.Report.Error (182, loc,
501 "An attribute argument must be a constant expression, typeof expression or array creation expression");
505 /// Emits the code for the expression
509 /// The Emit method is invoked to generate the code
510 /// for the expression.
512 public abstract void Emit (EmitContext ec);
515 // Emit code to branch to @target if this expression is equivalent to @on_true.
516 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
517 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
518 // including the use of conditional branches. Note also that a branch MUST be emitted
519 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
522 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
525 // Emit this expression for its side effects, not for its value.
526 // The default implementation is to emit the value, and then throw it away.
527 // Subclasses can provide more efficient implementations, but those MUST be equivalent
528 public virtual void EmitSideEffect (EmitContext ec)
531 ec.Emit (OpCodes.Pop);
535 /// Protected constructor. Only derivate types should
536 /// be able to be created
539 protected Expression ()
544 /// Returns a fully formed expression after a MemberLookup
547 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
549 if (spec is EventSpec)
550 return new EventExpr ((EventSpec) spec, loc);
551 if (spec is ConstSpec)
552 return new ConstantExpr ((ConstSpec) spec, loc);
553 if (spec is FieldSpec)
554 return new FieldExpr ((FieldSpec) spec, loc);
555 if (spec is PropertySpec)
556 return new PropertyExpr ((PropertySpec) spec, loc);
557 if (spec is TypeSpec)
558 return new TypeExpression (((TypeSpec) spec), loc);
563 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
565 var ctors = MemberCache.FindMembers (type, ConstructorInfo.ConstructorName, true);
567 rc.Report.SymbolRelatedToPreviousError (type);
569 // Report meaningful error for struct as they always have default ctor in C# context
570 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
572 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
573 type.GetSignatureForError ());
579 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
580 return r.ResolveMember<MethodSpec> (rc, ref args);
584 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
585 // `qualifier_type' or null to lookup members in the current class.
587 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, bool invocableOnly, Location loc)
589 var members = MemberCache.FindMembers (queried_type, name, false);
593 MemberSpec non_method = null;
594 MemberSpec ambig_non_method = null;
595 currentType = currentType ?? InternalType.FakeInternalType;
597 for (int i = 0; i < members.Count; ++i) {
598 var member = members[i];
600 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
601 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
604 if (arity > 0 && member.Arity != arity)
607 if (rc != null && !member.IsAccessible (currentType))
611 if (member is MethodSpec)
612 return new MethodGroupExpr (members, queried_type, loc);
614 if (!Invocation.IsMemberInvocable (member))
618 if (non_method == null || member is MethodSpec) {
620 } else if (currentType != null) {
621 ambig_non_method = member;
625 if (non_method != null) {
626 if (ambig_non_method != null && rc != null) {
627 rc.Report.SymbolRelatedToPreviousError (non_method);
628 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
629 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
630 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
633 if (non_method is MethodSpec)
634 return new MethodGroupExpr (members, queried_type, loc);
636 return ExprClassFromMemberInfo (non_method, loc);
639 if (members[0].DeclaringType.BaseType == null)
642 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
644 } while (members != null);
649 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
651 throw new NotImplementedException ();
654 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
656 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
660 /// Returns an expression that can be used to invoke operator true
661 /// on the expression if it exists.
663 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
665 return GetOperatorTrueOrFalse (ec, e, true, loc);
669 /// Returns an expression that can be used to invoke operator false
670 /// on the expression if it exists.
672 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
674 return GetOperatorTrueOrFalse (ec, e, false, loc);
677 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
679 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
680 var methods = MemberCache.GetUserOperator (e.type, op, false);
684 Arguments arguments = new Arguments (1);
685 arguments.Add (new Argument (e));
687 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
688 var oper = res.ResolveOperator (ec, ref arguments);
693 return new UserOperatorCall (oper, arguments, null, loc);
696 public virtual string ExprClassName
700 case ExprClass.Unresolved:
702 case ExprClass.Value:
704 case ExprClass.Variable:
706 case ExprClass.Namespace:
710 case ExprClass.MethodGroup:
711 return "method group";
712 case ExprClass.PropertyAccess:
713 return "property access";
714 case ExprClass.EventAccess:
715 return "event access";
716 case ExprClass.IndexerAccess:
717 return "indexer access";
718 case ExprClass.Nothing:
720 case ExprClass.TypeParameter:
721 return "type parameter";
723 throw new Exception ("Should not happen");
728 /// Reports that we were expecting `expr' to be of class `expected'
730 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
732 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
735 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
739 name = mc.GetSignatureForError ();
741 name = GetSignatureForError ();
743 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
744 name, was, expected);
747 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
749 string [] valid = new string [4];
752 if ((flags & ResolveFlags.VariableOrValue) != 0) {
753 valid [count++] = "variable";
754 valid [count++] = "value";
757 if ((flags & ResolveFlags.Type) != 0)
758 valid [count++] = "type";
760 if ((flags & ResolveFlags.MethodGroup) != 0)
761 valid [count++] = "method group";
764 valid [count++] = "unknown";
766 StringBuilder sb = new StringBuilder (valid [0]);
767 for (int i = 1; i < count - 1; i++) {
769 sb.Append (valid [i]);
772 sb.Append ("' or `");
773 sb.Append (valid [count - 1]);
776 ec.Report.Error (119, loc,
777 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
780 public static void UnsafeError (ResolveContext ec, Location loc)
782 UnsafeError (ec.Report, loc);
785 public static void UnsafeError (Report Report, Location loc)
787 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
792 // Returns the size of type `t' if known, otherwise, 0
794 public static int GetTypeSize (TypeSpec t)
796 if (t == TypeManager.int32_type ||
797 t == TypeManager.uint32_type ||
798 t == TypeManager.float_type)
800 else if (t == TypeManager.int64_type ||
801 t == TypeManager.uint64_type ||
802 t == TypeManager.double_type)
804 else if (t == TypeManager.byte_type ||
805 t == TypeManager.sbyte_type ||
806 t == TypeManager.bool_type)
808 else if (t == TypeManager.short_type ||
809 t == TypeManager.char_type ||
810 t == TypeManager.ushort_type)
812 else if (t == TypeManager.decimal_type)
818 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
820 ec.Report.SymbolRelatedToPreviousError (type);
821 if (ec.CurrentInitializerVariable != null) {
822 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
823 TypeManager.CSharpName (type), GetSignatureForError ());
825 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
826 GetSignatureForError ());
831 // Converts `source' to an int, uint, long or ulong.
833 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
835 if (source.type == InternalType.Dynamic) {
836 Arguments args = new Arguments (1);
837 args.Add (new Argument (source));
838 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
841 Expression converted;
843 using (ec.Set (ResolveContext.Options.CheckedScope)) {
844 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
845 if (converted == null)
846 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
847 if (converted == null)
848 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
849 if (converted == null)
850 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
852 if (converted == null) {
853 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
859 // Only positive constants are allowed at compile time
861 Constant c = converted as Constant;
862 if (c != null && c.IsNegative)
863 Error_NegativeArrayIndex (ec, source.loc);
865 // No conversion needed to array index
866 if (converted.Type == TypeManager.int32_type)
869 return new ArrayIndexCast (converted).Resolve (ec);
873 // Derived classes implement this method by cloning the fields that
874 // could become altered during the Resolve stage
876 // Only expressions that are created for the parser need to implement
879 protected virtual void CloneTo (CloneContext clonectx, Expression target)
881 throw new NotImplementedException (
883 "CloneTo not implemented for expression {0}", this.GetType ()));
887 // Clones an expression created by the parser.
889 // We only support expressions created by the parser so far, not
890 // expressions that have been resolved (many more classes would need
891 // to implement CloneTo).
893 // This infrastructure is here merely for Lambda expressions which
894 // compile the same code using different type values for the same
895 // arguments to find the correct overload
897 public virtual Expression Clone (CloneContext clonectx)
899 Expression cloned = (Expression) MemberwiseClone ();
900 CloneTo (clonectx, cloned);
906 // Implementation of expression to expression tree conversion
908 public abstract Expression CreateExpressionTree (ResolveContext ec);
910 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
912 return CreateExpressionFactoryCall (ec, name, null, args, loc);
915 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
917 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
920 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
922 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
925 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
927 TypeExpr texpr = TypeManager.expression_type_expr;
929 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
933 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
940 // Implemented by all expressions which support conversion from
941 // compiler expression to invokable runtime expression. Used by
942 // dynamic C# binder.
944 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
946 throw new NotImplementedException ("MakeExpression for " + GetType ());
951 /// This is just a base class for expressions that can
952 /// appear on statements (invocations, object creation,
953 /// assignments, post/pre increment and decrement). The idea
954 /// being that they would support an extra Emition interface that
955 /// does not leave a result on the stack.
957 public abstract class ExpressionStatement : Expression {
959 public ExpressionStatement ResolveStatement (BlockContext ec)
961 Expression e = Resolve (ec);
965 ExpressionStatement es = e as ExpressionStatement;
967 Error_InvalidExpressionStatement (ec);
973 /// Requests the expression to be emitted in a `statement'
974 /// context. This means that no new value is left on the
975 /// stack after invoking this method (constrasted with
976 /// Emit that will always leave a value on the stack).
978 public abstract void EmitStatement (EmitContext ec);
980 public override void EmitSideEffect (EmitContext ec)
987 /// This kind of cast is used to encapsulate the child
988 /// whose type is child.Type into an expression that is
989 /// reported to return "return_type". This is used to encapsulate
990 /// expressions which have compatible types, but need to be dealt
991 /// at higher levels with.
993 /// For example, a "byte" expression could be encapsulated in one
994 /// of these as an "unsigned int". The type for the expression
995 /// would be "unsigned int".
998 public abstract class TypeCast : Expression
1000 protected readonly Expression child;
1002 protected TypeCast (Expression child, TypeSpec return_type)
1004 eclass = child.eclass;
1005 loc = child.Location;
1010 public Expression Child {
1016 public override Expression CreateExpressionTree (ResolveContext ec)
1018 Arguments args = new Arguments (2);
1019 args.Add (new Argument (child.CreateExpressionTree (ec)));
1020 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1022 if (type.IsPointer || child.Type.IsPointer)
1023 Error_PointerInsideExpressionTree (ec);
1025 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1028 protected override Expression DoResolve (ResolveContext ec)
1030 // This should never be invoked, we are born in fully
1031 // initialized state.
1036 public override void Emit (EmitContext ec)
1041 public override SLE.Expression MakeExpression (BuilderContext ctx)
1043 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1044 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1045 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1048 protected override void CloneTo (CloneContext clonectx, Expression t)
1053 public override bool IsNull {
1054 get { return child.IsNull; }
1058 public class EmptyCast : TypeCast {
1059 EmptyCast (Expression child, TypeSpec target_type)
1060 : base (child, target_type)
1064 public static Expression Create (Expression child, TypeSpec type)
1066 Constant c = child as Constant;
1068 return new EmptyConstantCast (c, type);
1070 EmptyCast e = child as EmptyCast;
1072 return new EmptyCast (e.child, type);
1074 return new EmptyCast (child, type);
1077 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1079 child.EmitBranchable (ec, label, on_true);
1082 public override void EmitSideEffect (EmitContext ec)
1084 child.EmitSideEffect (ec);
1089 // Used for predefined class library user casts (no obsolete check, etc.)
1091 public class OperatorCast : TypeCast {
1092 MethodSpec conversion_operator;
1094 public OperatorCast (Expression child, TypeSpec target_type)
1095 : this (child, target_type, false)
1099 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1100 : base (child, target_type)
1102 conversion_operator = GetConversionOperator (find_explicit);
1103 if (conversion_operator == null)
1104 throw new InternalErrorException ("Outer conversion routine is out of sync");
1107 // Returns the implicit operator that converts from
1108 // 'child.Type' to our target type (type)
1109 MethodSpec GetConversionOperator (bool find_explicit)
1111 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1113 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1115 mi = MemberCache.GetUserOperator (type, op, true);
1118 foreach (MethodSpec oper in mi) {
1119 if (oper.ReturnType != type)
1122 if (oper.Parameters.Types [0] == child.Type)
1129 public override void Emit (EmitContext ec)
1132 ec.Emit (OpCodes.Call, conversion_operator);
1137 /// This is a numeric cast to a Decimal
1139 public class CastToDecimal : OperatorCast {
1140 public CastToDecimal (Expression child)
1141 : this (child, false)
1145 public CastToDecimal (Expression child, bool find_explicit)
1146 : base (child, TypeManager.decimal_type, find_explicit)
1152 /// This is an explicit numeric cast from a Decimal
1154 public class CastFromDecimal : TypeCast
1156 static Dictionary<TypeSpec, MethodSpec> operators;
1158 public CastFromDecimal (Expression child, TypeSpec return_type)
1159 : base (child, return_type)
1161 if (child.Type != TypeManager.decimal_type)
1162 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1165 // Returns the explicit operator that converts from an
1166 // express of type System.Decimal to 'type'.
1167 public Expression Resolve ()
1169 if (operators == null) {
1170 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1172 operators = new Dictionary<TypeSpec, MethodSpec> ();
1173 foreach (MethodSpec oper in all_oper) {
1174 AParametersCollection pd = oper.Parameters;
1175 if (pd.Types [0] == TypeManager.decimal_type)
1176 operators.Add (oper.ReturnType, oper);
1180 return operators.ContainsKey (type) ? this : null;
1183 public override void Emit (EmitContext ec)
1187 ec.Emit (OpCodes.Call, operators [type]);
1190 public static void Reset ()
1198 // Constant specialization of EmptyCast.
1199 // We need to special case this since an empty cast of
1200 // a constant is still a constant.
1202 public class EmptyConstantCast : Constant
1204 public Constant child;
1206 public EmptyConstantCast (Constant child, TypeSpec type)
1207 : base (child.Location)
1210 throw new ArgumentNullException ("child");
1213 this.eclass = child.eclass;
1217 public override string AsString ()
1219 return child.AsString ();
1222 public override object GetValue ()
1224 return child.GetValue ();
1227 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1229 if (child.Type == target_type)
1232 // FIXME: check that 'type' can be converted to 'target_type' first
1233 return child.ConvertExplicitly (in_checked_context, target_type);
1236 public override Expression CreateExpressionTree (ResolveContext ec)
1238 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1239 child.CreateExpressionTree (ec),
1240 new TypeOf (new TypeExpression (type, loc), loc));
1243 Error_PointerInsideExpressionTree (ec);
1245 return CreateExpressionFactoryCall (ec, "Convert", args);
1248 public override bool IsDefaultValue {
1249 get { return child.IsDefaultValue; }
1252 public override bool IsNegative {
1253 get { return child.IsNegative; }
1256 public override bool IsNull {
1257 get { return child.IsNull; }
1260 public override bool IsOneInteger {
1261 get { return child.IsOneInteger; }
1264 public override bool IsZeroInteger {
1265 get { return child.IsZeroInteger; }
1268 protected override Expression DoResolve (ResolveContext rc)
1273 public override void Emit (EmitContext ec)
1278 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1280 child.EmitBranchable (ec, label, on_true);
1282 // Only to make verifier happy
1283 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1284 ec.Emit (OpCodes.Unbox_Any, type);
1287 public override void EmitSideEffect (EmitContext ec)
1289 child.EmitSideEffect (ec);
1292 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1294 // FIXME: Do we need to check user conversions?
1295 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1297 return child.ConvertImplicitly (rc, target_type);
1302 /// This class is used to wrap literals which belong inside Enums
1304 public class EnumConstant : Constant
1306 public Constant Child;
1308 public EnumConstant (Constant child, TypeSpec enum_type)
1309 : base (child.Location)
1312 this.type = enum_type;
1315 protected EnumConstant (Location loc)
1320 protected override Expression DoResolve (ResolveContext rc)
1322 Child = Child.Resolve (rc);
1323 this.eclass = ExprClass.Value;
1327 public override void Emit (EmitContext ec)
1332 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1334 Child.EncodeAttributeValue (rc, enc, Child.Type);
1337 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1339 Child.EmitBranchable (ec, label, on_true);
1342 public override void EmitSideEffect (EmitContext ec)
1344 Child.EmitSideEffect (ec);
1347 public override string GetSignatureForError()
1349 return TypeManager.CSharpName (Type);
1352 public override object GetValue ()
1354 return Child.GetValue ();
1357 public override object GetTypedValue ()
1359 // FIXME: runtime is not ready to work with just emited enums
1360 if (!RootContext.StdLib) {
1361 return Child.GetValue ();
1365 // Small workaround for big problem
1366 // System.Enum.ToObject cannot be called on dynamic types
1367 // EnumBuilder has to be used, but we cannot use EnumBuilder
1368 // because it does not properly support generics
1370 // This works only sometimes
1372 if (type.MemberDefinition is TypeContainer)
1373 return Child.GetValue ();
1376 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1379 public override string AsString ()
1381 return Child.AsString ();
1384 public EnumConstant Increment()
1386 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1389 public override bool IsDefaultValue {
1391 return Child.IsDefaultValue;
1395 public override bool IsZeroInteger {
1396 get { return Child.IsZeroInteger; }
1399 public override bool IsNegative {
1401 return Child.IsNegative;
1405 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1407 if (Child.Type == target_type)
1410 return Child.ConvertExplicitly (in_checked_context, target_type);
1413 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1415 if (this.type == type) {
1419 if (!Convert.ImplicitStandardConversionExists (this, type)){
1423 return Child.ConvertImplicitly (rc, type);
1428 /// This kind of cast is used to encapsulate Value Types in objects.
1430 /// The effect of it is to box the value type emitted by the previous
1433 public class BoxedCast : TypeCast {
1435 public BoxedCast (Expression expr, TypeSpec target_type)
1436 : base (expr, target_type)
1438 eclass = ExprClass.Value;
1441 protected override Expression DoResolve (ResolveContext ec)
1443 // This should never be invoked, we are born in fully
1444 // initialized state.
1449 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1451 enc.Encode (child.Type);
1452 child.EncodeAttributeValue (rc, enc, child.Type);
1455 public override void Emit (EmitContext ec)
1459 ec.Emit (OpCodes.Box, child.Type);
1462 public override void EmitSideEffect (EmitContext ec)
1464 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1465 // so, we need to emit the box+pop instructions in most cases
1466 if (TypeManager.IsStruct (child.Type) &&
1467 (type == TypeManager.object_type || type == TypeManager.value_type))
1468 child.EmitSideEffect (ec);
1470 base.EmitSideEffect (ec);
1474 public class UnboxCast : TypeCast {
1475 public UnboxCast (Expression expr, TypeSpec return_type)
1476 : base (expr, return_type)
1480 protected override Expression DoResolve (ResolveContext ec)
1482 // This should never be invoked, we are born in fully
1483 // initialized state.
1488 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1490 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1491 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1492 return base.DoResolveLValue (ec, right_side);
1495 public override void Emit (EmitContext ec)
1499 ec.Emit (OpCodes.Unbox_Any, type);
1504 /// This is used to perform explicit numeric conversions.
1506 /// Explicit numeric conversions might trigger exceptions in a checked
1507 /// context, so they should generate the conv.ovf opcodes instead of
1510 public class ConvCast : TypeCast {
1511 public enum Mode : byte {
1512 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1514 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1515 U2_I1, U2_U1, U2_I2, U2_CH,
1516 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1517 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1518 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1519 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1520 CH_I1, CH_U1, CH_I2,
1521 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1522 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1528 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1529 : base (child, return_type)
1534 protected override Expression DoResolve (ResolveContext ec)
1536 // This should never be invoked, we are born in fully
1537 // initialized state.
1542 public override string ToString ()
1544 return String.Format ("ConvCast ({0}, {1})", mode, child);
1547 public override void Emit (EmitContext ec)
1551 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1553 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1554 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1555 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1556 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1557 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1560 case Mode.U1_CH: /* nothing */ break;
1562 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1563 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1564 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1565 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1566 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1567 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1570 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1571 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1572 case Mode.U2_CH: /* nothing */ break;
1574 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1575 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1576 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1577 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1578 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1579 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1580 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1582 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1583 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1584 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1585 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1586 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1587 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1589 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1590 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1591 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1592 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1593 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1594 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1595 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1596 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1599 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1600 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1601 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1602 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1603 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1604 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1605 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1606 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1607 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1609 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1610 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1611 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1613 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1614 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1615 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1616 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1618 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1619 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1620 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1621 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1623 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1624 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1625 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1626 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1627 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1628 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1629 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1630 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1631 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1632 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1634 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1638 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1639 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1640 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1641 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1642 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1645 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1647 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1648 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1649 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1650 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1651 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1652 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1655 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1656 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1657 case Mode.U2_CH: /* nothing */ break;
1659 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1660 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1661 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1662 case Mode.I4_U4: /* nothing */ break;
1663 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1665 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1667 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1668 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1669 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1670 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.U4_I4: /* nothing */ break;
1672 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1675 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1676 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1677 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1679 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1680 case Mode.I8_U8: /* nothing */ break;
1681 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1684 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1685 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1686 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1687 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1689 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1690 case Mode.U8_I8: /* nothing */ break;
1691 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1694 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1695 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1696 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1698 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1705 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1706 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1708 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1709 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1710 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1711 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1713 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1714 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1715 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1716 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1717 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1719 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1725 public class OpcodeCast : TypeCast {
1728 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1729 : base (child, return_type)
1734 protected override Expression DoResolve (ResolveContext ec)
1736 // This should never be invoked, we are born in fully
1737 // initialized state.
1742 public override void Emit (EmitContext ec)
1748 public TypeSpec UnderlyingType {
1749 get { return child.Type; }
1754 /// This kind of cast is used to encapsulate a child and cast it
1755 /// to the class requested
1757 public sealed class ClassCast : TypeCast {
1758 readonly bool forced;
1760 public ClassCast (Expression child, TypeSpec return_type)
1761 : base (child, return_type)
1765 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1766 : base (child, return_type)
1768 this.forced = forced;
1771 public override void Emit (EmitContext ec)
1775 bool gen = TypeManager.IsGenericParameter (child.Type);
1777 ec.Emit (OpCodes.Box, child.Type);
1779 if (type.IsGenericParameter) {
1780 ec.Emit (OpCodes.Unbox_Any, type);
1787 ec.Emit (OpCodes.Castclass, type);
1792 // Created during resolving pahse when an expression is wrapped or constantified
1793 // and original expression can be used later (e.g. for expression trees)
1795 public class ReducedExpression : Expression
1797 sealed class ReducedConstantExpression : EmptyConstantCast
1799 readonly Expression orig_expr;
1801 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1802 : base (expr, expr.Type)
1804 this.orig_expr = orig_expr;
1807 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1809 Constant c = base.ConvertImplicitly (rc, target_type);
1811 c = new ReducedConstantExpression (c, orig_expr);
1816 public override Expression CreateExpressionTree (ResolveContext ec)
1818 return orig_expr.CreateExpressionTree (ec);
1821 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1823 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1825 c = new ReducedConstantExpression (c, orig_expr);
1830 sealed class ReducedExpressionStatement : ExpressionStatement
1832 readonly Expression orig_expr;
1833 readonly ExpressionStatement stm;
1835 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1837 this.orig_expr = orig;
1839 this.loc = orig.Location;
1842 public override Expression CreateExpressionTree (ResolveContext ec)
1844 return orig_expr.CreateExpressionTree (ec);
1847 protected override Expression DoResolve (ResolveContext ec)
1849 eclass = stm.eclass;
1854 public override void Emit (EmitContext ec)
1859 public override void EmitStatement (EmitContext ec)
1861 stm.EmitStatement (ec);
1865 readonly Expression expr, orig_expr;
1867 private ReducedExpression (Expression expr, Expression orig_expr)
1870 this.eclass = expr.eclass;
1871 this.type = expr.Type;
1872 this.orig_expr = orig_expr;
1873 this.loc = orig_expr.Location;
1877 // Creates fully resolved expression switcher
1879 public static Constant Create (Constant expr, Expression original_expr)
1881 if (expr.eclass == ExprClass.Unresolved)
1882 throw new ArgumentException ("Unresolved expression");
1884 return new ReducedConstantExpression (expr, original_expr);
1887 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1889 return new ReducedExpressionStatement (s, orig);
1893 // Creates unresolved reduce expression. The original expression has to be
1896 public static Expression Create (Expression expr, Expression original_expr)
1898 Constant c = expr as Constant;
1900 return Create (c, original_expr);
1902 ExpressionStatement s = expr as ExpressionStatement;
1904 return Create (s, original_expr);
1906 if (expr.eclass == ExprClass.Unresolved)
1907 throw new ArgumentException ("Unresolved expression");
1909 return new ReducedExpression (expr, original_expr);
1912 public override Expression CreateExpressionTree (ResolveContext ec)
1914 return orig_expr.CreateExpressionTree (ec);
1917 protected override Expression DoResolve (ResolveContext ec)
1922 public override void Emit (EmitContext ec)
1927 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1929 expr.EmitBranchable (ec, target, on_true);
1932 public override SLE.Expression MakeExpression (BuilderContext ctx)
1934 return orig_expr.MakeExpression (ctx);
1939 // Standard composite pattern
1941 public abstract class CompositeExpression : Expression
1945 protected CompositeExpression (Expression expr)
1948 this.loc = expr.Location;
1951 public override Expression CreateExpressionTree (ResolveContext ec)
1953 return expr.CreateExpressionTree (ec);
1956 public Expression Child {
1957 get { return expr; }
1960 protected override Expression DoResolve (ResolveContext ec)
1962 expr = expr.Resolve (ec);
1965 eclass = expr.eclass;
1971 public override void Emit (EmitContext ec)
1976 public override bool IsNull {
1977 get { return expr.IsNull; }
1982 // Base of expressions used only to narrow resolve flow
1984 public abstract class ShimExpression : Expression
1986 protected Expression expr;
1988 protected ShimExpression (Expression expr)
1993 protected override void CloneTo (CloneContext clonectx, Expression t)
1998 ShimExpression target = (ShimExpression) t;
1999 target.expr = expr.Clone (clonectx);
2002 public override Expression CreateExpressionTree (ResolveContext ec)
2004 throw new NotSupportedException ("ET");
2007 public override void Emit (EmitContext ec)
2009 throw new InternalErrorException ("Missing Resolve call");
2012 public Expression Expr {
2013 get { return expr; }
2018 // Unresolved type name expressions
2020 public abstract class ATypeNameExpression : FullNamedExpression
2023 protected TypeArguments targs;
2025 protected ATypeNameExpression (string name, Location l)
2031 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2038 protected ATypeNameExpression (string name, int arity, Location l)
2039 : this (name, new UnboundTypeArguments (arity), l)
2045 protected int Arity {
2047 return targs == null ? 0 : targs.Count;
2051 public bool HasTypeArguments {
2053 return targs != null && !targs.IsEmpty;
2057 public string Name {
2066 public TypeArguments TypeArguments {
2074 public override bool Equals (object obj)
2076 ATypeNameExpression atne = obj as ATypeNameExpression;
2077 return atne != null && atne.Name == Name &&
2078 (targs == null || targs.Equals (atne.targs));
2081 public override int GetHashCode ()
2083 return Name.GetHashCode ();
2086 // TODO: Move it to MemberCore
2087 public static string GetMemberType (MemberCore mc)
2093 if (mc is FieldBase)
2095 if (mc is MethodCore)
2097 if (mc is EnumMember)
2105 public override string GetSignatureForError ()
2107 if (targs != null) {
2108 return Name + "<" + targs.GetSignatureForError () + ">";
2114 public abstract Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly);
2118 /// SimpleName expressions are formed of a single word and only happen at the beginning
2119 /// of a dotted-name.
2121 public class SimpleName : ATypeNameExpression
2123 public SimpleName (string name, Location l)
2128 public SimpleName (string name, TypeArguments args, Location l)
2129 : base (name, args, l)
2133 public SimpleName (string name, int arity, Location l)
2134 : base (name, arity, l)
2138 public SimpleName GetMethodGroup ()
2140 return new SimpleName (Name, targs, loc);
2143 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2145 if (ec.CurrentType != null) {
2146 if (ec.CurrentMemberDefinition != null) {
2147 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2149 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2155 // TODO MemberCache: Implement
2157 string ns = ec.CurrentType.Namespace;
2158 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2159 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2160 var type = a.GetType (fullname);
2162 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2163 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2168 if (ec.CurrentTypeDefinition != null) {
2169 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2171 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2178 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2179 if (retval != null) {
2180 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2182 var te = retval as TypeExpr;
2183 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2184 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2186 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2191 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2194 protected override Expression DoResolve (ResolveContext ec)
2196 return SimpleNameResolve (ec, null, false);
2199 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2201 return SimpleNameResolve (ec, right_side, false);
2204 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2206 int errors = ec.Compiler.Report.Errors;
2207 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2210 if (fne.Type != null && Arity > 0) {
2211 if (HasTypeArguments) {
2212 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2213 return ct.ResolveAsTypeStep (ec, false);
2216 return new GenericOpenTypeExpr (fne.Type, loc);
2220 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2222 if (!(fne is Namespace))
2226 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2227 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2228 ec.Compiler.Report.Error (1980, Location,
2229 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2230 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2233 return new DynamicTypeExpr (loc);
2239 if (silent || errors != ec.Compiler.Report.Errors)
2242 Error_TypeOrNamespaceNotFound (ec);
2246 public override Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly)
2248 int lookup_arity = Arity;
2249 bool errorMode = false;
2251 Block current_block = rc.CurrentBlock;
2255 // Stage 1: binding to local variables or parameters
2257 if (current_block != null && lookup_arity == 0) {
2258 LocalInfo vi = current_block.GetLocalInfo (Name);
2260 // TODO: pass vi in to speed things up
2261 e = new LocalVariableReference (rc.CurrentBlock, Name, loc);
2263 e = current_block.Toplevel.GetParameterReference (Name, loc);
2268 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2274 current_block.CheckInvariantMeaningInBlock (Name, this, loc);
2278 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2280 LocalInfo li = ikv as LocalInfo;
2281 // Supress CS0219 warning
2285 Error_VariableIsUsedBeforeItIsDeclared (rc.Report, Name);
2293 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2295 TypeSpec member_type = rc.CurrentType;
2296 TypeSpec current_type = member_type;
2297 for (; member_type != null; member_type = member_type.DeclaringType) {
2298 var me = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, invocableOnly, loc) as MemberExpr;
2303 if (me is MethodGroupExpr) {
2304 // Leave it to overload resolution to report correct error
2306 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2307 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2311 // MemberLookup does not check accessors availability, this is actually needed for properties only
2313 var pe = me as PropertyExpr;
2316 // Break as there is no other overload available anyway
2318 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2321 pe.Getter = pe.PropertyInfo.Get;
2323 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2326 pe.Setter = pe.PropertyInfo.Set;
2331 // TODO: It's used by EventExpr -> FieldExpr transformation only
2332 // TODO: Should go to MemberAccess
2333 me = me.ResolveMemberAccess (rc, null, null);
2337 me.SetTypeArguments (rc, targs);
2344 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2346 if (!invocableOnly) {
2347 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2353 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2357 if (RootContext.EvalMode) {
2358 var fi = Evaluator.LookupField (Name);
2360 return new FieldExpr (fi.Item1, loc);
2364 invocableOnly = false;
2369 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2371 Expression e = LookupNameExpression (ec, right_side == null, false);
2376 if (right_side != null) {
2377 if (e is TypeExpr) {
2378 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2382 e = e.ResolveLValue (ec, right_side);
2387 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2393 /// Represents a namespace or a type. The name of the class was inspired by
2394 /// section 10.8.1 (Fully Qualified Names).
2396 public abstract class FullNamedExpression : Expression
2398 protected override void CloneTo (CloneContext clonectx, Expression target)
2400 // Do nothing, most unresolved type expressions cannot be
2401 // resolved to different type
2404 public override Expression CreateExpressionTree (ResolveContext ec)
2406 throw new NotSupportedException ("ET");
2409 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2414 public override void Emit (EmitContext ec)
2416 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2417 GetSignatureForError ());
2422 /// Expression that evaluates to a type
2424 public abstract class TypeExpr : FullNamedExpression {
2425 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2427 TypeExpr t = DoResolveAsTypeStep (ec);
2431 eclass = ExprClass.Type;
2435 protected override Expression DoResolve (ResolveContext ec)
2437 return ResolveAsTypeTerminal (ec, false);
2440 public virtual bool CheckAccessLevel (IMemberContext mc)
2442 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2444 c = mc.CurrentMemberDefinition.Parent;
2446 return c.CheckAccessLevel (Type);
2449 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2451 public override bool Equals (object obj)
2453 TypeExpr tobj = obj as TypeExpr;
2457 return Type == tobj.Type;
2460 public override int GetHashCode ()
2462 return Type.GetHashCode ();
2467 /// Fully resolved Expression that already evaluated to a type
2469 public class TypeExpression : TypeExpr {
2470 public TypeExpression (TypeSpec t, Location l)
2473 eclass = ExprClass.Type;
2477 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2482 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2489 /// This class denotes an expression which evaluates to a member
2490 /// of a struct or a class.
2492 public abstract class MemberExpr : Expression
2495 // An instance expression associated with this member, if it's a
2496 // non-static member
2498 public Expression InstanceExpression;
2501 /// The name of this member.
2503 public abstract string Name {
2508 // When base.member is used
2510 public bool IsBase {
2511 get { return InstanceExpression is BaseThis; }
2515 /// Whether this is an instance member.
2517 public abstract bool IsInstance {
2522 /// Whether this is a static member.
2524 public abstract bool IsStatic {
2529 protected abstract TypeSpec DeclaringType {
2534 // Converts best base candidate for virtual method starting from QueriedBaseType
2536 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2539 // Only when base.member is used and method is virtual
2545 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2546 // means for base.member access we have to find the closest match after we found best candidate
2548 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2550 // The method could already be what we are looking for
2552 TypeSpec[] targs = null;
2553 if (method.DeclaringType != InstanceExpression.Type) {
2554 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2555 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2556 if (base_override.IsGeneric)
2557 targs = method.TypeArguments;
2559 method = base_override;
2563 // TODO: For now we do it for any hoisted call even if it's needed for
2564 // hoisted stories only but that requires a new expression wrapper
2565 if (rc.CurrentAnonymousMethod != null) {
2566 if (targs == null && method.IsGeneric) {
2567 targs = method.TypeArguments;
2568 method = method.GetGenericMethodDefinition ();
2571 if (method.Parameters.HasArglist)
2572 throw new NotImplementedException ("__arglist base call proxy");
2574 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2576 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2577 // get/set member expressions second call would fail to proxy because left expression
2578 // would be of 'this' and not 'base'
2579 if (rc.CurrentType.IsStruct)
2580 InstanceExpression = rc.GetThis (loc);
2584 method = method.MakeGenericMethod (targs);
2588 // Only base will allow this invocation to happen.
2590 if (method.IsAbstract) {
2591 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2597 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2599 if (InstanceExpression == null)
2602 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2603 var ct = rc.CurrentType;
2604 var expr_type = InstanceExpression.Type;
2605 if (ct != expr_type) {
2606 expr_type = expr_type.GetDefinition ();
2607 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2608 rc.Report.SymbolRelatedToPreviousError (member);
2609 rc.Report.Error (1540, loc,
2610 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2611 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2617 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2620 type = type.GetDefinition ();
2622 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2625 type = type.DeclaringType;
2626 } while (type != null);
2631 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2633 if (InstanceExpression != null) {
2634 InstanceExpression = InstanceExpression.Resolve (rc);
2635 CheckProtectedMemberAccess (rc, member);
2638 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2639 UnsafeError (rc, loc);
2642 if (!rc.IsObsolete) {
2643 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2645 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2648 if (!(member is FieldSpec))
2649 member.MemberDefinition.SetIsUsed ();
2652 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2654 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2658 // Implements identicial simple name and type-name
2660 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2663 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2666 // 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
2667 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2669 if (left is MemberExpr || left is VariableReference) {
2670 rc.Report.DisableReporting ();
2671 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2672 rc.Report.EnableReporting ();
2673 if (identical_type != null && identical_type.Type == left.Type)
2674 return identical_type;
2680 public bool ResolveInstanceExpression (ResolveContext rc)
2683 if (InstanceExpression != null) {
2684 if (InstanceExpression is TypeExpr) {
2685 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2686 if (oa != null && !rc.IsObsolete) {
2687 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2690 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2691 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2692 rc.Report.Error (176, loc,
2693 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2694 GetSignatureForError ());
2698 InstanceExpression = null;
2704 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2705 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2706 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2707 rc.Report.Error (236, loc,
2708 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2709 GetSignatureForError ());
2711 rc.Report.Error (120, loc,
2712 "An object reference is required to access non-static member `{0}'",
2713 GetSignatureForError ());
2718 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2719 rc.Report.Error (38, loc,
2720 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2721 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2724 InstanceExpression = rc.GetThis (loc);
2728 var me = InstanceExpression as MemberExpr;
2730 me.ResolveInstanceExpression (rc);
2732 var fe = me as FieldExpr;
2733 if (fe != null && fe.IsMarshalByRefAccess ()) {
2734 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2735 rc.Report.Warning (1690, 1, loc,
2736 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2737 me.GetSignatureForError ());
2744 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2746 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2747 ec.Report.Warning (1720, 1, left.Location,
2748 "Expression will always cause a `{0}'", "System.NullReferenceException");
2751 InstanceExpression = left;
2755 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2757 TypeSpec instance_type = InstanceExpression.Type;
2758 if (TypeManager.IsValueType (instance_type)) {
2759 if (InstanceExpression is IMemoryLocation) {
2760 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2762 LocalTemporary t = new LocalTemporary (instance_type);
2763 InstanceExpression.Emit (ec);
2765 t.AddressOf (ec, AddressOp.Store);
2768 InstanceExpression.Emit (ec);
2770 // Only to make verifier happy
2771 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2772 ec.Emit (OpCodes.Box, instance_type);
2775 if (prepare_for_load)
2776 ec.Emit (OpCodes.Dup);
2779 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2783 // Represents a group of extension method candidates for whole namespace
2785 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2787 NamespaceEntry namespace_entry;
2788 public readonly Expression ExtensionExpression;
2790 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2791 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2793 this.namespace_entry = n;
2794 this.ExtensionExpression = extensionExpr;
2797 public override bool IsStatic {
2798 get { return true; }
2801 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2803 if (namespace_entry == null)
2807 // For extension methodgroup we are not looking for base members but parent
2808 // namespace extension methods
2810 int arity = type_arguments == null ? 0 : type_arguments.Count;
2811 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2815 return found.Cast<MemberSpec> ().ToList ();
2818 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2820 // We are already here
2824 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2826 if (arguments == null)
2827 arguments = new Arguments (1);
2829 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2830 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2832 // Store resolved argument and restore original arguments
2834 // Clean-up modified arguments for error reporting
2835 arguments.RemoveAt (0);
2839 var me = ExtensionExpression as MemberExpr;
2841 me.ResolveInstanceExpression (ec);
2843 InstanceExpression = null;
2847 #region IErrorHandler Members
2849 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2854 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2856 rc.Report.SymbolRelatedToPreviousError (best);
2857 rc.Report.Error (1928, loc,
2858 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2859 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2862 rc.Report.Error (1929, loc,
2863 "Extension method instance type `{0}' cannot be converted to `{1}'",
2864 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2870 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2875 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2884 /// MethodGroupExpr represents a group of method candidates which
2885 /// can be resolved to the best method overload
2887 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2889 protected IList<MemberSpec> Methods;
2890 MethodSpec best_candidate;
2891 protected TypeArguments type_arguments;
2893 SimpleName simple_name;
2894 protected TypeSpec queried_type;
2896 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2900 this.type = InternalType.MethodGroup;
2902 eclass = ExprClass.MethodGroup;
2903 queried_type = type;
2906 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2907 : this (new MemberSpec[] { m }, type, loc)
2913 public MethodSpec BestCandidate {
2915 return best_candidate;
2919 protected override TypeSpec DeclaringType {
2921 return queried_type;
2925 public override bool IsInstance {
2927 if (best_candidate != null)
2928 return !best_candidate.IsStatic;
2934 public override bool IsStatic {
2936 if (best_candidate != null)
2937 return best_candidate.IsStatic;
2943 public override string Name {
2945 if (best_candidate != null)
2946 return best_candidate.Name;
2949 return Methods.First ().Name;
2956 // When best candidate is already know this factory can be used
2957 // to avoid expensive overload resolution to be called
2959 // NOTE: InstanceExpression has to be set manually
2961 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2963 return new MethodGroupExpr (best, queriedType, loc) {
2964 best_candidate = best
2968 public override string GetSignatureForError ()
2970 if (best_candidate != null)
2971 return best_candidate.GetSignatureForError ();
2973 return Methods.First ().GetSignatureForError ();
2976 public override Expression CreateExpressionTree (ResolveContext ec)
2978 if (best_candidate == null) {
2979 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
2983 if (best_candidate.IsConditionallyExcluded (loc))
2984 ec.Report.Error (765, loc,
2985 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
2987 return new TypeOfMethod (best_candidate, loc);
2990 protected override Expression DoResolve (ResolveContext ec)
2992 this.eclass = ExprClass.MethodGroup;
2994 if (InstanceExpression != null) {
2995 InstanceExpression = InstanceExpression.Resolve (ec);
2996 if (InstanceExpression == null)
3003 public override void Emit (EmitContext ec)
3005 throw new NotSupportedException ();
3008 public void EmitCall (EmitContext ec, Arguments arguments)
3010 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3013 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3015 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3016 Name, TypeManager.CSharpName (target));
3019 public static bool IsExtensionMethodArgument (Expression expr)
3022 // LAMESPEC: No details about which expressions are not allowed
3024 return !(expr is TypeExpr) && !(expr is BaseThis);
3028 /// Find the Applicable Function Members (7.4.2.1)
3030 /// me: Method Group expression with the members to select.
3031 /// it might contain constructors or methods (or anything
3032 /// that maps to a method).
3034 /// Arguments: ArrayList containing resolved Argument objects.
3036 /// loc: The location if we want an error to be reported, or a Null
3037 /// location for "probing" purposes.
3039 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3040 /// that is the best match of me on Arguments.
3043 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3045 // TODO: causes issues with probing mode, remove explicit Kind check
3046 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3049 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3050 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3051 r.BaseMembersProvider = this;
3054 if (cerrors != null)
3055 r.CustomErrors = cerrors;
3057 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3058 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3059 if (best_candidate == null)
3060 return r.BestCandidateIsDynamic ? this : null;
3062 // Overload resolver had to create a new method group, all checks bellow have already been executed
3063 if (r.BestCandidateNewMethodGroup != null)
3064 return r.BestCandidateNewMethodGroup;
3066 if (best_candidate.Kind == MemberKind.Method) {
3067 if (InstanceExpression != null) {
3068 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3069 InstanceExpression = null;
3071 if (best_candidate.IsStatic && simple_name != null) {
3072 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3075 InstanceExpression.Resolve (ec);
3079 ResolveInstanceExpression (ec);
3080 if (InstanceExpression != null)
3081 CheckProtectedMemberAccess (ec, best_candidate);
3084 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3088 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3090 simple_name = original;
3091 return base.ResolveMemberAccess (ec, left, original);
3094 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3096 type_arguments = ta;
3099 #region IBaseMembersProvider Members
3101 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3103 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3107 // Extension methods lookup after ordinary methods candidates failed to apply
3109 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3111 if (InstanceExpression == null)
3114 InstanceExpression = InstanceExpression.Resolve (rc);
3115 if (!IsExtensionMethodArgument (InstanceExpression))
3118 int arity = type_arguments == null ? 0 : type_arguments.Count;
3119 NamespaceEntry methods_scope = null;
3120 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3121 if (methods == null)
3124 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3125 emg.SetTypeArguments (rc, type_arguments);
3132 public struct OverloadResolver
3135 public enum Restrictions
3139 ProbingOnly = 1 << 1,
3140 CovariantDelegate = 1 << 2,
3141 NoBaseMembers = 1 << 3
3144 public interface IBaseMembersProvider
3146 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3147 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3150 public interface IErrorHandler
3152 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3153 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3154 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3155 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3158 sealed class NoBaseMembers : IBaseMembersProvider
3160 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3162 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3167 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3173 struct AmbiguousCandidate
3175 public readonly MemberSpec Member;
3176 public readonly bool Expanded;
3178 public AmbiguousCandidate (MemberSpec member, bool expanded)
3181 Expanded = expanded;
3186 IList<MemberSpec> members;
3187 TypeArguments type_arguments;
3188 IBaseMembersProvider base_provider;
3189 IErrorHandler custom_errors;
3190 Restrictions restrictions;
3191 MethodGroupExpr best_candidate_extension_group;
3193 SessionReportPrinter lambda_conv_msgs;
3194 ReportPrinter prev_recorder;
3196 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3197 : this (members, null, restrictions, loc)
3201 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3204 if (members == null || members.Count == 0)
3205 throw new ArgumentException ("empty members set");
3207 this.members = members;
3209 type_arguments = targs;
3210 this.restrictions = restrictions;
3211 if (IsDelegateInvoke)
3212 this.restrictions |= Restrictions.NoBaseMembers;
3214 base_provider = NoBaseMembers.Instance;
3219 public IBaseMembersProvider BaseMembersProvider {
3221 return base_provider;
3224 base_provider = value;
3228 public bool BestCandidateIsDynamic { get; set; }
3231 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3233 public MethodGroupExpr BestCandidateNewMethodGroup {
3235 return best_candidate_extension_group;
3239 public IErrorHandler CustomErrors {
3241 return custom_errors;
3244 custom_errors = value;
3248 TypeSpec DelegateType {
3250 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3251 throw new InternalErrorException ("Not running in delegate mode", loc);
3253 return members [0].DeclaringType;
3257 bool IsProbingOnly {
3259 return (restrictions & Restrictions.ProbingOnly) != 0;
3263 bool IsDelegateInvoke {
3265 return (restrictions & Restrictions.DelegateInvoke) != 0;
3272 // 7.4.3.3 Better conversion from expression
3273 // Returns : 1 if a->p is better,
3274 // 2 if a->q is better,
3275 // 0 if neither is better
3277 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3279 TypeSpec argument_type = a.Type;
3280 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3282 // Uwrap delegate from Expression<T>
3284 if (p.GetDefinition () == TypeManager.expression_type) {
3285 p = TypeManager.GetTypeArguments (p)[0];
3287 if (q.GetDefinition () == TypeManager.expression_type) {
3288 q = TypeManager.GetTypeArguments (q)[0];
3291 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3292 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3293 if (p == TypeManager.void_type && q != TypeManager.void_type)
3295 if (q == TypeManager.void_type && p != TypeManager.void_type)
3298 if (argument_type == p)
3301 if (argument_type == q)
3305 return BetterTypeConversion (ec, p, q);
3309 // 7.4.3.4 Better conversion from type
3311 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3313 if (p == null || q == null)
3314 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3316 if (p == TypeManager.int32_type) {
3317 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3319 } else if (p == TypeManager.int64_type) {
3320 if (q == TypeManager.uint64_type)
3322 } else if (p == TypeManager.sbyte_type) {
3323 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3324 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3326 } else if (p == TypeManager.short_type) {
3327 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3328 q == TypeManager.uint64_type)
3330 } else if (p == InternalType.Dynamic) {
3331 if (q == TypeManager.object_type)
3335 if (q == TypeManager.int32_type) {
3336 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3338 } if (q == TypeManager.int64_type) {
3339 if (p == TypeManager.uint64_type)
3341 } else if (q == TypeManager.sbyte_type) {
3342 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3343 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3345 } if (q == TypeManager.short_type) {
3346 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3347 p == TypeManager.uint64_type)
3349 } else if (q == InternalType.Dynamic) {
3350 if (p == TypeManager.object_type)
3354 // TODO: this is expensive
3355 Expression p_tmp = new EmptyExpression (p);
3356 Expression q_tmp = new EmptyExpression (q);
3358 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3359 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3361 if (p_to_q && !q_to_p)
3364 if (q_to_p && !p_to_q)
3371 /// Determines "Better function" between candidate
3372 /// and the current best match
3375 /// Returns a boolean indicating :
3376 /// false if candidate ain't better
3377 /// true if candidate is better than the current best match
3379 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3380 MemberSpec best, bool best_params)
3382 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3383 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3385 bool better_at_least_one = false;
3387 int args_count = args == null ? 0 : args.Count;
3389 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3390 Argument a = args[j];
3392 // Default arguments are ignored for better decision
3393 if (a.IsDefaultArgument)
3396 TypeSpec ct = candidate_pd.Types[c_idx];
3397 TypeSpec bt = best_pd.Types[b_idx];
3399 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3400 ct = TypeManager.GetElementType (ct);
3404 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3405 bt = TypeManager.GetElementType (bt);
3413 int result = BetterExpressionConversion (ec, a, ct, bt);
3415 // for each argument, the conversion to 'ct' should be no worse than
3416 // the conversion to 'bt'.
3420 // for at least one argument, the conversion to 'ct' should be better than
3421 // the conversion to 'bt'.
3423 better_at_least_one = true;
3426 if (better_at_least_one)
3430 // This handles the case
3432 // Add (float f1, float f2, float f3);
3433 // Add (params decimal [] foo);
3435 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3436 // first candidate would've chosen as better.
3442 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3446 // This handles the following cases:
3448 // Foo (int i) is better than Foo (int i, long l = 0)
3449 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3451 // Prefer non-optional version
3453 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3454 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3455 if (candidate_pd.Count >= best_pd.Count)
3458 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3465 // One is a non-generic method and second is a generic method, then non-generic is better
3467 if (best.IsGeneric != candidate.IsGeneric)
3468 return best.IsGeneric;
3471 // This handles the following cases:
3473 // Trim () is better than Trim (params char[] chars)
3474 // Concat (string s1, string s2, string s3) is better than
3475 // Concat (string s1, params string [] srest)
3476 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3478 // Prefer non-expanded version
3480 if (candidate_params != best_params)
3483 int candidate_param_count = candidate_pd.Count;
3484 int best_param_count = best_pd.Count;
3486 if (candidate_param_count != best_param_count)
3487 // can only happen if (candidate_params && best_params)
3488 return candidate_param_count > best_param_count && best_pd.HasParams;
3491 // Both methods have the same number of parameters, and the parameters have equal types
3492 // Pick the "more specific" signature using rules over original (non-inflated) types
3494 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3495 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3497 bool specific_at_least_once = false;
3498 for (j = 0; j < candidate_param_count; ++j) {
3499 var ct = candidate_def_pd.Types[j];
3500 var bt = best_def_pd.Types[j];
3503 TypeSpec specific = MoreSpecific (ct, bt);
3507 specific_at_least_once = true;
3510 if (specific_at_least_once)
3513 // FIXME: handle lifted operators
3519 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3521 rc.Report.Error (1729, loc,
3522 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3523 type.GetSignatureForError (), argCount.ToString ());
3527 /// Determines if the candidate method is applicable (section 14.4.2.1)
3528 /// to the given set of arguments
3529 /// A return value rates candidate method compatibility,
3530 /// 0 = the best, int.MaxValue = the worst
3532 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3534 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3535 int param_count = pd.Count;
3536 int optional_count = 0;
3539 if (arg_count != param_count) {
3540 for (int i = 0; i < pd.Count; ++i) {
3541 if (pd.FixedParameters[i].HasDefaultValue) {
3542 optional_count = pd.Count - i;
3547 int args_gap = System.Math.Abs (arg_count - param_count);
3548 if (optional_count != 0) {
3549 if (args_gap > optional_count)
3550 return int.MaxValue - 10000 + args_gap - optional_count;
3552 // Readjust expected number when params used
3555 if (arg_count < param_count)
3557 } else if (arg_count > param_count) {
3558 return int.MaxValue - 10000 + args_gap;
3560 } else if (arg_count != param_count) {
3562 return int.MaxValue - 10000 + args_gap;
3563 if (arg_count < param_count - 1)
3564 return int.MaxValue - 10000 + args_gap;
3567 // Resize to fit optional arguments
3568 if (optional_count != 0) {
3569 if (arguments == null) {
3570 arguments = new Arguments (optional_count);
3572 // Have to create a new container, so the next run can do same
3573 var resized = new Arguments (param_count);
3574 resized.AddRange (arguments);
3575 arguments = resized;
3578 for (int i = arg_count; i < param_count; ++i)
3579 arguments.Add (null);
3583 if (arg_count > 0) {
3585 // Shuffle named arguments to the right positions if there are any
3587 if (arguments[arg_count - 1] is NamedArgument) {
3588 arg_count = arguments.Count;
3590 for (int i = 0; i < arg_count; ++i) {
3591 bool arg_moved = false;
3593 NamedArgument na = arguments[i] as NamedArgument;
3597 int index = pd.GetParameterIndexByName (na.Name);
3599 // Named parameter not found or already reordered
3600 if (index == i || index < 0)
3604 if (index >= param_count) {
3605 // When using parameters which should not be available to the user
3606 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3609 arguments.Add (null);
3613 temp = arguments[index];
3615 // The slot has been taken by positional argument
3616 if (temp != null && !(temp is NamedArgument))
3621 arguments.MarkReorderedArgument (na);
3625 arguments[index] = arguments[i];
3626 arguments[i] = temp;
3633 arg_count = arguments.Count;
3635 } else if (arguments != null) {
3636 arg_count = arguments.Count;
3640 // 1. Handle generic method using type arguments when specified or type inference
3642 var ms = candidate as MethodSpec;
3643 if (ms != null && ms.IsGeneric) {
3644 if (type_arguments != null) {
3645 var g_args_count = ms.Arity;
3646 if (g_args_count != type_arguments.Count)
3647 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3649 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3652 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3653 // for now it simplifies things. I should probably add a callback to ResolveContext
3654 if (lambda_conv_msgs == null) {
3655 lambda_conv_msgs = new SessionReportPrinter ();
3656 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3659 score = TypeManager.InferTypeArguments (ec, arguments, ref ms);
3660 lambda_conv_msgs.EndSession ();
3663 return score - 20000;
3670 // Type arguments constraints have to match
3672 if (!ConstraintChecker.CheckAll (null, ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc))
3673 return int.MaxValue - 25000;
3676 if (type_arguments != null)
3677 return int.MaxValue - 15000;
3681 // 2. Each argument has to be implicitly convertible to method parameter
3683 Parameter.Modifier p_mod = 0;
3685 for (int i = 0; i < arg_count; i++) {
3686 Argument a = arguments[i];
3688 if (!pd.FixedParameters[i].HasDefaultValue)
3689 throw new InternalErrorException ();
3692 // Get the default value expression, we can use the same expression
3693 // if the type matches
3695 Expression e = pd.FixedParameters[i].DefaultValue;
3696 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3698 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3700 if (e == EmptyExpression.MissingValue && pd.Types[i] == TypeManager.object_type) {
3701 e = new MemberAccess (new MemberAccess (new MemberAccess (
3702 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3704 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc);
3710 arguments[i] = new Argument (e, Argument.AType.Default);
3714 if (p_mod != Parameter.Modifier.PARAMS) {
3715 p_mod = pd.FixedParameters[i].ModFlags;
3717 } else if (!params_expanded_form) {
3718 params_expanded_form = true;
3719 pt = ((ElementTypeSpec) pt).Element;
3725 if (!params_expanded_form)
3726 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3729 // It can be applicable in expanded form (when not doing exact match like for delegates)
3731 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3732 if (!params_expanded_form)
3733 pt = ((ElementTypeSpec) pt).Element;
3735 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3737 params_expanded_form = true;
3741 if (params_expanded_form)
3743 return (arg_count - i) * 2 + score;
3748 // When params parameter has notargument, will be provided later if the method is the best candidate
3750 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3751 params_expanded_form = true;
3756 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3759 // Types have to be identical when ref or out modifer
3760 // is used and argument is not of dynamic type
3762 if ((argument.Modifier | param_mod) != 0) {
3764 // Defer to dynamic binder
3766 if (argument.Type == InternalType.Dynamic)
3769 if (argument.Type != parameter) {
3771 // Do full equality check after quick path
3773 if (!TypeSpecComparer.IsEqual (argument.Type, parameter))
3778 // Deploy custom error reporting for lambda methods. When probing lambda methods
3779 // keep all errors reported in separate set and once we are done and no best
3780 // candidate found, this set is used to report more details about what was wrong
3783 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3784 if (lambda_conv_msgs == null) {
3785 lambda_conv_msgs = new SessionReportPrinter ();
3786 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3790 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3791 if (lambda_conv_msgs != null) {
3792 lambda_conv_msgs.EndSession ();
3799 if (argument.Modifier != param_mod)
3805 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3807 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3809 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3812 var ac_p = p as ArrayContainer;
3814 var ac_q = ((ArrayContainer) q);
3815 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3816 if (specific == ac_p.Element)
3818 if (specific == ac_q.Element)
3820 } else if (TypeManager.IsGenericType (p)) {
3821 var pargs = TypeManager.GetTypeArguments (p);
3822 var qargs = TypeManager.GetTypeArguments (q);
3824 bool p_specific_at_least_once = false;
3825 bool q_specific_at_least_once = false;
3827 for (int i = 0; i < pargs.Length; i++) {
3828 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3829 if (specific == pargs[i])
3830 p_specific_at_least_once = true;
3831 if (specific == qargs[i])
3832 q_specific_at_least_once = true;
3835 if (p_specific_at_least_once && !q_specific_at_least_once)
3837 if (!p_specific_at_least_once && q_specific_at_least_once)
3845 // Find the best method from candidate list
3847 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3849 List<AmbiguousCandidate> ambiguous_candidates = null;
3851 MemberSpec best_candidate;
3852 Arguments best_candidate_args = null;
3853 bool best_candidate_params = false;
3854 int best_candidate_rate;
3856 int args_count = args != null ? args.Count : 0;
3857 Arguments candidate_args = args;
3858 bool error_mode = false;
3859 var current_type = rc.CurrentType;
3860 MemberSpec invocable_member = null;
3862 // Be careful, cannot return until error reporter is restored
3864 best_candidate = null;
3865 best_candidate_rate = int.MaxValue;
3867 var type_members = members;
3871 for (int i = 0; i < type_members.Count; ++i) {
3872 var member = type_members[i];
3875 // Methods in a base class are not candidates if any method in a derived
3876 // class is applicable
3878 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3881 if (!member.IsAccessible (current_type) && !error_mode)
3884 if (!(member is IParametersMember)) {
3886 // Will use it later to report ambiguity between best method and invocable member
3888 if (Invocation.IsMemberInvocable (member))
3889 invocable_member = member;
3895 // Check if candidate is applicable
3897 bool params_expanded_form = false;
3898 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3901 // How does it score compare to others
3903 if (candidate_rate < best_candidate_rate) {
3904 best_candidate_rate = candidate_rate;
3905 best_candidate = member;
3906 best_candidate_args = candidate_args;
3907 best_candidate_params = params_expanded_form;
3908 } else if (candidate_rate == 0) {
3909 // Is new candidate better
3910 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3911 best_candidate = member;
3912 best_candidate_args = candidate_args;
3913 best_candidate_params = params_expanded_form;
3915 // It's not better but any other found later could be but we are not sure yet
3916 if (ambiguous_candidates == null)
3917 ambiguous_candidates = new List<AmbiguousCandidate> ();
3919 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3923 // Restore expanded arguments
3924 if (candidate_args != args)
3925 candidate_args = args;
3927 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3929 if (prev_recorder != null)
3930 rc.Report.SetPrinter (prev_recorder);
3934 // We've found exact match
3936 if (best_candidate_rate == 0)
3940 // Try extension methods lookup when no ordinary method match was found and provider enables it
3943 var emg = base_provider.LookupExtensionMethod (rc);
3945 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
3947 best_candidate_extension_group = emg;
3948 return (T) (MemberSpec) emg.BestCandidate;
3953 // Don't run expensive error reporting mode for probing
3960 lambda_conv_msgs = null;
3965 // No best member match found, report an error
3967 if (best_candidate_rate != 0 || error_mode) {
3968 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
3972 // TODO: HasDynamic is quite slow
3973 if (args_count != 0 && (restrictions & Restrictions.CovariantDelegate) == 0 && args.HasDynamic) {
3974 if (args [0].ArgType == Argument.AType.ExtensionType) {
3975 rc.Report.Error (1973, loc,
3976 "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",
3977 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError());
3980 BestCandidateIsDynamic = true;
3984 if (ambiguous_candidates != null) {
3986 // Now check that there are no ambiguities i.e the selected method
3987 // should be better than all the others
3989 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
3990 var candidate = ambiguous_candidates [ix];
3992 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
3993 var ambiguous = candidate.Member;
3994 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
3995 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3996 rc.Report.SymbolRelatedToPreviousError (ambiguous);
3997 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3998 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4001 return (T) best_candidate;
4006 if (invocable_member != null) {
4007 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4008 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4009 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4010 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4014 // And now check if the arguments are all
4015 // compatible, perform conversions if
4016 // necessary etc. and return if everything is
4019 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
4022 if (best_candidate == null)
4026 // Check ObsoleteAttribute on the best method
4028 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4029 if (oa != null && !rc.IsObsolete)
4030 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4032 best_candidate.MemberDefinition.SetIsUsed ();
4034 args = best_candidate_args;
4035 return (T) best_candidate;
4038 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4040 return ResolveMember<MethodSpec> (rc, ref args);
4043 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4044 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4046 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4049 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4050 ec.Report.SymbolRelatedToPreviousError (method);
4051 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4052 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4053 TypeManager.CSharpSignature (method));
4056 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4057 TypeManager.CSharpSignature (method));
4058 } else if (IsDelegateInvoke) {
4059 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4060 DelegateType.GetSignatureForError ());
4062 ec.Report.SymbolRelatedToPreviousError (method);
4063 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4064 method.GetSignatureForError ());
4067 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4069 string index = (idx + 1).ToString ();
4070 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4071 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4072 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4073 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4074 index, Parameter.GetModifierSignature (a.Modifier));
4076 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4077 index, Parameter.GetModifierSignature (mod));
4079 string p1 = a.GetSignatureForError ();
4080 string p2 = TypeManager.CSharpName (paramType);
4083 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4084 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4085 ec.Report.SymbolRelatedToPreviousError (paramType);
4088 ec.Report.Error (1503, loc,
4089 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4094 // We have failed to find exact match so we return error info about the closest match
4096 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
4098 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4099 int arg_count = args == null ? 0 : args.Count;
4101 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4102 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4103 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4107 if (lambda_conv_msgs != null) {
4108 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4113 // For candidates which match on parameters count report more details about incorrect arguments
4115 var pm = best_candidate as IParametersMember;
4117 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4118 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4119 // Reject any inaccessible member
4120 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4121 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4122 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4126 var ms = best_candidate as MethodSpec;
4127 if (ms != null && ms.IsGeneric) {
4128 bool constr_ok = true;
4129 if (ms.TypeArguments != null)
4130 constr_ok = ConstraintChecker.CheckAll (rc.MemberContext, ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4132 if (ta_count == 0) {
4133 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4137 rc.Report.Error (411, loc,
4138 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4139 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4146 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4152 // We failed to find any method with correct argument count, report best candidate
4154 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4157 if (best_candidate.Kind == MemberKind.Constructor) {
4158 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4159 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4160 } else if (IsDelegateInvoke) {
4161 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4162 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4163 DelegateType.GetSignatureForError (), arg_count.ToString ());
4165 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4166 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4167 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4168 name, arg_count.ToString ());
4172 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4174 var pm = member as IParametersMember;
4175 var pd = pm.Parameters;
4177 Parameter.Modifier p_mod = 0;
4179 int a_idx = 0, a_pos = 0;
4181 ArrayInitializer params_initializers = null;
4182 bool has_unsafe_arg = pm.MemberType.IsPointer;
4183 int arg_count = args == null ? 0 : args.Count;
4185 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4187 if (p_mod != Parameter.Modifier.PARAMS) {
4188 p_mod = pd.FixedParameters[a_idx].ModFlags;
4189 pt = pd.Types[a_idx];
4190 has_unsafe_arg |= pt.IsPointer;
4192 if (p_mod == Parameter.Modifier.PARAMS) {
4193 if (chose_params_expanded) {
4194 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4195 pt = TypeManager.GetElementType (pt);
4201 // Types have to be identical when ref or out modifer is used
4203 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4204 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4207 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4213 NamedArgument na = a as NamedArgument;
4215 int name_index = pd.GetParameterIndexByName (na.Name);
4216 if (name_index < 0 || name_index >= pd.Count) {
4217 if (IsDelegateInvoke) {
4218 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4219 ec.Report.Error (1746, na.Location,
4220 "The delegate `{0}' does not contain a parameter named `{1}'",
4221 DelegateType.GetSignatureForError (), na.Name);
4223 ec.Report.SymbolRelatedToPreviousError (member);
4224 ec.Report.Error (1739, na.Location,
4225 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4226 TypeManager.CSharpSignature (member), na.Name);
4228 } else if (args[name_index] != a) {
4229 if (IsDelegateInvoke)
4230 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4232 ec.Report.SymbolRelatedToPreviousError (member);
4234 ec.Report.Error (1744, na.Location,
4235 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4240 if (a.Expr.Type == InternalType.Dynamic)
4243 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4244 custom_errors.NoArgumentMatch (ec, member);
4248 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4253 // Convert params arguments to an array initializer
4255 if (params_initializers != null) {
4256 // we choose to use 'a.Expr' rather than 'conv' so that
4257 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4258 params_initializers.Add (a.Expr);
4259 args.RemoveAt (a_idx--);
4264 // Update the argument with the implicit conversion
4268 if (a_idx != arg_count) {
4269 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4274 // Fill not provided arguments required by params modifier
4276 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4278 args = new Arguments (1);
4280 pt = pd.Types[pd.Count - 1];
4281 pt = TypeManager.GetElementType (pt);
4282 has_unsafe_arg |= pt.IsPointer;
4283 params_initializers = new ArrayInitializer (0, loc);
4287 // Append an array argument with all params arguments
4289 if (params_initializers != null) {
4290 args.Add (new Argument (
4291 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4295 if (has_unsafe_arg && !ec.IsUnsafe) {
4296 Expression.UnsafeError (ec, loc);
4300 // We could infer inaccesible type arguments
4302 if (type_arguments == null && member.IsGeneric) {
4303 var ms = (MethodSpec) member;
4304 foreach (var ta in ms.TypeArguments) {
4305 if (!ta.IsAccessible (ec.CurrentType)) {
4306 ec.Report.SymbolRelatedToPreviousError (ta);
4307 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4317 public class ConstantExpr : MemberExpr
4321 public ConstantExpr (ConstSpec constant, Location loc)
4323 this.constant = constant;
4327 public override string Name {
4328 get { throw new NotImplementedException (); }
4331 public override bool IsInstance {
4332 get { return !IsStatic; }
4335 public override bool IsStatic {
4336 get { return true; }
4339 protected override TypeSpec DeclaringType {
4340 get { return constant.DeclaringType; }
4343 public override Expression CreateExpressionTree (ResolveContext ec)
4345 throw new NotSupportedException ("ET");
4348 protected override Expression DoResolve (ResolveContext rc)
4350 ResolveInstanceExpression (rc);
4351 DoBestMemberChecks (rc, constant);
4353 var c = constant.GetConstant (rc);
4355 // Creates reference expression to the constant value
4356 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4359 public override void Emit (EmitContext ec)
4361 throw new NotSupportedException ();
4364 public override string GetSignatureForError ()
4366 return constant.GetSignatureForError ();
4369 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4371 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4376 /// Fully resolved expression that evaluates to a Field
4378 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4379 protected FieldSpec spec;
4380 VariableInfo variable_info;
4382 LocalTemporary temp;
4385 protected FieldExpr (Location l)
4390 public FieldExpr (FieldSpec spec, Location loc)
4395 type = spec.MemberType;
4398 public FieldExpr (FieldBase fi, Location l)
4405 public override string Name {
4411 public bool IsHoisted {
4413 IVariableReference hv = InstanceExpression as IVariableReference;
4414 return hv != null && hv.IsHoisted;
4418 public override bool IsInstance {
4420 return !spec.IsStatic;
4424 public override bool IsStatic {
4426 return spec.IsStatic;
4430 public FieldSpec Spec {
4436 protected override TypeSpec DeclaringType {
4438 return spec.DeclaringType;
4442 public VariableInfo VariableInfo {
4444 return variable_info;
4450 public override string GetSignatureForError ()
4452 return TypeManager.GetFullNameSignature (spec);
4455 public bool IsMarshalByRefAccess ()
4457 // Checks possible ldflda of field access expression
4458 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4459 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4460 !(InstanceExpression is This);
4463 public void SetHasAddressTaken ()
4465 IVariableReference vr = InstanceExpression as IVariableReference;
4467 vr.SetHasAddressTaken ();
4470 public override Expression CreateExpressionTree (ResolveContext ec)
4472 Expression instance;
4473 if (InstanceExpression == null) {
4474 instance = new NullLiteral (loc);
4476 instance = InstanceExpression.CreateExpressionTree (ec);
4479 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4481 CreateTypeOfExpression ());
4483 return CreateExpressionFactoryCall (ec, "Field", args);
4486 public Expression CreateTypeOfExpression ()
4488 return new TypeOfField (spec, loc);
4491 protected override Expression DoResolve (ResolveContext ec)
4493 return DoResolve (ec, false, false);
4496 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4498 if (ResolveInstanceExpression (ec)) {
4499 // Resolve the field's instance expression while flow analysis is turned
4500 // off: when accessing a field "a.b", we must check whether the field
4501 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4503 if (lvalue_instance) {
4504 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4505 Expression right_side =
4506 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4508 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4511 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4512 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4516 if (InstanceExpression == null)
4519 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4520 InstanceExpression.CheckMarshalByRefAccess (ec);
4524 DoBestMemberChecks (ec, spec);
4526 var fb = spec as FixedFieldSpec;
4527 IVariableReference var = InstanceExpression as IVariableReference;
4529 if (lvalue_instance && var != null && var.VariableInfo != null) {
4530 var.VariableInfo.SetFieldAssigned (ec, Name);
4534 IFixedExpression fe = InstanceExpression as IFixedExpression;
4535 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4536 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4539 if (InstanceExpression.eclass != ExprClass.Variable) {
4540 ec.Report.SymbolRelatedToPreviousError (spec);
4541 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4542 TypeManager.GetFullNameSignature (spec));
4543 } else if (var != null && var.IsHoisted) {
4544 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4547 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4550 eclass = ExprClass.Variable;
4552 // If the instance expression is a local variable or parameter.
4553 if (var == null || var.VariableInfo == null)
4556 VariableInfo vi = var.VariableInfo;
4557 if (!vi.IsFieldAssigned (ec, Name, loc))
4560 variable_info = vi.GetSubStruct (Name);
4564 static readonly int [] codes = {
4565 191, // instance, write access
4566 192, // instance, out access
4567 198, // static, write access
4568 199, // static, out access
4569 1648, // member of value instance, write access
4570 1649, // member of value instance, out access
4571 1650, // member of value static, write access
4572 1651 // member of value static, out access
4575 static readonly string [] msgs = {
4576 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4577 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4578 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4579 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4580 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4581 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4582 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4583 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4586 // The return value is always null. Returning a value simplifies calling code.
4587 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4590 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4594 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4596 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4601 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4603 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4604 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4606 Expression e = DoResolve (ec, lvalue_instance, out_access);
4611 spec.MemberDefinition.SetIsAssigned ();
4613 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4614 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4615 ec.Report.Warning (420, 1, loc,
4616 "`{0}': A volatile field references will not be treated as volatile",
4617 spec.GetSignatureForError ());
4620 if (spec.IsReadOnly) {
4621 // InitOnly fields can only be assigned in constructors or initializers
4622 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4623 return Report_AssignToReadonly (ec, right_side);
4625 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4627 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4628 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4629 return Report_AssignToReadonly (ec, right_side);
4630 // static InitOnly fields cannot be assigned-to in an instance constructor
4631 if (IsStatic && !ec.IsStatic)
4632 return Report_AssignToReadonly (ec, right_side);
4633 // instance constructors can't modify InitOnly fields of other instances of the same type
4634 if (!IsStatic && !(InstanceExpression is This))
4635 return Report_AssignToReadonly (ec, right_side);
4639 if (right_side == EmptyExpression.OutAccess.Instance &&
4640 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4641 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4642 ec.Report.Warning (197, 1, loc,
4643 "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",
4644 GetSignatureForError ());
4647 eclass = ExprClass.Variable;
4651 public override int GetHashCode ()
4653 return spec.GetHashCode ();
4656 public bool IsFixed {
4659 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4661 IVariableReference variable = InstanceExpression as IVariableReference;
4662 if (variable != null)
4663 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4665 IFixedExpression fe = InstanceExpression as IFixedExpression;
4666 return fe != null && fe.IsFixed;
4670 public override bool Equals (object obj)
4672 FieldExpr fe = obj as FieldExpr;
4676 if (spec != fe.spec)
4679 if (InstanceExpression == null || fe.InstanceExpression == null)
4682 return InstanceExpression.Equals (fe.InstanceExpression);
4685 public void Emit (EmitContext ec, bool leave_copy)
4687 bool is_volatile = false;
4689 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4692 spec.MemberDefinition.SetIsUsed ();
4696 ec.Emit (OpCodes.Volatile);
4698 ec.Emit (OpCodes.Ldsfld, spec);
4701 EmitInstance (ec, false);
4703 // Optimization for build-in types
4704 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4705 ec.EmitLoadFromPtr (type);
4707 var ff = spec as FixedFieldSpec;
4709 ec.Emit (OpCodes.Ldflda, spec);
4710 ec.Emit (OpCodes.Ldflda, ff.Element);
4713 ec.Emit (OpCodes.Volatile);
4715 ec.Emit (OpCodes.Ldfld, spec);
4721 ec.Emit (OpCodes.Dup);
4723 temp = new LocalTemporary (this.Type);
4729 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4731 prepared = prepare_for_load;
4733 EmitInstance (ec, prepared);
4737 ec.Emit (OpCodes.Dup);
4739 temp = new LocalTemporary (this.Type);
4744 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4745 ec.Emit (OpCodes.Volatile);
4747 spec.MemberDefinition.SetIsAssigned ();
4750 ec.Emit (OpCodes.Stsfld, spec);
4752 ec.Emit (OpCodes.Stfld, spec);
4761 public override void Emit (EmitContext ec)
4766 public override void EmitSideEffect (EmitContext ec)
4768 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4770 if (is_volatile) // || is_marshal_by_ref ())
4771 base.EmitSideEffect (ec);
4774 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
4777 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
4778 name, GetSignatureForError ());
4781 public void AddressOf (EmitContext ec, AddressOp mode)
4783 if ((mode & AddressOp.Store) != 0)
4784 spec.MemberDefinition.SetIsAssigned ();
4785 if ((mode & AddressOp.Load) != 0)
4786 spec.MemberDefinition.SetIsUsed ();
4789 // Handle initonly fields specially: make a copy and then
4790 // get the address of the copy.
4793 if (spec.IsReadOnly){
4795 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4808 local = ec.DeclareLocal (type, false);
4809 ec.Emit (OpCodes.Stloc, local);
4810 ec.Emit (OpCodes.Ldloca, local);
4816 ec.Emit (OpCodes.Ldsflda, spec);
4819 EmitInstance (ec, false);
4820 ec.Emit (OpCodes.Ldflda, spec);
4824 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4826 return MakeExpression (ctx);
4829 public override SLE.Expression MakeExpression (BuilderContext ctx)
4831 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4834 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4836 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4842 /// Expression that evaluates to a Property. The Assign class
4843 /// might set the `Value' expression if we are in an assignment.
4845 /// This is not an LValue because we need to re-write the expression, we
4846 /// can not take data from the stack and store it.
4848 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4850 public PropertyExpr (PropertySpec spec, Location l)
4853 best_candidate = spec;
4854 type = spec.MemberType;
4859 protected override TypeSpec DeclaringType {
4861 return best_candidate.DeclaringType;
4865 public override string Name {
4867 return best_candidate.Name;
4871 public override bool IsInstance {
4877 public override bool IsStatic {
4879 return best_candidate.IsStatic;
4883 public PropertySpec PropertyInfo {
4885 return best_candidate;
4891 public override Expression CreateExpressionTree (ResolveContext ec)
4894 if (IsSingleDimensionalArrayLength ()) {
4895 args = new Arguments (1);
4896 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4897 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4900 args = new Arguments (2);
4901 if (InstanceExpression == null)
4902 args.Add (new Argument (new NullLiteral (loc)));
4904 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4905 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4906 return CreateExpressionFactoryCall (ec, "Property", args);
4909 public Expression CreateSetterTypeOfExpression ()
4911 return new TypeOfMethod (Setter, loc);
4914 public override string GetSignatureForError ()
4916 return best_candidate.GetSignatureForError ();
4919 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4921 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4924 public override SLE.Expression MakeExpression (BuilderContext ctx)
4926 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4929 void Error_PropertyNotValid (ResolveContext ec)
4931 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4932 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4933 GetSignatureForError ());
4936 bool IsSingleDimensionalArrayLength ()
4938 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4941 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4942 return ac != null && ac.Rank == 1;
4945 public override void Emit (EmitContext ec, bool leave_copy)
4948 // Special case: length of single dimension array property is turned into ldlen
4950 if (IsSingleDimensionalArrayLength ()) {
4952 EmitInstance (ec, false);
4953 ec.Emit (OpCodes.Ldlen);
4954 ec.Emit (OpCodes.Conv_I4);
4958 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
4961 ec.Emit (OpCodes.Dup);
4963 temp = new LocalTemporary (this.Type);
4969 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4971 Expression my_source = source;
4973 if (prepare_for_load) {
4978 ec.Emit (OpCodes.Dup);
4980 temp = new LocalTemporary (this.Type);
4984 } else if (leave_copy) {
4986 temp = new LocalTemporary (this.Type);
4991 Arguments args = new Arguments (1);
4992 args.Add (new Argument (my_source));
4994 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5002 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5004 eclass = ExprClass.PropertyAccess;
5006 if (best_candidate.IsNotRealProperty) {
5007 Error_PropertyNotValid (rc);
5010 if (ResolveInstanceExpression (rc)) {
5011 if (right_side != null && best_candidate.DeclaringType.IsStruct)
5012 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
5015 DoBestMemberChecks (rc, best_candidate);
5019 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5021 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5025 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5027 // getter and setter can be different for base calls
5028 MethodSpec getter, setter;
5029 protected T best_candidate;
5031 protected LocalTemporary temp;
5032 protected bool prepared;
5034 protected PropertyOrIndexerExpr (Location l)
5041 public MethodSpec Getter {
5050 public MethodSpec Setter {
5061 protected override Expression DoResolve (ResolveContext ec)
5063 if (eclass == ExprClass.Unresolved) {
5064 var expr = OverloadResolve (ec, null);
5068 if (InstanceExpression != null)
5069 InstanceExpression.CheckMarshalByRefAccess (ec);
5072 return expr.Resolve (ec);
5075 if (!ResolveGetter (ec))
5081 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5083 if (right_side == EmptyExpression.OutAccess.Instance) {
5084 // TODO: best_candidate can be null at this point
5085 if (best_candidate != null && ec.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5086 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5087 best_candidate.Name);
5089 right_side.DoResolveLValue (ec, this);
5094 // if the property/indexer returns a value type, and we try to set a field in it
5095 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5096 Error_CannotModifyIntermediateExpressionValue (ec);
5099 if (eclass == ExprClass.Unresolved) {
5100 var expr = OverloadResolve (ec, right_side);
5105 return expr.ResolveLValue (ec, right_side);
5108 if (!ResolveSetter (ec))
5115 // Implements the IAssignMethod interface for assignments
5117 public abstract void Emit (EmitContext ec, bool leave_copy);
5118 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5120 public override void Emit (EmitContext ec)
5125 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5127 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5129 bool ResolveGetter (ResolveContext rc)
5131 if (!best_candidate.HasGet) {
5132 if (InstanceExpression != EmptyExpression.Null) {
5133 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5134 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5135 best_candidate.GetSignatureForError ());
5138 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5139 if (best_candidate.HasDifferentAccessibility) {
5140 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5141 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5142 TypeManager.CSharpSignature (best_candidate));
5144 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5145 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5149 if (best_candidate.HasDifferentAccessibility) {
5150 CheckProtectedMemberAccess (rc, best_candidate.Get);
5153 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5157 bool ResolveSetter (ResolveContext rc)
5159 if (!best_candidate.HasSet) {
5160 if (rc.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5161 rc.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5162 best_candidate.Name);
5164 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5165 GetSignatureForError ());
5170 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5171 if (best_candidate.HasDifferentAccessibility) {
5172 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5173 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5174 GetSignatureForError ());
5176 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5177 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5181 if (best_candidate.HasDifferentAccessibility)
5182 CheckProtectedMemberAccess (rc, best_candidate.Set);
5184 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5190 /// Fully resolved expression that evaluates to an Event
5192 public class EventExpr : MemberExpr, IAssignMethod
5194 readonly EventSpec spec;
5197 public EventExpr (EventSpec spec, Location loc)
5205 protected override TypeSpec DeclaringType {
5207 return spec.DeclaringType;
5211 public override string Name {
5217 public override bool IsInstance {
5219 return !spec.IsStatic;
5223 public override bool IsStatic {
5225 return spec.IsStatic;
5229 public MethodSpec Operator {
5237 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5240 // If the event is local to this class, we transform ourselves into a FieldExpr
5243 if (spec.DeclaringType == ec.CurrentType ||
5244 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5246 if (spec.BackingField != null) {
5247 spec.MemberDefinition.SetIsUsed ();
5249 if (!ec.IsObsolete) {
5250 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5252 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5255 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5256 Error_AssignmentEventOnly (ec);
5258 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5260 InstanceExpression = null;
5262 return ml.ResolveMemberAccess (ec, left, original);
5266 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5267 Error_AssignmentEventOnly (ec);
5269 return base.ResolveMemberAccess (ec, left, original);
5272 public override Expression CreateExpressionTree (ResolveContext ec)
5274 throw new NotSupportedException ("ET");
5277 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5279 if (right_side == EmptyExpression.EventAddition) {
5280 op = spec.AccessorAdd;
5281 } else if (right_side == EmptyExpression.EventSubtraction) {
5282 op = spec.AccessorRemove;
5286 Error_AssignmentEventOnly (ec);
5290 op = CandidateToBaseOverride (ec, op);
5294 protected override Expression DoResolve (ResolveContext ec)
5296 eclass = ExprClass.EventAccess;
5297 type = spec.MemberType;
5299 ResolveInstanceExpression (ec);
5301 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5302 Error_CannotAssign (ec);
5305 DoBestMemberChecks (ec, spec);
5309 public override void Emit (EmitContext ec)
5311 throw new NotSupportedException ();
5312 //Error_CannotAssign ();
5315 #region IAssignMethod Members
5317 public void Emit (EmitContext ec, bool leave_copy)
5319 throw new NotImplementedException ();
5322 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5324 if (leave_copy || !prepare_for_load)
5325 throw new NotImplementedException ("EventExpr::EmitAssign");
5327 Arguments args = new Arguments (1);
5328 args.Add (new Argument (source));
5329 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5334 void Error_AssignmentEventOnly (ResolveContext ec)
5336 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5337 GetSignatureForError ());
5340 public void Error_CannotAssign (ResolveContext ec)
5342 ec.Report.Error (70, loc,
5343 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5344 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5347 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5349 name = name.Substring (0, name.LastIndexOf ('.'));
5350 base.Error_CannotCallAbstractBase (rc, name);
5353 public override string GetSignatureForError ()
5355 return TypeManager.CSharpSignature (spec);
5358 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5360 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5364 public class TemporaryVariable : VariableReference
5368 public TemporaryVariable (TypeSpec type, Location loc)
5374 public override Expression CreateExpressionTree (ResolveContext ec)
5376 throw new NotSupportedException ("ET");
5379 protected override Expression DoResolve (ResolveContext ec)
5381 eclass = ExprClass.Variable;
5383 TypeExpr te = new TypeExpression (type, loc);
5384 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5385 if (!li.Resolve (ec))
5389 // Don't capture temporary variables except when using
5390 // iterator redirection
5392 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5393 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5394 storey.CaptureLocalVariable (ec, li);
5400 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5402 return Resolve (ec);
5405 public override void Emit (EmitContext ec)
5410 public void EmitAssign (EmitContext ec, Expression source)
5412 EmitAssign (ec, source, false, false);
5415 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5417 return li.HoistedVariant;
5420 public override bool IsFixed {
5421 get { return true; }
5424 public override bool IsRef {
5425 get { return false; }
5428 public override string Name {
5429 get { throw new NotImplementedException (); }
5432 public override void SetHasAddressTaken ()
5434 throw new NotImplementedException ();
5437 protected override ILocalVariable Variable {
5441 public override VariableInfo VariableInfo {
5442 get { throw new NotImplementedException (); }
5447 /// Handles `var' contextual keyword; var becomes a keyword only
5448 /// if no type called var exists in a variable scope
5450 class VarExpr : SimpleName
5452 // Used for error reporting only
5453 int initializers_count;
5455 public VarExpr (Location loc)
5458 initializers_count = 1;
5461 public int VariableInitializersCount {
5463 this.initializers_count = value;
5467 public bool InferType (ResolveContext ec, Expression right_side)
5470 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5472 type = right_side.Type;
5473 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5474 ec.Report.Error (815, loc,
5475 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5476 type.GetSignatureForError ());
5480 eclass = ExprClass.Variable;
5484 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5486 if (RootContext.Version < LanguageVersion.V_3)
5487 base.Error_TypeOrNamespaceNotFound (ec);
5489 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5492 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
5494 TypeExpr te = base.ResolveAsContextualType (rc, true);
5498 if (RootContext.Version < LanguageVersion.V_3)
5499 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5501 if (initializers_count == 1)
5504 if (initializers_count > 1) {
5505 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5506 initializers_count = 1;
5510 if (initializers_count == 0) {
5511 initializers_count = 1;
5512 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");