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.type.IsAccessible (ec.CurrentType)) {
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, Constructor.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 protected static 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 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2503 public override bool Equals (object obj)
2505 TypeExpr tobj = obj as TypeExpr;
2509 return Type == tobj.Type;
2512 public override int GetHashCode ()
2514 return Type.GetHashCode ();
2519 /// Fully resolved Expression that already evaluated to a type
2521 public class TypeExpression : TypeExpr {
2522 public TypeExpression (TypeSpec t, Location l)
2525 eclass = ExprClass.Type;
2529 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2534 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2541 /// This class denotes an expression which evaluates to a member
2542 /// of a struct or a class.
2544 public abstract class MemberExpr : Expression
2547 // An instance expression associated with this member, if it's a
2548 // non-static member
2550 public Expression InstanceExpression;
2553 /// The name of this member.
2555 public abstract string Name {
2560 // When base.member is used
2562 public bool IsBase {
2563 get { return InstanceExpression is BaseThis; }
2567 /// Whether this is an instance member.
2569 public abstract bool IsInstance {
2574 /// Whether this is a static member.
2576 public abstract bool IsStatic {
2581 protected abstract TypeSpec DeclaringType {
2586 // Converts best base candidate for virtual method starting from QueriedBaseType
2588 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2591 // Only when base.member is used and method is virtual
2597 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2598 // means for base.member access we have to find the closest match after we found best candidate
2600 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2602 // The method could already be what we are looking for
2604 TypeSpec[] targs = null;
2605 if (method.DeclaringType != InstanceExpression.Type) {
2606 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2607 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2608 if (base_override.IsGeneric)
2609 targs = method.TypeArguments;
2611 method = base_override;
2615 // TODO: For now we do it for any hoisted call even if it's needed for
2616 // hoisted stories only but that requires a new expression wrapper
2617 if (rc.CurrentAnonymousMethod != null) {
2618 if (targs == null && method.IsGeneric) {
2619 targs = method.TypeArguments;
2620 method = method.GetGenericMethodDefinition ();
2623 if (method.Parameters.HasArglist)
2624 throw new NotImplementedException ("__arglist base call proxy");
2626 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2628 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2629 // get/set member expressions second call would fail to proxy because left expression
2630 // would be of 'this' and not 'base'
2631 if (rc.CurrentType.IsStruct)
2632 InstanceExpression = new This (loc).Resolve (rc);
2636 method = method.MakeGenericMethod (targs);
2640 // Only base will allow this invocation to happen.
2642 if (method.IsAbstract) {
2643 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2649 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2651 if (InstanceExpression == null)
2654 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2655 var ct = rc.CurrentType;
2656 var expr_type = InstanceExpression.Type;
2657 if (ct != expr_type) {
2658 expr_type = expr_type.GetDefinition ();
2659 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2660 rc.Report.SymbolRelatedToPreviousError (member);
2661 rc.Report.Error (1540, loc,
2662 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2663 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2669 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2672 type = type.GetDefinition ();
2674 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2677 type = type.DeclaringType;
2678 } while (type != null);
2683 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2685 if (InstanceExpression != null) {
2686 InstanceExpression = InstanceExpression.Resolve (rc);
2687 CheckProtectedMemberAccess (rc, member);
2690 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2691 UnsafeError (rc, loc);
2694 if (!rc.IsObsolete) {
2695 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2697 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2700 if (!(member is FieldSpec))
2701 member.MemberDefinition.SetIsUsed ();
2704 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2706 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2710 // Implements identicial simple name and type-name
2712 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2715 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2718 // 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
2719 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2721 if (left is MemberExpr || left is VariableReference) {
2722 rc.Report.DisableReporting ();
2723 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2724 rc.Report.EnableReporting ();
2725 if (identical_type != null && identical_type.Type == left.Type)
2726 return identical_type;
2732 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2735 if (InstanceExpression != null) {
2736 if (InstanceExpression is TypeExpr) {
2737 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2738 if (oa != null && !rc.IsObsolete) {
2739 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2742 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2743 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2744 rc.Report.Error (176, loc,
2745 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2746 GetSignatureForError ());
2750 InstanceExpression = null;
2756 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2757 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2758 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2759 rc.Report.Error (236, loc,
2760 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2761 GetSignatureForError ());
2763 rc.Report.Error (120, loc,
2764 "An object reference is required to access non-static member `{0}'",
2765 GetSignatureForError ());
2770 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2771 rc.Report.Error (38, loc,
2772 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2773 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2776 InstanceExpression = new This (loc);
2777 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2778 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2779 InstanceExpression = InstanceExpression.Resolve (rc);
2782 InstanceExpression = InstanceExpression.Resolve (rc);
2788 var me = InstanceExpression as MemberExpr;
2790 me.ResolveInstanceExpression (rc, rhs);
2792 var fe = me as FieldExpr;
2793 if (fe != null && fe.IsMarshalByRefAccess ()) {
2794 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2795 rc.Report.Warning (1690, 1, loc,
2796 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2797 me.GetSignatureForError ());
2804 // Run member-access postponed check once we know that
2805 // the expression is not field expression which is the only
2806 // expression which can use uninitialized this
2808 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2809 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2813 // Additional checks for l-value member access
2817 // TODO: It should be recursive but that would break csc compatibility
2819 if (InstanceExpression is UnboxCast) {
2820 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2827 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2829 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2830 ec.Report.Warning (1720, 1, left.Location,
2831 "Expression will always cause a `{0}'", "System.NullReferenceException");
2834 InstanceExpression = left;
2838 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2840 TypeSpec instance_type = InstanceExpression.Type;
2841 if (TypeManager.IsValueType (instance_type)) {
2842 if (InstanceExpression is IMemoryLocation) {
2843 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2845 LocalTemporary t = new LocalTemporary (instance_type);
2846 InstanceExpression.Emit (ec);
2848 t.AddressOf (ec, AddressOp.Store);
2851 InstanceExpression.Emit (ec);
2853 // Only to make verifier happy
2854 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2855 ec.Emit (OpCodes.Box, instance_type);
2858 if (prepare_for_load)
2859 ec.Emit (OpCodes.Dup);
2862 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2866 // Represents a group of extension method candidates for whole namespace
2868 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2870 NamespaceEntry namespace_entry;
2871 public readonly Expression ExtensionExpression;
2873 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2874 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2876 this.namespace_entry = n;
2877 this.ExtensionExpression = extensionExpr;
2880 public override bool IsStatic {
2881 get { return true; }
2884 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2886 if (namespace_entry == null)
2890 // For extension methodgroup we are not looking for base members but parent
2891 // namespace extension methods
2893 int arity = type_arguments == null ? 0 : type_arguments.Count;
2894 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2898 return found.Cast<MemberSpec> ().ToList ();
2901 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2903 // We are already here
2907 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2909 if (arguments == null)
2910 arguments = new Arguments (1);
2912 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2913 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2915 // Store resolved argument and restore original arguments
2917 // Clean-up modified arguments for error reporting
2918 arguments.RemoveAt (0);
2922 var me = ExtensionExpression as MemberExpr;
2924 me.ResolveInstanceExpression (ec, null);
2926 InstanceExpression = null;
2930 #region IErrorHandler Members
2932 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2937 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2939 rc.Report.SymbolRelatedToPreviousError (best);
2940 rc.Report.Error (1928, loc,
2941 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2942 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2945 rc.Report.Error (1929, loc,
2946 "Extension method instance type `{0}' cannot be converted to `{1}'",
2947 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2953 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2958 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2967 /// MethodGroupExpr represents a group of method candidates which
2968 /// can be resolved to the best method overload
2970 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2972 protected IList<MemberSpec> Methods;
2973 MethodSpec best_candidate;
2974 TypeSpec best_candidate_return;
2975 protected TypeArguments type_arguments;
2977 SimpleName simple_name;
2978 protected TypeSpec queried_type;
2980 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2984 this.type = InternalType.MethodGroup;
2986 eclass = ExprClass.MethodGroup;
2987 queried_type = type;
2990 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2991 : this (new MemberSpec[] { m }, type, loc)
2997 public MethodSpec BestCandidate {
2999 return best_candidate;
3003 public TypeSpec BestCandidateReturnType {
3005 return best_candidate_return;
3009 protected override TypeSpec DeclaringType {
3011 return queried_type;
3015 public override bool IsInstance {
3017 if (best_candidate != null)
3018 return !best_candidate.IsStatic;
3024 public override bool IsStatic {
3026 if (best_candidate != null)
3027 return best_candidate.IsStatic;
3033 public override string Name {
3035 if (best_candidate != null)
3036 return best_candidate.Name;
3039 return Methods.First ().Name;
3046 // When best candidate is already know this factory can be used
3047 // to avoid expensive overload resolution to be called
3049 // NOTE: InstanceExpression has to be set manually
3051 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3053 return new MethodGroupExpr (best, queriedType, loc) {
3054 best_candidate = best,
3055 best_candidate_return = best.ReturnType
3059 public override string GetSignatureForError ()
3061 if (best_candidate != null)
3062 return best_candidate.GetSignatureForError ();
3064 return Methods.First ().GetSignatureForError ();
3067 public override Expression CreateExpressionTree (ResolveContext ec)
3069 if (best_candidate == null) {
3070 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3074 if (best_candidate.IsConditionallyExcluded (loc))
3075 ec.Report.Error (765, loc,
3076 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3078 return new TypeOfMethod (best_candidate, loc);
3081 protected override Expression DoResolve (ResolveContext ec)
3083 this.eclass = ExprClass.MethodGroup;
3085 if (InstanceExpression != null) {
3086 InstanceExpression = InstanceExpression.Resolve (ec);
3087 if (InstanceExpression == null)
3094 public override void Emit (EmitContext ec)
3096 throw new NotSupportedException ();
3099 public void EmitCall (EmitContext ec, Arguments arguments)
3101 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3104 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3106 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3107 Name, TypeManager.CSharpName (target));
3110 public static bool IsExtensionMethodArgument (Expression expr)
3113 // LAMESPEC: No details about which expressions are not allowed
3115 return !(expr is TypeExpr) && !(expr is BaseThis);
3119 /// Find the Applicable Function Members (7.4.2.1)
3121 /// me: Method Group expression with the members to select.
3122 /// it might contain constructors or methods (or anything
3123 /// that maps to a method).
3125 /// Arguments: ArrayList containing resolved Argument objects.
3127 /// loc: The location if we want an error to be reported, or a Null
3128 /// location for "probing" purposes.
3130 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3131 /// that is the best match of me on Arguments.
3134 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3136 // TODO: causes issues with probing mode, remove explicit Kind check
3137 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3140 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3141 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3142 r.BaseMembersProvider = this;
3145 if (cerrors != null)
3146 r.CustomErrors = cerrors;
3148 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3149 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3150 if (best_candidate == null)
3151 return r.BestCandidateIsDynamic ? this : null;
3153 // Overload resolver had to create a new method group, all checks bellow have already been executed
3154 if (r.BestCandidateNewMethodGroup != null)
3155 return r.BestCandidateNewMethodGroup;
3157 if (best_candidate.Kind == MemberKind.Method) {
3158 if (InstanceExpression != null) {
3159 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3160 InstanceExpression = null;
3162 if (best_candidate.IsStatic && simple_name != null) {
3163 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3166 InstanceExpression.Resolve (ec);
3170 ResolveInstanceExpression (ec, null);
3171 if (InstanceExpression != null)
3172 CheckProtectedMemberAccess (ec, best_candidate);
3175 var base_override = CandidateToBaseOverride (ec, best_candidate);
3176 if (base_override == best_candidate) {
3177 best_candidate_return = r.BestCandidateReturnType;
3179 best_candidate = base_override;
3180 best_candidate_return = best_candidate.ReturnType;
3186 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3188 simple_name = original;
3189 return base.ResolveMemberAccess (ec, left, original);
3192 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3194 type_arguments = ta;
3197 #region IBaseMembersProvider Members
3199 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3201 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3204 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3206 if (queried_type == member.DeclaringType)
3209 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3210 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3214 // Extension methods lookup after ordinary methods candidates failed to apply
3216 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3218 if (InstanceExpression == null)
3221 InstanceExpression = InstanceExpression.Resolve (rc);
3222 if (!IsExtensionMethodArgument (InstanceExpression))
3225 int arity = type_arguments == null ? 0 : type_arguments.Count;
3226 NamespaceEntry methods_scope = null;
3227 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3228 if (methods == null)
3231 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3232 emg.SetTypeArguments (rc, type_arguments);
3239 public struct OverloadResolver
3242 public enum Restrictions
3246 ProbingOnly = 1 << 1,
3247 CovariantDelegate = 1 << 2,
3248 NoBaseMembers = 1 << 3,
3249 BaseMembersIncluded = 1 << 4
3252 public interface IBaseMembersProvider
3254 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3255 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3256 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3259 public interface IErrorHandler
3261 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3262 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3263 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3264 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3267 sealed class NoBaseMembers : IBaseMembersProvider
3269 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3271 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3276 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3281 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3287 struct AmbiguousCandidate
3289 public readonly MemberSpec Member;
3290 public readonly bool Expanded;
3291 public readonly AParametersCollection Parameters;
3293 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3296 Parameters = parameters;
3297 Expanded = expanded;
3302 IList<MemberSpec> members;
3303 TypeArguments type_arguments;
3304 IBaseMembersProvider base_provider;
3305 IErrorHandler custom_errors;
3306 Restrictions restrictions;
3307 MethodGroupExpr best_candidate_extension_group;
3308 TypeSpec best_candidate_return_type;
3310 SessionReportPrinter lambda_conv_msgs;
3311 ReportPrinter prev_recorder;
3313 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3314 : this (members, null, restrictions, loc)
3318 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3321 if (members == null || members.Count == 0)
3322 throw new ArgumentException ("empty members set");
3324 this.members = members;
3326 type_arguments = targs;
3327 this.restrictions = restrictions;
3328 if (IsDelegateInvoke)
3329 this.restrictions |= Restrictions.NoBaseMembers;
3331 base_provider = NoBaseMembers.Instance;
3336 public IBaseMembersProvider BaseMembersProvider {
3338 return base_provider;
3341 base_provider = value;
3345 public bool BestCandidateIsDynamic { get; set; }
3348 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3350 public MethodGroupExpr BestCandidateNewMethodGroup {
3352 return best_candidate_extension_group;
3357 // Return type can be different between best candidate and closest override
3359 public TypeSpec BestCandidateReturnType {
3361 return best_candidate_return_type;
3365 public IErrorHandler CustomErrors {
3367 return custom_errors;
3370 custom_errors = value;
3374 TypeSpec DelegateType {
3376 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3377 throw new InternalErrorException ("Not running in delegate mode", loc);
3379 return members [0].DeclaringType;
3383 bool IsProbingOnly {
3385 return (restrictions & Restrictions.ProbingOnly) != 0;
3389 bool IsDelegateInvoke {
3391 return (restrictions & Restrictions.DelegateInvoke) != 0;
3398 // 7.4.3.3 Better conversion from expression
3399 // Returns : 1 if a->p is better,
3400 // 2 if a->q is better,
3401 // 0 if neither is better
3403 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3405 TypeSpec argument_type = a.Type;
3406 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3408 // Uwrap delegate from Expression<T>
3410 if (p.GetDefinition () == TypeManager.expression_type) {
3411 p = TypeManager.GetTypeArguments (p)[0];
3413 if (q.GetDefinition () == TypeManager.expression_type) {
3414 q = TypeManager.GetTypeArguments (q)[0];
3417 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3418 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3419 if (p == TypeManager.void_type && q != TypeManager.void_type)
3421 if (q == TypeManager.void_type && p != TypeManager.void_type)
3424 if (argument_type == p)
3427 if (argument_type == q)
3431 return BetterTypeConversion (ec, p, q);
3435 // 7.4.3.4 Better conversion from type
3437 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3439 if (p == null || q == null)
3440 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3442 if (p == TypeManager.int32_type) {
3443 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3445 } else if (p == TypeManager.int64_type) {
3446 if (q == TypeManager.uint64_type)
3448 } else if (p == TypeManager.sbyte_type) {
3449 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3450 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3452 } else if (p == TypeManager.short_type) {
3453 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3454 q == TypeManager.uint64_type)
3456 } else if (p == InternalType.Dynamic) {
3457 // Dynamic is never better
3461 if (q == TypeManager.int32_type) {
3462 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3464 } if (q == TypeManager.int64_type) {
3465 if (p == TypeManager.uint64_type)
3467 } else if (q == TypeManager.sbyte_type) {
3468 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3469 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3471 } if (q == TypeManager.short_type) {
3472 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3473 p == TypeManager.uint64_type)
3475 } else if (q == InternalType.Dynamic) {
3476 // Dynamic is never better
3480 // FIXME: handle lifted operators
3482 // TODO: this is expensive
3483 Expression p_tmp = new EmptyExpression (p);
3484 Expression q_tmp = new EmptyExpression (q);
3486 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3487 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3489 if (p_to_q && !q_to_p)
3492 if (q_to_p && !p_to_q)
3499 /// Determines "Better function" between candidate
3500 /// and the current best match
3503 /// Returns a boolean indicating :
3504 /// false if candidate ain't better
3505 /// true if candidate is better than the current best match
3507 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3508 MemberSpec best, AParametersCollection bparam, bool best_params)
3510 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3511 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3513 bool better_at_least_one = false;
3515 int args_count = args == null ? 0 : args.Count;
3519 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3522 // Default arguments are ignored for better decision
3523 if (a.IsDefaultArgument)
3527 // When comparing named argument the parameter type index has to be looked up
3528 // in original parameter set (override version for virtual members)
3530 NamedArgument na = a as NamedArgument;
3532 int idx = cparam.GetParameterIndexByName (na.Name);
3533 ct = candidate_pd.Types[idx];
3534 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3535 ct = TypeManager.GetElementType (ct);
3537 idx = bparam.GetParameterIndexByName (na.Name);
3538 bt = best_pd.Types[idx];
3539 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3540 bt = TypeManager.GetElementType (bt);
3542 ct = candidate_pd.Types[c_idx];
3543 bt = best_pd.Types[b_idx];
3545 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3546 ct = TypeManager.GetElementType (ct);
3550 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3551 bt = TypeManager.GetElementType (bt);
3556 if (TypeSpecComparer.IsEqual (ct, bt))
3560 int result = BetterExpressionConversion (ec, a, ct, bt);
3562 // for each argument, the conversion to 'ct' should be no worse than
3563 // the conversion to 'bt'.
3567 // for at least one argument, the conversion to 'ct' should be better than
3568 // the conversion to 'bt'.
3570 better_at_least_one = true;
3573 if (better_at_least_one)
3577 // This handles the case
3579 // Add (float f1, float f2, float f3);
3580 // Add (params decimal [] foo);
3582 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3583 // first candidate would've chosen as better.
3585 if (!same && !a.IsDefaultArgument)
3589 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3593 // This handles the following cases:
3595 // Foo (int i) is better than Foo (int i, long l = 0)
3596 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3598 // Prefer non-optional version
3600 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3602 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3603 if (candidate_pd.Count >= best_pd.Count)
3606 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3613 // One is a non-generic method and second is a generic method, then non-generic is better
3615 if (best.IsGeneric != candidate.IsGeneric)
3616 return best.IsGeneric;
3619 // This handles the following cases:
3621 // Trim () is better than Trim (params char[] chars)
3622 // Concat (string s1, string s2, string s3) is better than
3623 // Concat (string s1, params string [] srest)
3624 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3626 // Prefer non-expanded version
3628 if (candidate_params != best_params)
3631 int candidate_param_count = candidate_pd.Count;
3632 int best_param_count = best_pd.Count;
3634 if (candidate_param_count != best_param_count)
3635 // can only happen if (candidate_params && best_params)
3636 return candidate_param_count > best_param_count && best_pd.HasParams;
3639 // Both methods have the same number of parameters, and the parameters have equal types
3640 // Pick the "more specific" signature using rules over original (non-inflated) types
3642 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3643 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3645 bool specific_at_least_once = false;
3646 for (j = 0; j < candidate_param_count; ++j) {
3647 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3649 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3650 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3652 ct = candidate_def_pd.Types[j];
3653 bt = best_def_pd.Types[j];
3658 TypeSpec specific = MoreSpecific (ct, bt);
3662 specific_at_least_once = true;
3665 if (specific_at_least_once)
3671 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3673 rc.Report.Error (1729, loc,
3674 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3675 type.GetSignatureForError (), argCount.ToString ());
3679 // Determines if the candidate method is applicable to the given set of arguments
3680 // There could be two different set of parameters for same candidate where one
3681 // is the closest override for default values and named arguments checks and second
3682 // one being the virtual base for the parameter types and modifiers.
3684 // A return value rates candidate method compatibility,
3685 // 0 = the best, int.MaxValue = the worst
3687 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)
3689 var pd = pm.Parameters;
3690 int param_count = pd.Count;
3691 int optional_count = 0;
3693 Arguments orig_args = arguments;
3695 if (arg_count != param_count) {
3696 for (int i = 0; i < pd.Count; ++i) {
3697 if (pd.FixedParameters[i].HasDefaultValue) {
3698 optional_count = pd.Count - i;
3703 int args_gap = System.Math.Abs (arg_count - param_count);
3704 if (optional_count != 0) {
3705 if (args_gap > optional_count)
3706 return int.MaxValue - 10000 + args_gap - optional_count;
3708 // Readjust expected number when params used
3711 if (arg_count < param_count)
3713 } else if (arg_count > param_count) {
3714 return int.MaxValue - 10000 + args_gap;
3716 } else if (arg_count != param_count) {
3718 return int.MaxValue - 10000 + args_gap;
3719 if (arg_count < param_count - 1)
3720 return int.MaxValue - 10000 + args_gap;
3723 // Resize to fit optional arguments
3724 if (optional_count != 0) {
3725 if (arguments == null) {
3726 arguments = new Arguments (optional_count);
3728 // Have to create a new container, so the next run can do same
3729 var resized = new Arguments (param_count);
3730 resized.AddRange (arguments);
3731 arguments = resized;
3734 for (int i = arg_count; i < param_count; ++i)
3735 arguments.Add (null);
3739 if (arg_count > 0) {
3741 // Shuffle named arguments to the right positions if there are any
3743 if (arguments[arg_count - 1] is NamedArgument) {
3744 arg_count = arguments.Count;
3746 for (int i = 0; i < arg_count; ++i) {
3747 bool arg_moved = false;
3749 NamedArgument na = arguments[i] as NamedArgument;
3753 int index = pd.GetParameterIndexByName (na.Name);
3755 // Named parameter not found
3759 // already reordered
3764 if (index >= param_count) {
3765 // When using parameters which should not be available to the user
3766 if ((pd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3769 arguments.Add (null);
3773 temp = arguments[index];
3775 // The slot has been taken by positional argument
3776 if (temp != null && !(temp is NamedArgument))
3781 arguments = arguments.MarkOrderedArgument (na);
3785 arguments[index] = arguments[i];
3786 arguments[i] = temp;
3793 arg_count = arguments.Count;
3795 } else if (arguments != null) {
3796 arg_count = arguments.Count;
3800 // 1. Handle generic method using type arguments when specified or type inference
3802 var ms = candidate as MethodSpec;
3803 if (ms != null && ms.IsGeneric) {
3804 // Setup constraint checker for probing only
3805 ConstraintChecker cc = new ConstraintChecker (null);
3807 if (type_arguments != null) {
3808 var g_args_count = ms.Arity;
3809 if (g_args_count != type_arguments.Count)
3810 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3812 ms = ms.MakeGenericMethod (type_arguments.Arguments);
3814 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3815 // for now it simplifies things. I should probably add a callback to ResolveContext
3816 if (lambda_conv_msgs == null) {
3817 lambda_conv_msgs = new SessionReportPrinter ();
3818 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3821 var ti = new TypeInference (arguments);
3822 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3823 lambda_conv_msgs.EndSession ();
3826 return ti.InferenceScore - 20000;
3828 if (i_args.Length != 0) {
3829 ms = ms.MakeGenericMethod (i_args);
3832 cc.IgnoreInferredDynamic = true;
3836 // Type arguments constraints have to match for the method to be applicable
3838 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3840 return int.MaxValue - 25000;
3844 // We have a generic return type and at same time the method is override which
3845 // means we have to also inflate override return type in case the candidate is
3846 // best candidate and override return type is different to base return type.
3848 // virtual Foo<T, object> with override Foo<T, dynamic>
3850 if (candidate != pm) {
3851 MethodSpec override_ms = (MethodSpec) pm;
3852 var inflator = new TypeParameterInflator (ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3853 returnType = inflator.Inflate (returnType);
3855 returnType = ms.ReturnType;
3861 if (type_arguments != null)
3862 return int.MaxValue - 15000;
3866 // 2. Each argument has to be implicitly convertible to method parameter
3868 Parameter.Modifier p_mod = 0;
3870 TypeSpec[] ptypes = ((IParametersMember) candidate).Parameters.Types;
3872 for (int i = 0; i < arg_count; i++) {
3873 Argument a = arguments[i];
3875 if (!pd.FixedParameters[i].HasDefaultValue) {
3876 arguments = orig_args;
3877 return arg_count * 2 + 2;
3881 // Get the default value expression, we can use the same expression
3882 // if the type matches
3884 Expression e = pd.FixedParameters[i].DefaultValue;
3885 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3887 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3889 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3890 e = new MemberAccess (new MemberAccess (new MemberAccess (
3891 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3893 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3899 arguments[i] = new Argument (e, Argument.AType.Default);
3903 if (p_mod != Parameter.Modifier.PARAMS) {
3904 p_mod = pd.FixedParameters[i].ModFlags;
3906 } else if (!params_expanded_form) {
3907 params_expanded_form = true;
3908 pt = ((ElementTypeSpec) pt).Element;
3914 if (!params_expanded_form) {
3915 if (a.ArgType == Argument.AType.ExtensionType) {
3917 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3920 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3921 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3922 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3927 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3930 dynamicArgument = true;
3935 // It can be applicable in expanded form (when not doing exact match like for delegates)
3937 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3938 if (!params_expanded_form)
3939 pt = ((ElementTypeSpec) pt).Element;
3942 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3945 params_expanded_form = true;
3946 } else if (score < 0) {
3947 params_expanded_form = true;
3948 dynamicArgument = true;
3953 if (params_expanded_form)
3955 return (arg_count - i) * 2 + score;
3960 // When params parameter has no argument it will be provided later if the method is the best candidate
3962 if (arg_count + 1 == pd.Count && (pd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
3963 params_expanded_form = true;
3966 // Restore original arguments for dynamic binder to keep the intention of original source code
3968 if (dynamicArgument)
3969 arguments = orig_args;
3975 // Tests argument compatibility with the parameter
3976 // The possible return values are
3978 // 1 - modifier mismatch
3979 // 2 - type mismatch
3980 // -1 - dynamic binding required
3982 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3985 // Types have to be identical when ref or out modifer
3986 // is used and argument is not of dynamic type
3988 if ((argument.Modifier | param_mod) != 0) {
3989 if (argument.Type != parameter) {
3991 // Do full equality check after quick path
3993 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
3995 // Using dynamic for ref/out parameter can still succeed at runtime
3997 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4004 if (argument.Modifier != param_mod) {
4006 // Using dynamic for ref/out parameter can still succeed at runtime
4008 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4015 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4019 // Deploy custom error reporting for lambda methods. When probing lambda methods
4020 // keep all errors reported in separate set and once we are done and no best
4021 // candidate found, this set is used to report more details about what was wrong
4024 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4025 if (lambda_conv_msgs == null) {
4026 lambda_conv_msgs = new SessionReportPrinter ();
4027 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4031 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4032 if (lambda_conv_msgs != null) {
4033 lambda_conv_msgs.EndSession ();
4043 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4045 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4047 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4050 var ac_p = p as ArrayContainer;
4052 var ac_q = ((ArrayContainer) q);
4053 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4054 if (specific == ac_p.Element)
4056 if (specific == ac_q.Element)
4058 } else if (TypeManager.IsGenericType (p)) {
4059 var pargs = TypeManager.GetTypeArguments (p);
4060 var qargs = TypeManager.GetTypeArguments (q);
4062 bool p_specific_at_least_once = false;
4063 bool q_specific_at_least_once = false;
4065 for (int i = 0; i < pargs.Length; i++) {
4066 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4067 if (specific == pargs[i])
4068 p_specific_at_least_once = true;
4069 if (specific == qargs[i])
4070 q_specific_at_least_once = true;
4073 if (p_specific_at_least_once && !q_specific_at_least_once)
4075 if (!p_specific_at_least_once && q_specific_at_least_once)
4083 // Find the best method from candidate list
4085 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4087 List<AmbiguousCandidate> ambiguous_candidates = null;
4089 MemberSpec best_candidate;
4090 Arguments best_candidate_args = null;
4091 bool best_candidate_params = false;
4092 bool best_candidate_dynamic = false;
4093 int best_candidate_rate;
4094 IParametersMember best_parameter_member = null;
4096 int args_count = args != null ? args.Count : 0;
4098 Arguments candidate_args = args;
4099 bool error_mode = false;
4100 var current_type = rc.CurrentType;
4101 MemberSpec invocable_member = null;
4103 // Be careful, cannot return until error reporter is restored
4105 best_candidate = null;
4106 best_candidate_rate = int.MaxValue;
4108 var type_members = members;
4112 for (int i = 0; i < type_members.Count; ++i) {
4113 var member = type_members[i];
4116 // Methods in a base class are not candidates if any method in a derived
4117 // class is applicable
4119 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4123 if (!member.IsAccessible (current_type))
4126 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4130 IParametersMember pm = member as IParametersMember;
4133 // Will use it later to report ambiguity between best method and invocable member
4135 if (Invocation.IsMemberInvocable (member))
4136 invocable_member = member;
4142 // Overload resolution is looking for base member but using parameter names
4143 // and default values from the closest member. That means to do expensive lookup
4144 // for the closest override for virtual or abstract members
4146 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4147 var override_params = base_provider.GetOverrideMemberParameters (member);
4148 if (override_params != null)
4149 pm = override_params;
4153 // Check if the member candidate is applicable
4155 bool params_expanded_form = false;
4156 bool dynamic_argument = false;
4157 TypeSpec rt = pm.MemberType;
4158 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4161 // How does it score compare to others
4163 if (candidate_rate < best_candidate_rate) {
4164 best_candidate_rate = candidate_rate;
4165 best_candidate = member;
4166 best_candidate_args = candidate_args;
4167 best_candidate_params = params_expanded_form;
4168 best_candidate_dynamic = dynamic_argument;
4169 best_parameter_member = pm;
4170 best_candidate_return_type = rt;
4171 } else if (candidate_rate == 0) {
4173 // The member look is done per type for most operations but sometimes
4174 // it's not possible like for binary operators overload because they
4175 // are unioned between 2 sides
4177 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4178 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4182 // Is the new candidate better
4183 if (BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params)) {
4184 best_candidate = member;
4185 best_candidate_args = candidate_args;
4186 best_candidate_params = params_expanded_form;
4187 best_candidate_dynamic = dynamic_argument;
4188 best_parameter_member = pm;
4189 best_candidate_return_type = rt;
4191 // It's not better but any other found later could be but we are not sure yet
4192 if (ambiguous_candidates == null)
4193 ambiguous_candidates = new List<AmbiguousCandidate> ();
4195 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4199 // Restore expanded arguments
4200 if (candidate_args != args)
4201 candidate_args = args;
4203 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4205 if (prev_recorder != null)
4206 rc.Report.SetPrinter (prev_recorder);
4210 // We've found exact match
4212 if (best_candidate_rate == 0)
4216 // Try extension methods lookup when no ordinary method match was found and provider enables it
4219 var emg = base_provider.LookupExtensionMethod (rc);
4221 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4223 best_candidate_extension_group = emg;
4224 return (T) (MemberSpec) emg.BestCandidate;
4229 // Don't run expensive error reporting mode for probing
4236 lambda_conv_msgs = null;
4241 // No best member match found, report an error
4243 if (best_candidate_rate != 0 || error_mode) {
4244 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4248 if (best_candidate_dynamic) {
4249 if (args[0].ArgType == Argument.AType.ExtensionType) {
4250 rc.Report.Error (1973, loc,
4251 "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",
4252 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4255 BestCandidateIsDynamic = true;
4259 if (ambiguous_candidates != null) {
4261 // Now check that there are no ambiguities i.e the selected method
4262 // should be better than all the others
4264 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4265 var candidate = ambiguous_candidates [ix];
4267 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4268 var ambiguous = candidate.Member;
4269 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4270 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4271 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4272 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4273 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4276 return (T) best_candidate;
4281 if (invocable_member != null) {
4282 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4283 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4284 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4285 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4289 // And now check if the arguments are all
4290 // compatible, perform conversions if
4291 // necessary etc. and return if everything is
4294 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4297 if (best_candidate == null)
4301 // Check ObsoleteAttribute on the best method
4303 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4304 if (oa != null && !rc.IsObsolete)
4305 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4307 best_candidate.MemberDefinition.SetIsUsed ();
4309 args = best_candidate_args;
4310 return (T) best_candidate;
4313 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4315 return ResolveMember<MethodSpec> (rc, ref args);
4318 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4319 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4321 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4324 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4325 ec.Report.SymbolRelatedToPreviousError (method);
4326 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4327 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4328 TypeManager.CSharpSignature (method));
4331 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4332 TypeManager.CSharpSignature (method));
4333 } else if (IsDelegateInvoke) {
4334 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4335 DelegateType.GetSignatureForError ());
4337 ec.Report.SymbolRelatedToPreviousError (method);
4338 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4339 method.GetSignatureForError ());
4342 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4344 string index = (idx + 1).ToString ();
4345 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4346 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4347 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4348 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4349 index, Parameter.GetModifierSignature (a.Modifier));
4351 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4352 index, Parameter.GetModifierSignature (mod));
4354 string p1 = a.GetSignatureForError ();
4355 string p2 = TypeManager.CSharpName (paramType);
4358 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4359 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4360 ec.Report.SymbolRelatedToPreviousError (paramType);
4363 ec.Report.Error (1503, loc,
4364 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4369 // We have failed to find exact match so we return error info about the closest match
4371 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4373 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4374 int arg_count = args == null ? 0 : args.Count;
4376 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4377 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4378 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4382 if (lambda_conv_msgs != null) {
4383 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4388 // For candidates which match on parameters count report more details about incorrect arguments
4391 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4392 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4393 // Reject any inaccessible member
4394 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4395 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4396 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4400 var ms = best_candidate as MethodSpec;
4401 if (ms != null && ms.IsGeneric) {
4402 bool constr_ok = true;
4403 if (ms.TypeArguments != null)
4404 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4406 if (ta_count == 0) {
4407 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4411 rc.Report.Error (411, loc,
4412 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4413 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4420 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4426 // We failed to find any method with correct argument count, report best candidate
4428 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4431 if (best_candidate.Kind == MemberKind.Constructor) {
4432 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4433 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4434 } else if (IsDelegateInvoke) {
4435 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4436 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4437 DelegateType.GetSignatureForError (), arg_count.ToString ());
4439 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4440 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4441 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4442 name, arg_count.ToString ());
4446 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4448 var pd = pm.Parameters;
4449 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4451 Parameter.Modifier p_mod = 0;
4453 int a_idx = 0, a_pos = 0;
4455 ArrayInitializer params_initializers = null;
4456 bool has_unsafe_arg = pm.MemberType.IsPointer;
4457 int arg_count = args == null ? 0 : args.Count;
4459 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4461 if (p_mod != Parameter.Modifier.PARAMS) {
4462 p_mod = pd.FixedParameters[a_idx].ModFlags;
4464 has_unsafe_arg |= pt.IsPointer;
4466 if (p_mod == Parameter.Modifier.PARAMS) {
4467 if (chose_params_expanded) {
4468 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4469 pt = TypeManager.GetElementType (pt);
4475 // Types have to be identical when ref or out modifer is used
4477 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4478 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4481 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4487 NamedArgument na = a as NamedArgument;
4489 int name_index = pd.GetParameterIndexByName (na.Name);
4490 if (name_index < 0 || name_index >= pd.Count) {
4491 if (IsDelegateInvoke) {
4492 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4493 ec.Report.Error (1746, na.Location,
4494 "The delegate `{0}' does not contain a parameter named `{1}'",
4495 DelegateType.GetSignatureForError (), na.Name);
4497 ec.Report.SymbolRelatedToPreviousError (member);
4498 ec.Report.Error (1739, na.Location,
4499 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4500 TypeManager.CSharpSignature (member), na.Name);
4502 } else if (args[name_index] != a) {
4503 if (IsDelegateInvoke)
4504 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4506 ec.Report.SymbolRelatedToPreviousError (member);
4508 ec.Report.Error (1744, na.Location,
4509 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4514 if (a.Expr.Type == InternalType.Dynamic)
4517 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4518 custom_errors.NoArgumentMatch (ec, member);
4522 Expression conv = null;
4523 if (a.ArgType == Argument.AType.ExtensionType) {
4524 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4527 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4529 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4532 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4539 // Convert params arguments to an array initializer
4541 if (params_initializers != null) {
4542 // we choose to use 'a.Expr' rather than 'conv' so that
4543 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4544 params_initializers.Add (a.Expr);
4545 args.RemoveAt (a_idx--);
4550 // Update the argument with the implicit conversion
4554 if (a_idx != arg_count) {
4555 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4560 // Fill not provided arguments required by params modifier
4562 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4564 args = new Arguments (1);
4566 pt = ptypes[pd.Count - 1];
4567 pt = TypeManager.GetElementType (pt);
4568 has_unsafe_arg |= pt.IsPointer;
4569 params_initializers = new ArrayInitializer (0, loc);
4573 // Append an array argument with all params arguments
4575 if (params_initializers != null) {
4576 args.Add (new Argument (
4577 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4581 if (has_unsafe_arg && !ec.IsUnsafe) {
4582 Expression.UnsafeError (ec, loc);
4586 // We could infer inaccesible type arguments
4588 if (type_arguments == null && member.IsGeneric) {
4589 var ms = (MethodSpec) member;
4590 foreach (var ta in ms.TypeArguments) {
4591 if (!ta.IsAccessible (ec.CurrentType)) {
4592 ec.Report.SymbolRelatedToPreviousError (ta);
4593 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4603 public class ConstantExpr : MemberExpr
4607 public ConstantExpr (ConstSpec constant, Location loc)
4609 this.constant = constant;
4613 public override string Name {
4614 get { throw new NotImplementedException (); }
4617 public override bool IsInstance {
4618 get { return !IsStatic; }
4621 public override bool IsStatic {
4622 get { return true; }
4625 protected override TypeSpec DeclaringType {
4626 get { return constant.DeclaringType; }
4629 public override Expression CreateExpressionTree (ResolveContext ec)
4631 throw new NotSupportedException ("ET");
4634 protected override Expression DoResolve (ResolveContext rc)
4636 ResolveInstanceExpression (rc, null);
4637 DoBestMemberChecks (rc, constant);
4639 var c = constant.GetConstant (rc);
4641 // Creates reference expression to the constant value
4642 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4645 public override void Emit (EmitContext ec)
4647 throw new NotSupportedException ();
4650 public override string GetSignatureForError ()
4652 return constant.GetSignatureForError ();
4655 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4657 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4662 /// Fully resolved expression that evaluates to a Field
4664 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4665 protected FieldSpec spec;
4666 VariableInfo variable_info;
4668 LocalTemporary temp;
4671 protected FieldExpr (Location l)
4676 public FieldExpr (FieldSpec spec, Location loc)
4681 type = spec.MemberType;
4684 public FieldExpr (FieldBase fi, Location l)
4691 public override string Name {
4697 public bool IsHoisted {
4699 IVariableReference hv = InstanceExpression as IVariableReference;
4700 return hv != null && hv.IsHoisted;
4704 public override bool IsInstance {
4706 return !spec.IsStatic;
4710 public override bool IsStatic {
4712 return spec.IsStatic;
4716 public FieldSpec Spec {
4722 protected override TypeSpec DeclaringType {
4724 return spec.DeclaringType;
4728 public VariableInfo VariableInfo {
4730 return variable_info;
4736 public override string GetSignatureForError ()
4738 return TypeManager.GetFullNameSignature (spec);
4741 public bool IsMarshalByRefAccess ()
4743 // Checks possible ldflda of field access expression
4744 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4745 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4746 !(InstanceExpression is This);
4749 public void SetHasAddressTaken ()
4751 IVariableReference vr = InstanceExpression as IVariableReference;
4753 vr.SetHasAddressTaken ();
4756 public override Expression CreateExpressionTree (ResolveContext ec)
4758 Expression instance;
4759 if (InstanceExpression == null) {
4760 instance = new NullLiteral (loc);
4762 instance = InstanceExpression.CreateExpressionTree (ec);
4765 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4767 CreateTypeOfExpression ());
4769 return CreateExpressionFactoryCall (ec, "Field", args);
4772 public Expression CreateTypeOfExpression ()
4774 return new TypeOfField (spec, loc);
4777 protected override Expression DoResolve (ResolveContext ec)
4779 return DoResolve (ec, null);
4782 Expression DoResolve (ResolveContext ec, Expression rhs)
4784 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4786 if (ResolveInstanceExpression (ec, rhs)) {
4787 // Resolve the field's instance expression while flow analysis is turned
4788 // off: when accessing a field "a.b", we must check whether the field
4789 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4791 if (lvalue_instance) {
4792 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4793 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4795 Expression right_side =
4796 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4798 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4801 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4802 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4806 if (InstanceExpression == null)
4810 DoBestMemberChecks (ec, spec);
4812 var fb = spec as FixedFieldSpec;
4813 IVariableReference var = InstanceExpression as IVariableReference;
4815 if (lvalue_instance && var != null && var.VariableInfo != null) {
4816 var.VariableInfo.SetFieldAssigned (ec, Name);
4820 IFixedExpression fe = InstanceExpression as IFixedExpression;
4821 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4822 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4825 if (InstanceExpression.eclass != ExprClass.Variable) {
4826 ec.Report.SymbolRelatedToPreviousError (spec);
4827 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4828 TypeManager.GetFullNameSignature (spec));
4829 } else if (var != null && var.IsHoisted) {
4830 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4833 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4836 eclass = ExprClass.Variable;
4838 // If the instance expression is a local variable or parameter.
4839 if (var == null || var.VariableInfo == null)
4842 VariableInfo vi = var.VariableInfo;
4843 if (!vi.IsFieldAssigned (ec, Name, loc))
4846 variable_info = vi.GetSubStruct (Name);
4850 static readonly int [] codes = {
4851 191, // instance, write access
4852 192, // instance, out access
4853 198, // static, write access
4854 199, // static, out access
4855 1648, // member of value instance, write access
4856 1649, // member of value instance, out access
4857 1650, // member of value static, write access
4858 1651 // member of value static, out access
4861 static readonly string [] msgs = {
4862 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4863 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4864 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4865 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4866 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4867 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4868 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4869 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4872 // The return value is always null. Returning a value simplifies calling code.
4873 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4876 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4880 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4882 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4887 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4889 Expression e = DoResolve (ec, right_side);
4894 spec.MemberDefinition.SetIsAssigned ();
4896 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4897 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4898 ec.Report.Warning (420, 1, loc,
4899 "`{0}': A volatile field references will not be treated as volatile",
4900 spec.GetSignatureForError ());
4903 if (spec.IsReadOnly) {
4904 // InitOnly fields can only be assigned in constructors or initializers
4905 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4906 return Report_AssignToReadonly (ec, right_side);
4908 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4910 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4911 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4912 return Report_AssignToReadonly (ec, right_side);
4913 // static InitOnly fields cannot be assigned-to in an instance constructor
4914 if (IsStatic && !ec.IsStatic)
4915 return Report_AssignToReadonly (ec, right_side);
4916 // instance constructors can't modify InitOnly fields of other instances of the same type
4917 if (!IsStatic && !(InstanceExpression is This))
4918 return Report_AssignToReadonly (ec, right_side);
4922 if (right_side == EmptyExpression.OutAccess.Instance &&
4923 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
4924 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4925 ec.Report.Warning (197, 1, loc,
4926 "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",
4927 GetSignatureForError ());
4930 eclass = ExprClass.Variable;
4934 public override int GetHashCode ()
4936 return spec.GetHashCode ();
4939 public bool IsFixed {
4942 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4944 IVariableReference variable = InstanceExpression as IVariableReference;
4945 if (variable != null)
4946 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4948 IFixedExpression fe = InstanceExpression as IFixedExpression;
4949 return fe != null && fe.IsFixed;
4953 public override bool Equals (object obj)
4955 FieldExpr fe = obj as FieldExpr;
4959 if (spec != fe.spec)
4962 if (InstanceExpression == null || fe.InstanceExpression == null)
4965 return InstanceExpression.Equals (fe.InstanceExpression);
4968 public void Emit (EmitContext ec, bool leave_copy)
4970 bool is_volatile = false;
4972 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4975 spec.MemberDefinition.SetIsUsed ();
4979 ec.Emit (OpCodes.Volatile);
4981 ec.Emit (OpCodes.Ldsfld, spec);
4984 EmitInstance (ec, false);
4986 // Optimization for build-in types
4987 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
4988 ec.EmitLoadFromPtr (type);
4990 var ff = spec as FixedFieldSpec;
4992 ec.Emit (OpCodes.Ldflda, spec);
4993 ec.Emit (OpCodes.Ldflda, ff.Element);
4996 ec.Emit (OpCodes.Volatile);
4998 ec.Emit (OpCodes.Ldfld, spec);
5004 ec.Emit (OpCodes.Dup);
5006 temp = new LocalTemporary (this.Type);
5012 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5014 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5016 EmitInstance (ec, prepared);
5020 ec.Emit (OpCodes.Dup);
5022 temp = new LocalTemporary (this.Type);
5027 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5028 ec.Emit (OpCodes.Volatile);
5030 spec.MemberDefinition.SetIsAssigned ();
5033 ec.Emit (OpCodes.Stsfld, spec);
5035 ec.Emit (OpCodes.Stfld, spec);
5044 public override void Emit (EmitContext ec)
5049 public override void EmitSideEffect (EmitContext ec)
5051 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5053 if (is_volatile) // || is_marshal_by_ref ())
5054 base.EmitSideEffect (ec);
5057 public void AddressOf (EmitContext ec, AddressOp mode)
5059 if ((mode & AddressOp.Store) != 0)
5060 spec.MemberDefinition.SetIsAssigned ();
5061 if ((mode & AddressOp.Load) != 0)
5062 spec.MemberDefinition.SetIsUsed ();
5065 // Handle initonly fields specially: make a copy and then
5066 // get the address of the copy.
5069 if (spec.IsReadOnly){
5071 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
5084 local = ec.DeclareLocal (type, false);
5085 ec.Emit (OpCodes.Stloc, local);
5086 ec.Emit (OpCodes.Ldloca, local);
5092 ec.Emit (OpCodes.Ldsflda, spec);
5095 EmitInstance (ec, false);
5096 ec.Emit (OpCodes.Ldflda, spec);
5100 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5102 return MakeExpression (ctx);
5105 public override SLE.Expression MakeExpression (BuilderContext ctx)
5107 return SLE.Expression.Field (
5108 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5109 spec.GetMetaInfo ());
5112 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5114 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5120 /// Expression that evaluates to a Property. The Assign class
5121 /// might set the `Value' expression if we are in an assignment.
5123 /// This is not an LValue because we need to re-write the expression, we
5124 /// can not take data from the stack and store it.
5126 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5128 public PropertyExpr (PropertySpec spec, Location l)
5131 best_candidate = spec;
5132 type = spec.MemberType;
5137 protected override TypeSpec DeclaringType {
5139 return best_candidate.DeclaringType;
5143 public override string Name {
5145 return best_candidate.Name;
5149 public override bool IsInstance {
5155 public override bool IsStatic {
5157 return best_candidate.IsStatic;
5161 public PropertySpec PropertyInfo {
5163 return best_candidate;
5169 public override Expression CreateExpressionTree (ResolveContext ec)
5172 if (IsSingleDimensionalArrayLength ()) {
5173 args = new Arguments (1);
5174 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5175 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5178 args = new Arguments (2);
5179 if (InstanceExpression == null)
5180 args.Add (new Argument (new NullLiteral (loc)));
5182 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5183 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5184 return CreateExpressionFactoryCall (ec, "Property", args);
5187 public Expression CreateSetterTypeOfExpression ()
5189 return new TypeOfMethod (Setter, loc);
5192 public override string GetSignatureForError ()
5194 return best_candidate.GetSignatureForError ();
5197 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5199 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5202 public override SLE.Expression MakeExpression (BuilderContext ctx)
5204 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5207 void Error_PropertyNotValid (ResolveContext ec)
5209 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5210 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5211 GetSignatureForError ());
5214 bool IsSingleDimensionalArrayLength ()
5216 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5219 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5220 return ac != null && ac.Rank == 1;
5223 public override void Emit (EmitContext ec, bool leave_copy)
5226 // Special case: length of single dimension array property is turned into ldlen
5228 if (IsSingleDimensionalArrayLength ()) {
5230 EmitInstance (ec, false);
5231 ec.Emit (OpCodes.Ldlen);
5232 ec.Emit (OpCodes.Conv_I4);
5236 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5239 ec.Emit (OpCodes.Dup);
5241 temp = new LocalTemporary (this.Type);
5247 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5251 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5252 args = new Arguments (0);
5257 ec.Emit (OpCodes.Dup);
5259 temp = new LocalTemporary (this.Type);
5264 args = new Arguments (1);
5268 temp = new LocalTemporary (this.Type);
5270 args.Add (new Argument (temp));
5272 args.Add (new Argument (source));
5276 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5284 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5286 eclass = ExprClass.PropertyAccess;
5288 if (best_candidate.IsNotRealProperty) {
5289 Error_PropertyNotValid (rc);
5292 ResolveInstanceExpression (rc, right_side);
5294 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5295 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5296 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5298 type = p.MemberType;
5302 DoBestMemberChecks (rc, best_candidate);
5306 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5308 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5312 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5314 // getter and setter can be different for base calls
5315 MethodSpec getter, setter;
5316 protected T best_candidate;
5318 protected LocalTemporary temp;
5319 protected bool prepared;
5321 protected PropertyOrIndexerExpr (Location l)
5328 public MethodSpec Getter {
5337 public MethodSpec Setter {
5348 protected override Expression DoResolve (ResolveContext ec)
5350 if (eclass == ExprClass.Unresolved) {
5351 var expr = OverloadResolve (ec, null);
5356 return expr.Resolve (ec);
5359 if (!ResolveGetter (ec))
5365 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5367 if (right_side == EmptyExpression.OutAccess.Instance) {
5368 // TODO: best_candidate can be null at this point
5369 INamedBlockVariable variable = null;
5370 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5371 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5372 best_candidate.Name);
5374 right_side.DoResolveLValue (ec, this);
5379 // if the property/indexer returns a value type, and we try to set a field in it
5380 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5381 Error_CannotModifyIntermediateExpressionValue (ec);
5384 if (eclass == ExprClass.Unresolved) {
5385 var expr = OverloadResolve (ec, right_side);
5390 return expr.ResolveLValue (ec, right_side);
5393 if (!ResolveSetter (ec))
5400 // Implements the IAssignMethod interface for assignments
5402 public abstract void Emit (EmitContext ec, bool leave_copy);
5403 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5405 public override void Emit (EmitContext ec)
5410 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5412 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5414 bool ResolveGetter (ResolveContext rc)
5416 if (!best_candidate.HasGet) {
5417 if (InstanceExpression != EmptyExpression.Null) {
5418 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5419 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5420 best_candidate.GetSignatureForError ());
5423 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5424 if (best_candidate.HasDifferentAccessibility) {
5425 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5426 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5427 TypeManager.CSharpSignature (best_candidate));
5429 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5430 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5434 if (best_candidate.HasDifferentAccessibility) {
5435 CheckProtectedMemberAccess (rc, best_candidate.Get);
5438 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5442 bool ResolveSetter (ResolveContext rc)
5444 if (!best_candidate.HasSet) {
5445 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5446 GetSignatureForError ());
5450 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5451 if (best_candidate.HasDifferentAccessibility) {
5452 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5453 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5454 GetSignatureForError ());
5456 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5457 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5461 if (best_candidate.HasDifferentAccessibility)
5462 CheckProtectedMemberAccess (rc, best_candidate.Set);
5464 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5470 /// Fully resolved expression that evaluates to an Event
5472 public class EventExpr : MemberExpr, IAssignMethod
5474 readonly EventSpec spec;
5477 public EventExpr (EventSpec spec, Location loc)
5485 protected override TypeSpec DeclaringType {
5487 return spec.DeclaringType;
5491 public override string Name {
5497 public override bool IsInstance {
5499 return !spec.IsStatic;
5503 public override bool IsStatic {
5505 return spec.IsStatic;
5509 public MethodSpec Operator {
5517 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5520 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5522 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5523 if (spec.BackingField != null &&
5524 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType))) {
5526 spec.MemberDefinition.SetIsUsed ();
5528 if (!ec.IsObsolete) {
5529 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5531 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5534 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5535 Error_AssignmentEventOnly (ec);
5537 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5539 InstanceExpression = null;
5541 return ml.ResolveMemberAccess (ec, left, original);
5545 return base.ResolveMemberAccess (ec, left, original);
5548 public override Expression CreateExpressionTree (ResolveContext ec)
5550 throw new NotSupportedException ("ET");
5553 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5555 if (right_side == EmptyExpression.EventAddition) {
5556 op = spec.AccessorAdd;
5557 } else if (right_side == EmptyExpression.EventSubtraction) {
5558 op = spec.AccessorRemove;
5562 Error_AssignmentEventOnly (ec);
5566 op = CandidateToBaseOverride (ec, op);
5570 protected override Expression DoResolve (ResolveContext ec)
5572 eclass = ExprClass.EventAccess;
5573 type = spec.MemberType;
5575 ResolveInstanceExpression (ec, null);
5577 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5578 Error_AssignmentEventOnly (ec);
5581 DoBestMemberChecks (ec, spec);
5585 public override void Emit (EmitContext ec)
5587 throw new NotSupportedException ();
5588 //Error_CannotAssign ();
5591 #region IAssignMethod Members
5593 public void Emit (EmitContext ec, bool leave_copy)
5595 throw new NotImplementedException ();
5598 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5600 if (leave_copy || !prepare_for_load)
5601 throw new NotImplementedException ("EventExpr::EmitAssign");
5603 Arguments args = new Arguments (1);
5604 args.Add (new Argument (source));
5605 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5610 void Error_AssignmentEventOnly (ResolveContext ec)
5612 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType)) {
5613 ec.Report.Error (79, loc,
5614 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5615 GetSignatureForError ());
5617 ec.Report.Error (70, loc,
5618 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5619 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5623 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5625 name = name.Substring (0, name.LastIndexOf ('.'));
5626 base.Error_CannotCallAbstractBase (rc, name);
5629 public override string GetSignatureForError ()
5631 return TypeManager.CSharpSignature (spec);
5634 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5636 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5640 public class TemporaryVariableReference : VariableReference
5642 public class Declarator : Statement
5644 TemporaryVariableReference variable;
5646 public Declarator (TemporaryVariableReference variable)
5648 this.variable = variable;
5652 protected override void DoEmit (EmitContext ec)
5654 variable.li.CreateBuilder (ec);
5657 protected override void CloneTo (CloneContext clonectx, Statement target)
5665 public TemporaryVariableReference (LocalVariable li, Location loc)
5668 this.type = li.Type;
5672 public override bool IsLockedByStatement {
5680 public LocalVariable LocalInfo {
5686 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5688 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5689 return new TemporaryVariableReference (li, loc);
5692 public override Expression CreateExpressionTree (ResolveContext ec)
5694 throw new NotSupportedException ("ET");
5697 protected override Expression DoResolve (ResolveContext ec)
5699 eclass = ExprClass.Variable;
5702 // Don't capture temporary variables except when using
5703 // iterator redirection
5705 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5706 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5707 storey.CaptureLocalVariable (ec, li);
5713 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5715 return Resolve (ec);
5718 public override void Emit (EmitContext ec)
5720 li.CreateBuilder (ec);
5725 public void EmitAssign (EmitContext ec, Expression source)
5727 li.CreateBuilder (ec);
5729 EmitAssign (ec, source, false, false);
5732 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5734 return li.HoistedVariant;
5737 public override bool IsFixed {
5738 get { return true; }
5741 public override bool IsRef {
5742 get { return false; }
5745 public override string Name {
5746 get { throw new NotImplementedException (); }
5749 public override void SetHasAddressTaken ()
5751 throw new NotImplementedException ();
5754 protected override ILocalVariable Variable {
5758 public override VariableInfo VariableInfo {
5759 get { throw new NotImplementedException (); }
5764 /// Handles `var' contextual keyword; var becomes a keyword only
5765 /// if no type called var exists in a variable scope
5767 class VarExpr : SimpleName
5769 public VarExpr (Location loc)
5774 public bool InferType (ResolveContext ec, Expression right_side)
5777 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5779 type = right_side.Type;
5780 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5781 ec.Report.Error (815, loc,
5782 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5783 type.GetSignatureForError ());
5787 eclass = ExprClass.Variable;
5791 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5793 if (RootContext.Version < LanguageVersion.V_3)
5794 base.Error_TypeOrNamespaceNotFound (ec);
5796 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");