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 public virtual string GetSignatureForError ()
134 return type.GetDefinition ().GetSignatureForError ();
137 public virtual bool IsNull {
144 /// Performs semantic analysis on the Expression
148 /// The Resolve method is invoked to perform the semantic analysis
151 /// The return value is an expression (it can be the
152 /// same expression in some cases) or a new
153 /// expression that better represents this node.
155 /// For example, optimizations of Unary (LiteralInt)
156 /// would return a new LiteralInt with a negated
159 /// If there is an error during semantic analysis,
160 /// then an error should be reported (using Report)
161 /// and a null value should be returned.
163 /// There are two side effects expected from calling
164 /// Resolve(): the the field variable "eclass" should
165 /// be set to any value of the enumeration
166 /// `ExprClass' and the type variable should be set
167 /// to a valid type (this is the type of the
170 protected abstract Expression DoResolve (ResolveContext rc);
172 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
178 // This is used if the expression should be resolved as a type or namespace name.
179 // the default implementation fails.
181 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
184 ResolveContext ec = new ResolveContext (rc);
185 Expression e = Resolve (ec);
187 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
194 // This is used to resolve the expression as a type, a null
195 // value will be returned if the expression is not a type
198 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
200 int errors = ec.Compiler.Report.Errors;
202 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
207 TypeExpr te = fne as TypeExpr;
209 if (!silent && errors == ec.Compiler.Report.Errors)
210 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
214 if (!te.CheckAccessLevel (ec)) {
215 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
216 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
222 // Obsolete checks cannot be done when resolving base context as they
223 // require type dependecies to be set but we are just resolving them
225 if (!silent && !(ec is TypeContainer.BaseContext)) {
226 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
227 if (obsolete_attr != null && !ec.IsObsolete) {
228 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
235 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
237 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
240 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
242 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
245 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
247 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
248 name, TypeManager.CSharpName (type));
251 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
253 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
254 "expressions can be used as a statement");
257 public void Error_InvalidExpressionStatement (BlockContext ec)
259 Error_InvalidExpressionStatement (ec.Report, loc);
262 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
264 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
267 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
269 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
272 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
274 // The error was already reported as CS1660
275 if (type == InternalType.AnonymousMethod)
279 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
280 string sig1 = type.DeclaringMethod == null ?
281 TypeManager.CSharpName (type.DeclaringType) :
282 TypeManager.CSharpSignature (type.DeclaringMethod);
283 string sig2 = target.DeclaringMethod == null ?
284 TypeManager.CSharpName (target.DeclaringType) :
285 TypeManager.CSharpSignature (target.DeclaringMethod);
286 ec.Report.ExtraInformation (loc,
288 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
289 Type.Name, sig1, sig2));
290 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
291 ec.Report.ExtraInformation (loc,
293 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
294 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
298 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
299 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
303 ec.Report.DisableReporting ();
304 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
305 ec.Report.EnableReporting ();
308 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
309 "An explicit conversion exists (are you missing a cast?)",
310 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
314 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
315 type.GetSignatureForError (), target.GetSignatureForError ());
318 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 report.SymbolRelatedToPreviousError (member);
323 if (member is TypeSpec)
324 member = ((TypeSpec) member).GetDefinition ();
326 member = ((MethodSpec) member).GetGenericMethodDefinition ();
328 string name = member.Kind == MemberKind.Method ? "method" : "type";
329 if (member.IsGeneric) {
330 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
331 name, member.GetSignatureForError (), member.Arity.ToString ());
333 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
334 name, member.GetSignatureForError ());
337 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
341 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
343 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
347 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
349 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
352 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
354 ec.Report.SymbolRelatedToPreviousError (type);
355 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
356 TypeManager.CSharpName (type), name);
359 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
361 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
364 protected void Error_VoidPointerOperation (ResolveContext rc)
366 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
369 public ResolveFlags ExprClassToResolveFlags {
373 case ExprClass.Namespace:
374 return ResolveFlags.Type;
376 case ExprClass.MethodGroup:
377 return ResolveFlags.MethodGroup;
379 case ExprClass.TypeParameter:
380 return ResolveFlags.TypeParameter;
382 case ExprClass.Value:
383 case ExprClass.Variable:
384 case ExprClass.PropertyAccess:
385 case ExprClass.EventAccess:
386 case ExprClass.IndexerAccess:
387 return ResolveFlags.VariableOrValue;
390 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
396 /// Resolves an expression and performs semantic analysis on it.
400 /// Currently Resolve wraps DoResolve to perform sanity
401 /// checking and assertion checking on what we expect from Resolve.
403 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
405 if (eclass != ExprClass.Unresolved)
415 if ((flags & e.ExprClassToResolveFlags) == 0) {
416 e.Error_UnexpectedKind (ec, flags, loc);
421 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
424 } catch (Exception ex) {
425 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
428 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
429 return EmptyExpression.Null; // TODO: Add location
434 /// Resolves an expression and performs semantic analysis on it.
436 public Expression Resolve (ResolveContext rc)
438 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
442 /// Resolves an expression for LValue assignment
446 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
447 /// checking and assertion checking on what we expect from Resolve
449 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
451 int errors = ec.Report.Errors;
452 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
454 Expression e = DoResolveLValue (ec, right_side);
456 if (e != null && out_access && !(e is IMemoryLocation)) {
457 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
458 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
460 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
461 // e.GetType () + " " + e.GetSignatureForError ());
466 if (errors == ec.Report.Errors) {
468 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
470 Error_ValueAssignment (ec, loc);
475 if (e.eclass == ExprClass.Unresolved)
476 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
478 if ((e.type == null) && !(e is GenericTypeExpr))
479 throw new Exception ("Expression " + e + " did not set its type after Resolve");
484 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
486 rc.Compiler.Report.Error (182, loc,
487 "An attribute argument must be a constant expression, typeof expression or array creation expression");
491 /// Emits the code for the expression
495 /// The Emit method is invoked to generate the code
496 /// for the expression.
498 public abstract void Emit (EmitContext ec);
501 // Emit code to branch to @target if this expression is equivalent to @on_true.
502 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
503 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
504 // including the use of conditional branches. Note also that a branch MUST be emitted
505 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
508 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
511 // Emit this expression for its side effects, not for its value.
512 // The default implementation is to emit the value, and then throw it away.
513 // Subclasses can provide more efficient implementations, but those MUST be equivalent
514 public virtual void EmitSideEffect (EmitContext ec)
517 ec.Emit (OpCodes.Pop);
521 /// Protected constructor. Only derivate types should
522 /// be able to be created
525 protected Expression ()
530 /// Returns a fully formed expression after a MemberLookup
533 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
535 if (spec is EventSpec)
536 return new EventExpr ((EventSpec) spec, loc);
537 if (spec is ConstSpec)
538 return new ConstantExpr ((ConstSpec) spec, loc);
539 if (spec is FieldSpec)
540 return new FieldExpr ((FieldSpec) spec, loc);
541 if (spec is PropertySpec)
542 return new PropertyExpr ((PropertySpec) spec, loc);
543 if (spec is TypeSpec)
544 return new TypeExpression (((TypeSpec) spec), loc);
549 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
551 var ctors = MemberCache.FindMembers (type, ConstructorInfo.ConstructorName, true);
553 rc.Report.SymbolRelatedToPreviousError (type);
555 // Report meaningful error for struct as they always have default ctor in C# context
556 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
558 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
559 type.GetSignatureForError ());
565 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
566 return r.ResolveMember<MethodSpec> (rc, ref args);
570 public enum MemberLookupRestrictions
579 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
580 // `qualifier_type' or null to lookup members in the current class.
582 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
584 var members = MemberCache.FindMembers (queried_type, name, false);
588 MemberSpec non_method = null;
589 MemberSpec ambig_non_method = null;
590 currentType = currentType ?? InternalType.FakeInternalType;
592 for (int i = 0; i < members.Count; ++i) {
593 var member = members[i];
595 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
596 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
599 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
603 if (!member.IsAccessible (currentType))
607 // With runtime binder we can have a situation where queried type is inaccessible
608 // because it came via dynamic object, the check about inconsisted accessibility
609 // had no effect as the type was unknown during compilation
612 // private class N { }
614 // public dynamic Foo ()
620 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (currentType))
624 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
625 if (member is MethodSpec)
626 return new MethodGroupExpr (members, queried_type, loc);
628 if (!Invocation.IsMemberInvocable (member))
632 if (non_method == null || member is MethodSpec) {
634 } else if (currentType != null) {
635 ambig_non_method = member;
639 if (non_method != null) {
640 if (ambig_non_method != null && rc != null) {
641 rc.Report.SymbolRelatedToPreviousError (non_method);
642 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
643 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
644 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
647 if (non_method is MethodSpec)
648 return new MethodGroupExpr (members, queried_type, loc);
650 return ExprClassFromMemberInfo (non_method, loc);
653 if (members[0].DeclaringType.BaseType == null)
656 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
658 } while (members != null);
663 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
665 throw new NotImplementedException ();
668 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
670 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
674 /// Returns an expression that can be used to invoke operator true
675 /// on the expression if it exists.
677 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
679 return GetOperatorTrueOrFalse (ec, e, true, loc);
683 /// Returns an expression that can be used to invoke operator false
684 /// on the expression if it exists.
686 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
688 return GetOperatorTrueOrFalse (ec, e, false, loc);
691 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
693 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
694 var methods = MemberCache.GetUserOperator (e.type, op, false);
698 Arguments arguments = new Arguments (1);
699 arguments.Add (new Argument (e));
701 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
702 var oper = res.ResolveOperator (ec, ref arguments);
707 return new UserOperatorCall (oper, arguments, null, loc);
710 public virtual string ExprClassName
714 case ExprClass.Unresolved:
716 case ExprClass.Value:
718 case ExprClass.Variable:
720 case ExprClass.Namespace:
724 case ExprClass.MethodGroup:
725 return "method group";
726 case ExprClass.PropertyAccess:
727 return "property access";
728 case ExprClass.EventAccess:
729 return "event access";
730 case ExprClass.IndexerAccess:
731 return "indexer access";
732 case ExprClass.Nothing:
734 case ExprClass.TypeParameter:
735 return "type parameter";
737 throw new Exception ("Should not happen");
742 /// Reports that we were expecting `expr' to be of class `expected'
744 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
746 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
749 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
753 name = mc.GetSignatureForError ();
755 name = GetSignatureForError ();
757 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
758 name, was, expected);
761 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
763 string [] valid = new string [4];
766 if ((flags & ResolveFlags.VariableOrValue) != 0) {
767 valid [count++] = "variable";
768 valid [count++] = "value";
771 if ((flags & ResolveFlags.Type) != 0)
772 valid [count++] = "type";
774 if ((flags & ResolveFlags.MethodGroup) != 0)
775 valid [count++] = "method group";
778 valid [count++] = "unknown";
780 StringBuilder sb = new StringBuilder (valid [0]);
781 for (int i = 1; i < count - 1; i++) {
783 sb.Append (valid [i]);
786 sb.Append ("' or `");
787 sb.Append (valid [count - 1]);
790 ec.Report.Error (119, loc,
791 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
794 public static void UnsafeError (ResolveContext ec, Location loc)
796 UnsafeError (ec.Report, loc);
799 public static void UnsafeError (Report Report, Location loc)
801 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
806 // Returns the size of type `t' if known, otherwise, 0
808 public static int GetTypeSize (TypeSpec t)
810 if (t == TypeManager.int32_type ||
811 t == TypeManager.uint32_type ||
812 t == TypeManager.float_type)
814 else if (t == TypeManager.int64_type ||
815 t == TypeManager.uint64_type ||
816 t == TypeManager.double_type)
818 else if (t == TypeManager.byte_type ||
819 t == TypeManager.sbyte_type ||
820 t == TypeManager.bool_type)
822 else if (t == TypeManager.short_type ||
823 t == TypeManager.char_type ||
824 t == TypeManager.ushort_type)
826 else if (t == TypeManager.decimal_type)
832 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
834 ec.Report.SymbolRelatedToPreviousError (type);
835 if (ec.CurrentInitializerVariable != null) {
836 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
837 TypeManager.CSharpName (type), GetSignatureForError ());
839 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
840 GetSignatureForError ());
845 // Converts `source' to an int, uint, long or ulong.
847 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
849 if (source.type == InternalType.Dynamic) {
850 Arguments args = new Arguments (1);
851 args.Add (new Argument (source));
852 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
855 Expression converted;
857 using (ec.Set (ResolveContext.Options.CheckedScope)) {
858 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
859 if (converted == null)
860 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
861 if (converted == null)
862 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
863 if (converted == null)
864 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
866 if (converted == null) {
867 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
873 // Only positive constants are allowed at compile time
875 Constant c = converted as Constant;
876 if (c != null && c.IsNegative)
877 Error_NegativeArrayIndex (ec, source.loc);
879 // No conversion needed to array index
880 if (converted.Type == TypeManager.int32_type)
883 return new ArrayIndexCast (converted).Resolve (ec);
887 // Derived classes implement this method by cloning the fields that
888 // could become altered during the Resolve stage
890 // Only expressions that are created for the parser need to implement
893 protected virtual void CloneTo (CloneContext clonectx, Expression target)
895 throw new NotImplementedException (
897 "CloneTo not implemented for expression {0}", this.GetType ()));
901 // Clones an expression created by the parser.
903 // We only support expressions created by the parser so far, not
904 // expressions that have been resolved (many more classes would need
905 // to implement CloneTo).
907 // This infrastructure is here merely for Lambda expressions which
908 // compile the same code using different type values for the same
909 // arguments to find the correct overload
911 public virtual Expression Clone (CloneContext clonectx)
913 Expression cloned = (Expression) MemberwiseClone ();
914 CloneTo (clonectx, cloned);
920 // Implementation of expression to expression tree conversion
922 public abstract Expression CreateExpressionTree (ResolveContext ec);
924 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
926 return CreateExpressionFactoryCall (ec, name, null, args, loc);
929 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
931 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
934 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
936 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
939 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
941 TypeExpr texpr = TypeManager.expression_type_expr;
943 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
947 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
954 // Implemented by all expressions which support conversion from
955 // compiler expression to invokable runtime expression. Used by
956 // dynamic C# binder.
958 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
960 throw new NotImplementedException ("MakeExpression for " + GetType ());
965 /// This is just a base class for expressions that can
966 /// appear on statements (invocations, object creation,
967 /// assignments, post/pre increment and decrement). The idea
968 /// being that they would support an extra Emition interface that
969 /// does not leave a result on the stack.
971 public abstract class ExpressionStatement : Expression {
973 public ExpressionStatement ResolveStatement (BlockContext ec)
975 Expression e = Resolve (ec);
979 ExpressionStatement es = e as ExpressionStatement;
981 Error_InvalidExpressionStatement (ec);
987 /// Requests the expression to be emitted in a `statement'
988 /// context. This means that no new value is left on the
989 /// stack after invoking this method (constrasted with
990 /// Emit that will always leave a value on the stack).
992 public abstract void EmitStatement (EmitContext ec);
994 public override void EmitSideEffect (EmitContext ec)
1001 /// This kind of cast is used to encapsulate the child
1002 /// whose type is child.Type into an expression that is
1003 /// reported to return "return_type". This is used to encapsulate
1004 /// expressions which have compatible types, but need to be dealt
1005 /// at higher levels with.
1007 /// For example, a "byte" expression could be encapsulated in one
1008 /// of these as an "unsigned int". The type for the expression
1009 /// would be "unsigned int".
1012 public abstract class TypeCast : Expression
1014 protected readonly Expression child;
1016 protected TypeCast (Expression child, TypeSpec return_type)
1018 eclass = child.eclass;
1019 loc = child.Location;
1024 public Expression Child {
1030 public override Expression CreateExpressionTree (ResolveContext ec)
1032 Arguments args = new Arguments (2);
1033 args.Add (new Argument (child.CreateExpressionTree (ec)));
1034 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1036 if (type.IsPointer || child.Type.IsPointer)
1037 Error_PointerInsideExpressionTree (ec);
1039 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1042 protected override Expression DoResolve (ResolveContext ec)
1044 // This should never be invoked, we are born in fully
1045 // initialized state.
1050 public override void Emit (EmitContext ec)
1055 public override SLE.Expression MakeExpression (BuilderContext ctx)
1057 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1058 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1059 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1062 protected override void CloneTo (CloneContext clonectx, Expression t)
1067 public override bool IsNull {
1068 get { return child.IsNull; }
1072 public class EmptyCast : TypeCast {
1073 EmptyCast (Expression child, TypeSpec target_type)
1074 : base (child, target_type)
1078 public static Expression Create (Expression child, TypeSpec type)
1080 Constant c = child as Constant;
1082 return new EmptyConstantCast (c, type);
1084 EmptyCast e = child as EmptyCast;
1086 return new EmptyCast (e.child, type);
1088 return new EmptyCast (child, type);
1091 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1093 child.EmitBranchable (ec, label, on_true);
1096 public override void EmitSideEffect (EmitContext ec)
1098 child.EmitSideEffect (ec);
1103 // Used for predefined class library user casts (no obsolete check, etc.)
1105 public class OperatorCast : TypeCast {
1106 MethodSpec conversion_operator;
1108 public OperatorCast (Expression child, TypeSpec target_type)
1109 : this (child, target_type, false)
1113 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1114 : base (child, target_type)
1116 conversion_operator = GetConversionOperator (find_explicit);
1117 if (conversion_operator == null)
1118 throw new InternalErrorException ("Outer conversion routine is out of sync");
1121 // Returns the implicit operator that converts from
1122 // 'child.Type' to our target type (type)
1123 MethodSpec GetConversionOperator (bool find_explicit)
1125 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1127 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1129 mi = MemberCache.GetUserOperator (type, op, true);
1132 foreach (MethodSpec oper in mi) {
1133 if (oper.ReturnType != type)
1136 if (oper.Parameters.Types [0] == child.Type)
1143 public override void Emit (EmitContext ec)
1146 ec.Emit (OpCodes.Call, conversion_operator);
1151 /// This is a numeric cast to a Decimal
1153 public class CastToDecimal : OperatorCast {
1154 public CastToDecimal (Expression child)
1155 : this (child, false)
1159 public CastToDecimal (Expression child, bool find_explicit)
1160 : base (child, TypeManager.decimal_type, find_explicit)
1166 /// This is an explicit numeric cast from a Decimal
1168 public class CastFromDecimal : TypeCast
1170 static Dictionary<TypeSpec, MethodSpec> operators;
1172 public CastFromDecimal (Expression child, TypeSpec return_type)
1173 : base (child, return_type)
1175 if (child.Type != TypeManager.decimal_type)
1176 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1179 // Returns the explicit operator that converts from an
1180 // express of type System.Decimal to 'type'.
1181 public Expression Resolve ()
1183 if (operators == null) {
1184 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1186 operators = new Dictionary<TypeSpec, MethodSpec> ();
1187 foreach (MethodSpec oper in all_oper) {
1188 AParametersCollection pd = oper.Parameters;
1189 if (pd.Types [0] == TypeManager.decimal_type)
1190 operators.Add (oper.ReturnType, oper);
1194 return operators.ContainsKey (type) ? this : null;
1197 public override void Emit (EmitContext ec)
1201 ec.Emit (OpCodes.Call, operators [type]);
1204 public static void Reset ()
1212 // Constant specialization of EmptyCast.
1213 // We need to special case this since an empty cast of
1214 // a constant is still a constant.
1216 public class EmptyConstantCast : Constant
1218 public Constant child;
1220 public EmptyConstantCast (Constant child, TypeSpec type)
1221 : base (child.Location)
1224 throw new ArgumentNullException ("child");
1227 this.eclass = child.eclass;
1231 public override string AsString ()
1233 return child.AsString ();
1236 public override object GetValue ()
1238 return child.GetValue ();
1241 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1243 if (child.Type == target_type)
1246 // FIXME: check that 'type' can be converted to 'target_type' first
1247 return child.ConvertExplicitly (in_checked_context, target_type);
1250 public override Expression CreateExpressionTree (ResolveContext ec)
1252 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1253 child.CreateExpressionTree (ec),
1254 new TypeOf (new TypeExpression (type, loc), loc));
1257 Error_PointerInsideExpressionTree (ec);
1259 return CreateExpressionFactoryCall (ec, "Convert", args);
1262 public override bool IsDefaultValue {
1263 get { return child.IsDefaultValue; }
1266 public override bool IsNegative {
1267 get { return child.IsNegative; }
1270 public override bool IsNull {
1271 get { return child.IsNull; }
1274 public override bool IsOneInteger {
1275 get { return child.IsOneInteger; }
1278 public override bool IsZeroInteger {
1279 get { return child.IsZeroInteger; }
1282 protected override Expression DoResolve (ResolveContext rc)
1287 public override void Emit (EmitContext ec)
1292 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1294 child.EmitBranchable (ec, label, on_true);
1296 // Only to make verifier happy
1297 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1298 ec.Emit (OpCodes.Unbox_Any, type);
1301 public override void EmitSideEffect (EmitContext ec)
1303 child.EmitSideEffect (ec);
1306 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1308 // FIXME: Do we need to check user conversions?
1309 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1311 return child.ConvertImplicitly (rc, target_type);
1316 /// This class is used to wrap literals which belong inside Enums
1318 public class EnumConstant : Constant
1320 public Constant Child;
1322 public EnumConstant (Constant child, TypeSpec enum_type)
1323 : base (child.Location)
1326 this.type = enum_type;
1329 protected EnumConstant (Location loc)
1334 protected override Expression DoResolve (ResolveContext rc)
1336 Child = Child.Resolve (rc);
1337 this.eclass = ExprClass.Value;
1341 public override void Emit (EmitContext ec)
1346 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1348 Child.EncodeAttributeValue (rc, enc, Child.Type);
1351 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1353 Child.EmitBranchable (ec, label, on_true);
1356 public override void EmitSideEffect (EmitContext ec)
1358 Child.EmitSideEffect (ec);
1361 public override string GetSignatureForError()
1363 return TypeManager.CSharpName (Type);
1366 public override object GetValue ()
1368 return Child.GetValue ();
1371 public override object GetTypedValue ()
1373 // FIXME: runtime is not ready to work with just emited enums
1374 if (!RootContext.StdLib) {
1375 return Child.GetValue ();
1379 // Small workaround for big problem
1380 // System.Enum.ToObject cannot be called on dynamic types
1381 // EnumBuilder has to be used, but we cannot use EnumBuilder
1382 // because it does not properly support generics
1384 // This works only sometimes
1386 if (type.MemberDefinition is TypeContainer)
1387 return Child.GetValue ();
1390 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1393 public override string AsString ()
1395 return Child.AsString ();
1398 public EnumConstant Increment()
1400 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1403 public override bool IsDefaultValue {
1405 return Child.IsDefaultValue;
1409 public override bool IsZeroInteger {
1410 get { return Child.IsZeroInteger; }
1413 public override bool IsNegative {
1415 return Child.IsNegative;
1419 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1421 if (Child.Type == target_type)
1424 return Child.ConvertExplicitly (in_checked_context, target_type);
1427 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1429 if (this.type == type) {
1433 if (!Convert.ImplicitStandardConversionExists (this, type)){
1437 return Child.ConvertImplicitly (rc, type);
1442 /// This kind of cast is used to encapsulate Value Types in objects.
1444 /// The effect of it is to box the value type emitted by the previous
1447 public class BoxedCast : TypeCast {
1449 public BoxedCast (Expression expr, TypeSpec target_type)
1450 : base (expr, target_type)
1452 eclass = ExprClass.Value;
1455 protected override Expression DoResolve (ResolveContext ec)
1457 // This should never be invoked, we are born in fully
1458 // initialized state.
1463 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1465 enc.Encode (child.Type);
1466 child.EncodeAttributeValue (rc, enc, child.Type);
1469 public override void Emit (EmitContext ec)
1473 ec.Emit (OpCodes.Box, child.Type);
1476 public override void EmitSideEffect (EmitContext ec)
1478 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1479 // so, we need to emit the box+pop instructions in most cases
1480 if (TypeManager.IsStruct (child.Type) &&
1481 (type == TypeManager.object_type || type == TypeManager.value_type))
1482 child.EmitSideEffect (ec);
1484 base.EmitSideEffect (ec);
1488 public class UnboxCast : TypeCast {
1489 public UnboxCast (Expression expr, TypeSpec return_type)
1490 : base (expr, return_type)
1494 protected override Expression DoResolve (ResolveContext ec)
1496 // This should never be invoked, we are born in fully
1497 // initialized state.
1502 public override void Emit (EmitContext ec)
1506 ec.Emit (OpCodes.Unbox_Any, type);
1511 /// This is used to perform explicit numeric conversions.
1513 /// Explicit numeric conversions might trigger exceptions in a checked
1514 /// context, so they should generate the conv.ovf opcodes instead of
1517 public class ConvCast : TypeCast {
1518 public enum Mode : byte {
1519 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1521 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1522 U2_I1, U2_U1, U2_I2, U2_CH,
1523 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1524 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1525 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1526 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1527 CH_I1, CH_U1, CH_I2,
1528 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1529 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1535 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1536 : base (child, return_type)
1541 protected override Expression DoResolve (ResolveContext ec)
1543 // This should never be invoked, we are born in fully
1544 // initialized state.
1549 public override string ToString ()
1551 return String.Format ("ConvCast ({0}, {1})", mode, child);
1554 public override void Emit (EmitContext ec)
1558 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1560 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1561 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1562 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1563 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1564 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1566 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1567 case Mode.U1_CH: /* nothing */ break;
1569 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1570 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1571 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1572 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1573 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1574 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1576 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1577 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1578 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1579 case Mode.U2_CH: /* nothing */ break;
1581 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1582 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1583 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1584 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1585 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1586 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1587 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1589 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1590 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1591 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1592 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1593 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1594 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1596 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1597 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1598 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1599 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1600 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1601 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1602 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1603 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1604 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1606 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1607 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1608 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1609 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1610 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1611 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1612 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1613 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1614 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1616 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1617 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1618 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1620 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1621 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1622 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1623 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1624 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1625 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1626 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1627 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1628 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1631 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1632 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1633 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1634 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1635 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1636 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1637 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1638 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1639 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1641 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1645 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1646 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1647 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1648 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1649 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1651 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1652 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1655 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1656 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1657 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1658 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1659 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1661 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1662 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1663 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1664 case Mode.U2_CH: /* nothing */ break;
1666 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1667 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1668 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1669 case Mode.I4_U4: /* nothing */ break;
1670 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1672 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1674 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1675 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1676 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1677 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.U4_I4: /* nothing */ break;
1679 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1681 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1682 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1683 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1684 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1685 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1686 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1687 case Mode.I8_U8: /* nothing */ break;
1688 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1689 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1691 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1692 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1693 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1694 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1695 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1696 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1697 case Mode.U8_I8: /* nothing */ break;
1698 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1699 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1701 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1702 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1703 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1705 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1706 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1707 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1708 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1709 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1710 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1711 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1712 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1713 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1716 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1717 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1718 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1719 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1720 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1721 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1722 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1723 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1724 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1726 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1732 class OpcodeCast : TypeCast
1736 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1737 : base (child, return_type)
1742 protected override Expression DoResolve (ResolveContext ec)
1744 // This should never be invoked, we are born in fully
1745 // initialized state.
1750 public override void Emit (EmitContext ec)
1756 public TypeSpec UnderlyingType {
1757 get { return child.Type; }
1762 // Opcode casts expression with 2 opcodes but only
1763 // single expression tree node
1765 class OpcodeCastDuplex : OpcodeCast
1767 readonly OpCode second;
1769 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1770 : base (child, returnType, first)
1772 this.second = second;
1775 public override void Emit (EmitContext ec)
1783 /// This kind of cast is used to encapsulate a child and cast it
1784 /// to the class requested
1786 public sealed class ClassCast : TypeCast {
1787 readonly bool forced;
1789 public ClassCast (Expression child, TypeSpec return_type)
1790 : base (child, return_type)
1794 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1795 : base (child, return_type)
1797 this.forced = forced;
1800 public override void Emit (EmitContext ec)
1804 bool gen = TypeManager.IsGenericParameter (child.Type);
1806 ec.Emit (OpCodes.Box, child.Type);
1808 if (type.IsGenericParameter) {
1809 ec.Emit (OpCodes.Unbox_Any, type);
1816 ec.Emit (OpCodes.Castclass, type);
1821 // Created during resolving pahse when an expression is wrapped or constantified
1822 // and original expression can be used later (e.g. for expression trees)
1824 public class ReducedExpression : Expression
1826 sealed class ReducedConstantExpression : EmptyConstantCast
1828 readonly Expression orig_expr;
1830 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1831 : base (expr, expr.Type)
1833 this.orig_expr = orig_expr;
1836 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1838 Constant c = base.ConvertImplicitly (rc, target_type);
1840 c = new ReducedConstantExpression (c, orig_expr);
1845 public override Expression CreateExpressionTree (ResolveContext ec)
1847 return orig_expr.CreateExpressionTree (ec);
1850 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1852 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1854 c = new ReducedConstantExpression (c, orig_expr);
1859 sealed class ReducedExpressionStatement : ExpressionStatement
1861 readonly Expression orig_expr;
1862 readonly ExpressionStatement stm;
1864 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1866 this.orig_expr = orig;
1868 this.loc = orig.Location;
1871 public override Expression CreateExpressionTree (ResolveContext ec)
1873 return orig_expr.CreateExpressionTree (ec);
1876 protected override Expression DoResolve (ResolveContext ec)
1878 eclass = stm.eclass;
1883 public override void Emit (EmitContext ec)
1888 public override void EmitStatement (EmitContext ec)
1890 stm.EmitStatement (ec);
1894 readonly Expression expr, orig_expr;
1896 private ReducedExpression (Expression expr, Expression orig_expr)
1899 this.eclass = expr.eclass;
1900 this.type = expr.Type;
1901 this.orig_expr = orig_expr;
1902 this.loc = orig_expr.Location;
1907 public Expression OriginalExpression {
1916 // Creates fully resolved expression switcher
1918 public static Constant Create (Constant expr, Expression original_expr)
1920 if (expr.eclass == ExprClass.Unresolved)
1921 throw new ArgumentException ("Unresolved expression");
1923 return new ReducedConstantExpression (expr, original_expr);
1926 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1928 return new ReducedExpressionStatement (s, orig);
1932 // Creates unresolved reduce expression. The original expression has to be
1935 public static Expression Create (Expression expr, Expression original_expr)
1937 Constant c = expr as Constant;
1939 return Create (c, original_expr);
1941 ExpressionStatement s = expr as ExpressionStatement;
1943 return Create (s, original_expr);
1945 if (expr.eclass == ExprClass.Unresolved)
1946 throw new ArgumentException ("Unresolved expression");
1948 return new ReducedExpression (expr, original_expr);
1951 public override Expression CreateExpressionTree (ResolveContext ec)
1953 return orig_expr.CreateExpressionTree (ec);
1956 protected override Expression DoResolve (ResolveContext ec)
1961 public override void Emit (EmitContext ec)
1966 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1968 expr.EmitBranchable (ec, target, on_true);
1971 public override SLE.Expression MakeExpression (BuilderContext ctx)
1973 return orig_expr.MakeExpression (ctx);
1978 // Standard composite pattern
1980 public abstract class CompositeExpression : Expression
1984 protected CompositeExpression (Expression expr)
1987 this.loc = expr.Location;
1990 public override Expression CreateExpressionTree (ResolveContext ec)
1992 return expr.CreateExpressionTree (ec);
1995 public Expression Child {
1996 get { return expr; }
1999 protected override Expression DoResolve (ResolveContext ec)
2001 expr = expr.Resolve (ec);
2004 eclass = expr.eclass;
2010 public override void Emit (EmitContext ec)
2015 public override bool IsNull {
2016 get { return expr.IsNull; }
2021 // Base of expressions used only to narrow resolve flow
2023 public abstract class ShimExpression : Expression
2025 protected Expression expr;
2027 protected ShimExpression (Expression expr)
2032 protected override void CloneTo (CloneContext clonectx, Expression t)
2037 ShimExpression target = (ShimExpression) t;
2038 target.expr = expr.Clone (clonectx);
2041 public override Expression CreateExpressionTree (ResolveContext ec)
2043 throw new NotSupportedException ("ET");
2046 public override void Emit (EmitContext ec)
2048 throw new InternalErrorException ("Missing Resolve call");
2051 public Expression Expr {
2052 get { return expr; }
2057 // Unresolved type name expressions
2059 public abstract class ATypeNameExpression : FullNamedExpression
2062 protected TypeArguments targs;
2064 protected ATypeNameExpression (string name, Location l)
2070 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2077 protected ATypeNameExpression (string name, int arity, Location l)
2078 : this (name, new UnboundTypeArguments (arity), l)
2084 protected int Arity {
2086 return targs == null ? 0 : targs.Count;
2090 public bool HasTypeArguments {
2092 return targs != null && !targs.IsEmpty;
2096 public string Name {
2105 public TypeArguments TypeArguments {
2113 public override bool Equals (object obj)
2115 ATypeNameExpression atne = obj as ATypeNameExpression;
2116 return atne != null && atne.Name == Name &&
2117 (targs == null || targs.Equals (atne.targs));
2120 public override int GetHashCode ()
2122 return Name.GetHashCode ();
2125 // TODO: Move it to MemberCore
2126 public static string GetMemberType (MemberCore mc)
2132 if (mc is FieldBase)
2134 if (mc is MethodCore)
2136 if (mc is EnumMember)
2144 public override string GetSignatureForError ()
2146 if (targs != null) {
2147 return Name + "<" + targs.GetSignatureForError () + ">";
2153 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2157 /// SimpleName expressions are formed of a single word and only happen at the beginning
2158 /// of a dotted-name.
2160 public class SimpleName : ATypeNameExpression
2162 public SimpleName (string name, Location l)
2167 public SimpleName (string name, TypeArguments args, Location l)
2168 : base (name, args, l)
2172 public SimpleName (string name, int arity, Location l)
2173 : base (name, arity, l)
2177 public SimpleName GetMethodGroup ()
2179 return new SimpleName (Name, targs, loc);
2182 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2184 if (ec.CurrentType != null) {
2185 if (ec.CurrentMemberDefinition != null) {
2186 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2188 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2194 // TODO MemberCache: Implement
2196 string ns = ec.CurrentType.Namespace;
2197 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2198 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2199 var type = a.GetType (fullname);
2201 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2202 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2207 if (ec.CurrentTypeDefinition != null) {
2208 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2210 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2217 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2218 if (retval != null) {
2219 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2221 var te = retval as TypeExpr;
2222 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2223 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2225 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2230 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2233 protected override Expression DoResolve (ResolveContext ec)
2235 return SimpleNameResolve (ec, null, false);
2238 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2240 return SimpleNameResolve (ec, right_side, false);
2243 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2245 int errors = ec.Compiler.Report.Errors;
2246 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2249 if (fne.Type != null && Arity > 0) {
2250 if (HasTypeArguments) {
2251 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2252 return ct.ResolveAsTypeStep (ec, false);
2255 return new GenericOpenTypeExpr (fne.Type, loc);
2259 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2261 if (!(fne is Namespace))
2265 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2266 if (!ec.Compiler.PredefinedAttributes.Dynamic.IsDefined) {
2267 ec.Compiler.Report.Error (1980, Location,
2268 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2269 ec.Compiler.PredefinedAttributes.Dynamic.GetSignatureForError ());
2272 return new DynamicTypeExpr (loc);
2278 if (silent || errors != ec.Compiler.Report.Errors)
2281 Error_TypeOrNamespaceNotFound (ec);
2285 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2287 int lookup_arity = Arity;
2288 bool errorMode = false;
2290 Block current_block = rc.CurrentBlock;
2291 INamedBlockVariable variable = null;
2292 bool variable_found = false;
2296 // Stage 1: binding to local variables or parameters
2298 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2300 if (current_block != null && lookup_arity == 0) {
2301 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2302 if (!variable.IsDeclared) {
2303 // We found local name in accessible block but it's not
2304 // initialized yet, maybe the user wanted to bind to something else
2306 variable_found = true;
2308 e = variable.CreateReferenceExpression (rc, loc);
2311 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2320 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2322 TypeSpec member_type = rc.CurrentType;
2323 TypeSpec current_type = member_type;
2324 for (; member_type != null; member_type = member_type.DeclaringType) {
2325 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2329 var me = e as MemberExpr;
2331 // The name matches a type, defer to ResolveAsTypeStep
2339 if (variable != null) {
2340 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2341 rc.Report.Error (844, loc,
2342 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2343 Name, me.GetSignatureForError ());
2347 } else if (me is MethodGroupExpr) {
2348 // Leave it to overload resolution to report correct error
2350 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2351 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2354 // LAMESPEC: again, ignores InvocableOnly
2355 if (variable != null) {
2356 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2357 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2361 // MemberLookup does not check accessors availability, this is actually needed for properties only
2363 var pe = me as PropertyExpr;
2366 // Break as there is no other overload available anyway
2367 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2368 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2371 pe.Getter = pe.PropertyInfo.Get;
2373 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2376 pe.Setter = pe.PropertyInfo.Set;
2381 // TODO: It's used by EventExpr -> FieldExpr transformation only
2382 // TODO: Should go to MemberAccess
2383 me = me.ResolveMemberAccess (rc, null, null);
2387 me.SetTypeArguments (rc, targs);
2394 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2396 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2397 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2399 if (variable != null) {
2400 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2401 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2409 if (variable_found) {
2410 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2412 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2418 if (RootContext.EvalMode) {
2419 var fi = Evaluator.LookupField (Name);
2421 return new FieldExpr (fi.Item1, loc);
2425 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2430 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2432 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2437 if (right_side != null) {
2438 if (e is TypeExpr) {
2439 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2443 e = e.ResolveLValue (ec, right_side);
2448 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2454 /// Represents a namespace or a type. The name of the class was inspired by
2455 /// section 10.8.1 (Fully Qualified Names).
2457 public abstract class FullNamedExpression : Expression
2459 protected override void CloneTo (CloneContext clonectx, Expression target)
2461 // Do nothing, most unresolved type expressions cannot be
2462 // resolved to different type
2465 public override Expression CreateExpressionTree (ResolveContext ec)
2467 throw new NotSupportedException ("ET");
2470 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2475 public override void Emit (EmitContext ec)
2477 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2478 GetSignatureForError ());
2483 /// Expression that evaluates to a type
2485 public abstract class TypeExpr : FullNamedExpression {
2486 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2488 TypeExpr t = DoResolveAsTypeStep (ec);
2492 eclass = ExprClass.Type;
2496 protected override Expression DoResolve (ResolveContext ec)
2498 return ResolveAsTypeTerminal (ec, false);
2501 public virtual bool CheckAccessLevel (IMemberContext mc)
2503 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2505 c = mc.CurrentMemberDefinition.Parent;
2507 return c.CheckAccessLevel (Type);
2510 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2512 public override bool Equals (object obj)
2514 TypeExpr tobj = obj as TypeExpr;
2518 return Type == tobj.Type;
2521 public override int GetHashCode ()
2523 return Type.GetHashCode ();
2528 /// Fully resolved Expression that already evaluated to a type
2530 public class TypeExpression : TypeExpr {
2531 public TypeExpression (TypeSpec t, Location l)
2534 eclass = ExprClass.Type;
2538 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2543 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2550 /// This class denotes an expression which evaluates to a member
2551 /// of a struct or a class.
2553 public abstract class MemberExpr : Expression
2556 // An instance expression associated with this member, if it's a
2557 // non-static member
2559 public Expression InstanceExpression;
2562 /// The name of this member.
2564 public abstract string Name {
2569 // When base.member is used
2571 public bool IsBase {
2572 get { return InstanceExpression is BaseThis; }
2576 /// Whether this is an instance member.
2578 public abstract bool IsInstance {
2583 /// Whether this is a static member.
2585 public abstract bool IsStatic {
2590 protected abstract TypeSpec DeclaringType {
2595 // Converts best base candidate for virtual method starting from QueriedBaseType
2597 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2600 // Only when base.member is used and method is virtual
2606 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2607 // means for base.member access we have to find the closest match after we found best candidate
2609 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2611 // The method could already be what we are looking for
2613 TypeSpec[] targs = null;
2614 if (method.DeclaringType != InstanceExpression.Type) {
2615 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2616 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2617 if (base_override.IsGeneric)
2618 targs = method.TypeArguments;
2620 method = base_override;
2624 // TODO: For now we do it for any hoisted call even if it's needed for
2625 // hoisted stories only but that requires a new expression wrapper
2626 if (rc.CurrentAnonymousMethod != null) {
2627 if (targs == null && method.IsGeneric) {
2628 targs = method.TypeArguments;
2629 method = method.GetGenericMethodDefinition ();
2632 if (method.Parameters.HasArglist)
2633 throw new NotImplementedException ("__arglist base call proxy");
2635 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2637 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2638 // get/set member expressions second call would fail to proxy because left expression
2639 // would be of 'this' and not 'base'
2640 if (rc.CurrentType.IsStruct)
2641 InstanceExpression = new This (loc).Resolve (rc);
2645 method = method.MakeGenericMethod (targs);
2649 // Only base will allow this invocation to happen.
2651 if (method.IsAbstract) {
2652 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2658 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2660 if (InstanceExpression == null)
2663 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2664 var ct = rc.CurrentType;
2665 var expr_type = InstanceExpression.Type;
2666 if (ct != expr_type) {
2667 expr_type = expr_type.GetDefinition ();
2668 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2669 rc.Report.SymbolRelatedToPreviousError (member);
2670 rc.Report.Error (1540, loc,
2671 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2672 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2678 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2681 type = type.GetDefinition ();
2683 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2686 type = type.DeclaringType;
2687 } while (type != null);
2692 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2694 if (InstanceExpression != null) {
2695 InstanceExpression = InstanceExpression.Resolve (rc);
2696 CheckProtectedMemberAccess (rc, member);
2699 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2700 UnsafeError (rc, loc);
2703 if (!rc.IsObsolete) {
2704 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2706 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2709 if (!(member is FieldSpec))
2710 member.MemberDefinition.SetIsUsed ();
2713 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2715 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2719 // Implements identicial simple name and type-name
2721 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2724 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2727 // 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
2728 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2730 if (left is MemberExpr || left is VariableReference) {
2731 rc.Report.DisableReporting ();
2732 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2733 rc.Report.EnableReporting ();
2734 if (identical_type != null && identical_type.Type == left.Type)
2735 return identical_type;
2741 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2744 if (InstanceExpression != null) {
2745 if (InstanceExpression is TypeExpr) {
2746 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2747 if (oa != null && !rc.IsObsolete) {
2748 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2751 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2752 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2753 rc.Report.Error (176, loc,
2754 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2755 GetSignatureForError ());
2759 InstanceExpression = null;
2765 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2766 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2767 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2768 rc.Report.Error (236, loc,
2769 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2770 GetSignatureForError ());
2772 rc.Report.Error (120, loc,
2773 "An object reference is required to access non-static member `{0}'",
2774 GetSignatureForError ());
2779 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2780 rc.Report.Error (38, loc,
2781 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2782 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2785 InstanceExpression = new This (loc);
2786 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2787 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2788 InstanceExpression = InstanceExpression.Resolve (rc);
2791 InstanceExpression = InstanceExpression.Resolve (rc);
2797 var me = InstanceExpression as MemberExpr;
2799 me.ResolveInstanceExpression (rc, rhs);
2801 var fe = me as FieldExpr;
2802 if (fe != null && fe.IsMarshalByRefAccess ()) {
2803 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2804 rc.Report.Warning (1690, 1, loc,
2805 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2806 me.GetSignatureForError ());
2813 // Run member-access postponed check once we know that
2814 // the expression is not field expression which is the only
2815 // expression which can use uninitialized this
2817 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2818 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2822 // Additional checks for l-value member access
2826 // TODO: It should be recursive but that would break csc compatibility
2828 if (InstanceExpression is UnboxCast) {
2829 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2836 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2838 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2839 ec.Report.Warning (1720, 1, left.Location,
2840 "Expression will always cause a `{0}'", "System.NullReferenceException");
2843 InstanceExpression = left;
2847 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2849 TypeSpec instance_type = InstanceExpression.Type;
2850 if (TypeManager.IsValueType (instance_type)) {
2851 if (InstanceExpression is IMemoryLocation) {
2852 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2854 LocalTemporary t = new LocalTemporary (instance_type);
2855 InstanceExpression.Emit (ec);
2857 t.AddressOf (ec, AddressOp.Store);
2860 InstanceExpression.Emit (ec);
2862 // Only to make verifier happy
2863 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2864 ec.Emit (OpCodes.Box, instance_type);
2867 if (prepare_for_load)
2868 ec.Emit (OpCodes.Dup);
2871 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2875 // Represents a group of extension method candidates for whole namespace
2877 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2879 NamespaceEntry namespace_entry;
2880 public readonly Expression ExtensionExpression;
2882 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2883 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2885 this.namespace_entry = n;
2886 this.ExtensionExpression = extensionExpr;
2889 public override bool IsStatic {
2890 get { return true; }
2893 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2895 if (namespace_entry == null)
2899 // For extension methodgroup we are not looking for base members but parent
2900 // namespace extension methods
2902 int arity = type_arguments == null ? 0 : type_arguments.Count;
2903 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2907 return found.Cast<MemberSpec> ().ToList ();
2910 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2912 // We are already here
2916 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2918 if (arguments == null)
2919 arguments = new Arguments (1);
2921 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2922 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2924 // Store resolved argument and restore original arguments
2926 // Clean-up modified arguments for error reporting
2927 arguments.RemoveAt (0);
2931 var me = ExtensionExpression as MemberExpr;
2933 me.ResolveInstanceExpression (ec, null);
2935 InstanceExpression = null;
2939 #region IErrorHandler Members
2941 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2946 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2948 rc.Report.SymbolRelatedToPreviousError (best);
2949 rc.Report.Error (1928, loc,
2950 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2951 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2954 rc.Report.Error (1929, loc,
2955 "Extension method instance type `{0}' cannot be converted to `{1}'",
2956 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2962 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2967 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2976 /// MethodGroupExpr represents a group of method candidates which
2977 /// can be resolved to the best method overload
2979 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2981 protected IList<MemberSpec> Methods;
2982 MethodSpec best_candidate;
2983 TypeSpec best_candidate_return;
2984 protected TypeArguments type_arguments;
2986 SimpleName simple_name;
2987 protected TypeSpec queried_type;
2989 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2993 this.type = InternalType.MethodGroup;
2995 eclass = ExprClass.MethodGroup;
2996 queried_type = type;
2999 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3000 : this (new MemberSpec[] { m }, type, loc)
3006 public MethodSpec BestCandidate {
3008 return best_candidate;
3012 public TypeSpec BestCandidateReturnType {
3014 return best_candidate_return;
3018 protected override TypeSpec DeclaringType {
3020 return queried_type;
3024 public override bool IsInstance {
3026 if (best_candidate != null)
3027 return !best_candidate.IsStatic;
3033 public override bool IsStatic {
3035 if (best_candidate != null)
3036 return best_candidate.IsStatic;
3042 public override string Name {
3044 if (best_candidate != null)
3045 return best_candidate.Name;
3048 return Methods.First ().Name;
3055 // When best candidate is already know this factory can be used
3056 // to avoid expensive overload resolution to be called
3058 // NOTE: InstanceExpression has to be set manually
3060 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3062 return new MethodGroupExpr (best, queriedType, loc) {
3063 best_candidate = best,
3064 best_candidate_return = best.ReturnType
3068 public override string GetSignatureForError ()
3070 if (best_candidate != null)
3071 return best_candidate.GetSignatureForError ();
3073 return Methods.First ().GetSignatureForError ();
3076 public override Expression CreateExpressionTree (ResolveContext ec)
3078 if (best_candidate == null) {
3079 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3083 if (best_candidate.IsConditionallyExcluded (loc))
3084 ec.Report.Error (765, loc,
3085 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3087 return new TypeOfMethod (best_candidate, loc);
3090 protected override Expression DoResolve (ResolveContext ec)
3092 this.eclass = ExprClass.MethodGroup;
3094 if (InstanceExpression != null) {
3095 InstanceExpression = InstanceExpression.Resolve (ec);
3096 if (InstanceExpression == null)
3103 public override void Emit (EmitContext ec)
3105 throw new NotSupportedException ();
3108 public void EmitCall (EmitContext ec, Arguments arguments)
3110 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3113 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3115 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3116 Name, TypeManager.CSharpName (target));
3119 public static bool IsExtensionMethodArgument (Expression expr)
3122 // LAMESPEC: No details about which expressions are not allowed
3124 return !(expr is TypeExpr) && !(expr is BaseThis);
3128 /// Find the Applicable Function Members (7.4.2.1)
3130 /// me: Method Group expression with the members to select.
3131 /// it might contain constructors or methods (or anything
3132 /// that maps to a method).
3134 /// Arguments: ArrayList containing resolved Argument objects.
3136 /// loc: The location if we want an error to be reported, or a Null
3137 /// location for "probing" purposes.
3139 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3140 /// that is the best match of me on Arguments.
3143 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3145 // TODO: causes issues with probing mode, remove explicit Kind check
3146 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3149 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3150 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3151 r.BaseMembersProvider = this;
3154 if (cerrors != null)
3155 r.CustomErrors = cerrors;
3157 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3158 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3159 if (best_candidate == null)
3160 return r.BestCandidateIsDynamic ? this : null;
3162 // Overload resolver had to create a new method group, all checks bellow have already been executed
3163 if (r.BestCandidateNewMethodGroup != null)
3164 return r.BestCandidateNewMethodGroup;
3166 if (best_candidate.Kind == MemberKind.Method) {
3167 if (InstanceExpression != null) {
3168 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3169 InstanceExpression = null;
3171 if (best_candidate.IsStatic && simple_name != null) {
3172 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3175 InstanceExpression.Resolve (ec);
3179 ResolveInstanceExpression (ec, null);
3180 if (InstanceExpression != null)
3181 CheckProtectedMemberAccess (ec, best_candidate);
3184 var base_override = CandidateToBaseOverride (ec, best_candidate);
3185 if (base_override == best_candidate) {
3186 best_candidate_return = r.BestCandidateReturnType;
3188 best_candidate = base_override;
3189 best_candidate_return = best_candidate.ReturnType;
3195 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3197 simple_name = original;
3198 return base.ResolveMemberAccess (ec, left, original);
3201 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3203 type_arguments = ta;
3206 #region IBaseMembersProvider Members
3208 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3210 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3213 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3215 if (queried_type == member.DeclaringType)
3218 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3219 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3223 // Extension methods lookup after ordinary methods candidates failed to apply
3225 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3227 if (InstanceExpression == null)
3230 InstanceExpression = InstanceExpression.Resolve (rc);
3231 if (!IsExtensionMethodArgument (InstanceExpression))
3234 int arity = type_arguments == null ? 0 : type_arguments.Count;
3235 NamespaceEntry methods_scope = null;
3236 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3237 if (methods == null)
3240 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3241 emg.SetTypeArguments (rc, type_arguments);
3248 public struct OverloadResolver
3251 public enum Restrictions
3255 ProbingOnly = 1 << 1,
3256 CovariantDelegate = 1 << 2,
3257 NoBaseMembers = 1 << 3,
3258 BaseMembersIncluded = 1 << 4
3261 public interface IBaseMembersProvider
3263 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3264 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3265 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3268 public interface IErrorHandler
3270 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3271 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3272 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3273 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3276 sealed class NoBaseMembers : IBaseMembersProvider
3278 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3280 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3285 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3290 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3296 struct AmbiguousCandidate
3298 public readonly MemberSpec Member;
3299 public readonly bool Expanded;
3300 public readonly AParametersCollection Parameters;
3302 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3305 Parameters = parameters;
3306 Expanded = expanded;
3311 IList<MemberSpec> members;
3312 TypeArguments type_arguments;
3313 IBaseMembersProvider base_provider;
3314 IErrorHandler custom_errors;
3315 Restrictions restrictions;
3316 MethodGroupExpr best_candidate_extension_group;
3317 TypeSpec best_candidate_return_type;
3319 SessionReportPrinter lambda_conv_msgs;
3320 ReportPrinter prev_recorder;
3322 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3323 : this (members, null, restrictions, loc)
3327 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3330 if (members == null || members.Count == 0)
3331 throw new ArgumentException ("empty members set");
3333 this.members = members;
3335 type_arguments = targs;
3336 this.restrictions = restrictions;
3337 if (IsDelegateInvoke)
3338 this.restrictions |= Restrictions.NoBaseMembers;
3340 base_provider = NoBaseMembers.Instance;
3345 public IBaseMembersProvider BaseMembersProvider {
3347 return base_provider;
3350 base_provider = value;
3354 public bool BestCandidateIsDynamic { get; set; }
3357 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3359 public MethodGroupExpr BestCandidateNewMethodGroup {
3361 return best_candidate_extension_group;
3366 // Return type can be different between best candidate and closest override
3368 public TypeSpec BestCandidateReturnType {
3370 return best_candidate_return_type;
3374 public IErrorHandler CustomErrors {
3376 return custom_errors;
3379 custom_errors = value;
3383 TypeSpec DelegateType {
3385 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3386 throw new InternalErrorException ("Not running in delegate mode", loc);
3388 return members [0].DeclaringType;
3392 bool IsProbingOnly {
3394 return (restrictions & Restrictions.ProbingOnly) != 0;
3398 bool IsDelegateInvoke {
3400 return (restrictions & Restrictions.DelegateInvoke) != 0;
3407 // 7.4.3.3 Better conversion from expression
3408 // Returns : 1 if a->p is better,
3409 // 2 if a->q is better,
3410 // 0 if neither is better
3412 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3414 TypeSpec argument_type = a.Type;
3415 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3417 // Uwrap delegate from Expression<T>
3419 if (p.GetDefinition () == TypeManager.expression_type) {
3420 p = TypeManager.GetTypeArguments (p)[0];
3422 if (q.GetDefinition () == TypeManager.expression_type) {
3423 q = TypeManager.GetTypeArguments (q)[0];
3426 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3427 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3428 if (p == TypeManager.void_type && q != TypeManager.void_type)
3430 if (q == TypeManager.void_type && p != TypeManager.void_type)
3433 if (argument_type == p)
3436 if (argument_type == q)
3440 return BetterTypeConversion (ec, p, q);
3444 // 7.4.3.4 Better conversion from type
3446 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3448 if (p == null || q == null)
3449 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3451 if (p == TypeManager.int32_type) {
3452 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3454 } else if (p == TypeManager.int64_type) {
3455 if (q == TypeManager.uint64_type)
3457 } else if (p == TypeManager.sbyte_type) {
3458 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3459 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3461 } else if (p == TypeManager.short_type) {
3462 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3463 q == TypeManager.uint64_type)
3465 } else if (p == InternalType.Dynamic) {
3466 // Dynamic is never better
3470 if (q == TypeManager.int32_type) {
3471 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3473 } if (q == TypeManager.int64_type) {
3474 if (p == TypeManager.uint64_type)
3476 } else if (q == TypeManager.sbyte_type) {
3477 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3478 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3480 } if (q == TypeManager.short_type) {
3481 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3482 p == TypeManager.uint64_type)
3484 } else if (q == InternalType.Dynamic) {
3485 // Dynamic is never better
3489 // TODO: this is expensive
3490 Expression p_tmp = new EmptyExpression (p);
3491 Expression q_tmp = new EmptyExpression (q);
3493 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3494 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3496 if (p_to_q && !q_to_p)
3499 if (q_to_p && !p_to_q)
3506 /// Determines "Better function" between candidate
3507 /// and the current best match
3510 /// Returns a boolean indicating :
3511 /// false if candidate ain't better
3512 /// true if candidate is better than the current best match
3514 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3515 MemberSpec best, AParametersCollection bparam, bool best_params)
3517 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3518 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3520 bool better_at_least_one = false;
3522 int args_count = args == null ? 0 : args.Count;
3525 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3526 Argument a = args[j];
3528 // Default arguments are ignored for better decision
3529 if (a.IsDefaultArgument)
3533 // When comparing named argument the parameter type index has to be looked up
3534 // in original parameter set (override version for virtual members)
3536 NamedArgument na = a as NamedArgument;
3538 int idx = cparam.GetParameterIndexByName (na.Name);
3539 ct = candidate_pd.Types[idx];
3540 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3541 ct = TypeManager.GetElementType (ct);
3543 idx = bparam.GetParameterIndexByName (na.Name);
3544 bt = best_pd.Types[idx];
3545 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3546 bt = TypeManager.GetElementType (bt);
3548 ct = candidate_pd.Types[c_idx];
3549 bt = best_pd.Types[b_idx];
3551 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3552 ct = TypeManager.GetElementType (ct);
3556 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3557 bt = TypeManager.GetElementType (bt);
3562 if (TypeSpecComparer.IsEqual (ct, bt))
3566 int result = BetterExpressionConversion (ec, a, ct, bt);
3568 // for each argument, the conversion to 'ct' should be no worse than
3569 // the conversion to 'bt'.
3573 // for at least one argument, the conversion to 'ct' should be better than
3574 // the conversion to 'bt'.
3576 better_at_least_one = true;
3579 if (better_at_least_one)
3583 // This handles the case
3585 // Add (float f1, float f2, float f3);
3586 // Add (params decimal [] foo);
3588 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3589 // first candidate would've chosen as better.
3595 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3599 // This handles the following cases:
3601 // Foo (int i) is better than Foo (int i, long l = 0)
3602 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3604 // Prefer non-optional version
3606 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3608 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3609 if (candidate_pd.Count >= best_pd.Count)
3612 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3619 // One is a non-generic method and second is a generic method, then non-generic is better
3621 if (best.IsGeneric != candidate.IsGeneric)
3622 return best.IsGeneric;
3625 // This handles the following cases:
3627 // Trim () is better than Trim (params char[] chars)
3628 // Concat (string s1, string s2, string s3) is better than
3629 // Concat (string s1, params string [] srest)
3630 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3632 // Prefer non-expanded version
3634 if (candidate_params != best_params)
3637 int candidate_param_count = candidate_pd.Count;
3638 int best_param_count = best_pd.Count;
3640 if (candidate_param_count != best_param_count)
3641 // can only happen if (candidate_params && best_params)
3642 return candidate_param_count > best_param_count && best_pd.HasParams;
3645 // Both methods have the same number of parameters, and the parameters have equal types
3646 // Pick the "more specific" signature using rules over original (non-inflated) types
3648 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3649 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3651 bool specific_at_least_once = false;
3652 for (j = 0; j < candidate_param_count; ++j) {
3653 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3655 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3656 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3658 ct = candidate_def_pd.Types[j];
3659 bt = best_def_pd.Types[j];
3664 TypeSpec specific = MoreSpecific (ct, bt);
3668 specific_at_least_once = true;
3671 if (specific_at_least_once)
3674 // FIXME: handle lifted operators
3680 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3682 rc.Report.Error (1729, loc,
3683 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3684 type.GetSignatureForError (), argCount.ToString ());
3688 // Determines if the candidate method is applicable to the given set of arguments
3689 // There could be two different set of parameters for same candidate where one
3690 // is the closest override for default values and named arguments checks and second
3691 // one being the virtual base for the parameter types and modifiers.
3693 // A return value rates candidate method compatibility,
3694 // 0 = the best, int.MaxValue = the worst
3696 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
3698 var pd = pm.Parameters;
3699 int param_count = pd.Count;
3700 int optional_count = 0;
3702 Arguments orig_args = arguments;
3704 if (arg_count != param_count) {
3705 for (int i = 0; i < pd.Count; ++i) {
3706 if (pd.FixedParameters[i].HasDefaultValue) {
3707 optional_count = pd.Count - i;
3712 int args_gap = System.Math.Abs (arg_count - param_count);
3713 if (optional_count != 0) {
3714 if (args_gap > optional_count)
3715 return int.MaxValue - 10000 + args_gap - optional_count;
3717 // Readjust expected number when params used
3720 if (arg_count < param_count)
3722 } else if (arg_count > param_count) {
3723 return int.MaxValue - 10000 + args_gap;
3725 } else if (arg_count != param_count) {
3727 return int.MaxValue - 10000 + args_gap;
3728 if (arg_count < param_count - 1)
3729 return int.MaxValue - 10000 + args_gap;
3732 // Resize to fit optional arguments
3733 if (optional_count != 0) {
3734 if (arguments == null) {
3735 arguments = new Arguments (optional_count);
3737 // Have to create a new container, so the next run can do same
3738 var resized = new Arguments (param_count);
3739 resized.AddRange (arguments);
3740 arguments = resized;
3743 for (int i = arg_count; i < param_count; ++i)
3744 arguments.Add (null);
3748 if (arg_count > 0) {
3750 // Shuffle named arguments to the right positions if there are any
3752 if (arguments[arg_count - 1] is NamedArgument) {
3753 arg_count = arguments.Count;
3755 for (int i = 0; i < arg_count; ++i) {
3756 bool arg_moved = false;
3758 NamedArgument na = arguments[i] as NamedArgument;
3762 int index = pd.GetParameterIndexByName (na.Name);
3764 // Named parameter not found
3768 // already reordered
3773 if (index >= param_count) {
3774 // When using parameters which should not be available to the user
3775 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3778 arguments.Add (null);
3782 temp = arguments[index];
3784 // The slot has been taken by positional argument
3785 if (temp != null && !(temp is NamedArgument))
3790 arguments = arguments.MarkOrderedArgument (na);
3794 arguments[index] = arguments[i];
3795 arguments[i] = temp;
3802 arg_count = arguments.Count;
3804 } else if (arguments != null) {
3805 arg_count = arguments.Count;
3809 // 1. Handle generic method using type arguments when specified or type inference
3811 var ms = candidate as MethodSpec;
3812 if (ms != null && ms.IsGeneric) {
3813 // Setup constraint checker for probing only
3814 ConstraintChecker cc = new ConstraintChecker (null);
3816 if (type_arguments != null) {
3817 var g_args_count = ms.Arity;
3818 if (g_args_count != type_arguments.Count)
3819 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3821 ms = ms.MakeGenericMethod (type_arguments.Arguments);
3823 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3824 // for now it simplifies things. I should probably add a callback to ResolveContext
3825 if (lambda_conv_msgs == null) {
3826 lambda_conv_msgs = new SessionReportPrinter ();
3827 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3830 var ti = new TypeInference (arguments);
3831 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3832 lambda_conv_msgs.EndSession ();
3835 return ti.InferenceScore - 20000;
3837 if (i_args.Length != 0) {
3838 ms = ms.MakeGenericMethod (i_args);
3841 cc.IgnoreInferredDynamic = true;
3845 // Type arguments constraints have to match for the method to be applicable
3847 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3849 return int.MaxValue - 25000;
3853 // We have a generic return type and at same time the method is override which
3854 // means we have to also inflate override return type in case the candidate is
3855 // best candidate and override return type is different to base return type.
3857 // virtual Foo<T, object> with override Foo<T, dynamic>
3859 if (candidate != pm) {
3860 MethodSpec override_ms = (MethodSpec) pm;
3861 var inflator = new TypeParameterInflator (ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3862 returnType = inflator.Inflate (returnType);
3864 returnType = ms.ReturnType;
3870 if (type_arguments != null)
3871 return int.MaxValue - 15000;
3875 // 2. Each argument has to be implicitly convertible to method parameter
3877 Parameter.Modifier p_mod = 0;
3879 TypeSpec[] ptypes = ((IParametersMember) candidate).Parameters.Types;
3881 for (int i = 0; i < arg_count; i++) {
3882 Argument a = arguments[i];
3884 if (!pd.FixedParameters[i].HasDefaultValue) {
3885 arguments = orig_args;
3886 return arg_count * 2 + 2;
3890 // Get the default value expression, we can use the same expression
3891 // if the type matches
3893 Expression e = pd.FixedParameters[i].DefaultValue;
3894 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3896 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3898 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3899 e = new MemberAccess (new MemberAccess (new MemberAccess (
3900 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3902 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3908 arguments[i] = new Argument (e, Argument.AType.Default);
3912 if (p_mod != Parameter.Modifier.PARAMS) {
3913 p_mod = pd.FixedParameters[i].ModFlags;
3915 } else if (!params_expanded_form) {
3916 params_expanded_form = true;
3917 pt = ((ElementTypeSpec) pt).Element;
3923 if (!params_expanded_form) {
3924 if (a.ArgType == Argument.AType.ExtensionType) {
3926 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3929 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3930 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3931 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3936 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3939 dynamicArgument = true;
3944 // It can be applicable in expanded form (when not doing exact match like for delegates)
3946 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3947 if (!params_expanded_form)
3948 pt = ((ElementTypeSpec) pt).Element;
3951 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3954 params_expanded_form = true;
3955 } else if (score < 0) {
3956 params_expanded_form = true;
3957 dynamicArgument = true;
3962 if (params_expanded_form)
3964 return (arg_count - i) * 2 + score;
3969 // When params parameter has no argument it will be provided later if the method is the best candidate
3971 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3972 params_expanded_form = true;
3975 // Restore original arguments for dynamic binder to keep the intention of original source code
3977 if (dynamicArgument)
3978 arguments = orig_args;
3984 // Tests argument compatibility with the parameter
3985 // The possible return values are
3987 // 1 - modifier mismatch
3988 // 2 - type mismatch
3989 // -1 - dynamic binding required
3991 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3994 // Types have to be identical when ref or out modifer
3995 // is used and argument is not of dynamic type
3997 if ((argument.Modifier | param_mod) != 0) {
3998 if (argument.Type != parameter) {
4000 // Do full equality check after quick path
4002 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4004 // Using dynamic for ref/out parameter can still succeed at runtime
4006 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4013 if (argument.Modifier != param_mod) {
4015 // Using dynamic for ref/out parameter can still succeed at runtime
4017 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4024 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4028 // Deploy custom error reporting for lambda methods. When probing lambda methods
4029 // keep all errors reported in separate set and once we are done and no best
4030 // candidate found, this set is used to report more details about what was wrong
4033 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4034 if (lambda_conv_msgs == null) {
4035 lambda_conv_msgs = new SessionReportPrinter ();
4036 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4040 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4041 if (lambda_conv_msgs != null) {
4042 lambda_conv_msgs.EndSession ();
4052 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4054 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4056 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4059 var ac_p = p as ArrayContainer;
4061 var ac_q = ((ArrayContainer) q);
4062 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4063 if (specific == ac_p.Element)
4065 if (specific == ac_q.Element)
4067 } else if (TypeManager.IsGenericType (p)) {
4068 var pargs = TypeManager.GetTypeArguments (p);
4069 var qargs = TypeManager.GetTypeArguments (q);
4071 bool p_specific_at_least_once = false;
4072 bool q_specific_at_least_once = false;
4074 for (int i = 0; i < pargs.Length; i++) {
4075 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4076 if (specific == pargs[i])
4077 p_specific_at_least_once = true;
4078 if (specific == qargs[i])
4079 q_specific_at_least_once = true;
4082 if (p_specific_at_least_once && !q_specific_at_least_once)
4084 if (!p_specific_at_least_once && q_specific_at_least_once)
4092 // Find the best method from candidate list
4094 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4096 List<AmbiguousCandidate> ambiguous_candidates = null;
4098 MemberSpec best_candidate;
4099 Arguments best_candidate_args = null;
4100 bool best_candidate_params = false;
4101 bool best_candidate_dynamic = false;
4102 int best_candidate_rate;
4103 IParametersMember best_parameter_member = null;
4105 int args_count = args != null ? args.Count : 0;
4107 Arguments candidate_args = args;
4108 bool error_mode = false;
4109 var current_type = rc.CurrentType;
4110 MemberSpec invocable_member = null;
4112 // Be careful, cannot return until error reporter is restored
4114 best_candidate = null;
4115 best_candidate_rate = int.MaxValue;
4117 var type_members = members;
4121 for (int i = 0; i < type_members.Count; ++i) {
4122 var member = type_members[i];
4125 // Methods in a base class are not candidates if any method in a derived
4126 // class is applicable
4128 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4132 if (!member.IsAccessible (current_type))
4135 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4139 IParametersMember pm = member as IParametersMember;
4142 // Will use it later to report ambiguity between best method and invocable member
4144 if (Invocation.IsMemberInvocable (member))
4145 invocable_member = member;
4151 // Overload resolution is looking for base member but using parameter names
4152 // and default values from the closest member. That means to do expensive lookup
4153 // for the closest override for virtual or abstract members
4155 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4156 var override_params = base_provider.GetOverrideMemberParameters (member);
4157 if (override_params != null)
4158 pm = override_params;
4162 // Check if the member candidate is applicable
4164 bool params_expanded_form = false;
4165 bool dynamic_argument = false;
4166 TypeSpec rt = pm.MemberType;
4167 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4170 // How does it score compare to others
4172 if (candidate_rate < best_candidate_rate) {
4173 best_candidate_rate = candidate_rate;
4174 best_candidate = member;
4175 best_candidate_args = candidate_args;
4176 best_candidate_params = params_expanded_form;
4177 best_candidate_dynamic = dynamic_argument;
4178 best_parameter_member = pm;
4179 best_candidate_return_type = rt;
4180 } else if (candidate_rate == 0) {
4182 // The member look is done per type for most operations but sometimes
4183 // it's not possible like for binary operators overload because they
4184 // are unioned between 2 sides
4186 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4187 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4191 // Is the new candidate better
4192 if (BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params)) {
4193 best_candidate = member;
4194 best_candidate_args = candidate_args;
4195 best_candidate_params = params_expanded_form;
4196 best_candidate_dynamic = dynamic_argument;
4197 best_parameter_member = pm;
4198 best_candidate_return_type = rt;
4200 // It's not better but any other found later could be but we are not sure yet
4201 if (ambiguous_candidates == null)
4202 ambiguous_candidates = new List<AmbiguousCandidate> ();
4204 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4208 // Restore expanded arguments
4209 if (candidate_args != args)
4210 candidate_args = args;
4212 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4214 if (prev_recorder != null)
4215 rc.Report.SetPrinter (prev_recorder);
4219 // We've found exact match
4221 if (best_candidate_rate == 0)
4225 // Try extension methods lookup when no ordinary method match was found and provider enables it
4228 var emg = base_provider.LookupExtensionMethod (rc);
4230 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4232 best_candidate_extension_group = emg;
4233 return (T) (MemberSpec) emg.BestCandidate;
4238 // Don't run expensive error reporting mode for probing
4245 lambda_conv_msgs = null;
4250 // No best member match found, report an error
4252 if (best_candidate_rate != 0 || error_mode) {
4253 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4257 if (best_candidate_dynamic) {
4258 if (args[0].ArgType == Argument.AType.ExtensionType) {
4259 rc.Report.Error (1973, loc,
4260 "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",
4261 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4264 BestCandidateIsDynamic = true;
4268 if (ambiguous_candidates != null) {
4270 // Now check that there are no ambiguities i.e the selected method
4271 // should be better than all the others
4273 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4274 var candidate = ambiguous_candidates [ix];
4276 if (!BetterFunction (rc, candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4277 var ambiguous = candidate.Member;
4278 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4279 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4280 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4281 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4282 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4285 return (T) best_candidate;
4290 if (invocable_member != null) {
4291 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4292 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4293 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4294 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4298 // And now check if the arguments are all
4299 // compatible, perform conversions if
4300 // necessary etc. and return if everything is
4303 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4306 if (best_candidate == null)
4310 // Check ObsoleteAttribute on the best method
4312 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4313 if (oa != null && !rc.IsObsolete)
4314 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4316 best_candidate.MemberDefinition.SetIsUsed ();
4318 args = best_candidate_args;
4319 return (T) best_candidate;
4322 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4324 return ResolveMember<MethodSpec> (rc, ref args);
4327 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4328 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4330 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4333 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4334 ec.Report.SymbolRelatedToPreviousError (method);
4335 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4336 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4337 TypeManager.CSharpSignature (method));
4340 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4341 TypeManager.CSharpSignature (method));
4342 } else if (IsDelegateInvoke) {
4343 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4344 DelegateType.GetSignatureForError ());
4346 ec.Report.SymbolRelatedToPreviousError (method);
4347 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4348 method.GetSignatureForError ());
4351 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4353 string index = (idx + 1).ToString ();
4354 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4355 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4356 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4357 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4358 index, Parameter.GetModifierSignature (a.Modifier));
4360 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4361 index, Parameter.GetModifierSignature (mod));
4363 string p1 = a.GetSignatureForError ();
4364 string p2 = TypeManager.CSharpName (paramType);
4367 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4368 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4369 ec.Report.SymbolRelatedToPreviousError (paramType);
4372 ec.Report.Error (1503, loc,
4373 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4378 // We have failed to find exact match so we return error info about the closest match
4380 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4382 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4383 int arg_count = args == null ? 0 : args.Count;
4385 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4386 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4387 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4391 if (lambda_conv_msgs != null) {
4392 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4397 // For candidates which match on parameters count report more details about incorrect arguments
4400 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4401 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4402 // Reject any inaccessible member
4403 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4404 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4405 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4409 var ms = best_candidate as MethodSpec;
4410 if (ms != null && ms.IsGeneric) {
4411 bool constr_ok = true;
4412 if (ms.TypeArguments != null)
4413 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4415 if (ta_count == 0) {
4416 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4420 rc.Report.Error (411, loc,
4421 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4422 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4429 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4435 // We failed to find any method with correct argument count, report best candidate
4437 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4440 if (best_candidate.Kind == MemberKind.Constructor) {
4441 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4442 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4443 } else if (IsDelegateInvoke) {
4444 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4445 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4446 DelegateType.GetSignatureForError (), arg_count.ToString ());
4448 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4449 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4450 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4451 name, arg_count.ToString ());
4455 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4457 var pd = pm.Parameters;
4458 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4460 Parameter.Modifier p_mod = 0;
4462 int a_idx = 0, a_pos = 0;
4464 ArrayInitializer params_initializers = null;
4465 bool has_unsafe_arg = pm.MemberType.IsPointer;
4466 int arg_count = args == null ? 0 : args.Count;
4468 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4470 if (p_mod != Parameter.Modifier.PARAMS) {
4471 p_mod = pd.FixedParameters[a_idx].ModFlags;
4473 has_unsafe_arg |= pt.IsPointer;
4475 if (p_mod == Parameter.Modifier.PARAMS) {
4476 if (chose_params_expanded) {
4477 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4478 pt = TypeManager.GetElementType (pt);
4484 // Types have to be identical when ref or out modifer is used
4486 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4487 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4490 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4496 NamedArgument na = a as NamedArgument;
4498 int name_index = pd.GetParameterIndexByName (na.Name);
4499 if (name_index < 0 || name_index >= pd.Count) {
4500 if (IsDelegateInvoke) {
4501 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4502 ec.Report.Error (1746, na.Location,
4503 "The delegate `{0}' does not contain a parameter named `{1}'",
4504 DelegateType.GetSignatureForError (), na.Name);
4506 ec.Report.SymbolRelatedToPreviousError (member);
4507 ec.Report.Error (1739, na.Location,
4508 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4509 TypeManager.CSharpSignature (member), na.Name);
4511 } else if (args[name_index] != a) {
4512 if (IsDelegateInvoke)
4513 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4515 ec.Report.SymbolRelatedToPreviousError (member);
4517 ec.Report.Error (1744, na.Location,
4518 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4523 if (a.Expr.Type == InternalType.Dynamic)
4526 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4527 custom_errors.NoArgumentMatch (ec, member);
4531 Expression conv = null;
4532 if (a.ArgType == Argument.AType.ExtensionType) {
4533 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4536 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4538 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4541 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4548 // Convert params arguments to an array initializer
4550 if (params_initializers != null) {
4551 // we choose to use 'a.Expr' rather than 'conv' so that
4552 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4553 params_initializers.Add (a.Expr);
4554 args.RemoveAt (a_idx--);
4559 // Update the argument with the implicit conversion
4563 if (a_idx != arg_count) {
4564 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4569 // Fill not provided arguments required by params modifier
4571 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4573 args = new Arguments (1);
4575 pt = ptypes[pd.Count - 1];
4576 pt = TypeManager.GetElementType (pt);
4577 has_unsafe_arg |= pt.IsPointer;
4578 params_initializers = new ArrayInitializer (0, loc);
4582 // Append an array argument with all params arguments
4584 if (params_initializers != null) {
4585 args.Add (new Argument (
4586 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4590 if (has_unsafe_arg && !ec.IsUnsafe) {
4591 Expression.UnsafeError (ec, loc);
4595 // We could infer inaccesible type arguments
4597 if (type_arguments == null && member.IsGeneric) {
4598 var ms = (MethodSpec) member;
4599 foreach (var ta in ms.TypeArguments) {
4600 if (!ta.IsAccessible (ec.CurrentType)) {
4601 ec.Report.SymbolRelatedToPreviousError (ta);
4602 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4612 public class ConstantExpr : MemberExpr
4616 public ConstantExpr (ConstSpec constant, Location loc)
4618 this.constant = constant;
4622 public override string Name {
4623 get { throw new NotImplementedException (); }
4626 public override bool IsInstance {
4627 get { return !IsStatic; }
4630 public override bool IsStatic {
4631 get { return true; }
4634 protected override TypeSpec DeclaringType {
4635 get { return constant.DeclaringType; }
4638 public override Expression CreateExpressionTree (ResolveContext ec)
4640 throw new NotSupportedException ("ET");
4643 protected override Expression DoResolve (ResolveContext rc)
4645 ResolveInstanceExpression (rc, null);
4646 DoBestMemberChecks (rc, constant);
4648 var c = constant.GetConstant (rc);
4650 // Creates reference expression to the constant value
4651 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4654 public override void Emit (EmitContext ec)
4656 throw new NotSupportedException ();
4659 public override string GetSignatureForError ()
4661 return constant.GetSignatureForError ();
4664 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4666 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4671 /// Fully resolved expression that evaluates to a Field
4673 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4674 protected FieldSpec spec;
4675 VariableInfo variable_info;
4677 LocalTemporary temp;
4680 protected FieldExpr (Location l)
4685 public FieldExpr (FieldSpec spec, Location loc)
4690 type = spec.MemberType;
4693 public FieldExpr (FieldBase fi, Location l)
4700 public override string Name {
4706 public bool IsHoisted {
4708 IVariableReference hv = InstanceExpression as IVariableReference;
4709 return hv != null && hv.IsHoisted;
4713 public override bool IsInstance {
4715 return !spec.IsStatic;
4719 public override bool IsStatic {
4721 return spec.IsStatic;
4725 public FieldSpec Spec {
4731 protected override TypeSpec DeclaringType {
4733 return spec.DeclaringType;
4737 public VariableInfo VariableInfo {
4739 return variable_info;
4745 public override string GetSignatureForError ()
4747 return TypeManager.GetFullNameSignature (spec);
4750 public bool IsMarshalByRefAccess ()
4752 // Checks possible ldflda of field access expression
4753 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4754 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4755 !(InstanceExpression is This);
4758 public void SetHasAddressTaken ()
4760 IVariableReference vr = InstanceExpression as IVariableReference;
4762 vr.SetHasAddressTaken ();
4765 public override Expression CreateExpressionTree (ResolveContext ec)
4767 Expression instance;
4768 if (InstanceExpression == null) {
4769 instance = new NullLiteral (loc);
4771 instance = InstanceExpression.CreateExpressionTree (ec);
4774 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4776 CreateTypeOfExpression ());
4778 return CreateExpressionFactoryCall (ec, "Field", args);
4781 public Expression CreateTypeOfExpression ()
4783 return new TypeOfField (spec, loc);
4786 protected override Expression DoResolve (ResolveContext ec)
4788 return DoResolve (ec, null);
4791 Expression DoResolve (ResolveContext ec, Expression rhs)
4793 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4795 if (ResolveInstanceExpression (ec, rhs)) {
4796 // Resolve the field's instance expression while flow analysis is turned
4797 // off: when accessing a field "a.b", we must check whether the field
4798 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4800 if (lvalue_instance) {
4801 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4802 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4804 Expression right_side =
4805 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4807 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4810 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4811 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4815 if (InstanceExpression == null)
4819 DoBestMemberChecks (ec, spec);
4821 var fb = spec as FixedFieldSpec;
4822 IVariableReference var = InstanceExpression as IVariableReference;
4824 if (lvalue_instance && var != null && var.VariableInfo != null) {
4825 var.VariableInfo.SetFieldAssigned (ec, Name);
4829 IFixedExpression fe = InstanceExpression as IFixedExpression;
4830 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4831 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4834 if (InstanceExpression.eclass != ExprClass.Variable) {
4835 ec.Report.SymbolRelatedToPreviousError (spec);
4836 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4837 TypeManager.GetFullNameSignature (spec));
4838 } else if (var != null && var.IsHoisted) {
4839 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4842 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4845 eclass = ExprClass.Variable;
4847 // If the instance expression is a local variable or parameter.
4848 if (var == null || var.VariableInfo == null)
4851 VariableInfo vi = var.VariableInfo;
4852 if (!vi.IsFieldAssigned (ec, Name, loc))
4855 variable_info = vi.GetSubStruct (Name);
4859 static readonly int [] codes = {
4860 191, // instance, write access
4861 192, // instance, out access
4862 198, // static, write access
4863 199, // static, out access
4864 1648, // member of value instance, write access
4865 1649, // member of value instance, out access
4866 1650, // member of value static, write access
4867 1651 // member of value static, out access
4870 static readonly string [] msgs = {
4871 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4872 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4873 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4874 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4875 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4876 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4877 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4878 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4881 // The return value is always null. Returning a value simplifies calling code.
4882 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4885 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4889 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4891 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4896 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4898 Expression e = DoResolve (ec, right_side);
4903 spec.MemberDefinition.SetIsAssigned ();
4905 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4906 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4907 ec.Report.Warning (420, 1, loc,
4908 "`{0}': A volatile field references will not be treated as volatile",
4909 spec.GetSignatureForError ());
4912 if (spec.IsReadOnly) {
4913 // InitOnly fields can only be assigned in constructors or initializers
4914 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4915 return Report_AssignToReadonly (ec, right_side);
4917 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4919 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4920 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4921 return Report_AssignToReadonly (ec, right_side);
4922 // static InitOnly fields cannot be assigned-to in an instance constructor
4923 if (IsStatic && !ec.IsStatic)
4924 return Report_AssignToReadonly (ec, right_side);
4925 // instance constructors can't modify InitOnly fields of other instances of the same type
4926 if (!IsStatic && !(InstanceExpression is This))
4927 return Report_AssignToReadonly (ec, right_side);
4931 if (right_side == EmptyExpression.OutAccess.Instance &&
4932 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4933 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4934 ec.Report.Warning (197, 1, loc,
4935 "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",
4936 GetSignatureForError ());
4939 eclass = ExprClass.Variable;
4943 public override int GetHashCode ()
4945 return spec.GetHashCode ();
4948 public bool IsFixed {
4951 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4953 IVariableReference variable = InstanceExpression as IVariableReference;
4954 if (variable != null)
4955 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4957 IFixedExpression fe = InstanceExpression as IFixedExpression;
4958 return fe != null && fe.IsFixed;
4962 public override bool Equals (object obj)
4964 FieldExpr fe = obj as FieldExpr;
4968 if (spec != fe.spec)
4971 if (InstanceExpression == null || fe.InstanceExpression == null)
4974 return InstanceExpression.Equals (fe.InstanceExpression);
4977 public void Emit (EmitContext ec, bool leave_copy)
4979 bool is_volatile = false;
4981 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4984 spec.MemberDefinition.SetIsUsed ();
4988 ec.Emit (OpCodes.Volatile);
4990 ec.Emit (OpCodes.Ldsfld, spec);
4993 EmitInstance (ec, false);
4995 // Optimization for build-in types
4996 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4997 ec.EmitLoadFromPtr (type);
4999 var ff = spec as FixedFieldSpec;
5001 ec.Emit (OpCodes.Ldflda, spec);
5002 ec.Emit (OpCodes.Ldflda, ff.Element);
5005 ec.Emit (OpCodes.Volatile);
5007 ec.Emit (OpCodes.Ldfld, spec);
5013 ec.Emit (OpCodes.Dup);
5015 temp = new LocalTemporary (this.Type);
5021 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5023 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5025 EmitInstance (ec, prepared);
5029 ec.Emit (OpCodes.Dup);
5031 temp = new LocalTemporary (this.Type);
5036 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5037 ec.Emit (OpCodes.Volatile);
5039 spec.MemberDefinition.SetIsAssigned ();
5042 ec.Emit (OpCodes.Stsfld, spec);
5044 ec.Emit (OpCodes.Stfld, spec);
5053 public override void Emit (EmitContext ec)
5058 public override void EmitSideEffect (EmitContext ec)
5060 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5062 if (is_volatile) // || is_marshal_by_ref ())
5063 base.EmitSideEffect (ec);
5066 public void AddressOf (EmitContext ec, AddressOp mode)
5068 if ((mode & AddressOp.Store) != 0)
5069 spec.MemberDefinition.SetIsAssigned ();
5070 if ((mode & AddressOp.Load) != 0)
5071 spec.MemberDefinition.SetIsUsed ();
5074 // Handle initonly fields specially: make a copy and then
5075 // get the address of the copy.
5078 if (spec.IsReadOnly){
5080 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5093 local = ec.DeclareLocal (type, false);
5094 ec.Emit (OpCodes.Stloc, local);
5095 ec.Emit (OpCodes.Ldloca, local);
5101 ec.Emit (OpCodes.Ldsflda, spec);
5104 EmitInstance (ec, false);
5105 ec.Emit (OpCodes.Ldflda, spec);
5109 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5111 return MakeExpression (ctx);
5114 public override SLE.Expression MakeExpression (BuilderContext ctx)
5116 return SLE.Expression.Field (
5117 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5118 spec.GetMetaInfo ());
5121 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5123 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5129 /// Expression that evaluates to a Property. The Assign class
5130 /// might set the `Value' expression if we are in an assignment.
5132 /// This is not an LValue because we need to re-write the expression, we
5133 /// can not take data from the stack and store it.
5135 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5137 public PropertyExpr (PropertySpec spec, Location l)
5140 best_candidate = spec;
5141 type = spec.MemberType;
5146 protected override TypeSpec DeclaringType {
5148 return best_candidate.DeclaringType;
5152 public override string Name {
5154 return best_candidate.Name;
5158 public override bool IsInstance {
5164 public override bool IsStatic {
5166 return best_candidate.IsStatic;
5170 public PropertySpec PropertyInfo {
5172 return best_candidate;
5178 public override Expression CreateExpressionTree (ResolveContext ec)
5181 if (IsSingleDimensionalArrayLength ()) {
5182 args = new Arguments (1);
5183 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5184 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5187 args = new Arguments (2);
5188 if (InstanceExpression == null)
5189 args.Add (new Argument (new NullLiteral (loc)));
5191 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5192 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5193 return CreateExpressionFactoryCall (ec, "Property", args);
5196 public Expression CreateSetterTypeOfExpression ()
5198 return new TypeOfMethod (Setter, loc);
5201 public override string GetSignatureForError ()
5203 return best_candidate.GetSignatureForError ();
5206 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5208 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5211 public override SLE.Expression MakeExpression (BuilderContext ctx)
5213 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5216 void Error_PropertyNotValid (ResolveContext ec)
5218 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5219 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5220 GetSignatureForError ());
5223 bool IsSingleDimensionalArrayLength ()
5225 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5228 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5229 return ac != null && ac.Rank == 1;
5232 public override void Emit (EmitContext ec, bool leave_copy)
5235 // Special case: length of single dimension array property is turned into ldlen
5237 if (IsSingleDimensionalArrayLength ()) {
5239 EmitInstance (ec, false);
5240 ec.Emit (OpCodes.Ldlen);
5241 ec.Emit (OpCodes.Conv_I4);
5245 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5248 ec.Emit (OpCodes.Dup);
5250 temp = new LocalTemporary (this.Type);
5256 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5260 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5261 args = new Arguments (0);
5266 ec.Emit (OpCodes.Dup);
5268 temp = new LocalTemporary (this.Type);
5273 args = new Arguments (1);
5277 temp = new LocalTemporary (this.Type);
5279 args.Add (new Argument (temp));
5281 args.Add (new Argument (source));
5285 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5293 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5295 eclass = ExprClass.PropertyAccess;
5297 if (best_candidate.IsNotRealProperty) {
5298 Error_PropertyNotValid (rc);
5301 ResolveInstanceExpression (rc, right_side);
5303 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5304 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5305 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5307 type = p.MemberType;
5311 DoBestMemberChecks (rc, best_candidate);
5315 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5317 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5321 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5323 // getter and setter can be different for base calls
5324 MethodSpec getter, setter;
5325 protected T best_candidate;
5327 protected LocalTemporary temp;
5328 protected bool prepared;
5330 protected PropertyOrIndexerExpr (Location l)
5337 public MethodSpec Getter {
5346 public MethodSpec Setter {
5357 protected override Expression DoResolve (ResolveContext ec)
5359 if (eclass == ExprClass.Unresolved) {
5360 var expr = OverloadResolve (ec, null);
5365 return expr.Resolve (ec);
5368 if (!ResolveGetter (ec))
5374 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5376 if (right_side == EmptyExpression.OutAccess.Instance) {
5377 // TODO: best_candidate can be null at this point
5378 INamedBlockVariable variable = null;
5379 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5380 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5381 best_candidate.Name);
5383 right_side.DoResolveLValue (ec, this);
5388 // if the property/indexer returns a value type, and we try to set a field in it
5389 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5390 Error_CannotModifyIntermediateExpressionValue (ec);
5393 if (eclass == ExprClass.Unresolved) {
5394 var expr = OverloadResolve (ec, right_side);
5399 return expr.ResolveLValue (ec, right_side);
5402 if (!ResolveSetter (ec))
5409 // Implements the IAssignMethod interface for assignments
5411 public abstract void Emit (EmitContext ec, bool leave_copy);
5412 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5414 public override void Emit (EmitContext ec)
5419 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5421 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5423 bool ResolveGetter (ResolveContext rc)
5425 if (!best_candidate.HasGet) {
5426 if (InstanceExpression != EmptyExpression.Null) {
5427 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5428 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5429 best_candidate.GetSignatureForError ());
5432 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5433 if (best_candidate.HasDifferentAccessibility) {
5434 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5435 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5436 TypeManager.CSharpSignature (best_candidate));
5438 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5439 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5443 if (best_candidate.HasDifferentAccessibility) {
5444 CheckProtectedMemberAccess (rc, best_candidate.Get);
5447 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5451 bool ResolveSetter (ResolveContext rc)
5453 if (!best_candidate.HasSet) {
5454 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5455 GetSignatureForError ());
5459 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5460 if (best_candidate.HasDifferentAccessibility) {
5461 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5462 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5463 GetSignatureForError ());
5465 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5466 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5470 if (best_candidate.HasDifferentAccessibility)
5471 CheckProtectedMemberAccess (rc, best_candidate.Set);
5473 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5479 /// Fully resolved expression that evaluates to an Event
5481 public class EventExpr : MemberExpr, IAssignMethod
5483 readonly EventSpec spec;
5486 public EventExpr (EventSpec spec, Location loc)
5494 protected override TypeSpec DeclaringType {
5496 return spec.DeclaringType;
5500 public override string Name {
5506 public override bool IsInstance {
5508 return !spec.IsStatic;
5512 public override bool IsStatic {
5514 return spec.IsStatic;
5518 public MethodSpec Operator {
5526 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5529 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5531 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5532 if (spec.BackingField != null &&
5533 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType))) {
5535 spec.MemberDefinition.SetIsUsed ();
5537 if (!ec.IsObsolete) {
5538 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5540 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5543 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5544 Error_AssignmentEventOnly (ec);
5546 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5548 InstanceExpression = null;
5550 return ml.ResolveMemberAccess (ec, left, original);
5553 Error_AssignmentEventOnly (ec);
5556 return base.ResolveMemberAccess (ec, left, original);
5559 public override Expression CreateExpressionTree (ResolveContext ec)
5561 throw new NotSupportedException ("ET");
5564 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5566 if (right_side == EmptyExpression.EventAddition) {
5567 op = spec.AccessorAdd;
5568 } else if (right_side == EmptyExpression.EventSubtraction) {
5569 op = spec.AccessorRemove;
5573 Error_AssignmentEventOnly (ec);
5577 op = CandidateToBaseOverride (ec, op);
5581 protected override Expression DoResolve (ResolveContext ec)
5583 eclass = ExprClass.EventAccess;
5584 type = spec.MemberType;
5586 ResolveInstanceExpression (ec, null);
5588 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5589 Error_CannotAssign (ec);
5592 DoBestMemberChecks (ec, spec);
5596 public override void Emit (EmitContext ec)
5598 throw new NotSupportedException ();
5599 //Error_CannotAssign ();
5602 #region IAssignMethod Members
5604 public void Emit (EmitContext ec, bool leave_copy)
5606 throw new NotImplementedException ();
5609 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5611 if (leave_copy || !prepare_for_load)
5612 throw new NotImplementedException ("EventExpr::EmitAssign");
5614 Arguments args = new Arguments (1);
5615 args.Add (new Argument (source));
5616 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5621 void Error_AssignmentEventOnly (ResolveContext ec)
5623 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5624 GetSignatureForError ());
5627 public void Error_CannotAssign (ResolveContext ec)
5629 ec.Report.Error (70, loc,
5630 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5631 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5634 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5636 name = name.Substring (0, name.LastIndexOf ('.'));
5637 base.Error_CannotCallAbstractBase (rc, name);
5640 public override string GetSignatureForError ()
5642 return TypeManager.CSharpSignature (spec);
5645 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5647 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5651 public class TemporaryVariableReference : VariableReference
5653 public class Declarator : Statement
5655 TemporaryVariableReference variable;
5657 public Declarator (TemporaryVariableReference variable)
5659 this.variable = variable;
5663 protected override void DoEmit (EmitContext ec)
5665 variable.li.CreateBuilder (ec);
5668 protected override void CloneTo (CloneContext clonectx, Statement target)
5676 public TemporaryVariableReference (LocalVariable li, Location loc)
5679 this.type = li.Type;
5683 public override bool IsLockedByStatement {
5691 public LocalVariable LocalInfo {
5697 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5699 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5700 return new TemporaryVariableReference (li, loc);
5703 public override Expression CreateExpressionTree (ResolveContext ec)
5705 throw new NotSupportedException ("ET");
5708 protected override Expression DoResolve (ResolveContext ec)
5710 eclass = ExprClass.Variable;
5713 // Don't capture temporary variables except when using
5714 // iterator redirection
5716 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5717 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5718 storey.CaptureLocalVariable (ec, li);
5724 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5726 return Resolve (ec);
5729 public override void Emit (EmitContext ec)
5731 li.CreateBuilder (ec);
5736 public void EmitAssign (EmitContext ec, Expression source)
5738 li.CreateBuilder (ec);
5740 EmitAssign (ec, source, false, false);
5743 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5745 return li.HoistedVariant;
5748 public override bool IsFixed {
5749 get { return true; }
5752 public override bool IsRef {
5753 get { return false; }
5756 public override string Name {
5757 get { throw new NotImplementedException (); }
5760 public override void SetHasAddressTaken ()
5762 throw new NotImplementedException ();
5765 protected override ILocalVariable Variable {
5769 public override VariableInfo VariableInfo {
5770 get { throw new NotImplementedException (); }
5775 /// Handles `var' contextual keyword; var becomes a keyword only
5776 /// if no type called var exists in a variable scope
5778 class VarExpr : SimpleName
5780 public VarExpr (Location loc)
5785 public bool InferType (ResolveContext ec, Expression right_side)
5788 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5790 type = right_side.Type;
5791 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5792 ec.Report.Error (815, loc,
5793 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5794 type.GetSignatureForError ());
5798 eclass = ExprClass.Variable;
5802 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5804 if (RootContext.Version < LanguageVersion.V_3)
5805 base.Error_TypeOrNamespaceNotFound (ec);
5807 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");