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;
16 using SLE = System.Linq.Expressions;
20 using IKVM.Reflection;
21 using IKVM.Reflection.Emit;
23 using System.Reflection;
24 using System.Reflection.Emit;
27 namespace Mono.CSharp {
30 /// The ExprClass class contains the is used to pass the
31 /// classification of an expression (value, variable, namespace,
32 /// type, method group, property access, event access, indexer access,
35 public enum ExprClass : byte {
51 /// This is used to tell Resolve in which types of expressions we're
55 public enum ResolveFlags {
56 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
59 // Returns a type expression.
62 // Returns a method group.
65 TypeParameter = 1 << 3,
67 // Mask of all the expression class flags.
68 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
72 // This is just as a hint to AddressOf of what will be done with the
75 public enum AddressOp {
82 /// This interface is implemented by variables
84 public interface IMemoryLocation {
86 /// The AddressOf method should generate code that loads
87 /// the address of the object and leaves it on the stack.
89 /// The `mode' argument is used to notify the expression
90 /// of whether this will be used to read from the address or
91 /// write to the address.
93 /// This is just a hint that can be used to provide good error
94 /// reporting, and should have no other side effects.
96 void AddressOf (EmitContext ec, AddressOp mode);
100 // An expressions resolved as a direct variable reference
102 public interface IVariableReference : IFixedExpression
104 bool IsHoisted { get; }
106 VariableInfo VariableInfo { get; }
108 void SetHasAddressTaken ();
112 // Implemented by an expression which could be or is always
115 public interface IFixedExpression
117 bool IsFixed { get; }
121 /// Base class for expressions
123 public abstract class Expression {
124 public ExprClass eclass;
125 protected TypeSpec type;
126 protected Location loc;
128 public TypeSpec Type {
130 set { type = value; }
133 public Location Location {
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public virtual bool IsNull {
149 /// Performs semantic analysis on the Expression
153 /// The Resolve method is invoked to perform the semantic analysis
156 /// The return value is an expression (it can be the
157 /// same expression in some cases) or a new
158 /// expression that better represents this node.
160 /// For example, optimizations of Unary (LiteralInt)
161 /// would return a new LiteralInt with a negated
164 /// If there is an error during semantic analysis,
165 /// then an error should be reported (using Report)
166 /// and a null value should be returned.
168 /// There are two side effects expected from calling
169 /// Resolve(): the the field variable "eclass" should
170 /// be set to any value of the enumeration
171 /// `ExprClass' and the type variable should be set
172 /// to a valid type (this is the type of the
175 protected abstract Expression DoResolve (ResolveContext rc);
177 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
183 // This is used if the expression should be resolved as a type or namespace name.
184 // the default implementation fails.
186 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
189 ResolveContext ec = new ResolveContext (rc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
199 // This is used to resolve the expression as a type, a null
200 // value will be returned if the expression is not a type
203 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
205 int errors = ec.Compiler.Report.Errors;
207 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
212 TypeExpr te = fne as TypeExpr;
214 if (!silent && errors == ec.Compiler.Report.Errors)
215 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
219 if (!te.type.IsAccessible (ec.CurrentType)) {
220 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
221 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
226 var dep = te.type.GetMissingDependencies ();
228 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
232 // Obsolete checks cannot be done when resolving base context as they
233 // require type dependecies to be set but we are just resolving them
235 if (!silent && !(ec is TypeContainer.BaseContext)) {
236 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
237 if (obsolete_attr != null && !ec.IsObsolete) {
238 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
245 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
247 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
250 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
252 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
255 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
257 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
258 name, TypeManager.CSharpName (type));
261 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
263 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
264 "expressions can be used as a statement");
267 public void Error_InvalidExpressionStatement (BlockContext ec)
269 Error_InvalidExpressionStatement (ec.Report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 string from_type = type.GetSignatureForError ();
289 string to_type = target.GetSignatureForError ();
290 if (from_type == to_type) {
291 from_type = string.Format ("{0} [{1}]", from_type, type.MemberDefinition.DeclaringAssembly.FullName);
292 to_type = string.Format ("{0} [{1}]", to_type, target.MemberDefinition.DeclaringAssembly.FullName);
296 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
301 ec.Report.DisableReporting ();
302 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
303 ec.Report.EnableReporting ();
306 ec.Report.Error (266, loc,
307 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
310 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
315 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
317 // Better message for possible generic expressions
318 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
319 report.SymbolRelatedToPreviousError (member);
320 if (member is TypeSpec)
321 member = ((TypeSpec) member).GetDefinition ();
323 member = ((MethodSpec) member).GetGenericMethodDefinition ();
325 string name = member.Kind == MemberKind.Method ? "method" : "type";
326 if (member.IsGeneric) {
327 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
328 name, member.GetSignatureForError (), member.Arity.ToString ());
330 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
331 name, member.GetSignatureForError ());
334 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
338 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
340 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
344 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
346 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
349 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
351 ec.Report.SymbolRelatedToPreviousError (type);
352 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
353 TypeManager.CSharpName (type), name);
356 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
358 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
361 protected void Error_VoidPointerOperation (ResolveContext rc)
363 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
366 public ResolveFlags ExprClassToResolveFlags {
370 case ExprClass.Namespace:
371 return ResolveFlags.Type;
373 case ExprClass.MethodGroup:
374 return ResolveFlags.MethodGroup;
376 case ExprClass.TypeParameter:
377 return ResolveFlags.TypeParameter;
379 case ExprClass.Value:
380 case ExprClass.Variable:
381 case ExprClass.PropertyAccess:
382 case ExprClass.EventAccess:
383 case ExprClass.IndexerAccess:
384 return ResolveFlags.VariableOrValue;
387 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
393 /// Resolves an expression and performs semantic analysis on it.
397 /// Currently Resolve wraps DoResolve to perform sanity
398 /// checking and assertion checking on what we expect from Resolve.
400 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
402 if (eclass != ExprClass.Unresolved)
412 if ((flags & e.ExprClassToResolveFlags) == 0) {
413 e.Error_UnexpectedKind (ec, flags, loc);
418 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
421 } catch (Exception ex) {
422 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
425 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
426 return EmptyExpression.Null; // TODO: Add location
431 /// Resolves an expression and performs semantic analysis on it.
433 public Expression Resolve (ResolveContext rc)
435 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
439 /// Resolves an expression for LValue assignment
443 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
444 /// checking and assertion checking on what we expect from Resolve
446 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
448 int errors = ec.Report.Errors;
449 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
451 Expression e = DoResolveLValue (ec, right_side);
453 if (e != null && out_access && !(e is IMemoryLocation)) {
454 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
455 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
457 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
458 // e.GetType () + " " + e.GetSignatureForError ());
463 if (errors == ec.Report.Errors) {
465 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
467 Error_ValueAssignment (ec, loc);
472 if (e.eclass == ExprClass.Unresolved)
473 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
475 if ((e.type == null) && !(e is GenericTypeExpr))
476 throw new Exception ("Expression " + e + " did not set its type after Resolve");
481 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
483 rc.Compiler.Report.Error (182, loc,
484 "An attribute argument must be a constant expression, typeof expression or array creation expression");
488 /// Emits the code for the expression
492 /// The Emit method is invoked to generate the code
493 /// for the expression.
495 public abstract void Emit (EmitContext ec);
498 // Emit code to branch to @target if this expression is equivalent to @on_true.
499 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
500 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
501 // including the use of conditional branches. Note also that a branch MUST be emitted
502 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
505 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
508 // Emit this expression for its side effects, not for its value.
509 // The default implementation is to emit the value, and then throw it away.
510 // Subclasses can provide more efficient implementations, but those MUST be equivalent
511 public virtual void EmitSideEffect (EmitContext ec)
514 ec.Emit (OpCodes.Pop);
518 /// Protected constructor. Only derivate types should
519 /// be able to be created
522 protected Expression ()
527 /// Returns a fully formed expression after a MemberLookup
530 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
532 if (spec is EventSpec)
533 return new EventExpr ((EventSpec) spec, loc);
534 if (spec is ConstSpec)
535 return new ConstantExpr ((ConstSpec) spec, loc);
536 if (spec is FieldSpec)
537 return new FieldExpr ((FieldSpec) spec, loc);
538 if (spec is PropertySpec)
539 return new PropertyExpr ((PropertySpec) spec, loc);
540 if (spec is TypeSpec)
541 return new TypeExpression (((TypeSpec) spec), loc);
546 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
548 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
550 rc.Report.SymbolRelatedToPreviousError (type);
552 // Report meaningful error for struct as they always have default ctor in C# context
553 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
555 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
556 type.GetSignatureForError ());
562 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
563 return r.ResolveMember<MethodSpec> (rc, ref args);
567 public enum MemberLookupRestrictions
576 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
577 // `qualifier_type' or null to lookup members in the current class.
579 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
581 var members = MemberCache.FindMembers (queried_type, name, false);
585 MemberSpec non_method = null;
586 MemberSpec ambig_non_method = null;
587 currentType = currentType ?? InternalType.FakeInternalType;
589 for (int i = 0; i < members.Count; ++i) {
590 var member = members[i];
592 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
593 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
596 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
600 if (!member.IsAccessible (currentType))
604 // With runtime binder we can have a situation where queried type is inaccessible
605 // because it came via dynamic object, the check about inconsisted accessibility
606 // had no effect as the type was unknown during compilation
609 // private class N { }
611 // public dynamic Foo ()
617 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (currentType))
621 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
622 if (member is MethodSpec)
623 return new MethodGroupExpr (members, queried_type, loc);
625 if (!Invocation.IsMemberInvocable (member))
629 if (non_method == null || member is MethodSpec) {
631 } else if (currentType != null) {
632 ambig_non_method = member;
636 if (non_method != null) {
637 if (ambig_non_method != null && rc != null) {
638 rc.Report.SymbolRelatedToPreviousError (non_method);
639 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
640 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
641 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
644 if (non_method is MethodSpec)
645 return new MethodGroupExpr (members, queried_type, loc);
647 return ExprClassFromMemberInfo (non_method, loc);
650 if (members[0].DeclaringType.BaseType == null)
653 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
655 } while (members != null);
660 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
662 throw new NotImplementedException ();
665 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
667 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
671 /// Returns an expression that can be used to invoke operator true
672 /// on the expression if it exists.
674 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
676 return GetOperatorTrueOrFalse (ec, e, true, loc);
680 /// Returns an expression that can be used to invoke operator false
681 /// on the expression if it exists.
683 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
685 return GetOperatorTrueOrFalse (ec, e, false, loc);
688 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
690 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
691 var methods = MemberCache.GetUserOperator (e.type, op, false);
695 Arguments arguments = new Arguments (1);
696 arguments.Add (new Argument (e));
698 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
699 var oper = res.ResolveOperator (ec, ref arguments);
704 return new UserOperatorCall (oper, arguments, null, loc);
707 public virtual string ExprClassName
711 case ExprClass.Unresolved:
713 case ExprClass.Value:
715 case ExprClass.Variable:
717 case ExprClass.Namespace:
721 case ExprClass.MethodGroup:
722 return "method group";
723 case ExprClass.PropertyAccess:
724 return "property access";
725 case ExprClass.EventAccess:
726 return "event access";
727 case ExprClass.IndexerAccess:
728 return "indexer access";
729 case ExprClass.Nothing:
731 case ExprClass.TypeParameter:
732 return "type parameter";
734 throw new Exception ("Should not happen");
739 /// Reports that we were expecting `expr' to be of class `expected'
741 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
743 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
746 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
750 name = mc.GetSignatureForError ();
752 name = GetSignatureForError ();
754 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
755 name, was, expected);
758 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
760 string [] valid = new string [4];
763 if ((flags & ResolveFlags.VariableOrValue) != 0) {
764 valid [count++] = "variable";
765 valid [count++] = "value";
768 if ((flags & ResolveFlags.Type) != 0)
769 valid [count++] = "type";
771 if ((flags & ResolveFlags.MethodGroup) != 0)
772 valid [count++] = "method group";
775 valid [count++] = "unknown";
777 StringBuilder sb = new StringBuilder (valid [0]);
778 for (int i = 1; i < count - 1; i++) {
780 sb.Append (valid [i]);
783 sb.Append ("' or `");
784 sb.Append (valid [count - 1]);
787 ec.Report.Error (119, loc,
788 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
791 public static void UnsafeError (ResolveContext ec, Location loc)
793 UnsafeError (ec.Report, loc);
796 public static void UnsafeError (Report Report, Location loc)
798 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
803 // Returns the size of type `t' if known, otherwise, 0
805 public static int GetTypeSize (TypeSpec t)
807 if (t == TypeManager.int32_type ||
808 t == TypeManager.uint32_type ||
809 t == TypeManager.float_type)
811 else if (t == TypeManager.int64_type ||
812 t == TypeManager.uint64_type ||
813 t == TypeManager.double_type)
815 else if (t == TypeManager.byte_type ||
816 t == TypeManager.sbyte_type ||
817 t == TypeManager.bool_type)
819 else if (t == TypeManager.short_type ||
820 t == TypeManager.char_type ||
821 t == TypeManager.ushort_type)
823 else if (t == TypeManager.decimal_type)
829 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
831 ec.Report.SymbolRelatedToPreviousError (type);
832 if (ec.CurrentInitializerVariable != null) {
833 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
834 TypeManager.CSharpName (type), GetSignatureForError ());
836 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
837 GetSignatureForError ());
842 // Converts `source' to an int, uint, long or ulong.
844 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
846 if (source.type == InternalType.Dynamic) {
847 Arguments args = new Arguments (1);
848 args.Add (new Argument (source));
849 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
852 Expression converted;
854 using (ec.Set (ResolveContext.Options.CheckedScope)) {
855 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
856 if (converted == null)
857 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
858 if (converted == null)
859 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
860 if (converted == null)
861 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
863 if (converted == null) {
864 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
870 // Only positive constants are allowed at compile time
872 Constant c = converted as Constant;
873 if (c != null && c.IsNegative)
874 Error_NegativeArrayIndex (ec, source.loc);
876 // No conversion needed to array index
877 if (converted.Type == TypeManager.int32_type)
880 return new ArrayIndexCast (converted).Resolve (ec);
884 // Derived classes implement this method by cloning the fields that
885 // could become altered during the Resolve stage
887 // Only expressions that are created for the parser need to implement
890 protected virtual void CloneTo (CloneContext clonectx, Expression target)
892 throw new NotImplementedException (
894 "CloneTo not implemented for expression {0}", this.GetType ()));
898 // Clones an expression created by the parser.
900 // We only support expressions created by the parser so far, not
901 // expressions that have been resolved (many more classes would need
902 // to implement CloneTo).
904 // This infrastructure is here merely for Lambda expressions which
905 // compile the same code using different type values for the same
906 // arguments to find the correct overload
908 public virtual Expression Clone (CloneContext clonectx)
910 Expression cloned = (Expression) MemberwiseClone ();
911 CloneTo (clonectx, cloned);
917 // Implementation of expression to expression tree conversion
919 public abstract Expression CreateExpressionTree (ResolveContext ec);
921 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
923 return CreateExpressionFactoryCall (ec, name, null, args, loc);
926 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
928 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
931 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
933 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
936 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
938 var t = ec.Module.PredefinedTypes.Expression.Resolve (loc);
942 return new TypeExpression (t, loc);
946 // Implemented by all expressions which support conversion from
947 // compiler expression to invokable runtime expression. Used by
948 // dynamic C# binder.
950 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
952 throw new NotImplementedException ("MakeExpression for " + GetType ());
957 /// This is just a base class for expressions that can
958 /// appear on statements (invocations, object creation,
959 /// assignments, post/pre increment and decrement). The idea
960 /// being that they would support an extra Emition interface that
961 /// does not leave a result on the stack.
963 public abstract class ExpressionStatement : Expression {
965 public ExpressionStatement ResolveStatement (BlockContext ec)
967 Expression e = Resolve (ec);
971 ExpressionStatement es = e as ExpressionStatement;
973 Error_InvalidExpressionStatement (ec);
979 /// Requests the expression to be emitted in a `statement'
980 /// context. This means that no new value is left on the
981 /// stack after invoking this method (constrasted with
982 /// Emit that will always leave a value on the stack).
984 public abstract void EmitStatement (EmitContext ec);
986 public override void EmitSideEffect (EmitContext ec)
993 /// This kind of cast is used to encapsulate the child
994 /// whose type is child.Type into an expression that is
995 /// reported to return "return_type". This is used to encapsulate
996 /// expressions which have compatible types, but need to be dealt
997 /// at higher levels with.
999 /// For example, a "byte" expression could be encapsulated in one
1000 /// of these as an "unsigned int". The type for the expression
1001 /// would be "unsigned int".
1004 public abstract class TypeCast : Expression
1006 protected readonly Expression child;
1008 protected TypeCast (Expression child, TypeSpec return_type)
1010 eclass = child.eclass;
1011 loc = child.Location;
1016 public Expression Child {
1022 public override Expression CreateExpressionTree (ResolveContext ec)
1024 Arguments args = new Arguments (2);
1025 args.Add (new Argument (child.CreateExpressionTree (ec)));
1026 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1028 if (type.IsPointer || child.Type.IsPointer)
1029 Error_PointerInsideExpressionTree (ec);
1031 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1034 protected override Expression DoResolve (ResolveContext ec)
1036 // This should never be invoked, we are born in fully
1037 // initialized state.
1042 public override void Emit (EmitContext ec)
1047 public override SLE.Expression MakeExpression (BuilderContext ctx)
1050 return base.MakeExpression (ctx);
1052 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1053 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1054 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1058 protected override void CloneTo (CloneContext clonectx, Expression t)
1063 public override bool IsNull {
1064 get { return child.IsNull; }
1068 public class EmptyCast : TypeCast {
1069 EmptyCast (Expression child, TypeSpec target_type)
1070 : base (child, target_type)
1074 public static Expression Create (Expression child, TypeSpec type)
1076 Constant c = child as Constant;
1078 return new EmptyConstantCast (c, type);
1080 EmptyCast e = child as EmptyCast;
1082 return new EmptyCast (e.child, type);
1084 return new EmptyCast (child, type);
1087 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1089 child.EmitBranchable (ec, label, on_true);
1092 public override void EmitSideEffect (EmitContext ec)
1094 child.EmitSideEffect (ec);
1099 // Used for predefined class library user casts (no obsolete check, etc.)
1101 public class OperatorCast : TypeCast {
1102 MethodSpec conversion_operator;
1104 public OperatorCast (Expression child, TypeSpec target_type)
1105 : this (child, target_type, false)
1109 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1110 : base (child, target_type)
1112 conversion_operator = GetConversionOperator (find_explicit);
1113 if (conversion_operator == null)
1114 throw new InternalErrorException ("Outer conversion routine is out of sync");
1117 // Returns the implicit operator that converts from
1118 // 'child.Type' to our target type (type)
1119 MethodSpec GetConversionOperator (bool find_explicit)
1121 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1123 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1125 mi = MemberCache.GetUserOperator (type, op, true);
1128 foreach (MethodSpec oper in mi) {
1129 if (oper.ReturnType != type)
1132 if (oper.Parameters.Types [0] == child.Type)
1139 public override void Emit (EmitContext ec)
1142 ec.Emit (OpCodes.Call, conversion_operator);
1147 /// This is a numeric cast to a Decimal
1149 public class CastToDecimal : OperatorCast {
1150 public CastToDecimal (Expression child)
1151 : this (child, false)
1155 public CastToDecimal (Expression child, bool find_explicit)
1156 : base (child, TypeManager.decimal_type, find_explicit)
1162 /// This is an explicit numeric cast from a Decimal
1164 public class CastFromDecimal : TypeCast
1166 static Dictionary<TypeSpec, MethodSpec> operators;
1168 public CastFromDecimal (Expression child, TypeSpec return_type)
1169 : base (child, return_type)
1171 if (child.Type != TypeManager.decimal_type)
1172 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1175 // Returns the explicit operator that converts from an
1176 // express of type System.Decimal to 'type'.
1177 public Expression Resolve ()
1179 if (operators == null) {
1180 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1182 operators = new Dictionary<TypeSpec, MethodSpec> ();
1183 foreach (MethodSpec oper in all_oper) {
1184 AParametersCollection pd = oper.Parameters;
1185 if (pd.Types [0] == TypeManager.decimal_type)
1186 operators.Add (oper.ReturnType, oper);
1190 return operators.ContainsKey (type) ? this : null;
1193 public override void Emit (EmitContext ec)
1197 ec.Emit (OpCodes.Call, operators [type]);
1200 public static void Reset ()
1208 // Constant specialization of EmptyCast.
1209 // We need to special case this since an empty cast of
1210 // a constant is still a constant.
1212 public class EmptyConstantCast : Constant
1214 public Constant child;
1216 public EmptyConstantCast (Constant child, TypeSpec type)
1217 : base (child.Location)
1220 throw new ArgumentNullException ("child");
1223 this.eclass = child.eclass;
1227 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1229 if (child.Type == target_type)
1232 // FIXME: check that 'type' can be converted to 'target_type' first
1233 return child.ConvertExplicitly (in_checked_context, target_type);
1236 public override Expression CreateExpressionTree (ResolveContext ec)
1238 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1239 child.CreateExpressionTree (ec),
1240 new TypeOf (new TypeExpression (type, loc), loc));
1243 Error_PointerInsideExpressionTree (ec);
1245 return CreateExpressionFactoryCall (ec, "Convert", args);
1248 public override bool IsDefaultValue {
1249 get { return child.IsDefaultValue; }
1252 public override bool IsNegative {
1253 get { return child.IsNegative; }
1256 public override bool IsNull {
1257 get { return child.IsNull; }
1260 public override bool IsOneInteger {
1261 get { return child.IsOneInteger; }
1264 public override bool IsZeroInteger {
1265 get { return child.IsZeroInteger; }
1268 protected override Expression DoResolve (ResolveContext rc)
1273 public override void Emit (EmitContext ec)
1278 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1280 child.EmitBranchable (ec, label, on_true);
1282 // Only to make verifier happy
1283 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1284 ec.Emit (OpCodes.Unbox_Any, type);
1287 public override void EmitSideEffect (EmitContext ec)
1289 child.EmitSideEffect (ec);
1292 public override object GetValue ()
1294 return child.GetValue ();
1297 public override string GetValueAsLiteral ()
1299 return child.GetValueAsLiteral ();
1302 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1304 // FIXME: Do we need to check user conversions?
1305 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1307 return child.ConvertImplicitly (rc, target_type);
1312 /// This class is used to wrap literals which belong inside Enums
1314 public class EnumConstant : Constant
1316 public Constant Child;
1318 public EnumConstant (Constant child, TypeSpec enum_type)
1319 : base (child.Location)
1322 this.type = enum_type;
1325 protected EnumConstant (Location loc)
1330 protected override Expression DoResolve (ResolveContext rc)
1332 Child = Child.Resolve (rc);
1333 this.eclass = ExprClass.Value;
1337 public override void Emit (EmitContext ec)
1342 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1344 Child.EncodeAttributeValue (rc, enc, Child.Type);
1347 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1349 Child.EmitBranchable (ec, label, on_true);
1352 public override void EmitSideEffect (EmitContext ec)
1354 Child.EmitSideEffect (ec);
1357 public override string GetSignatureForError()
1359 return TypeManager.CSharpName (Type);
1362 public override object GetValue ()
1364 return Child.GetValue ();
1368 public override object GetTypedValue ()
1371 // The method can be used in dynamic context only (on closed types)
1373 // System.Enum.ToObject cannot be called on dynamic types
1374 // EnumBuilder has to be used, but we cannot use EnumBuilder
1375 // because it does not properly support generics
1377 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1381 public override string GetValueAsLiteral ()
1383 return Child.GetValueAsLiteral ();
1386 public EnumConstant Increment()
1388 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1391 public override bool IsDefaultValue {
1393 return Child.IsDefaultValue;
1397 public override bool IsZeroInteger {
1398 get { return Child.IsZeroInteger; }
1401 public override bool IsNegative {
1403 return Child.IsNegative;
1407 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1409 if (Child.Type == target_type)
1412 return Child.ConvertExplicitly (in_checked_context, target_type);
1415 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1417 if (this.type == type) {
1421 if (!Convert.ImplicitStandardConversionExists (this, type)){
1425 return Child.ConvertImplicitly (rc, type);
1430 /// This kind of cast is used to encapsulate Value Types in objects.
1432 /// The effect of it is to box the value type emitted by the previous
1435 public class BoxedCast : TypeCast {
1437 public BoxedCast (Expression expr, TypeSpec target_type)
1438 : base (expr, target_type)
1440 eclass = ExprClass.Value;
1443 protected override Expression DoResolve (ResolveContext ec)
1445 // This should never be invoked, we are born in fully
1446 // initialized state.
1451 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1453 // Only boxing to object type is supported
1454 if (targetType != TypeManager.object_type) {
1455 base.EncodeAttributeValue (rc, enc, targetType);
1459 enc.Encode (child.Type);
1460 child.EncodeAttributeValue (rc, enc, child.Type);
1463 public override void Emit (EmitContext ec)
1467 ec.Emit (OpCodes.Box, child.Type);
1470 public override void EmitSideEffect (EmitContext ec)
1472 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1473 // so, we need to emit the box+pop instructions in most cases
1474 if (TypeManager.IsStruct (child.Type) &&
1475 (type == TypeManager.object_type || type == TypeManager.value_type))
1476 child.EmitSideEffect (ec);
1478 base.EmitSideEffect (ec);
1482 public class UnboxCast : TypeCast {
1483 public UnboxCast (Expression expr, TypeSpec return_type)
1484 : base (expr, return_type)
1488 protected override Expression DoResolve (ResolveContext ec)
1490 // This should never be invoked, we are born in fully
1491 // initialized state.
1496 public override void Emit (EmitContext ec)
1500 ec.Emit (OpCodes.Unbox_Any, type);
1505 /// This is used to perform explicit numeric conversions.
1507 /// Explicit numeric conversions might trigger exceptions in a checked
1508 /// context, so they should generate the conv.ovf opcodes instead of
1511 public class ConvCast : TypeCast {
1512 public enum Mode : byte {
1513 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1515 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1516 U2_I1, U2_U1, U2_I2, U2_CH,
1517 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1518 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1519 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1520 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1521 CH_I1, CH_U1, CH_I2,
1522 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1523 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1529 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1530 : base (child, return_type)
1535 protected override Expression DoResolve (ResolveContext ec)
1537 // This should never be invoked, we are born in fully
1538 // initialized state.
1543 public override string ToString ()
1545 return String.Format ("ConvCast ({0}, {1})", mode, child);
1548 public override void Emit (EmitContext ec)
1552 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1554 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1555 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1556 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1557 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1558 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1560 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1561 case Mode.U1_CH: /* nothing */ break;
1563 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1564 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1565 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1566 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1567 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1568 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1570 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1571 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1572 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1573 case Mode.U2_CH: /* nothing */ break;
1575 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1576 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1577 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1578 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1579 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1580 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1581 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1584 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1585 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1586 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1587 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1588 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1590 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1591 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1592 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1593 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1594 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1595 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1596 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1597 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1598 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1600 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1601 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1602 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1603 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1604 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1605 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1606 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1607 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1608 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1610 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1611 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1612 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1614 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1615 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1616 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1617 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1618 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1619 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1620 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1621 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1622 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1624 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1625 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1626 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1627 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1628 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1629 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1630 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1631 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1632 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1633 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1635 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1639 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1640 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1641 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1642 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1643 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1645 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1646 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1649 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1650 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1651 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1652 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1653 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1655 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1656 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1657 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1658 case Mode.U2_CH: /* nothing */ break;
1660 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1661 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1662 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1663 case Mode.I4_U4: /* nothing */ break;
1664 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1665 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1666 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1670 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1671 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.U4_I4: /* nothing */ break;
1673 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1675 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1676 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1677 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1678 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1679 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1680 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1681 case Mode.I8_U8: /* nothing */ break;
1682 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1683 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1685 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1686 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1687 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1688 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1689 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1690 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1691 case Mode.U8_I8: /* nothing */ break;
1692 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1693 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1695 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1696 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1697 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1699 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1700 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1701 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1702 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1703 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1704 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1705 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1706 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1707 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1709 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1710 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1711 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1712 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1713 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1714 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1715 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1716 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1717 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1718 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1720 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1726 class OpcodeCast : TypeCast
1730 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1731 : base (child, return_type)
1736 protected override Expression DoResolve (ResolveContext ec)
1738 // This should never be invoked, we are born in fully
1739 // initialized state.
1744 public override void Emit (EmitContext ec)
1750 public TypeSpec UnderlyingType {
1751 get { return child.Type; }
1756 // Opcode casts expression with 2 opcodes but only
1757 // single expression tree node
1759 class OpcodeCastDuplex : OpcodeCast
1761 readonly OpCode second;
1763 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1764 : base (child, returnType, first)
1766 this.second = second;
1769 public override void Emit (EmitContext ec)
1777 /// This kind of cast is used to encapsulate a child and cast it
1778 /// to the class requested
1780 public sealed class ClassCast : TypeCast {
1781 readonly bool forced;
1783 public ClassCast (Expression child, TypeSpec return_type)
1784 : base (child, return_type)
1788 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1789 : base (child, return_type)
1791 this.forced = forced;
1794 public override void Emit (EmitContext ec)
1798 bool gen = TypeManager.IsGenericParameter (child.Type);
1800 ec.Emit (OpCodes.Box, child.Type);
1802 if (type.IsGenericParameter) {
1803 ec.Emit (OpCodes.Unbox_Any, type);
1810 ec.Emit (OpCodes.Castclass, type);
1815 // Created during resolving pahse when an expression is wrapped or constantified
1816 // and original expression can be used later (e.g. for expression trees)
1818 public class ReducedExpression : Expression
1820 sealed class ReducedConstantExpression : EmptyConstantCast
1822 readonly Expression orig_expr;
1824 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1825 : base (expr, expr.Type)
1827 this.orig_expr = orig_expr;
1830 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1832 Constant c = base.ConvertImplicitly (rc, target_type);
1834 c = new ReducedConstantExpression (c, orig_expr);
1839 public override Expression CreateExpressionTree (ResolveContext ec)
1841 return orig_expr.CreateExpressionTree (ec);
1844 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1846 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1848 c = new ReducedConstantExpression (c, orig_expr);
1853 sealed class ReducedExpressionStatement : ExpressionStatement
1855 readonly Expression orig_expr;
1856 readonly ExpressionStatement stm;
1858 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1860 this.orig_expr = orig;
1862 this.loc = orig.Location;
1865 public override Expression CreateExpressionTree (ResolveContext ec)
1867 return orig_expr.CreateExpressionTree (ec);
1870 protected override Expression DoResolve (ResolveContext ec)
1872 eclass = stm.eclass;
1877 public override void Emit (EmitContext ec)
1882 public override void EmitStatement (EmitContext ec)
1884 stm.EmitStatement (ec);
1888 readonly Expression expr, orig_expr;
1890 private ReducedExpression (Expression expr, Expression orig_expr)
1893 this.eclass = expr.eclass;
1894 this.type = expr.Type;
1895 this.orig_expr = orig_expr;
1896 this.loc = orig_expr.Location;
1901 public Expression OriginalExpression {
1910 // Creates fully resolved expression switcher
1912 public static Constant Create (Constant expr, Expression original_expr)
1914 if (expr.eclass == ExprClass.Unresolved)
1915 throw new ArgumentException ("Unresolved expression");
1917 return new ReducedConstantExpression (expr, original_expr);
1920 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1922 return new ReducedExpressionStatement (s, orig);
1925 public static Expression Create (Expression expr, Expression original_expr)
1927 return Create (expr, original_expr, true);
1931 // Creates unresolved reduce expression. The original expression has to be
1932 // already resolved. Created expression is constant based based on `expr'
1933 // value unless canBeConstant is used
1935 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1937 if (canBeConstant) {
1938 Constant c = expr as Constant;
1940 return Create (c, original_expr);
1943 ExpressionStatement s = expr as ExpressionStatement;
1945 return Create (s, original_expr);
1947 if (expr.eclass == ExprClass.Unresolved)
1948 throw new ArgumentException ("Unresolved expression");
1950 return new ReducedExpression (expr, original_expr);
1953 public override Expression CreateExpressionTree (ResolveContext ec)
1955 return orig_expr.CreateExpressionTree (ec);
1958 protected override Expression DoResolve (ResolveContext ec)
1963 public override void Emit (EmitContext ec)
1968 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1970 expr.EmitBranchable (ec, target, on_true);
1973 public override SLE.Expression MakeExpression (BuilderContext ctx)
1975 return orig_expr.MakeExpression (ctx);
1980 // Standard composite pattern
1982 public abstract class CompositeExpression : Expression
1984 protected Expression expr;
1986 protected CompositeExpression (Expression expr)
1989 this.loc = expr.Location;
1992 public override Expression CreateExpressionTree (ResolveContext ec)
1994 return expr.CreateExpressionTree (ec);
1997 public Expression Child {
1998 get { return expr; }
2001 protected override Expression DoResolve (ResolveContext ec)
2003 expr = expr.Resolve (ec);
2006 eclass = expr.eclass;
2012 public override void Emit (EmitContext ec)
2017 public override bool IsNull {
2018 get { return expr.IsNull; }
2023 // Base of expressions used only to narrow resolve flow
2025 public abstract class ShimExpression : Expression
2027 protected Expression expr;
2029 protected ShimExpression (Expression expr)
2034 protected override void CloneTo (CloneContext clonectx, Expression t)
2039 ShimExpression target = (ShimExpression) t;
2040 target.expr = expr.Clone (clonectx);
2043 public override Expression CreateExpressionTree (ResolveContext ec)
2045 throw new NotSupportedException ("ET");
2048 public override void Emit (EmitContext ec)
2050 throw new InternalErrorException ("Missing Resolve call");
2053 public Expression Expr {
2054 get { return expr; }
2059 // Unresolved type name expressions
2061 public abstract class ATypeNameExpression : FullNamedExpression
2064 protected TypeArguments targs;
2066 protected ATypeNameExpression (string name, Location l)
2072 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2079 protected ATypeNameExpression (string name, int arity, Location l)
2080 : this (name, new UnboundTypeArguments (arity), l)
2086 protected int Arity {
2088 return targs == null ? 0 : targs.Count;
2092 public bool HasTypeArguments {
2094 return targs != null && !targs.IsEmpty;
2098 public string Name {
2107 public TypeArguments TypeArguments {
2115 public override bool Equals (object obj)
2117 ATypeNameExpression atne = obj as ATypeNameExpression;
2118 return atne != null && atne.Name == Name &&
2119 (targs == null || targs.Equals (atne.targs));
2122 public override int GetHashCode ()
2124 return Name.GetHashCode ();
2127 // TODO: Move it to MemberCore
2128 public static string GetMemberType (MemberCore mc)
2134 if (mc is FieldBase)
2136 if (mc is MethodCore)
2138 if (mc is EnumMember)
2146 public override string GetSignatureForError ()
2148 if (targs != null) {
2149 return Name + "<" + targs.GetSignatureForError () + ">";
2155 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2159 /// SimpleName expressions are formed of a single word and only happen at the beginning
2160 /// of a dotted-name.
2162 public class SimpleName : ATypeNameExpression
2164 public SimpleName (string name, Location l)
2169 public SimpleName (string name, TypeArguments args, Location l)
2170 : base (name, args, l)
2174 public SimpleName (string name, int arity, Location l)
2175 : base (name, arity, l)
2179 public SimpleName GetMethodGroup ()
2181 return new SimpleName (Name, targs, loc);
2184 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2186 if (ec.CurrentType != null) {
2187 if (ec.CurrentMemberDefinition != null) {
2188 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2190 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2196 // TODO MemberCache: Implement
2198 string ns = ec.CurrentType.Namespace;
2199 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2200 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2201 var type = a.GetType (fullname);
2203 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2204 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2209 if (ec.CurrentTypeDefinition != null) {
2210 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2212 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2219 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2220 if (retval != null) {
2221 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2223 var te = retval as TypeExpr;
2224 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2225 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2227 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2232 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2235 protected override Expression DoResolve (ResolveContext ec)
2237 return SimpleNameResolve (ec, null, false);
2240 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2242 return SimpleNameResolve (ec, right_side, false);
2245 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2247 int errors = ec.Compiler.Report.Errors;
2248 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2251 if (fne.Type != null && Arity > 0) {
2252 if (HasTypeArguments) {
2253 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2254 return ct.ResolveAsTypeStep (ec, false);
2257 return new GenericOpenTypeExpr (fne.Type, loc);
2261 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2263 if (!(fne is Namespace))
2267 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2268 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2269 ec.Compiler.Report.Error (1980, Location,
2270 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2271 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2274 return new DynamicTypeExpr (loc);
2280 if (silent || errors != ec.Compiler.Report.Errors)
2283 Error_TypeOrNamespaceNotFound (ec);
2287 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2289 int lookup_arity = Arity;
2290 bool errorMode = false;
2292 Block current_block = rc.CurrentBlock;
2293 INamedBlockVariable variable = null;
2294 bool variable_found = false;
2298 // Stage 1: binding to local variables or parameters
2300 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2302 if (current_block != null && lookup_arity == 0) {
2303 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2304 if (!variable.IsDeclared) {
2305 // We found local name in accessible block but it's not
2306 // initialized yet, maybe the user wanted to bind to something else
2308 variable_found = true;
2310 e = variable.CreateReferenceExpression (rc, loc);
2313 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2322 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2324 TypeSpec member_type = rc.CurrentType;
2325 TypeSpec current_type = member_type;
2326 for (; member_type != null; member_type = member_type.DeclaringType) {
2327 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2331 var me = e as MemberExpr;
2333 // The name matches a type, defer to ResolveAsTypeStep
2341 if (variable != null) {
2342 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2343 rc.Report.Error (844, loc,
2344 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2345 Name, me.GetSignatureForError ());
2349 } else if (me is MethodGroupExpr) {
2350 // Leave it to overload resolution to report correct error
2352 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2353 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2356 // LAMESPEC: again, ignores InvocableOnly
2357 if (variable != null) {
2358 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2359 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2363 // MemberLookup does not check accessors availability, this is actually needed for properties only
2365 var pe = me as PropertyExpr;
2368 // Break as there is no other overload available anyway
2369 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2370 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2373 pe.Getter = pe.PropertyInfo.Get;
2375 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2378 pe.Setter = pe.PropertyInfo.Set;
2383 // TODO: It's used by EventExpr -> FieldExpr transformation only
2384 // TODO: Should go to MemberAccess
2385 me = me.ResolveMemberAccess (rc, null, null);
2389 me.SetTypeArguments (rc, targs);
2396 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2398 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2399 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2401 if (variable != null) {
2402 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2403 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2411 if (variable_found) {
2412 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2414 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2420 if (RootContext.EvalMode) {
2421 var fi = Evaluator.LookupField (Name);
2423 return new FieldExpr (fi.Item1, loc);
2427 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2432 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2434 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2439 if (right_side != null) {
2440 if (e is TypeExpr) {
2441 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2445 e = e.ResolveLValue (ec, right_side);
2450 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2456 /// Represents a namespace or a type. The name of the class was inspired by
2457 /// section 10.8.1 (Fully Qualified Names).
2459 public abstract class FullNamedExpression : Expression
2461 protected override void CloneTo (CloneContext clonectx, Expression target)
2463 // Do nothing, most unresolved type expressions cannot be
2464 // resolved to different type
2467 public override Expression CreateExpressionTree (ResolveContext ec)
2469 throw new NotSupportedException ("ET");
2472 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2477 public override void Emit (EmitContext ec)
2479 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2480 GetSignatureForError ());
2485 /// Expression that evaluates to a type
2487 public abstract class TypeExpr : FullNamedExpression {
2488 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2490 TypeExpr t = DoResolveAsTypeStep (ec);
2494 eclass = ExprClass.Type;
2498 protected override Expression DoResolve (ResolveContext ec)
2500 return ResolveAsTypeTerminal (ec, false);
2503 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2505 public override bool Equals (object obj)
2507 TypeExpr tobj = obj as TypeExpr;
2511 return Type == tobj.Type;
2514 public override int GetHashCode ()
2516 return Type.GetHashCode ();
2521 /// Fully resolved Expression that already evaluated to a type
2523 public class TypeExpression : TypeExpr {
2524 public TypeExpression (TypeSpec t, Location l)
2527 eclass = ExprClass.Type;
2531 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2536 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2543 /// This class denotes an expression which evaluates to a member
2544 /// of a struct or a class.
2546 public abstract class MemberExpr : Expression
2549 // An instance expression associated with this member, if it's a
2550 // non-static member
2552 public Expression InstanceExpression;
2555 /// The name of this member.
2557 public abstract string Name {
2562 // When base.member is used
2564 public bool IsBase {
2565 get { return InstanceExpression is BaseThis; }
2569 /// Whether this is an instance member.
2571 public abstract bool IsInstance {
2576 /// Whether this is a static member.
2578 public abstract bool IsStatic {
2583 protected abstract TypeSpec DeclaringType {
2588 // Converts best base candidate for virtual method starting from QueriedBaseType
2590 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2593 // Only when base.member is used and method is virtual
2599 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2600 // means for base.member access we have to find the closest match after we found best candidate
2602 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2604 // The method could already be what we are looking for
2606 TypeSpec[] targs = null;
2607 if (method.DeclaringType != InstanceExpression.Type) {
2608 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2609 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2610 if (base_override.IsGeneric)
2611 targs = method.TypeArguments;
2613 method = base_override;
2617 // TODO: For now we do it for any hoisted call even if it's needed for
2618 // hoisted stories only but that requires a new expression wrapper
2619 if (rc.CurrentAnonymousMethod != null) {
2620 if (targs == null && method.IsGeneric) {
2621 targs = method.TypeArguments;
2622 method = method.GetGenericMethodDefinition ();
2625 if (method.Parameters.HasArglist)
2626 throw new NotImplementedException ("__arglist base call proxy");
2628 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2630 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2631 // get/set member expressions second call would fail to proxy because left expression
2632 // would be of 'this' and not 'base'
2633 if (rc.CurrentType.IsStruct)
2634 InstanceExpression = new This (loc).Resolve (rc);
2638 method = method.MakeGenericMethod (targs);
2642 // Only base will allow this invocation to happen.
2644 if (method.IsAbstract) {
2645 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2651 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2653 if (InstanceExpression == null)
2656 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2657 var ct = rc.CurrentType;
2658 var expr_type = InstanceExpression.Type;
2659 if (ct != expr_type) {
2660 expr_type = expr_type.GetDefinition ();
2661 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2662 rc.Report.SymbolRelatedToPreviousError (member);
2663 rc.Report.Error (1540, loc,
2664 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2665 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2671 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2674 type = type.GetDefinition ();
2676 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2679 type = type.DeclaringType;
2680 } while (type != null);
2685 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2687 if (InstanceExpression != null) {
2688 InstanceExpression = InstanceExpression.Resolve (rc);
2689 CheckProtectedMemberAccess (rc, member);
2692 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2693 UnsafeError (rc, loc);
2696 var dep = member.GetMissingDependencies ();
2698 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2701 if (!rc.IsObsolete) {
2702 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2704 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2707 if (!(member is FieldSpec))
2708 member.MemberDefinition.SetIsUsed ();
2711 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2713 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2717 // Implements identicial simple name and type-name
2719 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2722 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2725 // 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
2726 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2728 if (left is MemberExpr || left is VariableReference) {
2729 rc.Report.DisableReporting ();
2730 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2731 rc.Report.EnableReporting ();
2732 if (identical_type != null && identical_type.Type == left.Type)
2733 return identical_type;
2739 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2742 if (InstanceExpression != null) {
2743 if (InstanceExpression is TypeExpr) {
2744 var t = InstanceExpression.Type;
2746 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2747 if (oa != null && !rc.IsObsolete) {
2748 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2751 t = t.DeclaringType;
2752 } while (t != null);
2754 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2755 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2756 rc.Report.Error (176, loc,
2757 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2758 GetSignatureForError ());
2762 InstanceExpression = null;
2768 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2769 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2770 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2771 rc.Report.Error (236, loc,
2772 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2773 GetSignatureForError ());
2775 rc.Report.Error (120, loc,
2776 "An object reference is required to access non-static member `{0}'",
2777 GetSignatureForError ());
2782 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2783 rc.Report.Error (38, loc,
2784 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2785 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2788 InstanceExpression = new This (loc);
2789 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2790 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2791 InstanceExpression = InstanceExpression.Resolve (rc);
2794 InstanceExpression = InstanceExpression.Resolve (rc);
2800 var me = InstanceExpression as MemberExpr;
2802 me.ResolveInstanceExpression (rc, rhs);
2804 var fe = me as FieldExpr;
2805 if (fe != null && fe.IsMarshalByRefAccess ()) {
2806 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2807 rc.Report.Warning (1690, 1, loc,
2808 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2809 me.GetSignatureForError ());
2816 // Run member-access postponed check once we know that
2817 // the expression is not field expression which is the only
2818 // expression which can use uninitialized this
2820 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2821 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2825 // Additional checks for l-value member access
2829 // TODO: It should be recursive but that would break csc compatibility
2831 if (InstanceExpression is UnboxCast) {
2832 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2839 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2841 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2842 ec.Report.Warning (1720, 1, left.Location,
2843 "Expression will always cause a `{0}'", "System.NullReferenceException");
2846 InstanceExpression = left;
2850 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2852 TypeSpec instance_type = InstanceExpression.Type;
2853 if (TypeManager.IsValueType (instance_type)) {
2854 if (InstanceExpression is IMemoryLocation) {
2855 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2857 LocalTemporary t = new LocalTemporary (instance_type);
2858 InstanceExpression.Emit (ec);
2860 t.AddressOf (ec, AddressOp.Store);
2863 InstanceExpression.Emit (ec);
2865 // Only to make verifier happy
2866 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2867 ec.Emit (OpCodes.Box, instance_type);
2870 if (prepare_for_load)
2871 ec.Emit (OpCodes.Dup);
2874 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2878 // Represents a group of extension method candidates for whole namespace
2880 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2882 NamespaceEntry namespace_entry;
2883 public readonly Expression ExtensionExpression;
2885 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2886 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2888 this.namespace_entry = n;
2889 this.ExtensionExpression = extensionExpr;
2892 public override bool IsStatic {
2893 get { return true; }
2896 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2898 if (namespace_entry == null)
2902 // For extension methodgroup we are not looking for base members but parent
2903 // namespace extension methods
2905 int arity = type_arguments == null ? 0 : type_arguments.Count;
2906 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2910 return found.Cast<MemberSpec> ().ToList ();
2913 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2915 // We are already here
2919 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2921 if (arguments == null)
2922 arguments = new Arguments (1);
2924 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2925 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2927 // Store resolved argument and restore original arguments
2929 // Clean-up modified arguments for error reporting
2930 arguments.RemoveAt (0);
2934 var me = ExtensionExpression as MemberExpr;
2936 me.ResolveInstanceExpression (ec, null);
2938 InstanceExpression = null;
2942 #region IErrorHandler Members
2944 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2949 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2951 rc.Report.SymbolRelatedToPreviousError (best);
2952 rc.Report.Error (1928, loc,
2953 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2954 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2957 rc.Report.Error (1929, loc,
2958 "Extension method instance type `{0}' cannot be converted to `{1}'",
2959 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2965 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2970 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2979 /// MethodGroupExpr represents a group of method candidates which
2980 /// can be resolved to the best method overload
2982 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2984 protected IList<MemberSpec> Methods;
2985 MethodSpec best_candidate;
2986 TypeSpec best_candidate_return;
2987 protected TypeArguments type_arguments;
2989 SimpleName simple_name;
2990 protected TypeSpec queried_type;
2992 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2996 this.type = InternalType.MethodGroup;
2998 eclass = ExprClass.MethodGroup;
2999 queried_type = type;
3002 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3003 : this (new MemberSpec[] { m }, type, loc)
3009 public MethodSpec BestCandidate {
3011 return best_candidate;
3015 public TypeSpec BestCandidateReturnType {
3017 return best_candidate_return;
3021 protected override TypeSpec DeclaringType {
3023 return queried_type;
3027 public override bool IsInstance {
3029 if (best_candidate != null)
3030 return !best_candidate.IsStatic;
3036 public override bool IsStatic {
3038 if (best_candidate != null)
3039 return best_candidate.IsStatic;
3045 public override string Name {
3047 if (best_candidate != null)
3048 return best_candidate.Name;
3051 return Methods.First ().Name;
3058 // When best candidate is already know this factory can be used
3059 // to avoid expensive overload resolution to be called
3061 // NOTE: InstanceExpression has to be set manually
3063 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3065 return new MethodGroupExpr (best, queriedType, loc) {
3066 best_candidate = best,
3067 best_candidate_return = best.ReturnType
3071 public override string GetSignatureForError ()
3073 if (best_candidate != null)
3074 return best_candidate.GetSignatureForError ();
3076 return Methods.First ().GetSignatureForError ();
3079 public override Expression CreateExpressionTree (ResolveContext ec)
3081 if (best_candidate == null) {
3082 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3086 if (best_candidate.IsConditionallyExcluded (loc))
3087 ec.Report.Error (765, loc,
3088 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3090 return new TypeOfMethod (best_candidate, loc);
3093 protected override Expression DoResolve (ResolveContext ec)
3095 this.eclass = ExprClass.MethodGroup;
3097 if (InstanceExpression != null) {
3098 InstanceExpression = InstanceExpression.Resolve (ec);
3099 if (InstanceExpression == null)
3106 public override void Emit (EmitContext ec)
3108 throw new NotSupportedException ();
3111 public void EmitCall (EmitContext ec, Arguments arguments)
3113 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3116 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3118 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3119 Name, TypeManager.CSharpName (target));
3122 public static bool IsExtensionMethodArgument (Expression expr)
3125 // LAMESPEC: No details about which expressions are not allowed
3127 return !(expr is TypeExpr) && !(expr is BaseThis);
3131 /// Find the Applicable Function Members (7.4.2.1)
3133 /// me: Method Group expression with the members to select.
3134 /// it might contain constructors or methods (or anything
3135 /// that maps to a method).
3137 /// Arguments: ArrayList containing resolved Argument objects.
3139 /// loc: The location if we want an error to be reported, or a Null
3140 /// location for "probing" purposes.
3142 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3143 /// that is the best match of me on Arguments.
3146 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3148 // TODO: causes issues with probing mode, remove explicit Kind check
3149 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3152 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3153 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3154 r.BaseMembersProvider = this;
3157 if (cerrors != null)
3158 r.CustomErrors = cerrors;
3160 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3161 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3162 if (best_candidate == null)
3163 return r.BestCandidateIsDynamic ? this : null;
3165 // Overload resolver had to create a new method group, all checks bellow have already been executed
3166 if (r.BestCandidateNewMethodGroup != null)
3167 return r.BestCandidateNewMethodGroup;
3169 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3170 if (InstanceExpression != null) {
3171 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3172 InstanceExpression = null;
3174 if (best_candidate.IsStatic && simple_name != null) {
3175 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3178 InstanceExpression.Resolve (ec);
3182 ResolveInstanceExpression (ec, null);
3183 if (InstanceExpression != null)
3184 CheckProtectedMemberAccess (ec, best_candidate);
3187 var base_override = CandidateToBaseOverride (ec, best_candidate);
3188 if (base_override == best_candidate) {
3189 best_candidate_return = r.BestCandidateReturnType;
3191 best_candidate = base_override;
3192 best_candidate_return = best_candidate.ReturnType;
3198 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3200 simple_name = original;
3201 return base.ResolveMemberAccess (ec, left, original);
3204 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3206 type_arguments = ta;
3209 #region IBaseMembersProvider Members
3211 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3213 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3216 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3218 if (queried_type == member.DeclaringType)
3221 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3222 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3226 // Extension methods lookup after ordinary methods candidates failed to apply
3228 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3230 if (InstanceExpression == null)
3233 InstanceExpression = InstanceExpression.Resolve (rc);
3234 if (!IsExtensionMethodArgument (InstanceExpression))
3237 int arity = type_arguments == null ? 0 : type_arguments.Count;
3238 NamespaceEntry methods_scope = null;
3239 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3240 if (methods == null)
3243 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3244 emg.SetTypeArguments (rc, type_arguments);
3251 public struct OverloadResolver
3254 public enum Restrictions
3258 ProbingOnly = 1 << 1,
3259 CovariantDelegate = 1 << 2,
3260 NoBaseMembers = 1 << 3,
3261 BaseMembersIncluded = 1 << 4
3264 public interface IBaseMembersProvider
3266 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3267 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3268 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3271 public interface IErrorHandler
3273 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3274 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3275 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3276 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3279 sealed class NoBaseMembers : IBaseMembersProvider
3281 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3283 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3288 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3293 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3299 struct AmbiguousCandidate
3301 public readonly MemberSpec Member;
3302 public readonly bool Expanded;
3303 public readonly AParametersCollection Parameters;
3305 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3308 Parameters = parameters;
3309 Expanded = expanded;
3314 IList<MemberSpec> members;
3315 TypeArguments type_arguments;
3316 IBaseMembersProvider base_provider;
3317 IErrorHandler custom_errors;
3318 Restrictions restrictions;
3319 MethodGroupExpr best_candidate_extension_group;
3320 TypeSpec best_candidate_return_type;
3322 SessionReportPrinter lambda_conv_msgs;
3323 ReportPrinter prev_recorder;
3325 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3326 : this (members, null, restrictions, loc)
3330 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3333 if (members == null || members.Count == 0)
3334 throw new ArgumentException ("empty members set");
3336 this.members = members;
3338 type_arguments = targs;
3339 this.restrictions = restrictions;
3340 if (IsDelegateInvoke)
3341 this.restrictions |= Restrictions.NoBaseMembers;
3343 base_provider = NoBaseMembers.Instance;
3348 public IBaseMembersProvider BaseMembersProvider {
3350 return base_provider;
3353 base_provider = value;
3357 public bool BestCandidateIsDynamic { get; set; }
3360 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3362 public MethodGroupExpr BestCandidateNewMethodGroup {
3364 return best_candidate_extension_group;
3369 // Return type can be different between best candidate and closest override
3371 public TypeSpec BestCandidateReturnType {
3373 return best_candidate_return_type;
3377 public IErrorHandler CustomErrors {
3379 return custom_errors;
3382 custom_errors = value;
3386 TypeSpec DelegateType {
3388 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3389 throw new InternalErrorException ("Not running in delegate mode", loc);
3391 return members [0].DeclaringType;
3395 bool IsProbingOnly {
3397 return (restrictions & Restrictions.ProbingOnly) != 0;
3401 bool IsDelegateInvoke {
3403 return (restrictions & Restrictions.DelegateInvoke) != 0;
3410 // 7.4.3.3 Better conversion from expression
3411 // Returns : 1 if a->p is better,
3412 // 2 if a->q is better,
3413 // 0 if neither is better
3415 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3417 TypeSpec argument_type = a.Type;
3420 // If argument is an anonymous function
3422 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3424 // p and q are delegate types or expression tree types
3426 if (p.GetDefinition () == TypeManager.expression_type || q.GetDefinition () == TypeManager.expression_type) {
3427 if (q.MemberDefinition != p.MemberDefinition) {
3432 // Uwrap delegate from Expression<T>
3434 q = TypeManager.GetTypeArguments (q)[0];
3435 p = TypeManager.GetTypeArguments (p)[0];
3438 var p_m = Delegate.GetInvokeMethod (ec.Compiler, p);
3439 var q_m = Delegate.GetInvokeMethod (ec.Compiler, q);
3442 // With identical parameter lists
3444 if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
3451 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3453 if (p == TypeManager.void_type) {
3454 return q != TypeManager.void_type ? 2 : 0;
3458 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3460 if (q == TypeManager.void_type) {
3461 return p != TypeManager.void_type ? 1: 0;
3464 if (argument_type == p)
3467 if (argument_type == q)
3471 return BetterTypeConversion (ec, p, q);
3475 // 7.4.3.4 Better conversion from type
3477 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3479 if (p == null || q == null)
3480 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3482 if (p == TypeManager.int32_type) {
3483 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3485 } else if (p == TypeManager.int64_type) {
3486 if (q == TypeManager.uint64_type)
3488 } else if (p == TypeManager.sbyte_type) {
3489 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3490 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3492 } else if (p == TypeManager.short_type) {
3493 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3494 q == TypeManager.uint64_type)
3496 } else if (p == InternalType.Dynamic) {
3497 // Dynamic is never better
3501 if (q == TypeManager.int32_type) {
3502 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3504 } if (q == TypeManager.int64_type) {
3505 if (p == TypeManager.uint64_type)
3507 } else if (q == TypeManager.sbyte_type) {
3508 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3509 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3511 } if (q == TypeManager.short_type) {
3512 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3513 p == TypeManager.uint64_type)
3515 } else if (q == InternalType.Dynamic) {
3516 // Dynamic is never better
3520 // FIXME: handle lifted operators
3522 // TODO: this is expensive
3523 Expression p_tmp = new EmptyExpression (p);
3524 Expression q_tmp = new EmptyExpression (q);
3526 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3527 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3529 if (p_to_q && !q_to_p)
3532 if (q_to_p && !p_to_q)
3539 /// Determines "Better function" between candidate
3540 /// and the current best match
3543 /// Returns a boolean indicating :
3544 /// false if candidate ain't better
3545 /// true if candidate is better than the current best match
3547 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3548 MemberSpec best, AParametersCollection bparam, bool best_params)
3550 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3551 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3553 bool better_at_least_one = false;
3555 int args_count = args == null ? 0 : args.Count;
3559 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3562 // Default arguments are ignored for better decision
3563 if (a.IsDefaultArgument)
3567 // When comparing named argument the parameter type index has to be looked up
3568 // in original parameter set (override version for virtual members)
3570 NamedArgument na = a as NamedArgument;
3572 int idx = cparam.GetParameterIndexByName (na.Name);
3573 ct = candidate_pd.Types[idx];
3574 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3575 ct = TypeManager.GetElementType (ct);
3577 idx = bparam.GetParameterIndexByName (na.Name);
3578 bt = best_pd.Types[idx];
3579 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3580 bt = TypeManager.GetElementType (bt);
3582 ct = candidate_pd.Types[c_idx];
3583 bt = best_pd.Types[b_idx];
3585 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3586 ct = TypeManager.GetElementType (ct);
3590 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3591 bt = TypeManager.GetElementType (bt);
3596 if (TypeSpecComparer.IsEqual (ct, bt))
3600 int result = BetterExpressionConversion (ec, a, ct, bt);
3602 // for each argument, the conversion to 'ct' should be no worse than
3603 // the conversion to 'bt'.
3607 // for at least one argument, the conversion to 'ct' should be better than
3608 // the conversion to 'bt'.
3610 better_at_least_one = true;
3613 if (better_at_least_one)
3617 // This handles the case
3619 // Add (float f1, float f2, float f3);
3620 // Add (params decimal [] foo);
3622 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3623 // first candidate would've chosen as better.
3625 if (!same && !a.IsDefaultArgument)
3629 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3633 // This handles the following cases:
3635 // Foo (int i) is better than Foo (int i, long l = 0)
3636 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3638 // Prefer non-optional version
3640 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3642 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3643 if (candidate_pd.Count >= best_pd.Count)
3646 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3653 // One is a non-generic method and second is a generic method, then non-generic is better
3655 if (best.IsGeneric != candidate.IsGeneric)
3656 return best.IsGeneric;
3659 // This handles the following cases:
3661 // Trim () is better than Trim (params char[] chars)
3662 // Concat (string s1, string s2, string s3) is better than
3663 // Concat (string s1, params string [] srest)
3664 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3666 // Prefer non-expanded version
3668 if (candidate_params != best_params)
3671 int candidate_param_count = candidate_pd.Count;
3672 int best_param_count = best_pd.Count;
3674 if (candidate_param_count != best_param_count)
3675 // can only happen if (candidate_params && best_params)
3676 return candidate_param_count > best_param_count && best_pd.HasParams;
3679 // Both methods have the same number of parameters, and the parameters have equal types
3680 // Pick the "more specific" signature using rules over original (non-inflated) types
3682 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3683 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3685 bool specific_at_least_once = false;
3686 for (j = 0; j < args_count; ++j) {
3687 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3689 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3690 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3692 ct = candidate_def_pd.Types[j];
3693 bt = best_def_pd.Types[j];
3698 TypeSpec specific = MoreSpecific (ct, bt);
3702 specific_at_least_once = true;
3705 if (specific_at_least_once)
3711 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3713 rc.Report.Error (1729, loc,
3714 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3715 type.GetSignatureForError (), argCount.ToString ());
3719 // Determines if the candidate method is applicable to the given set of arguments
3720 // There could be two different set of parameters for same candidate where one
3721 // is the closest override for default values and named arguments checks and second
3722 // one being the virtual base for the parameter types and modifiers.
3724 // A return value rates candidate method compatibility,
3725 // 0 = the best, int.MaxValue = the worst
3727 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)
3729 // Parameters of most-derived type used mainly for named and optional parameters
3730 var pd = pm.Parameters;
3732 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3733 // params modifier instead of most-derived type
3734 var cpd = ((IParametersMember) candidate).Parameters;
3735 int param_count = pd.Count;
3736 int optional_count = 0;
3738 Arguments orig_args = arguments;
3740 if (arg_count != param_count) {
3741 for (int i = 0; i < pd.Count; ++i) {
3742 if (pd.FixedParameters[i].HasDefaultValue) {
3743 optional_count = pd.Count - i;
3748 if (optional_count != 0) {
3749 // Readjust expected number when params used
3750 if (cpd.HasParams) {
3752 if (arg_count < param_count)
3754 } else if (arg_count > param_count) {
3755 int args_gap = System.Math.Abs (arg_count - param_count);
3756 return int.MaxValue - 10000 + args_gap;
3758 } else if (arg_count != param_count) {
3759 int args_gap = System.Math.Abs (arg_count - param_count);
3761 return int.MaxValue - 10000 + args_gap;
3762 if (arg_count < param_count - 1)
3763 return int.MaxValue - 10000 + args_gap;
3766 // Resize to fit optional arguments
3767 if (optional_count != 0) {
3768 if (arguments == null) {
3769 arguments = new Arguments (optional_count);
3771 // Have to create a new container, so the next run can do same
3772 var resized = new Arguments (param_count);
3773 resized.AddRange (arguments);
3774 arguments = resized;
3777 for (int i = arg_count; i < param_count; ++i)
3778 arguments.Add (null);
3782 if (arg_count > 0) {
3784 // Shuffle named arguments to the right positions if there are any
3786 if (arguments[arg_count - 1] is NamedArgument) {
3787 arg_count = arguments.Count;
3789 for (int i = 0; i < arg_count; ++i) {
3790 bool arg_moved = false;
3792 NamedArgument na = arguments[i] as NamedArgument;
3796 int index = pd.GetParameterIndexByName (na.Name);
3798 // Named parameter not found
3802 // already reordered
3807 if (index >= param_count) {
3808 // When using parameters which should not be available to the user
3809 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3812 arguments.Add (null);
3816 temp = arguments[index];
3818 // The slot has been taken by positional argument
3819 if (temp != null && !(temp is NamedArgument))
3824 arguments = arguments.MarkOrderedArgument (na);
3828 arguments[index] = arguments[i];
3829 arguments[i] = temp;
3836 arg_count = arguments.Count;
3838 } else if (arguments != null) {
3839 arg_count = arguments.Count;
3843 // 1. Handle generic method using type arguments when specified or type inference
3846 var ms = candidate as MethodSpec;
3847 if (ms != null && ms.IsGeneric) {
3848 // Setup constraint checker for probing only
3849 ConstraintChecker cc = new ConstraintChecker (null);
3851 if (type_arguments != null) {
3852 var g_args_count = ms.Arity;
3853 if (g_args_count != type_arguments.Count)
3854 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3856 ms = ms.MakeGenericMethod (type_arguments.Arguments);
3858 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3859 // for now it simplifies things. I should probably add a callback to ResolveContext
3860 if (lambda_conv_msgs == null) {
3861 lambda_conv_msgs = new SessionReportPrinter ();
3862 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3865 var ti = new TypeInference (arguments);
3866 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3867 lambda_conv_msgs.EndSession ();
3870 return ti.InferenceScore - 20000;
3872 if (i_args.Length != 0) {
3873 ms = ms.MakeGenericMethod (i_args);
3876 cc.IgnoreInferredDynamic = true;
3880 // Type arguments constraints have to match for the method to be applicable
3882 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3884 return int.MaxValue - 25000;
3888 // We have a generic return type and at same time the method is override which
3889 // means we have to also inflate override return type in case the candidate is
3890 // best candidate and override return type is different to base return type.
3892 // virtual Foo<T, object> with override Foo<T, dynamic>
3894 if (candidate != pm) {
3895 MethodSpec override_ms = (MethodSpec) pm;
3896 var inflator = new TypeParameterInflator (ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3897 returnType = inflator.Inflate (returnType);
3899 returnType = ms.ReturnType;
3903 ptypes = ms.Parameters.Types;
3905 if (type_arguments != null)
3906 return int.MaxValue - 15000;
3912 // 2. Each argument has to be implicitly convertible to method parameter
3914 Parameter.Modifier p_mod = 0;
3917 for (int i = 0; i < arg_count; i++) {
3918 Argument a = arguments[i];
3920 if (!pd.FixedParameters[i].HasDefaultValue) {
3921 arguments = orig_args;
3922 return arg_count * 2 + 2;
3926 // Get the default value expression, we can use the same expression
3927 // if the type matches
3929 Expression e = pd.FixedParameters[i].DefaultValue;
3930 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3932 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3934 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3935 e = new MemberAccess (new MemberAccess (new MemberAccess (
3936 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3938 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3944 arguments[i] = new Argument (e, Argument.AType.Default);
3948 if (p_mod != Parameter.Modifier.PARAMS) {
3949 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3951 } else if (!params_expanded_form) {
3952 params_expanded_form = true;
3953 pt = ((ElementTypeSpec) pt).Element;
3959 if (!params_expanded_form) {
3960 if (a.ArgType == Argument.AType.ExtensionType) {
3962 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3965 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3966 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3967 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3972 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3975 dynamicArgument = true;
3980 // It can be applicable in expanded form (when not doing exact match like for delegates)
3982 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3983 if (!params_expanded_form)
3984 pt = ((ElementTypeSpec) pt).Element;
3987 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3990 params_expanded_form = true;
3991 } else if (score < 0) {
3992 params_expanded_form = true;
3993 dynamicArgument = true;
3998 if (params_expanded_form)
4000 return (arg_count - i) * 2 + score;
4005 // When params parameter has no argument it will be provided later if the method is the best candidate
4007 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4008 params_expanded_form = true;
4011 // Restore original arguments for dynamic binder to keep the intention of original source code
4013 if (dynamicArgument)
4014 arguments = orig_args;
4020 // Tests argument compatibility with the parameter
4021 // The possible return values are
4023 // 1 - modifier mismatch
4024 // 2 - type mismatch
4025 // -1 - dynamic binding required
4027 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4030 // Types have to be identical when ref or out modifer
4031 // is used and argument is not of dynamic type
4033 if ((argument.Modifier | param_mod) != 0) {
4034 if (argument.Type != parameter) {
4036 // Do full equality check after quick path
4038 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4040 // Using dynamic for ref/out parameter can still succeed at runtime
4042 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4049 if (argument.Modifier != param_mod) {
4051 // Using dynamic for ref/out parameter can still succeed at runtime
4053 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4060 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4064 // Deploy custom error reporting for lambda methods. When probing lambda methods
4065 // keep all errors reported in separate set and once we are done and no best
4066 // candidate found, this set is used to report more details about what was wrong
4069 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4070 if (lambda_conv_msgs == null) {
4071 lambda_conv_msgs = new SessionReportPrinter ();
4072 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4076 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4077 if (lambda_conv_msgs != null) {
4078 lambda_conv_msgs.EndSession ();
4088 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4090 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4092 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4095 var ac_p = p as ArrayContainer;
4097 var ac_q = ((ArrayContainer) q);
4098 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4099 if (specific == ac_p.Element)
4101 if (specific == ac_q.Element)
4103 } else if (TypeManager.IsGenericType (p)) {
4104 var pargs = TypeManager.GetTypeArguments (p);
4105 var qargs = TypeManager.GetTypeArguments (q);
4107 bool p_specific_at_least_once = false;
4108 bool q_specific_at_least_once = false;
4110 for (int i = 0; i < pargs.Length; i++) {
4111 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4112 if (specific == pargs[i])
4113 p_specific_at_least_once = true;
4114 if (specific == qargs[i])
4115 q_specific_at_least_once = true;
4118 if (p_specific_at_least_once && !q_specific_at_least_once)
4120 if (!p_specific_at_least_once && q_specific_at_least_once)
4128 // Find the best method from candidate list
4130 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4132 List<AmbiguousCandidate> ambiguous_candidates = null;
4134 MemberSpec best_candidate;
4135 Arguments best_candidate_args = null;
4136 bool best_candidate_params = false;
4137 bool best_candidate_dynamic = false;
4138 int best_candidate_rate;
4139 IParametersMember best_parameter_member = null;
4141 int args_count = args != null ? args.Count : 0;
4143 Arguments candidate_args = args;
4144 bool error_mode = false;
4145 var current_type = rc.CurrentType;
4146 MemberSpec invocable_member = null;
4148 // Be careful, cannot return until error reporter is restored
4150 best_candidate = null;
4151 best_candidate_rate = int.MaxValue;
4153 var type_members = members;
4157 for (int i = 0; i < type_members.Count; ++i) {
4158 var member = type_members[i];
4161 // Methods in a base class are not candidates if any method in a derived
4162 // class is applicable
4164 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4168 if (!member.IsAccessible (current_type))
4171 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4175 IParametersMember pm = member as IParametersMember;
4178 // Will use it later to report ambiguity between best method and invocable member
4180 if (Invocation.IsMemberInvocable (member))
4181 invocable_member = member;
4187 // Overload resolution is looking for base member but using parameter names
4188 // and default values from the closest member. That means to do expensive lookup
4189 // for the closest override for virtual or abstract members
4191 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4192 var override_params = base_provider.GetOverrideMemberParameters (member);
4193 if (override_params != null)
4194 pm = override_params;
4198 // Check if the member candidate is applicable
4200 bool params_expanded_form = false;
4201 bool dynamic_argument = false;
4202 TypeSpec rt = pm.MemberType;
4203 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4206 // How does it score compare to others
4208 if (candidate_rate < best_candidate_rate) {
4209 best_candidate_rate = candidate_rate;
4210 best_candidate = member;
4211 best_candidate_args = candidate_args;
4212 best_candidate_params = params_expanded_form;
4213 best_candidate_dynamic = dynamic_argument;
4214 best_parameter_member = pm;
4215 best_candidate_return_type = rt;
4216 } else if (candidate_rate == 0) {
4218 // The member look is done per type for most operations but sometimes
4219 // it's not possible like for binary operators overload because they
4220 // are unioned between 2 sides
4222 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4223 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4228 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4230 // We pack all interface members into top level type which makes the overload resolution
4231 // more complicated for interfaces. We compensate it by removing methods with same
4232 // signature when building the cache hence this path should not really be hit often
4235 // interface IA { void Foo (int arg); }
4236 // interface IB : IA { void Foo (params int[] args); }
4238 // IB::Foo is the best overload when calling IB.Foo (1)
4241 if (ambiguous_candidates != null) {
4242 foreach (var amb_cand in ambiguous_candidates) {
4243 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4252 ambiguous_candidates = null;
4255 // Is the new candidate better
4256 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4260 best_candidate = member;
4261 best_candidate_args = candidate_args;
4262 best_candidate_params = params_expanded_form;
4263 best_candidate_dynamic = dynamic_argument;
4264 best_parameter_member = pm;
4265 best_candidate_return_type = rt;
4267 // It's not better but any other found later could be but we are not sure yet
4268 if (ambiguous_candidates == null)
4269 ambiguous_candidates = new List<AmbiguousCandidate> ();
4271 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4275 // Restore expanded arguments
4276 if (candidate_args != args)
4277 candidate_args = args;
4279 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4281 if (prev_recorder != null)
4282 rc.Report.SetPrinter (prev_recorder);
4286 // We've found exact match
4288 if (best_candidate_rate == 0)
4292 // Try extension methods lookup when no ordinary method match was found and provider enables it
4295 var emg = base_provider.LookupExtensionMethod (rc);
4297 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4299 best_candidate_extension_group = emg;
4300 return (T) (MemberSpec) emg.BestCandidate;
4305 // Don't run expensive error reporting mode for probing
4312 lambda_conv_msgs = null;
4317 // No best member match found, report an error
4319 if (best_candidate_rate != 0 || error_mode) {
4320 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4324 if (best_candidate_dynamic) {
4325 if (args[0].ArgType == Argument.AType.ExtensionType) {
4326 rc.Report.Error (1973, loc,
4327 "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",
4328 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4331 BestCandidateIsDynamic = true;
4335 if (ambiguous_candidates != null) {
4337 // Now check that there are no ambiguities i.e the selected method
4338 // should be better than all the others
4340 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4341 var candidate = ambiguous_candidates [ix];
4343 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4344 var ambiguous = candidate.Member;
4345 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4346 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4347 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4348 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4349 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4352 return (T) best_candidate;
4357 if (invocable_member != null) {
4358 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4359 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4360 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4361 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4365 // And now check if the arguments are all
4366 // compatible, perform conversions if
4367 // necessary etc. and return if everything is
4370 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4373 if (best_candidate == null)
4377 // Check ObsoleteAttribute on the best method
4379 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4380 if (oa != null && !rc.IsObsolete)
4381 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4383 var dep = best_candidate.GetMissingDependencies ();
4385 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4388 best_candidate.MemberDefinition.SetIsUsed ();
4390 args = best_candidate_args;
4391 return (T) best_candidate;
4394 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4396 return ResolveMember<MethodSpec> (rc, ref args);
4399 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4400 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4402 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4405 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4406 ec.Report.SymbolRelatedToPreviousError (method);
4407 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4408 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4409 TypeManager.CSharpSignature (method));
4412 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4413 TypeManager.CSharpSignature (method));
4414 } else if (IsDelegateInvoke) {
4415 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4416 DelegateType.GetSignatureForError ());
4418 ec.Report.SymbolRelatedToPreviousError (method);
4419 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4420 method.GetSignatureForError ());
4423 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4425 string index = (idx + 1).ToString ();
4426 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4427 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4428 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4429 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4430 index, Parameter.GetModifierSignature (a.Modifier));
4432 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4433 index, Parameter.GetModifierSignature (mod));
4435 string p1 = a.GetSignatureForError ();
4436 string p2 = TypeManager.CSharpName (paramType);
4439 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4440 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4441 ec.Report.SymbolRelatedToPreviousError (paramType);
4444 ec.Report.Error (1503, loc,
4445 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4450 // We have failed to find exact match so we return error info about the closest match
4452 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4454 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4455 int arg_count = args == null ? 0 : args.Count;
4457 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4458 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4459 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4463 if (lambda_conv_msgs != null) {
4464 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4469 // For candidates which match on parameters count report more details about incorrect arguments
4472 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4473 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4474 // Reject any inaccessible member
4475 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4476 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4477 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4481 var ms = best_candidate as MethodSpec;
4482 if (ms != null && ms.IsGeneric) {
4483 bool constr_ok = true;
4484 if (ms.TypeArguments != null)
4485 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4487 if (ta_count == 0) {
4488 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4492 rc.Report.Error (411, loc,
4493 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4494 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4501 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4507 // We failed to find any method with correct argument count, report best candidate
4509 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4512 if (best_candidate.Kind == MemberKind.Constructor) {
4513 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4514 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4515 } else if (IsDelegateInvoke) {
4516 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4517 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4518 DelegateType.GetSignatureForError (), arg_count.ToString ());
4520 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4521 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4522 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4523 name, arg_count.ToString ());
4527 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4529 var pd = pm.Parameters;
4530 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4532 Parameter.Modifier p_mod = 0;
4534 int a_idx = 0, a_pos = 0;
4536 ArrayInitializer params_initializers = null;
4537 bool has_unsafe_arg = pm.MemberType.IsPointer;
4538 int arg_count = args == null ? 0 : args.Count;
4540 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4542 if (p_mod != Parameter.Modifier.PARAMS) {
4543 p_mod = pd.FixedParameters[a_idx].ModFlags;
4545 has_unsafe_arg |= pt.IsPointer;
4547 if (p_mod == Parameter.Modifier.PARAMS) {
4548 if (chose_params_expanded) {
4549 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4550 pt = TypeManager.GetElementType (pt);
4556 // Types have to be identical when ref or out modifer is used
4558 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4559 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4562 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4568 NamedArgument na = a as NamedArgument;
4570 int name_index = pd.GetParameterIndexByName (na.Name);
4571 if (name_index < 0 || name_index >= pd.Count) {
4572 if (IsDelegateInvoke) {
4573 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4574 ec.Report.Error (1746, na.Location,
4575 "The delegate `{0}' does not contain a parameter named `{1}'",
4576 DelegateType.GetSignatureForError (), na.Name);
4578 ec.Report.SymbolRelatedToPreviousError (member);
4579 ec.Report.Error (1739, na.Location,
4580 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4581 TypeManager.CSharpSignature (member), na.Name);
4583 } else if (args[name_index] != a) {
4584 if (IsDelegateInvoke)
4585 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4587 ec.Report.SymbolRelatedToPreviousError (member);
4589 ec.Report.Error (1744, na.Location,
4590 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4595 if (a.Expr.Type == InternalType.Dynamic)
4598 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4599 custom_errors.NoArgumentMatch (ec, member);
4603 Expression conv = null;
4604 if (a.ArgType == Argument.AType.ExtensionType) {
4605 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4608 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4610 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4613 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4620 // Convert params arguments to an array initializer
4622 if (params_initializers != null) {
4623 // we choose to use 'a.Expr' rather than 'conv' so that
4624 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4625 params_initializers.Add (a.Expr);
4626 args.RemoveAt (a_idx--);
4631 // Update the argument with the implicit conversion
4635 if (a_idx != arg_count) {
4636 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4641 // Fill not provided arguments required by params modifier
4643 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4645 args = new Arguments (1);
4647 pt = ptypes[pd.Count - 1];
4648 pt = TypeManager.GetElementType (pt);
4649 has_unsafe_arg |= pt.IsPointer;
4650 params_initializers = new ArrayInitializer (0, loc);
4654 // Append an array argument with all params arguments
4656 if (params_initializers != null) {
4657 args.Add (new Argument (
4658 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4662 if (has_unsafe_arg && !ec.IsUnsafe) {
4663 Expression.UnsafeError (ec, loc);
4667 // We could infer inaccesible type arguments
4669 if (type_arguments == null && member.IsGeneric) {
4670 var ms = (MethodSpec) member;
4671 foreach (var ta in ms.TypeArguments) {
4672 if (!ta.IsAccessible (ec.CurrentType)) {
4673 ec.Report.SymbolRelatedToPreviousError (ta);
4674 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4684 public class ConstantExpr : MemberExpr
4688 public ConstantExpr (ConstSpec constant, Location loc)
4690 this.constant = constant;
4694 public override string Name {
4695 get { throw new NotImplementedException (); }
4698 public override bool IsInstance {
4699 get { return !IsStatic; }
4702 public override bool IsStatic {
4703 get { return true; }
4706 protected override TypeSpec DeclaringType {
4707 get { return constant.DeclaringType; }
4710 public override Expression CreateExpressionTree (ResolveContext ec)
4712 throw new NotSupportedException ("ET");
4715 protected override Expression DoResolve (ResolveContext rc)
4717 ResolveInstanceExpression (rc, null);
4718 DoBestMemberChecks (rc, constant);
4720 var c = constant.GetConstant (rc);
4722 // Creates reference expression to the constant value
4723 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4726 public override void Emit (EmitContext ec)
4728 throw new NotSupportedException ();
4731 public override string GetSignatureForError ()
4733 return constant.GetSignatureForError ();
4736 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4738 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4743 /// Fully resolved expression that evaluates to a Field
4745 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4746 protected FieldSpec spec;
4747 VariableInfo variable_info;
4749 LocalTemporary temp;
4752 protected FieldExpr (Location l)
4757 public FieldExpr (FieldSpec spec, Location loc)
4762 type = spec.MemberType;
4765 public FieldExpr (FieldBase fi, Location l)
4772 public override string Name {
4778 public bool IsHoisted {
4780 IVariableReference hv = InstanceExpression as IVariableReference;
4781 return hv != null && hv.IsHoisted;
4785 public override bool IsInstance {
4787 return !spec.IsStatic;
4791 public override bool IsStatic {
4793 return spec.IsStatic;
4797 public FieldSpec Spec {
4803 protected override TypeSpec DeclaringType {
4805 return spec.DeclaringType;
4809 public VariableInfo VariableInfo {
4811 return variable_info;
4817 public override string GetSignatureForError ()
4819 return TypeManager.GetFullNameSignature (spec);
4822 public bool IsMarshalByRefAccess ()
4824 // Checks possible ldflda of field access expression
4825 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4826 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4827 !(InstanceExpression is This);
4830 public void SetHasAddressTaken ()
4832 IVariableReference vr = InstanceExpression as IVariableReference;
4834 vr.SetHasAddressTaken ();
4837 public override Expression CreateExpressionTree (ResolveContext ec)
4839 Expression instance;
4840 if (InstanceExpression == null) {
4841 instance = new NullLiteral (loc);
4843 instance = InstanceExpression.CreateExpressionTree (ec);
4846 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4848 CreateTypeOfExpression ());
4850 return CreateExpressionFactoryCall (ec, "Field", args);
4853 public Expression CreateTypeOfExpression ()
4855 return new TypeOfField (spec, loc);
4858 protected override Expression DoResolve (ResolveContext ec)
4860 return DoResolve (ec, null);
4863 Expression DoResolve (ResolveContext ec, Expression rhs)
4865 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4867 if (ResolveInstanceExpression (ec, rhs)) {
4868 // Resolve the field's instance expression while flow analysis is turned
4869 // off: when accessing a field "a.b", we must check whether the field
4870 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4872 if (lvalue_instance) {
4873 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4874 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4876 Expression right_side =
4877 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4879 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4882 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4883 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4887 if (InstanceExpression == null)
4891 DoBestMemberChecks (ec, spec);
4893 var fb = spec as FixedFieldSpec;
4894 IVariableReference var = InstanceExpression as IVariableReference;
4896 if (lvalue_instance && var != null && var.VariableInfo != null) {
4897 var.VariableInfo.SetFieldAssigned (ec, Name);
4901 IFixedExpression fe = InstanceExpression as IFixedExpression;
4902 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4903 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4906 if (InstanceExpression.eclass != ExprClass.Variable) {
4907 ec.Report.SymbolRelatedToPreviousError (spec);
4908 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4909 TypeManager.GetFullNameSignature (spec));
4910 } else if (var != null && var.IsHoisted) {
4911 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4914 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4917 eclass = ExprClass.Variable;
4919 // If the instance expression is a local variable or parameter.
4920 if (var == null || var.VariableInfo == null)
4923 VariableInfo vi = var.VariableInfo;
4924 if (!vi.IsFieldAssigned (ec, Name, loc))
4927 variable_info = vi.GetSubStruct (Name);
4931 static readonly int [] codes = {
4932 191, // instance, write access
4933 192, // instance, out access
4934 198, // static, write access
4935 199, // static, out access
4936 1648, // member of value instance, write access
4937 1649, // member of value instance, out access
4938 1650, // member of value static, write access
4939 1651 // member of value static, out access
4942 static readonly string [] msgs = {
4943 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4944 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4945 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4946 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4947 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4948 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4949 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4950 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4953 // The return value is always null. Returning a value simplifies calling code.
4954 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4957 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4961 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4963 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4968 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4970 Expression e = DoResolve (ec, right_side);
4975 spec.MemberDefinition.SetIsAssigned ();
4977 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4978 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4979 ec.Report.Warning (420, 1, loc,
4980 "`{0}': A volatile field references will not be treated as volatile",
4981 spec.GetSignatureForError ());
4984 if (spec.IsReadOnly) {
4985 // InitOnly fields can only be assigned in constructors or initializers
4986 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4987 return Report_AssignToReadonly (ec, right_side);
4989 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4991 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4992 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4993 return Report_AssignToReadonly (ec, right_side);
4994 // static InitOnly fields cannot be assigned-to in an instance constructor
4995 if (IsStatic && !ec.IsStatic)
4996 return Report_AssignToReadonly (ec, right_side);
4997 // instance constructors can't modify InitOnly fields of other instances of the same type
4998 if (!IsStatic && !(InstanceExpression is This))
4999 return Report_AssignToReadonly (ec, right_side);
5003 if (right_side == EmptyExpression.OutAccess.Instance &&
5004 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
5005 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5006 ec.Report.Warning (197, 1, loc,
5007 "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",
5008 GetSignatureForError ());
5011 eclass = ExprClass.Variable;
5015 public override int GetHashCode ()
5017 return spec.GetHashCode ();
5020 public bool IsFixed {
5023 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5025 IVariableReference variable = InstanceExpression as IVariableReference;
5026 if (variable != null)
5027 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5029 IFixedExpression fe = InstanceExpression as IFixedExpression;
5030 return fe != null && fe.IsFixed;
5034 public override bool Equals (object obj)
5036 FieldExpr fe = obj as FieldExpr;
5040 if (spec != fe.spec)
5043 if (InstanceExpression == null || fe.InstanceExpression == null)
5046 return InstanceExpression.Equals (fe.InstanceExpression);
5049 public void Emit (EmitContext ec, bool leave_copy)
5051 bool is_volatile = false;
5053 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5056 spec.MemberDefinition.SetIsUsed ();
5060 ec.Emit (OpCodes.Volatile);
5062 ec.Emit (OpCodes.Ldsfld, spec);
5065 EmitInstance (ec, false);
5067 // Optimization for build-in types
5068 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
5069 ec.EmitLoadFromPtr (type);
5071 var ff = spec as FixedFieldSpec;
5073 ec.Emit (OpCodes.Ldflda, spec);
5074 ec.Emit (OpCodes.Ldflda, ff.Element);
5077 ec.Emit (OpCodes.Volatile);
5079 ec.Emit (OpCodes.Ldfld, spec);
5085 ec.Emit (OpCodes.Dup);
5087 temp = new LocalTemporary (this.Type);
5093 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5095 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5097 EmitInstance (ec, prepared);
5101 ec.Emit (OpCodes.Dup);
5103 temp = new LocalTemporary (this.Type);
5108 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5109 ec.Emit (OpCodes.Volatile);
5111 spec.MemberDefinition.SetIsAssigned ();
5114 ec.Emit (OpCodes.Stsfld, spec);
5116 ec.Emit (OpCodes.Stfld, spec);
5125 public override void Emit (EmitContext ec)
5130 public override void EmitSideEffect (EmitContext ec)
5132 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5134 if (is_volatile) // || is_marshal_by_ref ())
5135 base.EmitSideEffect (ec);
5138 public void AddressOf (EmitContext ec, AddressOp mode)
5140 if ((mode & AddressOp.Store) != 0)
5141 spec.MemberDefinition.SetIsAssigned ();
5142 if ((mode & AddressOp.Load) != 0)
5143 spec.MemberDefinition.SetIsUsed ();
5146 // Handle initonly fields specially: make a copy and then
5147 // get the address of the copy.
5150 if (spec.IsReadOnly){
5152 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5165 local = ec.DeclareLocal (type, false);
5166 ec.Emit (OpCodes.Stloc, local);
5167 ec.Emit (OpCodes.Ldloca, local);
5173 ec.Emit (OpCodes.Ldsflda, spec);
5176 EmitInstance (ec, false);
5177 ec.Emit (OpCodes.Ldflda, spec);
5181 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5183 return MakeExpression (ctx);
5186 public override SLE.Expression MakeExpression (BuilderContext ctx)
5189 return base.MakeExpression (ctx);
5191 return SLE.Expression.Field (
5192 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5193 spec.GetMetaInfo ());
5197 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5199 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5205 /// Expression that evaluates to a Property. The Assign class
5206 /// might set the `Value' expression if we are in an assignment.
5208 /// This is not an LValue because we need to re-write the expression, we
5209 /// can not take data from the stack and store it.
5211 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5213 public PropertyExpr (PropertySpec spec, Location l)
5216 best_candidate = spec;
5217 type = spec.MemberType;
5222 protected override TypeSpec DeclaringType {
5224 return best_candidate.DeclaringType;
5228 public override string Name {
5230 return best_candidate.Name;
5234 public override bool IsInstance {
5240 public override bool IsStatic {
5242 return best_candidate.IsStatic;
5246 public PropertySpec PropertyInfo {
5248 return best_candidate;
5254 public override Expression CreateExpressionTree (ResolveContext ec)
5257 if (IsSingleDimensionalArrayLength ()) {
5258 args = new Arguments (1);
5259 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5260 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5263 args = new Arguments (2);
5264 if (InstanceExpression == null)
5265 args.Add (new Argument (new NullLiteral (loc)));
5267 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5268 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5269 return CreateExpressionFactoryCall (ec, "Property", args);
5272 public Expression CreateSetterTypeOfExpression ()
5274 return new TypeOfMethod (Setter, loc);
5277 public override string GetSignatureForError ()
5279 return best_candidate.GetSignatureForError ();
5282 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5285 return base.MakeExpression (ctx);
5287 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5291 public override SLE.Expression MakeExpression (BuilderContext ctx)
5294 return base.MakeExpression (ctx);
5296 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5300 void Error_PropertyNotValid (ResolveContext ec)
5302 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5303 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5304 GetSignatureForError ());
5307 bool IsSingleDimensionalArrayLength ()
5309 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5312 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5313 return ac != null && ac.Rank == 1;
5316 public override void Emit (EmitContext ec, bool leave_copy)
5319 // Special case: length of single dimension array property is turned into ldlen
5321 if (IsSingleDimensionalArrayLength ()) {
5323 EmitInstance (ec, false);
5324 ec.Emit (OpCodes.Ldlen);
5325 ec.Emit (OpCodes.Conv_I4);
5329 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5332 ec.Emit (OpCodes.Dup);
5334 temp = new LocalTemporary (this.Type);
5340 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5344 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5345 args = new Arguments (0);
5350 ec.Emit (OpCodes.Dup);
5352 temp = new LocalTemporary (this.Type);
5357 args = new Arguments (1);
5361 temp = new LocalTemporary (this.Type);
5363 args.Add (new Argument (temp));
5365 args.Add (new Argument (source));
5369 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5377 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5379 eclass = ExprClass.PropertyAccess;
5381 if (best_candidate.IsNotRealProperty) {
5382 Error_PropertyNotValid (rc);
5385 ResolveInstanceExpression (rc, right_side);
5387 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5388 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5389 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5391 type = p.MemberType;
5395 DoBestMemberChecks (rc, best_candidate);
5399 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5401 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5405 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5407 // getter and setter can be different for base calls
5408 MethodSpec getter, setter;
5409 protected T best_candidate;
5411 protected LocalTemporary temp;
5412 protected bool prepared;
5414 protected PropertyOrIndexerExpr (Location l)
5421 public MethodSpec Getter {
5430 public MethodSpec Setter {
5441 protected override Expression DoResolve (ResolveContext ec)
5443 if (eclass == ExprClass.Unresolved) {
5444 var expr = OverloadResolve (ec, null);
5449 return expr.Resolve (ec);
5452 if (!ResolveGetter (ec))
5458 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5460 if (right_side == EmptyExpression.OutAccess.Instance) {
5461 // TODO: best_candidate can be null at this point
5462 INamedBlockVariable variable = null;
5463 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5464 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5465 best_candidate.Name);
5467 right_side.DoResolveLValue (ec, this);
5472 // if the property/indexer returns a value type, and we try to set a field in it
5473 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5474 Error_CannotModifyIntermediateExpressionValue (ec);
5477 if (eclass == ExprClass.Unresolved) {
5478 var expr = OverloadResolve (ec, right_side);
5483 return expr.ResolveLValue (ec, right_side);
5486 if (!ResolveSetter (ec))
5493 // Implements the IAssignMethod interface for assignments
5495 public abstract void Emit (EmitContext ec, bool leave_copy);
5496 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5498 public override void Emit (EmitContext ec)
5503 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5505 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5507 bool ResolveGetter (ResolveContext rc)
5509 if (!best_candidate.HasGet) {
5510 if (InstanceExpression != EmptyExpression.Null) {
5511 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5512 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5513 best_candidate.GetSignatureForError ());
5516 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5517 if (best_candidate.HasDifferentAccessibility) {
5518 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5519 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5520 TypeManager.CSharpSignature (best_candidate));
5522 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5523 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5527 if (best_candidate.HasDifferentAccessibility) {
5528 CheckProtectedMemberAccess (rc, best_candidate.Get);
5531 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5535 bool ResolveSetter (ResolveContext rc)
5537 if (!best_candidate.HasSet) {
5538 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5539 GetSignatureForError ());
5543 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5544 if (best_candidate.HasDifferentAccessibility) {
5545 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5546 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5547 GetSignatureForError ());
5549 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5550 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5554 if (best_candidate.HasDifferentAccessibility)
5555 CheckProtectedMemberAccess (rc, best_candidate.Set);
5557 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5563 /// Fully resolved expression that evaluates to an Event
5565 public class EventExpr : MemberExpr, IAssignMethod
5567 readonly EventSpec spec;
5570 public EventExpr (EventSpec spec, Location loc)
5578 protected override TypeSpec DeclaringType {
5580 return spec.DeclaringType;
5584 public override string Name {
5590 public override bool IsInstance {
5592 return !spec.IsStatic;
5596 public override bool IsStatic {
5598 return spec.IsStatic;
5602 public MethodSpec Operator {
5610 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5613 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5615 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5616 if (spec.BackingField != null &&
5617 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5619 spec.MemberDefinition.SetIsUsed ();
5621 if (!ec.IsObsolete) {
5622 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5624 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5627 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5628 Error_AssignmentEventOnly (ec);
5630 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5632 InstanceExpression = null;
5634 return ml.ResolveMemberAccess (ec, left, original);
5638 return base.ResolveMemberAccess (ec, left, original);
5641 public override Expression CreateExpressionTree (ResolveContext ec)
5643 throw new NotSupportedException ("ET");
5646 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5648 if (right_side == EmptyExpression.EventAddition) {
5649 op = spec.AccessorAdd;
5650 } else if (right_side == EmptyExpression.EventSubtraction) {
5651 op = spec.AccessorRemove;
5655 Error_AssignmentEventOnly (ec);
5659 op = CandidateToBaseOverride (ec, op);
5663 protected override Expression DoResolve (ResolveContext ec)
5665 eclass = ExprClass.EventAccess;
5666 type = spec.MemberType;
5668 ResolveInstanceExpression (ec, null);
5670 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5671 Error_AssignmentEventOnly (ec);
5674 DoBestMemberChecks (ec, spec);
5678 public override void Emit (EmitContext ec)
5680 throw new NotSupportedException ();
5681 //Error_CannotAssign ();
5684 #region IAssignMethod Members
5686 public void Emit (EmitContext ec, bool leave_copy)
5688 throw new NotImplementedException ();
5691 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5693 if (leave_copy || !prepare_for_load)
5694 throw new NotImplementedException ("EventExpr::EmitAssign");
5696 Arguments args = new Arguments (1);
5697 args.Add (new Argument (source));
5698 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5703 void Error_AssignmentEventOnly (ResolveContext ec)
5705 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5706 ec.Report.Error (79, loc,
5707 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5708 GetSignatureForError ());
5710 ec.Report.Error (70, loc,
5711 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5712 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5716 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5718 name = name.Substring (0, name.LastIndexOf ('.'));
5719 base.Error_CannotCallAbstractBase (rc, name);
5722 public override string GetSignatureForError ()
5724 return TypeManager.CSharpSignature (spec);
5727 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5729 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5733 public class TemporaryVariableReference : VariableReference
5735 public class Declarator : Statement
5737 TemporaryVariableReference variable;
5739 public Declarator (TemporaryVariableReference variable)
5741 this.variable = variable;
5745 protected override void DoEmit (EmitContext ec)
5747 variable.li.CreateBuilder (ec);
5750 protected override void CloneTo (CloneContext clonectx, Statement target)
5758 public TemporaryVariableReference (LocalVariable li, Location loc)
5761 this.type = li.Type;
5765 public override bool IsLockedByStatement {
5773 public LocalVariable LocalInfo {
5779 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5781 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5782 return new TemporaryVariableReference (li, loc);
5785 public override Expression CreateExpressionTree (ResolveContext ec)
5787 throw new NotSupportedException ("ET");
5790 protected override Expression DoResolve (ResolveContext ec)
5792 eclass = ExprClass.Variable;
5795 // Don't capture temporary variables except when using
5796 // iterator redirection
5798 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5799 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5800 storey.CaptureLocalVariable (ec, li);
5806 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5808 return Resolve (ec);
5811 public override void Emit (EmitContext ec)
5813 li.CreateBuilder (ec);
5818 public void EmitAssign (EmitContext ec, Expression source)
5820 li.CreateBuilder (ec);
5822 EmitAssign (ec, source, false, false);
5825 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5827 return li.HoistedVariant;
5830 public override bool IsFixed {
5831 get { return true; }
5834 public override bool IsRef {
5835 get { return false; }
5838 public override string Name {
5839 get { throw new NotImplementedException (); }
5842 public override void SetHasAddressTaken ()
5844 throw new NotImplementedException ();
5847 protected override ILocalVariable Variable {
5851 public override VariableInfo VariableInfo {
5852 get { throw new NotImplementedException (); }
5857 /// Handles `var' contextual keyword; var becomes a keyword only
5858 /// if no type called var exists in a variable scope
5860 class VarExpr : SimpleName
5862 public VarExpr (Location loc)
5867 public bool InferType (ResolveContext ec, Expression right_side)
5870 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5872 type = right_side.Type;
5873 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5874 ec.Report.Error (815, loc,
5875 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5876 type.GetSignatureForError ());
5880 eclass = ExprClass.Variable;
5884 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5886 if (RootContext.Version < LanguageVersion.V_3)
5887 base.Error_TypeOrNamespaceNotFound (ec);
5889 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");