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
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 int args_gap = System.Math.Abs (arg_count - param_count);
3749 if (optional_count != 0) {
3750 if (args_gap > optional_count)
3751 return int.MaxValue - 10000 + args_gap - optional_count;
3753 // Readjust expected number when params used
3754 if (cpd.HasParams) {
3756 if (arg_count < param_count)
3758 } else if (arg_count > param_count) {
3759 return int.MaxValue - 10000 + args_gap;
3761 } else if (arg_count != param_count) {
3763 return int.MaxValue - 10000 + args_gap;
3764 if (arg_count < param_count - 1)
3765 return int.MaxValue - 10000 + args_gap;
3768 // Resize to fit optional arguments
3769 if (optional_count != 0) {
3770 if (arguments == null) {
3771 arguments = new Arguments (optional_count);
3773 // Have to create a new container, so the next run can do same
3774 var resized = new Arguments (param_count);
3775 resized.AddRange (arguments);
3776 arguments = resized;
3779 for (int i = arg_count; i < param_count; ++i)
3780 arguments.Add (null);
3784 if (arg_count > 0) {
3786 // Shuffle named arguments to the right positions if there are any
3788 if (arguments[arg_count - 1] is NamedArgument) {
3789 arg_count = arguments.Count;
3791 for (int i = 0; i < arg_count; ++i) {
3792 bool arg_moved = false;
3794 NamedArgument na = arguments[i] as NamedArgument;
3798 int index = pd.GetParameterIndexByName (na.Name);
3800 // Named parameter not found
3804 // already reordered
3809 if (index >= param_count) {
3810 // When using parameters which should not be available to the user
3811 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3814 arguments.Add (null);
3818 temp = arguments[index];
3820 // The slot has been taken by positional argument
3821 if (temp != null && !(temp is NamedArgument))
3826 arguments = arguments.MarkOrderedArgument (na);
3830 arguments[index] = arguments[i];
3831 arguments[i] = temp;
3838 arg_count = arguments.Count;
3840 } else if (arguments != null) {
3841 arg_count = arguments.Count;
3845 // 1. Handle generic method using type arguments when specified or type inference
3848 var ms = candidate as MethodSpec;
3849 if (ms != null && ms.IsGeneric) {
3850 // Setup constraint checker for probing only
3851 ConstraintChecker cc = new ConstraintChecker (null);
3853 if (type_arguments != null) {
3854 var g_args_count = ms.Arity;
3855 if (g_args_count != type_arguments.Count)
3856 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3858 ms = ms.MakeGenericMethod (type_arguments.Arguments);
3860 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3861 // for now it simplifies things. I should probably add a callback to ResolveContext
3862 if (lambda_conv_msgs == null) {
3863 lambda_conv_msgs = new SessionReportPrinter ();
3864 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3867 var ti = new TypeInference (arguments);
3868 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3869 lambda_conv_msgs.EndSession ();
3872 return ti.InferenceScore - 20000;
3874 if (i_args.Length != 0) {
3875 ms = ms.MakeGenericMethod (i_args);
3878 cc.IgnoreInferredDynamic = true;
3882 // Type arguments constraints have to match for the method to be applicable
3884 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3886 return int.MaxValue - 25000;
3890 // We have a generic return type and at same time the method is override which
3891 // means we have to also inflate override return type in case the candidate is
3892 // best candidate and override return type is different to base return type.
3894 // virtual Foo<T, object> with override Foo<T, dynamic>
3896 if (candidate != pm) {
3897 MethodSpec override_ms = (MethodSpec) pm;
3898 var inflator = new TypeParameterInflator (ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3899 returnType = inflator.Inflate (returnType);
3901 returnType = ms.ReturnType;
3905 ptypes = ms.Parameters.Types;
3907 if (type_arguments != null)
3908 return int.MaxValue - 15000;
3914 // 2. Each argument has to be implicitly convertible to method parameter
3916 Parameter.Modifier p_mod = 0;
3919 for (int i = 0; i < arg_count; i++) {
3920 Argument a = arguments[i];
3922 if (!pd.FixedParameters[i].HasDefaultValue) {
3923 arguments = orig_args;
3924 return arg_count * 2 + 2;
3928 // Get the default value expression, we can use the same expression
3929 // if the type matches
3931 Expression e = pd.FixedParameters[i].DefaultValue;
3932 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3934 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3936 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3937 e = new MemberAccess (new MemberAccess (new MemberAccess (
3938 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3940 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3946 arguments[i] = new Argument (e, Argument.AType.Default);
3950 if (p_mod != Parameter.Modifier.PARAMS) {
3951 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3953 } else if (!params_expanded_form) {
3954 params_expanded_form = true;
3955 pt = ((ElementTypeSpec) pt).Element;
3961 if (!params_expanded_form) {
3962 if (a.ArgType == Argument.AType.ExtensionType) {
3964 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3967 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3968 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3969 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3974 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3977 dynamicArgument = true;
3982 // It can be applicable in expanded form (when not doing exact match like for delegates)
3984 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3985 if (!params_expanded_form)
3986 pt = ((ElementTypeSpec) pt).Element;
3989 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3992 params_expanded_form = true;
3993 } else if (score < 0) {
3994 params_expanded_form = true;
3995 dynamicArgument = true;
4000 if (params_expanded_form)
4002 return (arg_count - i) * 2 + score;
4007 // When params parameter has no argument it will be provided later if the method is the best candidate
4009 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4010 params_expanded_form = true;
4013 // Restore original arguments for dynamic binder to keep the intention of original source code
4015 if (dynamicArgument)
4016 arguments = orig_args;
4022 // Tests argument compatibility with the parameter
4023 // The possible return values are
4025 // 1 - modifier mismatch
4026 // 2 - type mismatch
4027 // -1 - dynamic binding required
4029 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4032 // Types have to be identical when ref or out modifer
4033 // is used and argument is not of dynamic type
4035 if ((argument.Modifier | param_mod) != 0) {
4036 if (argument.Type != parameter) {
4038 // Do full equality check after quick path
4040 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4042 // Using dynamic for ref/out parameter can still succeed at runtime
4044 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4051 if (argument.Modifier != param_mod) {
4053 // Using dynamic for ref/out parameter can still succeed at runtime
4055 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4062 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4066 // Deploy custom error reporting for lambda methods. When probing lambda methods
4067 // keep all errors reported in separate set and once we are done and no best
4068 // candidate found, this set is used to report more details about what was wrong
4071 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4072 if (lambda_conv_msgs == null) {
4073 lambda_conv_msgs = new SessionReportPrinter ();
4074 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4078 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4079 if (lambda_conv_msgs != null) {
4080 lambda_conv_msgs.EndSession ();
4090 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4092 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4094 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4097 var ac_p = p as ArrayContainer;
4099 var ac_q = ((ArrayContainer) q);
4100 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4101 if (specific == ac_p.Element)
4103 if (specific == ac_q.Element)
4105 } else if (TypeManager.IsGenericType (p)) {
4106 var pargs = TypeManager.GetTypeArguments (p);
4107 var qargs = TypeManager.GetTypeArguments (q);
4109 bool p_specific_at_least_once = false;
4110 bool q_specific_at_least_once = false;
4112 for (int i = 0; i < pargs.Length; i++) {
4113 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4114 if (specific == pargs[i])
4115 p_specific_at_least_once = true;
4116 if (specific == qargs[i])
4117 q_specific_at_least_once = true;
4120 if (p_specific_at_least_once && !q_specific_at_least_once)
4122 if (!p_specific_at_least_once && q_specific_at_least_once)
4130 // Find the best method from candidate list
4132 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4134 List<AmbiguousCandidate> ambiguous_candidates = null;
4136 MemberSpec best_candidate;
4137 Arguments best_candidate_args = null;
4138 bool best_candidate_params = false;
4139 bool best_candidate_dynamic = false;
4140 int best_candidate_rate;
4141 IParametersMember best_parameter_member = null;
4143 int args_count = args != null ? args.Count : 0;
4145 Arguments candidate_args = args;
4146 bool error_mode = false;
4147 var current_type = rc.CurrentType;
4148 MemberSpec invocable_member = null;
4150 // Be careful, cannot return until error reporter is restored
4152 best_candidate = null;
4153 best_candidate_rate = int.MaxValue;
4155 var type_members = members;
4159 for (int i = 0; i < type_members.Count; ++i) {
4160 var member = type_members[i];
4163 // Methods in a base class are not candidates if any method in a derived
4164 // class is applicable
4166 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4170 if (!member.IsAccessible (current_type))
4173 if (rc.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4177 IParametersMember pm = member as IParametersMember;
4180 // Will use it later to report ambiguity between best method and invocable member
4182 if (Invocation.IsMemberInvocable (member))
4183 invocable_member = member;
4189 // Overload resolution is looking for base member but using parameter names
4190 // and default values from the closest member. That means to do expensive lookup
4191 // for the closest override for virtual or abstract members
4193 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4194 var override_params = base_provider.GetOverrideMemberParameters (member);
4195 if (override_params != null)
4196 pm = override_params;
4200 // Check if the member candidate is applicable
4202 bool params_expanded_form = false;
4203 bool dynamic_argument = false;
4204 TypeSpec rt = pm.MemberType;
4205 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4208 // How does it score compare to others
4210 if (candidate_rate < best_candidate_rate) {
4211 best_candidate_rate = candidate_rate;
4212 best_candidate = member;
4213 best_candidate_args = candidate_args;
4214 best_candidate_params = params_expanded_form;
4215 best_candidate_dynamic = dynamic_argument;
4216 best_parameter_member = pm;
4217 best_candidate_return_type = rt;
4218 } else if (candidate_rate == 0) {
4220 // The member look is done per type for most operations but sometimes
4221 // it's not possible like for binary operators overload because they
4222 // are unioned between 2 sides
4224 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4225 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4230 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4232 // We pack all interface members into top level type which makes the overload resolution
4233 // more complicated for interfaces. We compensate it by removing methods with same
4234 // signature when building the cache hence this path should not really be hit often
4237 // interface IA { void Foo (int arg); }
4238 // interface IB : IA { void Foo (params int[] args); }
4240 // IB::Foo is the best overload when calling IB.Foo (1)
4243 if (ambiguous_candidates != null) {
4244 foreach (var amb_cand in ambiguous_candidates) {
4245 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4254 ambiguous_candidates = null;
4257 // Is the new candidate better
4258 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4262 best_candidate = member;
4263 best_candidate_args = candidate_args;
4264 best_candidate_params = params_expanded_form;
4265 best_candidate_dynamic = dynamic_argument;
4266 best_parameter_member = pm;
4267 best_candidate_return_type = rt;
4269 // It's not better but any other found later could be but we are not sure yet
4270 if (ambiguous_candidates == null)
4271 ambiguous_candidates = new List<AmbiguousCandidate> ();
4273 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4277 // Restore expanded arguments
4278 if (candidate_args != args)
4279 candidate_args = args;
4281 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4283 if (prev_recorder != null)
4284 rc.Report.SetPrinter (prev_recorder);
4288 // We've found exact match
4290 if (best_candidate_rate == 0)
4294 // Try extension methods lookup when no ordinary method match was found and provider enables it
4297 var emg = base_provider.LookupExtensionMethod (rc);
4299 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4301 best_candidate_extension_group = emg;
4302 return (T) (MemberSpec) emg.BestCandidate;
4307 // Don't run expensive error reporting mode for probing
4314 lambda_conv_msgs = null;
4319 // No best member match found, report an error
4321 if (best_candidate_rate != 0 || error_mode) {
4322 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4326 if (best_candidate_dynamic) {
4327 if (args[0].ArgType == Argument.AType.ExtensionType) {
4328 rc.Report.Error (1973, loc,
4329 "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",
4330 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4333 BestCandidateIsDynamic = true;
4337 if (ambiguous_candidates != null) {
4339 // Now check that there are no ambiguities i.e the selected method
4340 // should be better than all the others
4342 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4343 var candidate = ambiguous_candidates [ix];
4345 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4346 var ambiguous = candidate.Member;
4347 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4348 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4349 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4350 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4351 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4354 return (T) best_candidate;
4359 if (invocable_member != null) {
4360 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4361 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4362 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4363 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4367 // And now check if the arguments are all
4368 // compatible, perform conversions if
4369 // necessary etc. and return if everything is
4372 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4375 if (best_candidate == null)
4379 // Check ObsoleteAttribute on the best method
4381 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4382 if (oa != null && !rc.IsObsolete)
4383 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4385 var dep = best_candidate.GetMissingDependencies ();
4387 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4390 best_candidate.MemberDefinition.SetIsUsed ();
4392 args = best_candidate_args;
4393 return (T) best_candidate;
4396 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4398 return ResolveMember<MethodSpec> (rc, ref args);
4401 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4402 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4404 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4407 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4408 ec.Report.SymbolRelatedToPreviousError (method);
4409 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4410 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4411 TypeManager.CSharpSignature (method));
4414 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4415 TypeManager.CSharpSignature (method));
4416 } else if (IsDelegateInvoke) {
4417 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4418 DelegateType.GetSignatureForError ());
4420 ec.Report.SymbolRelatedToPreviousError (method);
4421 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4422 method.GetSignatureForError ());
4425 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4427 string index = (idx + 1).ToString ();
4428 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4429 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4430 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4431 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4432 index, Parameter.GetModifierSignature (a.Modifier));
4434 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4435 index, Parameter.GetModifierSignature (mod));
4437 string p1 = a.GetSignatureForError ();
4438 string p2 = TypeManager.CSharpName (paramType);
4441 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4442 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4443 ec.Report.SymbolRelatedToPreviousError (paramType);
4446 ec.Report.Error (1503, loc,
4447 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4452 // We have failed to find exact match so we return error info about the closest match
4454 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4456 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4457 int arg_count = args == null ? 0 : args.Count;
4459 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4460 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4461 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4465 if (lambda_conv_msgs != null) {
4466 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4471 // For candidates which match on parameters count report more details about incorrect arguments
4474 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4475 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4476 // Reject any inaccessible member
4477 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4478 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4479 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4483 var ms = best_candidate as MethodSpec;
4484 if (ms != null && ms.IsGeneric) {
4485 bool constr_ok = true;
4486 if (ms.TypeArguments != null)
4487 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4489 if (ta_count == 0) {
4490 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4494 rc.Report.Error (411, loc,
4495 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4496 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4503 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4509 // We failed to find any method with correct argument count, report best candidate
4511 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4514 if (best_candidate.Kind == MemberKind.Constructor) {
4515 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4516 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4517 } else if (IsDelegateInvoke) {
4518 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4519 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4520 DelegateType.GetSignatureForError (), arg_count.ToString ());
4522 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4523 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4524 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4525 name, arg_count.ToString ());
4529 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4531 var pd = pm.Parameters;
4532 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4534 Parameter.Modifier p_mod = 0;
4536 int a_idx = 0, a_pos = 0;
4538 ArrayInitializer params_initializers = null;
4539 bool has_unsafe_arg = pm.MemberType.IsPointer;
4540 int arg_count = args == null ? 0 : args.Count;
4542 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4544 if (p_mod != Parameter.Modifier.PARAMS) {
4545 p_mod = pd.FixedParameters[a_idx].ModFlags;
4547 has_unsafe_arg |= pt.IsPointer;
4549 if (p_mod == Parameter.Modifier.PARAMS) {
4550 if (chose_params_expanded) {
4551 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4552 pt = TypeManager.GetElementType (pt);
4558 // Types have to be identical when ref or out modifer is used
4560 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4561 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4564 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4570 NamedArgument na = a as NamedArgument;
4572 int name_index = pd.GetParameterIndexByName (na.Name);
4573 if (name_index < 0 || name_index >= pd.Count) {
4574 if (IsDelegateInvoke) {
4575 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4576 ec.Report.Error (1746, na.Location,
4577 "The delegate `{0}' does not contain a parameter named `{1}'",
4578 DelegateType.GetSignatureForError (), na.Name);
4580 ec.Report.SymbolRelatedToPreviousError (member);
4581 ec.Report.Error (1739, na.Location,
4582 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4583 TypeManager.CSharpSignature (member), na.Name);
4585 } else if (args[name_index] != a) {
4586 if (IsDelegateInvoke)
4587 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4589 ec.Report.SymbolRelatedToPreviousError (member);
4591 ec.Report.Error (1744, na.Location,
4592 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4597 if (a.Expr.Type == InternalType.Dynamic)
4600 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4601 custom_errors.NoArgumentMatch (ec, member);
4605 Expression conv = null;
4606 if (a.ArgType == Argument.AType.ExtensionType) {
4607 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4610 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4612 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4615 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4622 // Convert params arguments to an array initializer
4624 if (params_initializers != null) {
4625 // we choose to use 'a.Expr' rather than 'conv' so that
4626 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4627 params_initializers.Add (a.Expr);
4628 args.RemoveAt (a_idx--);
4633 // Update the argument with the implicit conversion
4637 if (a_idx != arg_count) {
4638 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4643 // Fill not provided arguments required by params modifier
4645 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4647 args = new Arguments (1);
4649 pt = ptypes[pd.Count - 1];
4650 pt = TypeManager.GetElementType (pt);
4651 has_unsafe_arg |= pt.IsPointer;
4652 params_initializers = new ArrayInitializer (0, loc);
4656 // Append an array argument with all params arguments
4658 if (params_initializers != null) {
4659 args.Add (new Argument (
4660 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4664 if (has_unsafe_arg && !ec.IsUnsafe) {
4665 Expression.UnsafeError (ec, loc);
4669 // We could infer inaccesible type arguments
4671 if (type_arguments == null && member.IsGeneric) {
4672 var ms = (MethodSpec) member;
4673 foreach (var ta in ms.TypeArguments) {
4674 if (!ta.IsAccessible (ec.CurrentType)) {
4675 ec.Report.SymbolRelatedToPreviousError (ta);
4676 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4686 public class ConstantExpr : MemberExpr
4690 public ConstantExpr (ConstSpec constant, Location loc)
4692 this.constant = constant;
4696 public override string Name {
4697 get { throw new NotImplementedException (); }
4700 public override bool IsInstance {
4701 get { return !IsStatic; }
4704 public override bool IsStatic {
4705 get { return true; }
4708 protected override TypeSpec DeclaringType {
4709 get { return constant.DeclaringType; }
4712 public override Expression CreateExpressionTree (ResolveContext ec)
4714 throw new NotSupportedException ("ET");
4717 protected override Expression DoResolve (ResolveContext rc)
4719 ResolveInstanceExpression (rc, null);
4720 DoBestMemberChecks (rc, constant);
4722 var c = constant.GetConstant (rc);
4724 // Creates reference expression to the constant value
4725 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4728 public override void Emit (EmitContext ec)
4730 throw new NotSupportedException ();
4733 public override string GetSignatureForError ()
4735 return constant.GetSignatureForError ();
4738 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4740 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4745 /// Fully resolved expression that evaluates to a Field
4747 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4748 protected FieldSpec spec;
4749 VariableInfo variable_info;
4751 LocalTemporary temp;
4754 protected FieldExpr (Location l)
4759 public FieldExpr (FieldSpec spec, Location loc)
4764 type = spec.MemberType;
4767 public FieldExpr (FieldBase fi, Location l)
4774 public override string Name {
4780 public bool IsHoisted {
4782 IVariableReference hv = InstanceExpression as IVariableReference;
4783 return hv != null && hv.IsHoisted;
4787 public override bool IsInstance {
4789 return !spec.IsStatic;
4793 public override bool IsStatic {
4795 return spec.IsStatic;
4799 public FieldSpec Spec {
4805 protected override TypeSpec DeclaringType {
4807 return spec.DeclaringType;
4811 public VariableInfo VariableInfo {
4813 return variable_info;
4819 public override string GetSignatureForError ()
4821 return TypeManager.GetFullNameSignature (spec);
4824 public bool IsMarshalByRefAccess ()
4826 // Checks possible ldflda of field access expression
4827 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4828 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4829 !(InstanceExpression is This);
4832 public void SetHasAddressTaken ()
4834 IVariableReference vr = InstanceExpression as IVariableReference;
4836 vr.SetHasAddressTaken ();
4839 public override Expression CreateExpressionTree (ResolveContext ec)
4841 Expression instance;
4842 if (InstanceExpression == null) {
4843 instance = new NullLiteral (loc);
4845 instance = InstanceExpression.CreateExpressionTree (ec);
4848 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4850 CreateTypeOfExpression ());
4852 return CreateExpressionFactoryCall (ec, "Field", args);
4855 public Expression CreateTypeOfExpression ()
4857 return new TypeOfField (spec, loc);
4860 protected override Expression DoResolve (ResolveContext ec)
4862 return DoResolve (ec, null);
4865 Expression DoResolve (ResolveContext ec, Expression rhs)
4867 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4869 if (ResolveInstanceExpression (ec, rhs)) {
4870 // Resolve the field's instance expression while flow analysis is turned
4871 // off: when accessing a field "a.b", we must check whether the field
4872 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4874 if (lvalue_instance) {
4875 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4876 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4878 Expression right_side =
4879 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4881 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4884 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4885 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4889 if (InstanceExpression == null)
4893 DoBestMemberChecks (ec, spec);
4895 var fb = spec as FixedFieldSpec;
4896 IVariableReference var = InstanceExpression as IVariableReference;
4898 if (lvalue_instance && var != null && var.VariableInfo != null) {
4899 var.VariableInfo.SetFieldAssigned (ec, Name);
4903 IFixedExpression fe = InstanceExpression as IFixedExpression;
4904 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4905 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4908 if (InstanceExpression.eclass != ExprClass.Variable) {
4909 ec.Report.SymbolRelatedToPreviousError (spec);
4910 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4911 TypeManager.GetFullNameSignature (spec));
4912 } else if (var != null && var.IsHoisted) {
4913 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4916 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4919 eclass = ExprClass.Variable;
4921 // If the instance expression is a local variable or parameter.
4922 if (var == null || var.VariableInfo == null)
4925 VariableInfo vi = var.VariableInfo;
4926 if (!vi.IsFieldAssigned (ec, Name, loc))
4929 variable_info = vi.GetSubStruct (Name);
4933 static readonly int [] codes = {
4934 191, // instance, write access
4935 192, // instance, out access
4936 198, // static, write access
4937 199, // static, out access
4938 1648, // member of value instance, write access
4939 1649, // member of value instance, out access
4940 1650, // member of value static, write access
4941 1651 // member of value static, out access
4944 static readonly string [] msgs = {
4945 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4946 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4947 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4948 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4949 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4950 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4951 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4952 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4955 // The return value is always null. Returning a value simplifies calling code.
4956 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4959 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4963 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4965 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4970 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4972 Expression e = DoResolve (ec, right_side);
4977 spec.MemberDefinition.SetIsAssigned ();
4979 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4980 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4981 ec.Report.Warning (420, 1, loc,
4982 "`{0}': A volatile field references will not be treated as volatile",
4983 spec.GetSignatureForError ());
4986 if (spec.IsReadOnly) {
4987 // InitOnly fields can only be assigned in constructors or initializers
4988 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4989 return Report_AssignToReadonly (ec, right_side);
4991 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4993 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4994 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4995 return Report_AssignToReadonly (ec, right_side);
4996 // static InitOnly fields cannot be assigned-to in an instance constructor
4997 if (IsStatic && !ec.IsStatic)
4998 return Report_AssignToReadonly (ec, right_side);
4999 // instance constructors can't modify InitOnly fields of other instances of the same type
5000 if (!IsStatic && !(InstanceExpression is This))
5001 return Report_AssignToReadonly (ec, right_side);
5005 if (right_side == EmptyExpression.OutAccess.Instance &&
5006 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
5007 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5008 ec.Report.Warning (197, 1, loc,
5009 "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",
5010 GetSignatureForError ());
5013 eclass = ExprClass.Variable;
5017 public override int GetHashCode ()
5019 return spec.GetHashCode ();
5022 public bool IsFixed {
5025 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5027 IVariableReference variable = InstanceExpression as IVariableReference;
5028 if (variable != null)
5029 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5031 IFixedExpression fe = InstanceExpression as IFixedExpression;
5032 return fe != null && fe.IsFixed;
5036 public override bool Equals (object obj)
5038 FieldExpr fe = obj as FieldExpr;
5042 if (spec != fe.spec)
5045 if (InstanceExpression == null || fe.InstanceExpression == null)
5048 return InstanceExpression.Equals (fe.InstanceExpression);
5051 public void Emit (EmitContext ec, bool leave_copy)
5053 bool is_volatile = false;
5055 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5058 spec.MemberDefinition.SetIsUsed ();
5062 ec.Emit (OpCodes.Volatile);
5064 ec.Emit (OpCodes.Ldsfld, spec);
5067 EmitInstance (ec, false);
5069 // Optimization for build-in types
5070 if (TypeManager.IsStruct (type) && type == ec.MemberContext.CurrentType && InstanceExpression.Type == type) {
5071 ec.EmitLoadFromPtr (type);
5073 var ff = spec as FixedFieldSpec;
5075 ec.Emit (OpCodes.Ldflda, spec);
5076 ec.Emit (OpCodes.Ldflda, ff.Element);
5079 ec.Emit (OpCodes.Volatile);
5081 ec.Emit (OpCodes.Ldfld, spec);
5087 ec.Emit (OpCodes.Dup);
5089 temp = new LocalTemporary (this.Type);
5095 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5097 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5099 EmitInstance (ec, prepared);
5103 ec.Emit (OpCodes.Dup);
5105 temp = new LocalTemporary (this.Type);
5110 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5111 ec.Emit (OpCodes.Volatile);
5113 spec.MemberDefinition.SetIsAssigned ();
5116 ec.Emit (OpCodes.Stsfld, spec);
5118 ec.Emit (OpCodes.Stfld, spec);
5127 public override void Emit (EmitContext ec)
5132 public override void EmitSideEffect (EmitContext ec)
5134 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5136 if (is_volatile) // || is_marshal_by_ref ())
5137 base.EmitSideEffect (ec);
5140 public void AddressOf (EmitContext ec, AddressOp mode)
5142 if ((mode & AddressOp.Store) != 0)
5143 spec.MemberDefinition.SetIsAssigned ();
5144 if ((mode & AddressOp.Load) != 0)
5145 spec.MemberDefinition.SetIsUsed ();
5148 // Handle initonly fields specially: make a copy and then
5149 // get the address of the copy.
5152 if (spec.IsReadOnly){
5154 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5167 local = ec.DeclareLocal (type, false);
5168 ec.Emit (OpCodes.Stloc, local);
5169 ec.Emit (OpCodes.Ldloca, local);
5175 ec.Emit (OpCodes.Ldsflda, spec);
5178 EmitInstance (ec, false);
5179 ec.Emit (OpCodes.Ldflda, spec);
5183 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5185 return MakeExpression (ctx);
5188 public override SLE.Expression MakeExpression (BuilderContext ctx)
5191 return base.MakeExpression (ctx);
5193 return SLE.Expression.Field (
5194 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5195 spec.GetMetaInfo ());
5199 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5201 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5207 /// Expression that evaluates to a Property. The Assign class
5208 /// might set the `Value' expression if we are in an assignment.
5210 /// This is not an LValue because we need to re-write the expression, we
5211 /// can not take data from the stack and store it.
5213 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5215 public PropertyExpr (PropertySpec spec, Location l)
5218 best_candidate = spec;
5219 type = spec.MemberType;
5224 protected override TypeSpec DeclaringType {
5226 return best_candidate.DeclaringType;
5230 public override string Name {
5232 return best_candidate.Name;
5236 public override bool IsInstance {
5242 public override bool IsStatic {
5244 return best_candidate.IsStatic;
5248 public PropertySpec PropertyInfo {
5250 return best_candidate;
5256 public override Expression CreateExpressionTree (ResolveContext ec)
5259 if (IsSingleDimensionalArrayLength ()) {
5260 args = new Arguments (1);
5261 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5262 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5265 args = new Arguments (2);
5266 if (InstanceExpression == null)
5267 args.Add (new Argument (new NullLiteral (loc)));
5269 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5270 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5271 return CreateExpressionFactoryCall (ec, "Property", args);
5274 public Expression CreateSetterTypeOfExpression ()
5276 return new TypeOfMethod (Setter, loc);
5279 public override string GetSignatureForError ()
5281 return best_candidate.GetSignatureForError ();
5284 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5287 return base.MakeExpression (ctx);
5289 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5293 public override SLE.Expression MakeExpression (BuilderContext ctx)
5296 return base.MakeExpression (ctx);
5298 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5302 void Error_PropertyNotValid (ResolveContext ec)
5304 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5305 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5306 GetSignatureForError ());
5309 bool IsSingleDimensionalArrayLength ()
5311 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5314 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5315 return ac != null && ac.Rank == 1;
5318 public override void Emit (EmitContext ec, bool leave_copy)
5321 // Special case: length of single dimension array property is turned into ldlen
5323 if (IsSingleDimensionalArrayLength ()) {
5325 EmitInstance (ec, false);
5326 ec.Emit (OpCodes.Ldlen);
5327 ec.Emit (OpCodes.Conv_I4);
5331 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5334 ec.Emit (OpCodes.Dup);
5336 temp = new LocalTemporary (this.Type);
5342 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5346 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5347 args = new Arguments (0);
5352 ec.Emit (OpCodes.Dup);
5354 temp = new LocalTemporary (this.Type);
5359 args = new Arguments (1);
5363 temp = new LocalTemporary (this.Type);
5365 args.Add (new Argument (temp));
5367 args.Add (new Argument (source));
5371 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5379 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5381 eclass = ExprClass.PropertyAccess;
5383 if (best_candidate.IsNotRealProperty) {
5384 Error_PropertyNotValid (rc);
5387 ResolveInstanceExpression (rc, right_side);
5389 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5390 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5391 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5393 type = p.MemberType;
5397 DoBestMemberChecks (rc, best_candidate);
5401 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5403 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5407 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5409 // getter and setter can be different for base calls
5410 MethodSpec getter, setter;
5411 protected T best_candidate;
5413 protected LocalTemporary temp;
5414 protected bool prepared;
5416 protected PropertyOrIndexerExpr (Location l)
5423 public MethodSpec Getter {
5432 public MethodSpec Setter {
5443 protected override Expression DoResolve (ResolveContext ec)
5445 if (eclass == ExprClass.Unresolved) {
5446 var expr = OverloadResolve (ec, null);
5451 return expr.Resolve (ec);
5454 if (!ResolveGetter (ec))
5460 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5462 if (right_side == EmptyExpression.OutAccess.Instance) {
5463 // TODO: best_candidate can be null at this point
5464 INamedBlockVariable variable = null;
5465 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5466 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5467 best_candidate.Name);
5469 right_side.DoResolveLValue (ec, this);
5474 // if the property/indexer returns a value type, and we try to set a field in it
5475 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5476 Error_CannotModifyIntermediateExpressionValue (ec);
5479 if (eclass == ExprClass.Unresolved) {
5480 var expr = OverloadResolve (ec, right_side);
5485 return expr.ResolveLValue (ec, right_side);
5488 if (!ResolveSetter (ec))
5495 // Implements the IAssignMethod interface for assignments
5497 public abstract void Emit (EmitContext ec, bool leave_copy);
5498 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5500 public override void Emit (EmitContext ec)
5505 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5507 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5509 bool ResolveGetter (ResolveContext rc)
5511 if (!best_candidate.HasGet) {
5512 if (InstanceExpression != EmptyExpression.Null) {
5513 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5514 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5515 best_candidate.GetSignatureForError ());
5518 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5519 if (best_candidate.HasDifferentAccessibility) {
5520 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5521 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5522 TypeManager.CSharpSignature (best_candidate));
5524 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5525 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5529 if (best_candidate.HasDifferentAccessibility) {
5530 CheckProtectedMemberAccess (rc, best_candidate.Get);
5533 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5537 bool ResolveSetter (ResolveContext rc)
5539 if (!best_candidate.HasSet) {
5540 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5541 GetSignatureForError ());
5545 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5546 if (best_candidate.HasDifferentAccessibility) {
5547 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5548 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5549 GetSignatureForError ());
5551 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5552 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5556 if (best_candidate.HasDifferentAccessibility)
5557 CheckProtectedMemberAccess (rc, best_candidate.Set);
5559 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5565 /// Fully resolved expression that evaluates to an Event
5567 public class EventExpr : MemberExpr, IAssignMethod
5569 readonly EventSpec spec;
5572 public EventExpr (EventSpec spec, Location loc)
5580 protected override TypeSpec DeclaringType {
5582 return spec.DeclaringType;
5586 public override string Name {
5592 public override bool IsInstance {
5594 return !spec.IsStatic;
5598 public override bool IsStatic {
5600 return spec.IsStatic;
5604 public MethodSpec Operator {
5612 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5615 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5617 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5618 if (spec.BackingField != null &&
5619 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5621 spec.MemberDefinition.SetIsUsed ();
5623 if (!ec.IsObsolete) {
5624 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5626 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5629 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5630 Error_AssignmentEventOnly (ec);
5632 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5634 InstanceExpression = null;
5636 return ml.ResolveMemberAccess (ec, left, original);
5640 return base.ResolveMemberAccess (ec, left, original);
5643 public override Expression CreateExpressionTree (ResolveContext ec)
5645 throw new NotSupportedException ("ET");
5648 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5650 if (right_side == EmptyExpression.EventAddition) {
5651 op = spec.AccessorAdd;
5652 } else if (right_side == EmptyExpression.EventSubtraction) {
5653 op = spec.AccessorRemove;
5657 Error_AssignmentEventOnly (ec);
5661 op = CandidateToBaseOverride (ec, op);
5665 protected override Expression DoResolve (ResolveContext ec)
5667 eclass = ExprClass.EventAccess;
5668 type = spec.MemberType;
5670 ResolveInstanceExpression (ec, null);
5672 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5673 Error_AssignmentEventOnly (ec);
5676 DoBestMemberChecks (ec, spec);
5680 public override void Emit (EmitContext ec)
5682 throw new NotSupportedException ();
5683 //Error_CannotAssign ();
5686 #region IAssignMethod Members
5688 public void Emit (EmitContext ec, bool leave_copy)
5690 throw new NotImplementedException ();
5693 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5695 if (leave_copy || !prepare_for_load)
5696 throw new NotImplementedException ("EventExpr::EmitAssign");
5698 Arguments args = new Arguments (1);
5699 args.Add (new Argument (source));
5700 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5705 void Error_AssignmentEventOnly (ResolveContext ec)
5707 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5708 ec.Report.Error (79, loc,
5709 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5710 GetSignatureForError ());
5712 ec.Report.Error (70, loc,
5713 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5714 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5718 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5720 name = name.Substring (0, name.LastIndexOf ('.'));
5721 base.Error_CannotCallAbstractBase (rc, name);
5724 public override string GetSignatureForError ()
5726 return TypeManager.CSharpSignature (spec);
5729 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5731 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5735 public class TemporaryVariableReference : VariableReference
5737 public class Declarator : Statement
5739 TemporaryVariableReference variable;
5741 public Declarator (TemporaryVariableReference variable)
5743 this.variable = variable;
5747 protected override void DoEmit (EmitContext ec)
5749 variable.li.CreateBuilder (ec);
5752 protected override void CloneTo (CloneContext clonectx, Statement target)
5760 public TemporaryVariableReference (LocalVariable li, Location loc)
5763 this.type = li.Type;
5767 public override bool IsLockedByStatement {
5775 public LocalVariable LocalInfo {
5781 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5783 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5784 return new TemporaryVariableReference (li, loc);
5787 public override Expression CreateExpressionTree (ResolveContext ec)
5789 throw new NotSupportedException ("ET");
5792 protected override Expression DoResolve (ResolveContext ec)
5794 eclass = ExprClass.Variable;
5797 // Don't capture temporary variables except when using
5798 // iterator redirection
5800 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5801 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5802 storey.CaptureLocalVariable (ec, li);
5808 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5810 return Resolve (ec);
5813 public override void Emit (EmitContext ec)
5815 li.CreateBuilder (ec);
5820 public void EmitAssign (EmitContext ec, Expression source)
5822 li.CreateBuilder (ec);
5824 EmitAssign (ec, source, false, false);
5827 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5829 return li.HoistedVariant;
5832 public override bool IsFixed {
5833 get { return true; }
5836 public override bool IsRef {
5837 get { return false; }
5840 public override string Name {
5841 get { throw new NotImplementedException (); }
5844 public override void SetHasAddressTaken ()
5846 throw new NotImplementedException ();
5849 protected override ILocalVariable Variable {
5853 public override VariableInfo VariableInfo {
5854 get { throw new NotImplementedException (); }
5859 /// Handles `var' contextual keyword; var becomes a keyword only
5860 /// if no type called var exists in a variable scope
5862 class VarExpr : SimpleName
5864 public VarExpr (Location loc)
5869 public bool InferType (ResolveContext ec, Expression right_side)
5872 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5874 type = right_side.Type;
5875 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5876 ec.Report.Error (815, loc,
5877 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5878 type.GetSignatureForError ());
5882 eclass = ExprClass.Variable;
5886 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5888 if (RootContext.Version < LanguageVersion.V_3)
5889 base.Error_TypeOrNamespaceNotFound (ec);
5891 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");