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 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 e = e.ResolveLValue (ec, right_side);
2381 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2387 /// Represents a namespace or a type. The name of the class was inspired by
2388 /// section 10.8.1 (Fully Qualified Names).
2390 public abstract class FullNamedExpression : Expression
2392 protected override void CloneTo (CloneContext clonectx, Expression target)
2394 // Do nothing, most unresolved type expressions cannot be
2395 // resolved to different type
2398 public override Expression CreateExpressionTree (ResolveContext ec)
2400 throw new NotSupportedException ("ET");
2403 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2408 public override void Emit (EmitContext ec)
2410 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2411 GetSignatureForError ());
2416 /// Expression that evaluates to a type
2418 public abstract class TypeExpr : FullNamedExpression {
2419 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2421 TypeExpr t = DoResolveAsTypeStep (ec);
2425 eclass = ExprClass.Type;
2429 protected override Expression DoResolve (ResolveContext ec)
2431 return ResolveAsTypeTerminal (ec, false);
2434 public virtual bool CheckAccessLevel (IMemberContext mc)
2436 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2438 c = mc.CurrentMemberDefinition.Parent;
2440 return c.CheckAccessLevel (Type);
2443 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2445 public override bool Equals (object obj)
2447 TypeExpr tobj = obj as TypeExpr;
2451 return Type == tobj.Type;
2454 public override int GetHashCode ()
2456 return Type.GetHashCode ();
2461 /// Fully resolved Expression that already evaluated to a type
2463 public class TypeExpression : TypeExpr {
2464 public TypeExpression (TypeSpec t, Location l)
2467 eclass = ExprClass.Type;
2471 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2476 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2483 /// This class denotes an expression which evaluates to a member
2484 /// of a struct or a class.
2486 public abstract class MemberExpr : Expression
2489 // An instance expression associated with this member, if it's a
2490 // non-static member
2492 public Expression InstanceExpression;
2495 /// The name of this member.
2497 public abstract string Name {
2502 // When base.member is used
2504 public bool IsBase {
2505 get { return InstanceExpression is BaseThis; }
2509 /// Whether this is an instance member.
2511 public abstract bool IsInstance {
2516 /// Whether this is a static member.
2518 public abstract bool IsStatic {
2523 protected abstract TypeSpec DeclaringType {
2528 // Converts best base candidate for virtual method starting from QueriedBaseType
2530 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2533 // Only when base.member is used and method is virtual
2539 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2540 // means for base.member access we have to find the closest match after we found best candidate
2542 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2544 // The method could already be what we are looking for
2546 TypeSpec[] targs = null;
2547 if (method.DeclaringType != InstanceExpression.Type) {
2548 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2549 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2550 if (base_override.IsGeneric)
2551 targs = method.TypeArguments;
2553 method = base_override;
2557 // TODO: For now we do it for any hoisted call even if it's needed for
2558 // hoisted stories only but that requires a new expression wrapper
2559 if (rc.CurrentAnonymousMethod != null) {
2560 if (targs == null && method.IsGeneric) {
2561 targs = method.TypeArguments;
2562 method = method.GetGenericMethodDefinition ();
2565 if (method.Parameters.HasArglist)
2566 throw new NotImplementedException ("__arglist base call proxy");
2568 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2570 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2571 // get/set member expressions second call would fail to proxy because left expression
2572 // would be of 'this' and not 'base'
2573 if (rc.CurrentType.IsStruct)
2574 InstanceExpression = rc.GetThis (loc);
2578 method = method.MakeGenericMethod (targs);
2582 // Only base will allow this invocation to happen.
2584 if (method.IsAbstract) {
2585 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2591 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2593 if (InstanceExpression == null)
2596 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2597 var ct = rc.CurrentType;
2598 var expr_type = InstanceExpression.Type;
2599 if (ct != expr_type) {
2600 expr_type = expr_type.GetDefinition ();
2601 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2602 rc.Report.SymbolRelatedToPreviousError (member);
2603 rc.Report.Error (1540, loc,
2604 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2605 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2611 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2614 type = type.GetDefinition ();
2616 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2619 type = type.DeclaringType;
2620 } while (type != null);
2625 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2627 if (InstanceExpression != null) {
2628 InstanceExpression = InstanceExpression.Resolve (rc);
2629 CheckProtectedMemberAccess (rc, member);
2632 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2633 UnsafeError (rc, loc);
2636 if (!rc.IsObsolete) {
2637 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2639 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2642 if (!(member is FieldSpec))
2643 member.MemberDefinition.SetIsUsed ();
2646 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2648 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2652 // Implements identicial simple name and type-name
2654 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2657 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2660 // 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
2661 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2663 if (left is MemberExpr || left is VariableReference) {
2664 rc.Report.DisableReporting ();
2665 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2666 rc.Report.EnableReporting ();
2667 if (identical_type != null && identical_type.Type == left.Type)
2668 return identical_type;
2674 public bool ResolveInstanceExpression (ResolveContext rc)
2677 if (InstanceExpression != null) {
2678 if (InstanceExpression is TypeExpr) {
2679 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2680 if (oa != null && !rc.IsObsolete) {
2681 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2684 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2685 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2686 rc.Report.Error (176, loc,
2687 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2688 GetSignatureForError ());
2692 InstanceExpression = null;
2698 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2699 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2700 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2701 rc.Report.Error (236, loc,
2702 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2703 GetSignatureForError ());
2705 rc.Report.Error (120, loc,
2706 "An object reference is required to access non-static member `{0}'",
2707 GetSignatureForError ());
2712 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2713 rc.Report.Error (38, loc,
2714 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2715 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2718 InstanceExpression = rc.GetThis (loc);
2722 var me = InstanceExpression as MemberExpr;
2724 me.ResolveInstanceExpression (rc);
2726 var fe = me as FieldExpr;
2727 if (fe != null && fe.IsMarshalByRefAccess ()) {
2728 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2729 rc.Report.Warning (1690, 1, loc,
2730 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2731 me.GetSignatureForError ());
2738 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2740 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2741 ec.Report.Warning (1720, 1, left.Location,
2742 "Expression will always cause a `{0}'", "System.NullReferenceException");
2745 InstanceExpression = left;
2749 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2751 TypeSpec instance_type = InstanceExpression.Type;
2752 if (TypeManager.IsValueType (instance_type)) {
2753 if (InstanceExpression is IMemoryLocation) {
2754 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2756 LocalTemporary t = new LocalTemporary (instance_type);
2757 InstanceExpression.Emit (ec);
2759 t.AddressOf (ec, AddressOp.Store);
2762 InstanceExpression.Emit (ec);
2764 // Only to make verifier happy
2765 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2766 ec.Emit (OpCodes.Box, instance_type);
2769 if (prepare_for_load)
2770 ec.Emit (OpCodes.Dup);
2773 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2777 // Represents a group of extension method candidates for whole namespace
2779 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2781 NamespaceEntry namespace_entry;
2782 public readonly Expression ExtensionExpression;
2784 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2785 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2787 this.namespace_entry = n;
2788 this.ExtensionExpression = extensionExpr;
2791 public override bool IsStatic {
2792 get { return true; }
2795 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2797 if (namespace_entry == null)
2801 // For extension methodgroup we are not looking for base members but parent
2802 // namespace extension methods
2804 int arity = type_arguments == null ? 0 : type_arguments.Count;
2805 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2809 return found.Cast<MemberSpec> ().ToList ();
2812 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2814 // We are already here
2818 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2820 if (arguments == null)
2821 arguments = new Arguments (1);
2823 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2824 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2826 // Store resolved argument and restore original arguments
2828 // Clean-up modified arguments for error reporting
2829 arguments.RemoveAt (0);
2833 var me = ExtensionExpression as MemberExpr;
2835 me.ResolveInstanceExpression (ec);
2837 InstanceExpression = null;
2841 #region IErrorHandler Members
2843 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2848 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2850 rc.Report.SymbolRelatedToPreviousError (best);
2851 rc.Report.Error (1928, loc,
2852 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2853 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2856 rc.Report.Error (1929, loc,
2857 "Extension method instance type `{0}' cannot be converted to `{1}'",
2858 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2864 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2869 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2878 /// MethodGroupExpr represents a group of method candidates which
2879 /// can be resolved to the best method overload
2881 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2883 protected IList<MemberSpec> Methods;
2884 MethodSpec best_candidate;
2885 protected TypeArguments type_arguments;
2887 SimpleName simple_name;
2888 protected TypeSpec queried_type;
2890 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2894 this.type = InternalType.MethodGroup;
2896 eclass = ExprClass.MethodGroup;
2897 queried_type = type;
2900 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2901 : this (new MemberSpec[] { m }, type, loc)
2907 public MethodSpec BestCandidate {
2909 return best_candidate;
2913 protected override TypeSpec DeclaringType {
2915 return queried_type;
2919 public override bool IsInstance {
2921 if (best_candidate != null)
2922 return !best_candidate.IsStatic;
2928 public override bool IsStatic {
2930 if (best_candidate != null)
2931 return best_candidate.IsStatic;
2937 public override string Name {
2939 if (best_candidate != null)
2940 return best_candidate.Name;
2943 return Methods.First ().Name;
2950 // When best candidate is already know this factory can be used
2951 // to avoid expensive overload resolution to be called
2953 // NOTE: InstanceExpression has to be set manually
2955 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2957 return new MethodGroupExpr (best, queriedType, loc) {
2958 best_candidate = best
2962 public override string GetSignatureForError ()
2964 if (best_candidate != null)
2965 return best_candidate.GetSignatureForError ();
2967 return Methods.First ().GetSignatureForError ();
2970 public override Expression CreateExpressionTree (ResolveContext ec)
2972 if (best_candidate == null) {
2973 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
2977 if (best_candidate.IsConditionallyExcluded (loc))
2978 ec.Report.Error (765, loc,
2979 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
2981 return new TypeOfMethod (best_candidate, loc);
2984 protected override Expression DoResolve (ResolveContext ec)
2986 this.eclass = ExprClass.MethodGroup;
2988 if (InstanceExpression != null) {
2989 InstanceExpression = InstanceExpression.Resolve (ec);
2990 if (InstanceExpression == null)
2997 public override void Emit (EmitContext ec)
2999 throw new NotSupportedException ();
3002 public void EmitCall (EmitContext ec, Arguments arguments)
3004 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3007 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3009 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3010 Name, TypeManager.CSharpName (target));
3013 public static bool IsExtensionMethodArgument (Expression expr)
3016 // LAMESPEC: No details about which expressions are not allowed
3018 return !(expr is BaseThis);
3022 /// Find the Applicable Function Members (7.4.2.1)
3024 /// me: Method Group expression with the members to select.
3025 /// it might contain constructors or methods (or anything
3026 /// that maps to a method).
3028 /// Arguments: ArrayList containing resolved Argument objects.
3030 /// loc: The location if we want an error to be reported, or a Null
3031 /// location for "probing" purposes.
3033 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3034 /// that is the best match of me on Arguments.
3037 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3039 // TODO: causes issues with probing mode, remove explicit Kind check
3040 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3043 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3044 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3045 r.BaseMembersProvider = this;
3048 if (cerrors != null)
3049 r.CustomErrors = cerrors;
3051 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3052 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3053 if (best_candidate == null)
3054 return r.BestCandidateIsDynamic ? this : null;
3056 // Overload resolver had to create a new method group, all checks bellow have already been executed
3057 if (r.BestCandidateNewMethodGroup != null)
3058 return r.BestCandidateNewMethodGroup;
3060 if (best_candidate.Kind == MemberKind.Method) {
3061 if (InstanceExpression != null) {
3062 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3063 InstanceExpression = null;
3065 if (best_candidate.IsStatic && simple_name != null) {
3066 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3069 InstanceExpression.Resolve (ec);
3073 ResolveInstanceExpression (ec);
3074 if (InstanceExpression != null)
3075 CheckProtectedMemberAccess (ec, best_candidate);
3077 if (best_candidate.IsGeneric) {
3078 ConstraintChecker.CheckAll (ec.MemberContext, best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments,
3079 best_candidate.Constraints, loc);
3083 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3087 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3089 simple_name = original;
3090 return base.ResolveMemberAccess (ec, left, original);
3093 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3095 type_arguments = ta;
3098 #region IBaseMembersProvider Members
3100 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3102 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3106 // Extension methods lookup after ordinary methods candidates failed to apply
3108 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3110 if (InstanceExpression == null)
3113 InstanceExpression = InstanceExpression.Resolve (rc);
3114 if (!IsExtensionMethodArgument (InstanceExpression))
3117 int arity = type_arguments == null ? 0 : type_arguments.Count;
3118 NamespaceEntry methods_scope = null;
3119 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3120 if (methods == null)
3123 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3124 emg.SetTypeArguments (rc, type_arguments);
3131 public struct OverloadResolver
3134 public enum Restrictions
3138 ProbingOnly = 1 << 1,
3140 NoBaseMembers = 1 << 3
3143 public interface IBaseMembersProvider
3145 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3146 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3149 public interface IErrorHandler
3151 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3152 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3153 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3154 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3157 sealed class NoBaseMembers : IBaseMembersProvider
3159 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3161 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3166 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3172 struct AmbiguousCandidate
3174 public readonly MemberSpec Member;
3175 public readonly bool Expanded;
3177 public AmbiguousCandidate (MemberSpec member, bool expanded)
3180 Expanded = expanded;
3185 IList<MemberSpec> members;
3186 TypeArguments type_arguments;
3187 IBaseMembersProvider base_provider;
3188 IErrorHandler custom_errors;
3189 Restrictions restrictions;
3190 MethodGroupExpr best_candidate_extension_group;
3192 SessionReportPrinter lambda_conv_msgs;
3193 ReportPrinter prev_recorder;
3195 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3196 : this (members, null, restrictions, loc)
3200 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3203 if (members == null || members.Count == 0)
3204 throw new ArgumentException ("empty members set");
3206 this.members = members;
3208 type_arguments = targs;
3209 this.restrictions = restrictions;
3210 if (IsDelegateInvoke)
3211 this.restrictions |= Restrictions.NoBaseMembers;
3213 base_provider = NoBaseMembers.Instance;
3218 public IBaseMembersProvider BaseMembersProvider {
3220 return base_provider;
3223 base_provider = value;
3227 public bool BestCandidateIsDynamic { get; set; }
3230 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3232 public MethodGroupExpr BestCandidateNewMethodGroup {
3234 return best_candidate_extension_group;
3238 public IErrorHandler CustomErrors {
3240 return custom_errors;
3243 custom_errors = value;
3247 TypeSpec DelegateType {
3249 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3250 throw new InternalErrorException ("Not running in delegate mode", loc);
3252 return members [0].DeclaringType;
3256 bool IsProbingOnly {
3258 return (restrictions & Restrictions.ProbingOnly) != 0;
3262 bool IsDelegateInvoke {
3264 return (restrictions & Restrictions.DelegateInvoke) != 0;
3271 // 7.4.3.3 Better conversion from expression
3272 // Returns : 1 if a->p is better,
3273 // 2 if a->q is better,
3274 // 0 if neither is better
3276 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3278 TypeSpec argument_type = a.Type;
3279 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3281 // Uwrap delegate from Expression<T>
3283 if (p.GetDefinition () == TypeManager.expression_type) {
3284 p = TypeManager.GetTypeArguments (p)[0];
3286 if (q.GetDefinition () == TypeManager.expression_type) {
3287 q = TypeManager.GetTypeArguments (q)[0];
3290 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3291 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3292 if (p == TypeManager.void_type && q != TypeManager.void_type)
3294 if (q == TypeManager.void_type && p != TypeManager.void_type)
3297 if (argument_type == p)
3300 if (argument_type == q)
3304 return BetterTypeConversion (ec, p, q);
3308 // 7.4.3.4 Better conversion from type
3310 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3312 if (p == null || q == null)
3313 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3315 if (p == TypeManager.int32_type) {
3316 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3318 } else if (p == TypeManager.int64_type) {
3319 if (q == TypeManager.uint64_type)
3321 } else if (p == TypeManager.sbyte_type) {
3322 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3323 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3325 } else if (p == TypeManager.short_type) {
3326 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3327 q == TypeManager.uint64_type)
3329 } else if (p == InternalType.Dynamic) {
3330 if (q == TypeManager.object_type)
3334 if (q == TypeManager.int32_type) {
3335 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3337 } if (q == TypeManager.int64_type) {
3338 if (p == TypeManager.uint64_type)
3340 } else if (q == TypeManager.sbyte_type) {
3341 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3342 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3344 } if (q == TypeManager.short_type) {
3345 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3346 p == TypeManager.uint64_type)
3348 } else if (q == InternalType.Dynamic) {
3349 if (p == TypeManager.object_type)
3353 // TODO: this is expensive
3354 Expression p_tmp = new EmptyExpression (p);
3355 Expression q_tmp = new EmptyExpression (q);
3357 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3358 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3360 if (p_to_q && !q_to_p)
3363 if (q_to_p && !p_to_q)
3370 /// Determines "Better function" between candidate
3371 /// and the current best match
3374 /// Returns a boolean indicating :
3375 /// false if candidate ain't better
3376 /// true if candidate is better than the current best match
3378 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3379 MemberSpec best, bool best_params)
3381 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3382 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3384 bool better_at_least_one = false;
3386 int args_count = args == null ? 0 : args.Count;
3388 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3389 Argument a = args[j];
3391 // Default arguments are ignored for better decision
3392 if (a.IsDefaultArgument)
3395 TypeSpec ct = candidate_pd.Types[c_idx];
3396 TypeSpec bt = best_pd.Types[b_idx];
3398 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3399 ct = TypeManager.GetElementType (ct);
3403 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3404 bt = TypeManager.GetElementType (bt);
3412 int result = BetterExpressionConversion (ec, a, ct, bt);
3414 // for each argument, the conversion to 'ct' should be no worse than
3415 // the conversion to 'bt'.
3419 // for at least one argument, the conversion to 'ct' should be better than
3420 // the conversion to 'bt'.
3422 better_at_least_one = true;
3425 if (better_at_least_one)
3429 // This handles the case
3431 // Add (float f1, float f2, float f3);
3432 // Add (params decimal [] foo);
3434 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3435 // first candidate would've chosen as better.
3441 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3445 // This handles the following cases:
3447 // Foo (int i) is better than Foo (int i, long l = 0)
3448 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3450 // Prefer non-optional version
3452 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3453 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3454 if (candidate_pd.Count >= best_pd.Count)
3457 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3464 // One is a non-generic method and second is a generic method, then non-generic is better
3466 if (best.IsGeneric != candidate.IsGeneric)
3467 return best.IsGeneric;
3470 // This handles the following cases:
3472 // Trim () is better than Trim (params char[] chars)
3473 // Concat (string s1, string s2, string s3) is better than
3474 // Concat (string s1, params string [] srest)
3475 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3477 // Prefer non-expanded version
3479 if (candidate_params != best_params)
3482 int candidate_param_count = candidate_pd.Count;
3483 int best_param_count = best_pd.Count;
3485 if (candidate_param_count != best_param_count)
3486 // can only happen if (candidate_params && best_params)
3487 return candidate_param_count > best_param_count && best_pd.HasParams;
3490 // Both methods have the same number of parameters, and the parameters have equal types
3491 // Pick the "more specific" signature using rules over original (non-inflated) types
3493 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3494 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3496 bool specific_at_least_once = false;
3497 for (j = 0; j < candidate_param_count; ++j) {
3498 var ct = candidate_def_pd.Types[j];
3499 var bt = best_def_pd.Types[j];
3502 TypeSpec specific = MoreSpecific (ct, bt);
3506 specific_at_least_once = true;
3509 if (specific_at_least_once)
3512 // FIXME: handle lifted operators
3518 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3520 rc.Report.Error (1729, loc,
3521 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3522 type.GetSignatureForError (), argCount.ToString ());
3526 /// Determines if the candidate method is applicable (section 14.4.2.1)
3527 /// to the given set of arguments
3528 /// A return value rates candidate method compatibility,
3529 /// 0 = the best, int.MaxValue = the worst
3531 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3533 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3534 int param_count = pd.Count;
3535 int optional_count = 0;
3537 if (arg_count != param_count) {
3538 for (int i = 0; i < pd.Count; ++i) {
3539 if (pd.FixedParameters[i].HasDefaultValue) {
3540 optional_count = pd.Count - i;
3545 int args_gap = System.Math.Abs (arg_count - param_count);
3546 if (optional_count != 0) {
3547 if (args_gap > optional_count)
3548 return int.MaxValue - 10000 + args_gap - optional_count;
3550 // Readjust expected number when params used
3553 if (arg_count < param_count)
3555 } else if (arg_count > param_count) {
3556 return int.MaxValue - 10000 + args_gap;
3558 } else if (arg_count != param_count) {
3560 return int.MaxValue - 10000 + args_gap;
3561 if (arg_count < param_count - 1)
3562 return int.MaxValue - 10000 + args_gap;
3565 // Initialize expanded form of a method with 1 params parameter
3566 params_expanded_form = param_count == 1 && pd.HasParams;
3568 // Resize to fit optional arguments
3569 if (optional_count != 0) {
3571 if (arguments == null) {
3572 resized = new Arguments (optional_count);
3574 resized = new Arguments (param_count);
3575 resized.AddRange (arguments);
3578 for (int i = arg_count; i < param_count; ++i)
3580 arguments = resized;
3584 if (arg_count > 0) {
3586 // Shuffle named arguments to the right positions if there are any
3588 if (arguments[arg_count - 1] is NamedArgument) {
3589 arg_count = arguments.Count;
3591 for (int i = 0; i < arg_count; ++i) {
3592 bool arg_moved = false;
3594 NamedArgument na = arguments[i] as NamedArgument;
3598 int index = pd.GetParameterIndexByName (na.Name);
3600 // Named parameter not found or already reordered
3604 // When using parameters which should not be available to the user
3605 if (index >= param_count)
3609 arguments.MarkReorderedArgument (na);
3613 Argument temp = arguments[index];
3614 arguments[index] = arguments[i];
3615 arguments[i] = temp;
3622 arg_count = arguments.Count;
3624 } else if (arguments != null) {
3625 arg_count = arguments.Count;
3629 // 1. Handle generic method using type arguments when specified or type inference
3631 var ms = candidate as MethodSpec;
3632 if (ms != null && ms.IsGeneric) {
3633 if (type_arguments != null) {
3634 var g_args_count = ms.Arity;
3635 if (g_args_count != type_arguments.Count)
3636 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3638 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3641 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3642 // for now it simplifies things. I should probably add a callback to ResolveContext
3643 if (lambda_conv_msgs == null) {
3644 lambda_conv_msgs = new SessionReportPrinter ();
3645 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3648 int score = TypeManager.InferTypeArguments (ec, arguments, ref ms);
3649 lambda_conv_msgs.EndSession ();
3652 return score - 20000;
3658 if (type_arguments != null)
3659 return int.MaxValue - 15000;
3663 // 2. Each argument has to be implicitly convertible to method parameter
3665 Parameter.Modifier p_mod = 0;
3667 for (int i = 0; i < arg_count; i++) {
3668 Argument a = arguments[i];
3670 if (!pd.FixedParameters[i].HasDefaultValue)
3671 throw new InternalErrorException ();
3673 Expression e = pd.FixedParameters[i].DefaultValue as Constant;
3675 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc).Resolve (ec);
3677 arguments[i] = new Argument (e, Argument.AType.Default);
3681 if (p_mod != Parameter.Modifier.PARAMS) {
3682 p_mod = pd.FixedParameters[i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3685 params_expanded_form = true;
3688 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3690 if (!params_expanded_form)
3691 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3694 // It can be applicable in expanded form (when not doing exact match like for delegates)
3696 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.Covariant) == 0) {
3697 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3699 params_expanded_form = true;
3703 if (params_expanded_form)
3705 return (arg_count - i) * 2 + score;
3709 if (arg_count != pd.Count)
3710 params_expanded_form = true;
3715 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3718 // Types have to be identical when ref or out modifer is used
3720 if ((arg_mod | param_mod) != 0) {
3721 if (argument.Type != parameter && !TypeSpecComparer.IsEqual (argument.Type, parameter)) {
3726 // Deploy custom error reporting for lambda methods. When probing lambda methods
3727 // keep all errors reported in separate set and once we are done and no best
3728 // candidate found, this set is used to report more details about what was wrong
3731 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3732 if (lambda_conv_msgs == null) {
3733 lambda_conv_msgs = new SessionReportPrinter ();
3734 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3738 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3739 if (lambda_conv_msgs != null) {
3740 lambda_conv_msgs.EndSession ();
3743 if (argument.Type == InternalType.Dynamic)
3750 if (arg_mod != param_mod)
3756 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3758 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3760 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3763 var ac_p = p as ArrayContainer;
3765 var ac_q = ((ArrayContainer) q);
3766 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3767 if (specific == ac_p.Element)
3769 if (specific == ac_q.Element)
3771 } else if (TypeManager.IsGenericType (p)) {
3772 var pargs = TypeManager.GetTypeArguments (p);
3773 var qargs = TypeManager.GetTypeArguments (q);
3775 bool p_specific_at_least_once = false;
3776 bool q_specific_at_least_once = false;
3778 for (int i = 0; i < pargs.Length; i++) {
3779 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3780 if (specific == pargs[i])
3781 p_specific_at_least_once = true;
3782 if (specific == qargs[i])
3783 q_specific_at_least_once = true;
3786 if (p_specific_at_least_once && !q_specific_at_least_once)
3788 if (!p_specific_at_least_once && q_specific_at_least_once)
3796 // Find the best method from candidate list
3798 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3800 List<AmbiguousCandidate> ambiguous_candidates = null;
3802 MemberSpec best_candidate;
3803 Arguments best_candidate_args = null;
3804 bool best_candidate_params = false;
3805 int best_candidate_rate;
3807 int args_count = args != null ? args.Count : 0;
3808 Arguments candidate_args = args;
3809 bool error_mode = false;
3810 var current_type = rc.CurrentType;
3811 MemberSpec invocable_member = null;
3813 // Be careful, cannot return until error reporter is restored
3815 best_candidate = null;
3816 best_candidate_rate = int.MaxValue;
3818 var type_members = members;
3822 for (int i = 0; i < type_members.Count; ++i) {
3823 var member = type_members[i];
3826 // Methods in a base class are not candidates if any method in a derived
3827 // class is applicable
3829 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3832 if (!member.IsAccessible (current_type) && !error_mode)
3835 if (!(member is IParametersMember)) {
3837 // Will use it later to report ambiguity between best method and invocable member
3839 if (Invocation.IsMemberInvocable (member))
3840 invocable_member = member;
3846 // Check if candidate is applicable
3848 bool params_expanded_form = false;
3849 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3852 // How does it score compare to others
3854 if (candidate_rate < best_candidate_rate) {
3855 best_candidate_rate = candidate_rate;
3856 best_candidate = member;
3857 best_candidate_args = candidate_args;
3858 best_candidate_params = params_expanded_form;
3859 } else if (candidate_rate == 0) {
3860 // Is new candidate better
3861 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3862 best_candidate = member;
3863 best_candidate_args = candidate_args;
3864 best_candidate_params = params_expanded_form;
3866 // It's not better but any other found later could be but we are not sure yet
3867 if (ambiguous_candidates == null)
3868 ambiguous_candidates = new List<AmbiguousCandidate> ();
3870 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3874 // Restore expanded arguments
3875 if (candidate_args != args)
3876 candidate_args = args;
3878 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3880 if (prev_recorder != null)
3881 rc.Report.SetPrinter (prev_recorder);
3885 // We've found exact match
3887 if (best_candidate_rate == 0)
3891 // Try extension methods lookup when no ordinary method match was found and provider enables it
3894 var emg = base_provider.LookupExtensionMethod (rc);
3896 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
3898 best_candidate_extension_group = emg;
3899 return (T) (MemberSpec) emg.BestCandidate;
3904 // Don't run expensive error reporting mode for probing
3911 lambda_conv_msgs = null;
3916 // No best member match found, report an error
3918 if (best_candidate_rate != 0 || error_mode) {
3919 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
3924 if (args_count != 0 && args.HasDynamic) {
3925 if (args [0].ArgType == Argument.AType.ExtensionType) {
3926 rc.Report.Error (1973, loc,
3927 "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",
3928 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError());
3931 BestCandidateIsDynamic = true;
3935 if (ambiguous_candidates != null) {
3937 // Now check that there are no ambiguities i.e the selected method
3938 // should be better than all the others
3940 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
3941 var candidate = ambiguous_candidates [ix];
3943 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
3944 var ambiguous = candidate.Member;
3945 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
3946 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3947 rc.Report.SymbolRelatedToPreviousError (ambiguous);
3948 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3949 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
3952 return (T) best_candidate;
3957 if (invocable_member != null) {
3958 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3959 rc.Report.SymbolRelatedToPreviousError (invocable_member);
3960 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
3961 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
3965 // And now check if the arguments are all
3966 // compatible, perform conversions if
3967 // necessary etc. and return if everything is
3970 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
3973 if (best_candidate == null)
3977 // Check ObsoleteAttribute on the best method
3979 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
3980 if (oa != null && !rc.IsObsolete)
3981 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
3983 best_candidate.MemberDefinition.SetIsUsed ();
3985 args = best_candidate_args;
3986 return (T) best_candidate;
3989 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
3991 return ResolveMember<MethodSpec> (rc, ref args);
3994 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
3995 Argument a, AParametersCollection expected_par, TypeSpec paramType)
3997 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4000 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4001 ec.Report.SymbolRelatedToPreviousError (method);
4002 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4003 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4004 TypeManager.CSharpSignature (method));
4007 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4008 TypeManager.CSharpSignature (method));
4009 } else if (IsDelegateInvoke) {
4010 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4011 DelegateType.GetSignatureForError ());
4013 ec.Report.SymbolRelatedToPreviousError (method);
4014 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4015 method.GetSignatureForError ());
4018 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4020 string index = (idx + 1).ToString ();
4021 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4022 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4023 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4024 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4025 index, Parameter.GetModifierSignature (a.Modifier));
4027 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4028 index, Parameter.GetModifierSignature (mod));
4030 string p1 = a.GetSignatureForError ();
4031 string p2 = TypeManager.CSharpName (paramType);
4034 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4035 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4036 ec.Report.SymbolRelatedToPreviousError (paramType);
4039 ec.Report.Error (1503, loc,
4040 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4045 // We have failed to find exact match so we return error info about the closest match
4047 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
4049 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4050 int arg_count = args == null ? 0 : args.Count;
4052 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4053 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4054 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4058 if (lambda_conv_msgs != null) {
4059 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4064 // For candidates which match on parameters count report more details about incorrect arguments
4066 var pm = best_candidate as IParametersMember;
4068 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4069 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4070 // Reject any inaccessible member
4071 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4072 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4073 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4077 var ms = best_candidate as MethodSpec;
4078 if (ms != null && ms.IsGeneric && ta_count == 0) {
4079 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4082 rc.Report.Error (411, loc,
4083 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4084 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4088 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4094 // We failed to find any method with correct argument count, report best candidate
4096 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4099 if (best_candidate.Kind == MemberKind.Constructor) {
4100 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4101 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4102 } else if (IsDelegateInvoke) {
4103 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4104 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4105 DelegateType.GetSignatureForError (), arg_count.ToString ());
4107 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4108 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4109 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4110 name, arg_count.ToString ());
4114 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4116 var pm = member as IParametersMember;
4117 var pd = pm.Parameters;
4119 Parameter.Modifier p_mod = 0;
4121 int a_idx = 0, a_pos = 0;
4123 ArrayInitializer params_initializers = null;
4124 bool has_unsafe_arg = pm.MemberType.IsPointer;
4125 int arg_count = args == null ? 0 : args.Count;
4127 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4129 if (p_mod != Parameter.Modifier.PARAMS) {
4130 p_mod = pd.FixedParameters[a_idx].ModFlags;
4131 pt = pd.Types[a_idx];
4132 has_unsafe_arg |= pt.IsPointer;
4134 if (p_mod == Parameter.Modifier.PARAMS) {
4135 if (chose_params_expanded) {
4136 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4137 pt = TypeManager.GetElementType (pt);
4143 // Types have to be identical when ref or out modifer is used
4145 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4146 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4149 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4155 NamedArgument na = a as NamedArgument;
4157 int name_index = pd.GetParameterIndexByName (na.Name);
4158 if (name_index < 0 || name_index >= pd.Count) {
4159 if (IsDelegateInvoke) {
4160 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4161 ec.Report.Error (1746, na.Location,
4162 "The delegate `{0}' does not contain a parameter named `{1}'",
4163 DelegateType.GetSignatureForError (), na.Name);
4165 ec.Report.SymbolRelatedToPreviousError (member);
4166 ec.Report.Error (1739, na.Location,
4167 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4168 TypeManager.CSharpSignature (member), na.Name);
4170 } else if (args[name_index] != a) {
4171 if (IsDelegateInvoke)
4172 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4174 ec.Report.SymbolRelatedToPreviousError (member);
4176 ec.Report.Error (1744, na.Location,
4177 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4182 if (a.Expr.Type == InternalType.Dynamic)
4185 if ((restrictions & Restrictions.Covariant) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4186 custom_errors.NoArgumentMatch (ec, member);
4190 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4195 // Convert params arguments to an array initializer
4197 if (params_initializers != null) {
4198 // we choose to use 'a.Expr' rather than 'conv' so that
4199 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4200 params_initializers.Add (a.Expr);
4201 args.RemoveAt (a_idx--);
4206 // Update the argument with the implicit conversion
4210 if (a_idx != arg_count) {
4211 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4216 // Fill not provided arguments required by params modifier
4218 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4220 args = new Arguments (1);
4222 pt = pd.Types[pd.Count - 1];
4223 pt = TypeManager.GetElementType (pt);
4224 has_unsafe_arg |= pt.IsPointer;
4225 params_initializers = new ArrayInitializer (0, loc);
4229 // Append an array argument with all params arguments
4231 if (params_initializers != null) {
4232 args.Add (new Argument (
4233 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4237 if (has_unsafe_arg && !ec.IsUnsafe) {
4238 Expression.UnsafeError (ec, loc);
4245 public class ConstantExpr : MemberExpr
4249 public ConstantExpr (ConstSpec constant, Location loc)
4251 this.constant = constant;
4255 public override string Name {
4256 get { throw new NotImplementedException (); }
4259 public override bool IsInstance {
4260 get { return !IsStatic; }
4263 public override bool IsStatic {
4264 get { return true; }
4267 protected override TypeSpec DeclaringType {
4268 get { return constant.DeclaringType; }
4271 public override Expression CreateExpressionTree (ResolveContext ec)
4273 throw new NotSupportedException ("ET");
4276 protected override Expression DoResolve (ResolveContext rc)
4278 ResolveInstanceExpression (rc);
4279 DoBestMemberChecks (rc, constant);
4281 var c = constant.GetConstant (rc);
4283 // Creates reference expression to the constant value
4284 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4287 public override void Emit (EmitContext ec)
4289 throw new NotSupportedException ();
4292 public override string GetSignatureForError ()
4294 return constant.GetSignatureForError ();
4297 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4299 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4304 /// Fully resolved expression that evaluates to a Field
4306 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4307 protected FieldSpec spec;
4308 VariableInfo variable_info;
4310 LocalTemporary temp;
4313 protected FieldExpr (Location l)
4318 public FieldExpr (FieldSpec spec, Location loc)
4323 type = spec.MemberType;
4326 public FieldExpr (FieldBase fi, Location l)
4333 public override string Name {
4339 public bool IsHoisted {
4341 IVariableReference hv = InstanceExpression as IVariableReference;
4342 return hv != null && hv.IsHoisted;
4346 public override bool IsInstance {
4348 return !spec.IsStatic;
4352 public override bool IsStatic {
4354 return spec.IsStatic;
4358 public FieldSpec Spec {
4364 protected override TypeSpec DeclaringType {
4366 return spec.DeclaringType;
4370 public VariableInfo VariableInfo {
4372 return variable_info;
4378 public override string GetSignatureForError ()
4380 return TypeManager.GetFullNameSignature (spec);
4383 public bool IsMarshalByRefAccess ()
4385 // Checks possible ldflda of field access expression
4386 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4387 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4388 !(InstanceExpression is This);
4391 public void SetHasAddressTaken ()
4393 IVariableReference vr = InstanceExpression as IVariableReference;
4395 vr.SetHasAddressTaken ();
4398 public override Expression CreateExpressionTree (ResolveContext ec)
4400 Expression instance;
4401 if (InstanceExpression == null) {
4402 instance = new NullLiteral (loc);
4404 instance = InstanceExpression.CreateExpressionTree (ec);
4407 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4409 CreateTypeOfExpression ());
4411 return CreateExpressionFactoryCall (ec, "Field", args);
4414 public Expression CreateTypeOfExpression ()
4416 return new TypeOfField (spec, loc);
4419 protected override Expression DoResolve (ResolveContext ec)
4421 return DoResolve (ec, false, false);
4424 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4426 if (ResolveInstanceExpression (ec)) {
4427 // Resolve the field's instance expression while flow analysis is turned
4428 // off: when accessing a field "a.b", we must check whether the field
4429 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4431 if (lvalue_instance) {
4432 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4433 Expression right_side =
4434 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4436 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4439 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4440 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4444 if (InstanceExpression == null)
4447 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4448 InstanceExpression.CheckMarshalByRefAccess (ec);
4452 DoBestMemberChecks (ec, spec);
4454 var fb = spec as FixedFieldSpec;
4455 IVariableReference var = InstanceExpression as IVariableReference;
4457 if (lvalue_instance && var != null && var.VariableInfo != null) {
4458 var.VariableInfo.SetFieldAssigned (ec, Name);
4462 IFixedExpression fe = InstanceExpression as IFixedExpression;
4463 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4464 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4467 if (InstanceExpression.eclass != ExprClass.Variable) {
4468 ec.Report.SymbolRelatedToPreviousError (spec);
4469 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4470 TypeManager.GetFullNameSignature (spec));
4471 } else if (var != null && var.IsHoisted) {
4472 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4475 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4478 eclass = ExprClass.Variable;
4480 // If the instance expression is a local variable or parameter.
4481 if (var == null || var.VariableInfo == null)
4484 VariableInfo vi = var.VariableInfo;
4485 if (!vi.IsFieldAssigned (ec, Name, loc))
4488 variable_info = vi.GetSubStruct (Name);
4492 static readonly int [] codes = {
4493 191, // instance, write access
4494 192, // instance, out access
4495 198, // static, write access
4496 199, // static, out access
4497 1648, // member of value instance, write access
4498 1649, // member of value instance, out access
4499 1650, // member of value static, write access
4500 1651 // member of value static, out access
4503 static readonly string [] msgs = {
4504 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4505 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4506 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4507 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4508 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4509 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4510 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4511 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4514 // The return value is always null. Returning a value simplifies calling code.
4515 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4518 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4522 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4524 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4529 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4531 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4532 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4534 Expression e = DoResolve (ec, lvalue_instance, out_access);
4539 spec.MemberDefinition.SetIsAssigned ();
4541 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4542 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4543 ec.Report.Warning (420, 1, loc,
4544 "`{0}': A volatile field references will not be treated as volatile",
4545 spec.GetSignatureForError ());
4548 if (spec.IsReadOnly) {
4549 // InitOnly fields can only be assigned in constructors or initializers
4550 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4551 return Report_AssignToReadonly (ec, right_side);
4553 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4555 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4556 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4557 return Report_AssignToReadonly (ec, right_side);
4558 // static InitOnly fields cannot be assigned-to in an instance constructor
4559 if (IsStatic && !ec.IsStatic)
4560 return Report_AssignToReadonly (ec, right_side);
4561 // instance constructors can't modify InitOnly fields of other instances of the same type
4562 if (!IsStatic && !(InstanceExpression is This))
4563 return Report_AssignToReadonly (ec, right_side);
4567 if (right_side == EmptyExpression.OutAccess.Instance &&
4568 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4569 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4570 ec.Report.Warning (197, 1, loc,
4571 "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",
4572 GetSignatureForError ());
4575 eclass = ExprClass.Variable;
4579 public override int GetHashCode ()
4581 return spec.GetHashCode ();
4584 public bool IsFixed {
4587 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4589 IVariableReference variable = InstanceExpression as IVariableReference;
4590 if (variable != null)
4591 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4593 IFixedExpression fe = InstanceExpression as IFixedExpression;
4594 return fe != null && fe.IsFixed;
4598 public override bool Equals (object obj)
4600 FieldExpr fe = obj as FieldExpr;
4604 if (spec != fe.spec)
4607 if (InstanceExpression == null || fe.InstanceExpression == null)
4610 return InstanceExpression.Equals (fe.InstanceExpression);
4613 public void Emit (EmitContext ec, bool leave_copy)
4615 bool is_volatile = false;
4617 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4620 spec.MemberDefinition.SetIsUsed ();
4624 ec.Emit (OpCodes.Volatile);
4626 ec.Emit (OpCodes.Ldsfld, spec);
4629 EmitInstance (ec, false);
4631 // Optimization for build-in types
4632 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4633 ec.EmitLoadFromPtr (type);
4635 var ff = spec as FixedFieldSpec;
4637 ec.Emit (OpCodes.Ldflda, spec);
4638 ec.Emit (OpCodes.Ldflda, ff.Element);
4641 ec.Emit (OpCodes.Volatile);
4643 ec.Emit (OpCodes.Ldfld, spec);
4649 ec.Emit (OpCodes.Dup);
4651 temp = new LocalTemporary (this.Type);
4657 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4659 prepared = prepare_for_load;
4661 EmitInstance (ec, prepared);
4665 ec.Emit (OpCodes.Dup);
4667 temp = new LocalTemporary (this.Type);
4672 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4673 ec.Emit (OpCodes.Volatile);
4675 spec.MemberDefinition.SetIsAssigned ();
4678 ec.Emit (OpCodes.Stsfld, spec);
4680 ec.Emit (OpCodes.Stfld, spec);
4689 public override void Emit (EmitContext ec)
4694 public override void EmitSideEffect (EmitContext ec)
4696 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4698 if (is_volatile) // || is_marshal_by_ref ())
4699 base.EmitSideEffect (ec);
4702 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
4705 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
4706 name, GetSignatureForError ());
4709 public void AddressOf (EmitContext ec, AddressOp mode)
4711 if ((mode & AddressOp.Store) != 0)
4712 spec.MemberDefinition.SetIsAssigned ();
4713 if ((mode & AddressOp.Load) != 0)
4714 spec.MemberDefinition.SetIsUsed ();
4717 // Handle initonly fields specially: make a copy and then
4718 // get the address of the copy.
4721 if (spec.IsReadOnly){
4723 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4736 local = ec.DeclareLocal (type, false);
4737 ec.Emit (OpCodes.Stloc, local);
4738 ec.Emit (OpCodes.Ldloca, local);
4744 ec.Emit (OpCodes.Ldsflda, spec);
4747 EmitInstance (ec, false);
4748 ec.Emit (OpCodes.Ldflda, spec);
4752 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4754 return MakeExpression (ctx);
4757 public override SLE.Expression MakeExpression (BuilderContext ctx)
4759 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4762 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4764 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4770 /// Expression that evaluates to a Property. The Assign class
4771 /// might set the `Value' expression if we are in an assignment.
4773 /// This is not an LValue because we need to re-write the expression, we
4774 /// can not take data from the stack and store it.
4776 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4778 public PropertyExpr (PropertySpec spec, Location l)
4781 best_candidate = spec;
4782 type = spec.MemberType;
4787 protected override TypeSpec DeclaringType {
4789 return best_candidate.DeclaringType;
4793 public override string Name {
4795 return best_candidate.Name;
4799 public override bool IsInstance {
4805 public override bool IsStatic {
4807 return best_candidate.IsStatic;
4811 public PropertySpec PropertyInfo {
4813 return best_candidate;
4819 public override Expression CreateExpressionTree (ResolveContext ec)
4822 if (IsSingleDimensionalArrayLength ()) {
4823 args = new Arguments (1);
4824 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4825 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4828 args = new Arguments (2);
4829 if (InstanceExpression == null)
4830 args.Add (new Argument (new NullLiteral (loc)));
4832 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4833 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4834 return CreateExpressionFactoryCall (ec, "Property", args);
4837 public Expression CreateSetterTypeOfExpression ()
4839 return new TypeOfMethod (Setter, loc);
4842 public override string GetSignatureForError ()
4844 return best_candidate.GetSignatureForError ();
4847 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4849 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4852 public override SLE.Expression MakeExpression (BuilderContext ctx)
4854 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4857 void Error_PropertyNotValid (ResolveContext ec)
4859 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4860 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4861 GetSignatureForError ());
4864 bool IsSingleDimensionalArrayLength ()
4866 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4869 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4870 return ac != null && ac.Rank == 1;
4873 public override void Emit (EmitContext ec, bool leave_copy)
4876 // Special case: length of single dimension array property is turned into ldlen
4878 if (IsSingleDimensionalArrayLength ()) {
4880 EmitInstance (ec, false);
4881 ec.Emit (OpCodes.Ldlen);
4882 ec.Emit (OpCodes.Conv_I4);
4886 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
4889 ec.Emit (OpCodes.Dup);
4891 temp = new LocalTemporary (this.Type);
4897 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4899 Expression my_source = source;
4901 if (prepare_for_load) {
4906 ec.Emit (OpCodes.Dup);
4908 temp = new LocalTemporary (this.Type);
4912 } else if (leave_copy) {
4914 temp = new LocalTemporary (this.Type);
4919 Arguments args = new Arguments (1);
4920 args.Add (new Argument (my_source));
4922 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
4930 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
4932 eclass = ExprClass.PropertyAccess;
4934 if (best_candidate.IsNotRealProperty) {
4935 Error_PropertyNotValid (rc);
4938 if (ResolveInstanceExpression (rc)) {
4939 if (right_side != null && best_candidate.DeclaringType.IsStruct)
4940 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
4943 DoBestMemberChecks (rc, best_candidate);
4947 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4949 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
4953 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
4955 // getter and setter can be different for base calls
4956 MethodSpec getter, setter;
4957 protected T best_candidate;
4959 protected LocalTemporary temp;
4960 protected bool prepared;
4962 protected PropertyOrIndexerExpr (Location l)
4969 public MethodSpec Getter {
4978 public MethodSpec Setter {
4989 protected override Expression DoResolve (ResolveContext ec)
4991 if (eclass == ExprClass.Unresolved) {
4992 var expr = OverloadResolve (ec, null);
4996 if (InstanceExpression != null)
4997 InstanceExpression.CheckMarshalByRefAccess (ec);
5000 return expr.Resolve (ec);
5003 if (!ResolveGetter (ec))
5009 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5011 if (right_side == EmptyExpression.OutAccess.Instance) {
5012 // TODO: best_candidate can be null at this point
5013 if (best_candidate != null && ec.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5014 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5015 best_candidate.Name);
5017 right_side.DoResolveLValue (ec, this);
5022 // if the property/indexer returns a value type, and we try to set a field in it
5023 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5024 Error_CannotModifyIntermediateExpressionValue (ec);
5027 if (eclass == ExprClass.Unresolved) {
5028 var expr = OverloadResolve (ec, right_side);
5033 return expr.ResolveLValue (ec, right_side);
5036 if (!ResolveSetter (ec))
5043 // Implements the IAssignMethod interface for assignments
5045 public abstract void Emit (EmitContext ec, bool leave_copy);
5046 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5048 public override void Emit (EmitContext ec)
5053 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5055 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5057 bool ResolveGetter (ResolveContext rc)
5059 if (!best_candidate.HasGet) {
5060 if (InstanceExpression != EmptyExpression.Null) {
5061 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5062 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5063 best_candidate.GetSignatureForError ());
5066 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5067 if (best_candidate.HasDifferentAccessibility) {
5068 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5069 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5070 TypeManager.CSharpSignature (best_candidate));
5072 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5073 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5077 if (best_candidate.HasDifferentAccessibility) {
5078 CheckProtectedMemberAccess (rc, best_candidate.Get);
5081 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5085 bool ResolveSetter (ResolveContext rc)
5087 if (!best_candidate.HasSet) {
5088 if (rc.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5089 rc.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5090 best_candidate.Name);
5092 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5093 GetSignatureForError ());
5098 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5099 if (best_candidate.HasDifferentAccessibility) {
5100 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5101 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5102 GetSignatureForError ());
5104 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5105 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5109 if (best_candidate.HasDifferentAccessibility)
5110 CheckProtectedMemberAccess (rc, best_candidate.Set);
5112 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5118 /// Fully resolved expression that evaluates to an Event
5120 public class EventExpr : MemberExpr, IAssignMethod
5122 readonly EventSpec spec;
5125 public EventExpr (EventSpec spec, Location loc)
5133 protected override TypeSpec DeclaringType {
5135 return spec.DeclaringType;
5139 public override string Name {
5145 public override bool IsInstance {
5147 return !spec.IsStatic;
5151 public override bool IsStatic {
5153 return spec.IsStatic;
5157 public MethodSpec Operator {
5165 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5168 // If the event is local to this class, we transform ourselves into a FieldExpr
5171 if (spec.DeclaringType == ec.CurrentType ||
5172 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5174 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5175 // EventField mi = spec.MemberDefinition as EventField;
5177 if (spec.BackingField != null) {
5178 spec.MemberDefinition.SetIsUsed ();
5180 if (!ec.IsObsolete) {
5181 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5183 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5186 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5187 Error_AssignmentEventOnly (ec);
5189 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5191 InstanceExpression = null;
5193 return ml.ResolveMemberAccess (ec, left, original);
5197 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5198 Error_AssignmentEventOnly (ec);
5200 return base.ResolveMemberAccess (ec, left, original);
5203 public override Expression CreateExpressionTree (ResolveContext ec)
5205 throw new NotSupportedException ("ET");
5208 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5210 if (right_side == EmptyExpression.EventAddition) {
5211 op = spec.AccessorAdd;
5212 } else if (right_side == EmptyExpression.EventSubtraction) {
5213 op = spec.AccessorRemove;
5217 Error_AssignmentEventOnly (ec);
5221 op = CandidateToBaseOverride (ec, op);
5225 protected override Expression DoResolve (ResolveContext ec)
5227 eclass = ExprClass.EventAccess;
5228 type = spec.MemberType;
5230 ResolveInstanceExpression (ec);
5232 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5233 Error_CannotAssign (ec);
5236 DoBestMemberChecks (ec, spec);
5240 public override void Emit (EmitContext ec)
5242 throw new NotSupportedException ();
5243 //Error_CannotAssign ();
5246 #region IAssignMethod Members
5248 public void Emit (EmitContext ec, bool leave_copy)
5250 throw new NotImplementedException ();
5253 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5255 if (leave_copy || !prepare_for_load)
5256 throw new NotImplementedException ("EventExpr::EmitAssign");
5258 Arguments args = new Arguments (1);
5259 args.Add (new Argument (source));
5260 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5265 void Error_AssignmentEventOnly (ResolveContext ec)
5267 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5268 GetSignatureForError ());
5271 public void Error_CannotAssign (ResolveContext ec)
5273 ec.Report.Error (70, loc,
5274 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5275 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5278 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5280 name = name.Substring (0, name.LastIndexOf ('.'));
5281 base.Error_CannotCallAbstractBase (rc, name);
5284 public override string GetSignatureForError ()
5286 return TypeManager.CSharpSignature (spec);
5289 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5291 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5295 public class TemporaryVariable : VariableReference
5299 public TemporaryVariable (TypeSpec type, Location loc)
5305 public override Expression CreateExpressionTree (ResolveContext ec)
5307 throw new NotSupportedException ("ET");
5310 protected override Expression DoResolve (ResolveContext ec)
5312 eclass = ExprClass.Variable;
5314 TypeExpr te = new TypeExpression (type, loc);
5315 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5316 if (!li.Resolve (ec))
5320 // Don't capture temporary variables except when using
5321 // iterator redirection
5323 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5324 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5325 storey.CaptureLocalVariable (ec, li);
5331 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5333 return Resolve (ec);
5336 public override void Emit (EmitContext ec)
5341 public void EmitAssign (EmitContext ec, Expression source)
5343 EmitAssign (ec, source, false, false);
5346 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5348 return li.HoistedVariant;
5351 public override bool IsFixed {
5352 get { return true; }
5355 public override bool IsRef {
5356 get { return false; }
5359 public override string Name {
5360 get { throw new NotImplementedException (); }
5363 public override void SetHasAddressTaken ()
5365 throw new NotImplementedException ();
5368 protected override ILocalVariable Variable {
5372 public override VariableInfo VariableInfo {
5373 get { throw new NotImplementedException (); }
5378 /// Handles `var' contextual keyword; var becomes a keyword only
5379 /// if no type called var exists in a variable scope
5381 class VarExpr : SimpleName
5383 // Used for error reporting only
5384 int initializers_count;
5386 public VarExpr (Location loc)
5389 initializers_count = 1;
5392 public int VariableInitializersCount {
5394 this.initializers_count = value;
5398 public bool InferType (ResolveContext ec, Expression right_side)
5401 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5403 type = right_side.Type;
5404 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5405 ec.Report.Error (815, loc,
5406 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5407 type.GetSignatureForError ());
5411 eclass = ExprClass.Variable;
5415 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5417 if (RootContext.Version < LanguageVersion.V_3)
5418 base.Error_TypeOrNamespaceNotFound (ec);
5420 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5423 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
5425 TypeExpr te = base.ResolveAsContextualType (rc, true);
5429 if (RootContext.Version < LanguageVersion.V_3)
5430 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5432 if (initializers_count == 1)
5435 if (initializers_count > 1) {
5436 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5437 initializers_count = 1;
5441 if (initializers_count == 0) {
5442 initializers_count = 1;
5443 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");