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 // FIXME: THIS IS TOO SLOW and it should not be needed either
206 int errors = ec.Module.Compiler.Report.Errors;
208 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
213 TypeExpr te = fne as TypeExpr;
215 if (!silent && errors == ec.Module.Compiler.Report.Errors)
216 fne.Error_UnexpectedKind (ec.Module.Compiler.Report, null, "type", loc);
220 if (!te.type.IsAccessible (ec.CurrentType)) {
221 ec.Module.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
222 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
227 var dep = te.type.GetMissingDependencies ();
229 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
233 // Obsolete checks cannot be done when resolving base context as they
234 // require type dependecies to be set but we are just resolving them
236 if (!silent && !(ec is TypeContainer.BaseContext)) {
237 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
238 if (obsolete_attr != null && !ec.IsObsolete) {
239 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Module.Compiler.Report);
246 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
248 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
251 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
253 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
256 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
258 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
259 name, TypeManager.CSharpName (type));
262 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
264 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
265 "expressions can be used as a statement");
268 public void Error_InvalidExpressionStatement (BlockContext ec)
270 Error_InvalidExpressionStatement (ec.Report, loc);
273 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
275 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
278 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
280 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
283 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
285 // The error was already reported as CS1660
286 if (type == InternalType.AnonymousMethod)
289 string from_type = type.GetSignatureForError ();
290 string to_type = target.GetSignatureForError ();
291 if (from_type == to_type) {
292 from_type = string.Format ("{0} [{1}]", from_type, type.MemberDefinition.DeclaringAssembly.FullName);
293 to_type = string.Format ("{0} [{1}]", to_type, target.MemberDefinition.DeclaringAssembly.FullName);
297 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
302 ec.Report.DisableReporting ();
303 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
304 ec.Report.EnableReporting ();
307 ec.Report.Error (266, loc,
308 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
311 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
316 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
318 // Better message for possible generic expressions
319 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
320 report.SymbolRelatedToPreviousError (member);
321 if (member is TypeSpec)
322 member = ((TypeSpec) member).GetDefinition ();
324 member = ((MethodSpec) member).GetGenericMethodDefinition ();
326 string name = member.Kind == MemberKind.Method ? "method" : "type";
327 if (member.IsGeneric) {
328 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
329 name, member.GetSignatureForError (), member.Arity.ToString ());
331 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
332 name, member.GetSignatureForError ());
335 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
339 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
341 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
345 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
347 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
350 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
352 ec.Report.SymbolRelatedToPreviousError (type);
353 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
354 TypeManager.CSharpName (type), name);
357 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
359 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
362 protected void Error_VoidPointerOperation (ResolveContext rc)
364 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
367 public ResolveFlags ExprClassToResolveFlags {
371 case ExprClass.Namespace:
372 return ResolveFlags.Type;
374 case ExprClass.MethodGroup:
375 return ResolveFlags.MethodGroup;
377 case ExprClass.TypeParameter:
378 return ResolveFlags.TypeParameter;
380 case ExprClass.Value:
381 case ExprClass.Variable:
382 case ExprClass.PropertyAccess:
383 case ExprClass.EventAccess:
384 case ExprClass.IndexerAccess:
385 return ResolveFlags.VariableOrValue;
388 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
394 /// Resolves an expression and performs semantic analysis on it.
398 /// Currently Resolve wraps DoResolve to perform sanity
399 /// checking and assertion checking on what we expect from Resolve.
401 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
403 if (eclass != ExprClass.Unresolved)
413 if ((flags & e.ExprClassToResolveFlags) == 0) {
414 e.Error_UnexpectedKind (ec, flags, loc);
419 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
422 } catch (Exception ex) {
423 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
426 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
427 return EmptyExpression.Null; // TODO: Add location
432 /// Resolves an expression and performs semantic analysis on it.
434 public Expression Resolve (ResolveContext rc)
436 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
440 /// Resolves an expression for LValue assignment
444 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
445 /// checking and assertion checking on what we expect from Resolve
447 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
449 int errors = ec.Report.Errors;
450 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
452 Expression e = DoResolveLValue (ec, right_side);
454 if (e != null && out_access && !(e is IMemoryLocation)) {
455 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
456 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
458 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
459 // e.GetType () + " " + e.GetSignatureForError ());
464 if (errors == ec.Report.Errors) {
466 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
468 Error_ValueAssignment (ec, loc);
473 if (e.eclass == ExprClass.Unresolved)
474 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
476 if ((e.type == null) && !(e is GenericTypeExpr))
477 throw new Exception ("Expression " + e + " did not set its type after Resolve");
482 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
484 rc.Module.Compiler.Report.Error (182, loc,
485 "An attribute argument must be a constant expression, typeof expression or array creation expression");
489 /// Emits the code for the expression
493 /// The Emit method is invoked to generate the code
494 /// for the expression.
496 public abstract void Emit (EmitContext ec);
499 // Emit code to branch to @target if this expression is equivalent to @on_true.
500 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
501 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
502 // including the use of conditional branches. Note also that a branch MUST be emitted
503 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
506 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
509 // Emit this expression for its side effects, not for its value.
510 // The default implementation is to emit the value, and then throw it away.
511 // Subclasses can provide more efficient implementations, but those MUST be equivalent
512 public virtual void EmitSideEffect (EmitContext ec)
515 ec.Emit (OpCodes.Pop);
519 /// Protected constructor. Only derivate types should
520 /// be able to be created
523 protected Expression ()
528 /// Returns a fully formed expression after a MemberLookup
531 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
533 if (spec is EventSpec)
534 return new EventExpr ((EventSpec) spec, loc);
535 if (spec is ConstSpec)
536 return new ConstantExpr ((ConstSpec) spec, loc);
537 if (spec is FieldSpec)
538 return new FieldExpr ((FieldSpec) spec, loc);
539 if (spec is PropertySpec)
540 return new PropertyExpr ((PropertySpec) spec, loc);
541 if (spec is TypeSpec)
542 return new TypeExpression (((TypeSpec) spec), loc);
547 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
549 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
551 rc.Report.SymbolRelatedToPreviousError (type);
553 // Report meaningful error for struct as they always have default ctor in C# context
554 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
556 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
557 type.GetSignatureForError ());
563 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
564 return r.ResolveMember<MethodSpec> (rc, ref args);
568 public enum MemberLookupRestrictions
577 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
578 // `qualifier_type' or null to lookup members in the current class.
580 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
582 var members = MemberCache.FindMembers (queried_type, name, false);
586 MemberSpec non_method = null;
587 MemberSpec ambig_non_method = null;
588 currentType = currentType ?? InternalType.FakeInternalType;
590 for (int i = 0; i < members.Count; ++i) {
591 var member = members[i];
593 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
594 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
597 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
601 if (!member.IsAccessible (currentType))
605 // With runtime binder we can have a situation where queried type is inaccessible
606 // because it came via dynamic object, the check about inconsisted accessibility
607 // had no effect as the type was unknown during compilation
610 // private class N { }
612 // public dynamic Foo ()
618 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (currentType))
622 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
623 if (member is MethodSpec)
624 return new MethodGroupExpr (members, queried_type, loc);
626 if (!Invocation.IsMemberInvocable (member))
630 if (non_method == null || member is MethodSpec) {
632 } else if (currentType != null) {
633 ambig_non_method = member;
637 if (non_method != null) {
638 if (ambig_non_method != null && rc != null) {
639 rc.Report.SymbolRelatedToPreviousError (non_method);
640 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
641 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
642 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
645 if (non_method is MethodSpec)
646 return new MethodGroupExpr (members, queried_type, loc);
648 return ExprClassFromMemberInfo (non_method, loc);
651 if (members[0].DeclaringType.BaseType == null)
654 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
656 } while (members != null);
661 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
663 throw new NotImplementedException ();
666 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
668 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
672 /// Returns an expression that can be used to invoke operator true
673 /// on the expression if it exists.
675 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
677 return GetOperatorTrueOrFalse (ec, e, true, loc);
681 /// Returns an expression that can be used to invoke operator false
682 /// on the expression if it exists.
684 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
686 return GetOperatorTrueOrFalse (ec, e, false, loc);
689 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
691 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
692 var methods = MemberCache.GetUserOperator (e.type, op, false);
696 Arguments arguments = new Arguments (1);
697 arguments.Add (new Argument (e));
699 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
700 var oper = res.ResolveOperator (ec, ref arguments);
705 return new UserOperatorCall (oper, arguments, null, loc);
708 public virtual string ExprClassName
712 case ExprClass.Unresolved:
714 case ExprClass.Value:
716 case ExprClass.Variable:
718 case ExprClass.Namespace:
722 case ExprClass.MethodGroup:
723 return "method group";
724 case ExprClass.PropertyAccess:
725 return "property access";
726 case ExprClass.EventAccess:
727 return "event access";
728 case ExprClass.IndexerAccess:
729 return "indexer access";
730 case ExprClass.Nothing:
732 case ExprClass.TypeParameter:
733 return "type parameter";
735 throw new Exception ("Should not happen");
740 /// Reports that we were expecting `expr' to be of class `expected'
742 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
744 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
747 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
751 name = mc.GetSignatureForError ();
753 name = GetSignatureForError ();
755 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
756 name, was, expected);
759 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
761 string [] valid = new string [4];
764 if ((flags & ResolveFlags.VariableOrValue) != 0) {
765 valid [count++] = "variable";
766 valid [count++] = "value";
769 if ((flags & ResolveFlags.Type) != 0)
770 valid [count++] = "type";
772 if ((flags & ResolveFlags.MethodGroup) != 0)
773 valid [count++] = "method group";
776 valid [count++] = "unknown";
778 StringBuilder sb = new StringBuilder (valid [0]);
779 for (int i = 1; i < count - 1; i++) {
781 sb.Append (valid [i]);
784 sb.Append ("' or `");
785 sb.Append (valid [count - 1]);
788 ec.Report.Error (119, loc,
789 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
792 public static void UnsafeError (ResolveContext ec, Location loc)
794 UnsafeError (ec.Report, loc);
797 public static void UnsafeError (Report Report, Location loc)
799 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
804 // Returns the size of type `t' if known, otherwise, 0
806 public static int GetTypeSize (TypeSpec t)
808 if (t == TypeManager.int32_type ||
809 t == TypeManager.uint32_type ||
810 t == TypeManager.float_type)
812 else if (t == TypeManager.int64_type ||
813 t == TypeManager.uint64_type ||
814 t == TypeManager.double_type)
816 else if (t == TypeManager.byte_type ||
817 t == TypeManager.sbyte_type ||
818 t == TypeManager.bool_type)
820 else if (t == TypeManager.short_type ||
821 t == TypeManager.char_type ||
822 t == TypeManager.ushort_type)
824 else if (t == TypeManager.decimal_type)
830 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
832 ec.Report.SymbolRelatedToPreviousError (type);
833 if (ec.CurrentInitializerVariable != null) {
834 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
835 TypeManager.CSharpName (type), GetSignatureForError ());
837 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
838 GetSignatureForError ());
843 // Converts `source' to an int, uint, long or ulong.
845 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
847 if (source.type == InternalType.Dynamic) {
848 Arguments args = new Arguments (1);
849 args.Add (new Argument (source));
850 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
853 Expression converted;
855 using (ec.Set (ResolveContext.Options.CheckedScope)) {
856 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
857 if (converted == null)
858 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
859 if (converted == null)
860 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
861 if (converted == null)
862 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
864 if (converted == null) {
865 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
871 // Only positive constants are allowed at compile time
873 Constant c = converted as Constant;
874 if (c != null && c.IsNegative)
875 Error_NegativeArrayIndex (ec, source.loc);
877 // No conversion needed to array index
878 if (converted.Type == TypeManager.int32_type)
881 return new ArrayIndexCast (converted).Resolve (ec);
885 // Derived classes implement this method by cloning the fields that
886 // could become altered during the Resolve stage
888 // Only expressions that are created for the parser need to implement
891 protected virtual void CloneTo (CloneContext clonectx, Expression target)
893 throw new NotImplementedException (
895 "CloneTo not implemented for expression {0}", this.GetType ()));
899 // Clones an expression created by the parser.
901 // We only support expressions created by the parser so far, not
902 // expressions that have been resolved (many more classes would need
903 // to implement CloneTo).
905 // This infrastructure is here merely for Lambda expressions which
906 // compile the same code using different type values for the same
907 // arguments to find the correct overload
909 public virtual Expression Clone (CloneContext clonectx)
911 Expression cloned = (Expression) MemberwiseClone ();
912 CloneTo (clonectx, cloned);
918 // Implementation of expression to expression tree conversion
920 public abstract Expression CreateExpressionTree (ResolveContext ec);
922 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
924 return CreateExpressionFactoryCall (ec, name, null, args, loc);
927 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
929 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
932 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
934 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
937 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
939 var t = ec.Module.PredefinedTypes.Expression.Resolve (loc);
943 return new TypeExpression (t, loc);
947 // Implemented by all expressions which support conversion from
948 // compiler expression to invokable runtime expression. Used by
949 // dynamic C# binder.
951 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
953 throw new NotImplementedException ("MakeExpression for " + GetType ());
958 /// This is just a base class for expressions that can
959 /// appear on statements (invocations, object creation,
960 /// assignments, post/pre increment and decrement). The idea
961 /// being that they would support an extra Emition interface that
962 /// does not leave a result on the stack.
964 public abstract class ExpressionStatement : Expression {
966 public ExpressionStatement ResolveStatement (BlockContext ec)
968 Expression e = Resolve (ec);
972 ExpressionStatement es = e as ExpressionStatement;
974 Error_InvalidExpressionStatement (ec);
980 /// Requests the expression to be emitted in a `statement'
981 /// context. This means that no new value is left on the
982 /// stack after invoking this method (constrasted with
983 /// Emit that will always leave a value on the stack).
985 public abstract void EmitStatement (EmitContext ec);
987 public override void EmitSideEffect (EmitContext ec)
994 /// This kind of cast is used to encapsulate the child
995 /// whose type is child.Type into an expression that is
996 /// reported to return "return_type". This is used to encapsulate
997 /// expressions which have compatible types, but need to be dealt
998 /// at higher levels with.
1000 /// For example, a "byte" expression could be encapsulated in one
1001 /// of these as an "unsigned int". The type for the expression
1002 /// would be "unsigned int".
1005 public abstract class TypeCast : Expression
1007 protected readonly Expression child;
1009 protected TypeCast (Expression child, TypeSpec return_type)
1011 eclass = child.eclass;
1012 loc = child.Location;
1017 public Expression Child {
1023 public override Expression CreateExpressionTree (ResolveContext ec)
1025 Arguments args = new Arguments (2);
1026 args.Add (new Argument (child.CreateExpressionTree (ec)));
1027 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1029 if (type.IsPointer || child.Type.IsPointer)
1030 Error_PointerInsideExpressionTree (ec);
1032 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1035 protected override Expression DoResolve (ResolveContext ec)
1037 // This should never be invoked, we are born in fully
1038 // initialized state.
1043 public override void Emit (EmitContext ec)
1048 public override SLE.Expression MakeExpression (BuilderContext ctx)
1051 return base.MakeExpression (ctx);
1053 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1054 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1055 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1059 protected override void CloneTo (CloneContext clonectx, Expression t)
1064 public override bool IsNull {
1065 get { return child.IsNull; }
1069 public class EmptyCast : TypeCast {
1070 EmptyCast (Expression child, TypeSpec target_type)
1071 : base (child, target_type)
1075 public static Expression Create (Expression child, TypeSpec type)
1077 Constant c = child as Constant;
1079 return new EmptyConstantCast (c, type);
1081 EmptyCast e = child as EmptyCast;
1083 return new EmptyCast (e.child, type);
1085 return new EmptyCast (child, type);
1088 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1090 child.EmitBranchable (ec, label, on_true);
1093 public override void EmitSideEffect (EmitContext ec)
1095 child.EmitSideEffect (ec);
1100 // Used for predefined class library user casts (no obsolete check, etc.)
1102 public class OperatorCast : TypeCast {
1103 MethodSpec conversion_operator;
1105 public OperatorCast (Expression child, TypeSpec target_type)
1106 : this (child, target_type, false)
1110 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1111 : base (child, target_type)
1113 conversion_operator = GetConversionOperator (find_explicit);
1114 if (conversion_operator == null)
1115 throw new InternalErrorException ("Outer conversion routine is out of sync");
1118 // Returns the implicit operator that converts from
1119 // 'child.Type' to our target type (type)
1120 MethodSpec GetConversionOperator (bool find_explicit)
1122 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1124 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1126 mi = MemberCache.GetUserOperator (type, op, true);
1129 foreach (MethodSpec oper in mi) {
1130 if (oper.ReturnType != type)
1133 if (oper.Parameters.Types [0] == child.Type)
1140 public override void Emit (EmitContext ec)
1143 ec.Emit (OpCodes.Call, conversion_operator);
1148 /// This is a numeric cast to a Decimal
1150 public class CastToDecimal : OperatorCast {
1151 public CastToDecimal (Expression child)
1152 : this (child, false)
1156 public CastToDecimal (Expression child, bool find_explicit)
1157 : base (child, TypeManager.decimal_type, find_explicit)
1163 /// This is an explicit numeric cast from a Decimal
1165 public class CastFromDecimal : TypeCast
1167 static Dictionary<TypeSpec, MethodSpec> operators;
1169 public CastFromDecimal (Expression child, TypeSpec return_type)
1170 : base (child, return_type)
1172 if (child.Type != TypeManager.decimal_type)
1173 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1176 // Returns the explicit operator that converts from an
1177 // express of type System.Decimal to 'type'.
1178 public Expression Resolve ()
1180 if (operators == null) {
1181 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1183 operators = new Dictionary<TypeSpec, MethodSpec> ();
1184 foreach (MethodSpec oper in all_oper) {
1185 AParametersCollection pd = oper.Parameters;
1186 if (pd.Types [0] == TypeManager.decimal_type)
1187 operators.Add (oper.ReturnType, oper);
1191 return operators.ContainsKey (type) ? this : null;
1194 public override void Emit (EmitContext ec)
1198 ec.Emit (OpCodes.Call, operators [type]);
1201 public static void Reset ()
1209 // Constant specialization of EmptyCast.
1210 // We need to special case this since an empty cast of
1211 // a constant is still a constant.
1213 public class EmptyConstantCast : Constant
1215 public Constant child;
1217 public EmptyConstantCast (Constant child, TypeSpec type)
1218 : base (child.Location)
1221 throw new ArgumentNullException ("child");
1224 this.eclass = child.eclass;
1228 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1230 if (child.Type == target_type)
1233 // FIXME: check that 'type' can be converted to 'target_type' first
1234 return child.ConvertExplicitly (in_checked_context, target_type);
1237 public override Expression CreateExpressionTree (ResolveContext ec)
1239 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1240 child.CreateExpressionTree (ec),
1241 new TypeOf (new TypeExpression (type, loc), loc));
1244 Error_PointerInsideExpressionTree (ec);
1246 return CreateExpressionFactoryCall (ec, "Convert", args);
1249 public override bool IsDefaultValue {
1250 get { return child.IsDefaultValue; }
1253 public override bool IsNegative {
1254 get { return child.IsNegative; }
1257 public override bool IsNull {
1258 get { return child.IsNull; }
1261 public override bool IsOneInteger {
1262 get { return child.IsOneInteger; }
1265 public override bool IsZeroInteger {
1266 get { return child.IsZeroInteger; }
1269 protected override Expression DoResolve (ResolveContext rc)
1274 public override void Emit (EmitContext ec)
1279 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1281 child.EmitBranchable (ec, label, on_true);
1283 // Only to make verifier happy
1284 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1285 ec.Emit (OpCodes.Unbox_Any, type);
1288 public override void EmitSideEffect (EmitContext ec)
1290 child.EmitSideEffect (ec);
1293 public override object GetValue ()
1295 return child.GetValue ();
1298 public override string GetValueAsLiteral ()
1300 return child.GetValueAsLiteral ();
1303 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1305 // FIXME: Do we need to check user conversions?
1306 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1308 return child.ConvertImplicitly (rc, target_type);
1313 /// This class is used to wrap literals which belong inside Enums
1315 public class EnumConstant : Constant
1317 public Constant Child;
1319 public EnumConstant (Constant child, TypeSpec enum_type)
1320 : base (child.Location)
1323 this.type = enum_type;
1326 protected EnumConstant (Location loc)
1331 protected override Expression DoResolve (ResolveContext rc)
1333 Child = Child.Resolve (rc);
1334 this.eclass = ExprClass.Value;
1338 public override void Emit (EmitContext ec)
1343 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1345 Child.EncodeAttributeValue (rc, enc, Child.Type);
1348 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1350 Child.EmitBranchable (ec, label, on_true);
1353 public override void EmitSideEffect (EmitContext ec)
1355 Child.EmitSideEffect (ec);
1358 public override string GetSignatureForError()
1360 return TypeManager.CSharpName (Type);
1363 public override object GetValue ()
1365 return Child.GetValue ();
1369 public override object GetTypedValue ()
1372 // The method can be used in dynamic context only (on closed types)
1374 // System.Enum.ToObject cannot be called on dynamic types
1375 // EnumBuilder has to be used, but we cannot use EnumBuilder
1376 // because it does not properly support generics
1378 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1382 public override string GetValueAsLiteral ()
1384 return Child.GetValueAsLiteral ();
1387 public EnumConstant Increment()
1389 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1392 public override bool IsDefaultValue {
1394 return Child.IsDefaultValue;
1398 public override bool IsZeroInteger {
1399 get { return Child.IsZeroInteger; }
1402 public override bool IsNegative {
1404 return Child.IsNegative;
1408 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1410 if (Child.Type == target_type)
1413 return Child.ConvertExplicitly (in_checked_context, target_type);
1416 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1418 if (this.type == type) {
1422 if (!Convert.ImplicitStandardConversionExists (this, type)){
1426 return Child.ConvertImplicitly (rc, type);
1431 /// This kind of cast is used to encapsulate Value Types in objects.
1433 /// The effect of it is to box the value type emitted by the previous
1436 public class BoxedCast : TypeCast {
1438 public BoxedCast (Expression expr, TypeSpec target_type)
1439 : base (expr, target_type)
1441 eclass = ExprClass.Value;
1444 protected override Expression DoResolve (ResolveContext ec)
1446 // This should never be invoked, we are born in fully
1447 // initialized state.
1452 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1454 // Only boxing to object type is supported
1455 if (targetType != TypeManager.object_type) {
1456 base.EncodeAttributeValue (rc, enc, targetType);
1460 enc.Encode (child.Type);
1461 child.EncodeAttributeValue (rc, enc, child.Type);
1464 public override void Emit (EmitContext ec)
1468 ec.Emit (OpCodes.Box, child.Type);
1471 public override void EmitSideEffect (EmitContext ec)
1473 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1474 // so, we need to emit the box+pop instructions in most cases
1475 if (TypeManager.IsStruct (child.Type) &&
1476 (type == TypeManager.object_type || type == TypeManager.value_type))
1477 child.EmitSideEffect (ec);
1479 base.EmitSideEffect (ec);
1483 public class UnboxCast : TypeCast {
1484 public UnboxCast (Expression expr, TypeSpec return_type)
1485 : base (expr, return_type)
1489 protected override Expression DoResolve (ResolveContext ec)
1491 // This should never be invoked, we are born in fully
1492 // initialized state.
1497 public override void Emit (EmitContext ec)
1501 ec.Emit (OpCodes.Unbox_Any, type);
1506 /// This is used to perform explicit numeric conversions.
1508 /// Explicit numeric conversions might trigger exceptions in a checked
1509 /// context, so they should generate the conv.ovf opcodes instead of
1512 public class ConvCast : TypeCast {
1513 public enum Mode : byte {
1514 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1516 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1517 U2_I1, U2_U1, U2_I2, U2_CH,
1518 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1519 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1520 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1521 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1522 CH_I1, CH_U1, CH_I2,
1523 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1524 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1530 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1531 : base (child, return_type)
1536 protected override Expression DoResolve (ResolveContext ec)
1538 // This should never be invoked, we are born in fully
1539 // initialized state.
1544 public override string ToString ()
1546 return String.Format ("ConvCast ({0}, {1})", mode, child);
1549 public override void Emit (EmitContext ec)
1553 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1555 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1556 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1557 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1558 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1559 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1561 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1562 case Mode.U1_CH: /* nothing */ break;
1564 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1565 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1566 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1567 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1568 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1569 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1571 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1572 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1573 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1574 case Mode.U2_CH: /* nothing */ break;
1576 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1577 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1578 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1579 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1580 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1581 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1582 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1584 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1585 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1586 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1587 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1588 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1589 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1591 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1592 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1593 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1594 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1595 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1596 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1597 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1598 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1599 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1601 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1602 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1603 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1604 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1605 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1606 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1607 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1608 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1609 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1611 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1612 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1613 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1615 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1616 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1617 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1618 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1619 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1620 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1621 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1622 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1623 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1625 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1626 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1627 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1628 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1629 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1630 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1631 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1632 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1633 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1634 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1636 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1640 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1641 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1642 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1643 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1644 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1646 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1647 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1649 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1650 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1651 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1652 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1653 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1654 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1656 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1657 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1658 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1659 case Mode.U2_CH: /* nothing */ break;
1661 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1662 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1663 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1664 case Mode.I4_U4: /* nothing */ break;
1665 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1666 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1667 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1669 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1670 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1671 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1672 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1673 case Mode.U4_I4: /* nothing */ break;
1674 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1676 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1677 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1678 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1679 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1681 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1682 case Mode.I8_U8: /* nothing */ break;
1683 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1684 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1686 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1687 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1688 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1689 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1690 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1691 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1692 case Mode.U8_I8: /* nothing */ break;
1693 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1694 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1696 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1697 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1698 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1700 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1701 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1702 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1703 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1704 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1705 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1706 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1707 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1708 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1710 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1711 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1712 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1713 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1714 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1715 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1716 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1717 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1718 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1719 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1721 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1727 class OpcodeCast : TypeCast
1731 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1732 : base (child, return_type)
1737 protected override Expression DoResolve (ResolveContext ec)
1739 // This should never be invoked, we are born in fully
1740 // initialized state.
1745 public override void Emit (EmitContext ec)
1751 public TypeSpec UnderlyingType {
1752 get { return child.Type; }
1757 // Opcode casts expression with 2 opcodes but only
1758 // single expression tree node
1760 class OpcodeCastDuplex : OpcodeCast
1762 readonly OpCode second;
1764 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1765 : base (child, returnType, first)
1767 this.second = second;
1770 public override void Emit (EmitContext ec)
1778 /// This kind of cast is used to encapsulate a child and cast it
1779 /// to the class requested
1781 public sealed class ClassCast : TypeCast {
1782 readonly bool forced;
1784 public ClassCast (Expression child, TypeSpec return_type)
1785 : base (child, return_type)
1789 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1790 : base (child, return_type)
1792 this.forced = forced;
1795 public override void Emit (EmitContext ec)
1799 bool gen = TypeManager.IsGenericParameter (child.Type);
1801 ec.Emit (OpCodes.Box, child.Type);
1803 if (type.IsGenericParameter) {
1804 ec.Emit (OpCodes.Unbox_Any, type);
1811 ec.Emit (OpCodes.Castclass, type);
1816 // Created during resolving pahse when an expression is wrapped or constantified
1817 // and original expression can be used later (e.g. for expression trees)
1819 public class ReducedExpression : Expression
1821 sealed class ReducedConstantExpression : EmptyConstantCast
1823 readonly Expression orig_expr;
1825 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1826 : base (expr, expr.Type)
1828 this.orig_expr = orig_expr;
1831 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1833 Constant c = base.ConvertImplicitly (rc, target_type);
1835 c = new ReducedConstantExpression (c, orig_expr);
1840 public override Expression CreateExpressionTree (ResolveContext ec)
1842 return orig_expr.CreateExpressionTree (ec);
1845 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1847 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1849 c = new ReducedConstantExpression (c, orig_expr);
1854 sealed class ReducedExpressionStatement : ExpressionStatement
1856 readonly Expression orig_expr;
1857 readonly ExpressionStatement stm;
1859 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1861 this.orig_expr = orig;
1863 this.loc = orig.Location;
1866 public override Expression CreateExpressionTree (ResolveContext ec)
1868 return orig_expr.CreateExpressionTree (ec);
1871 protected override Expression DoResolve (ResolveContext ec)
1873 eclass = stm.eclass;
1878 public override void Emit (EmitContext ec)
1883 public override void EmitStatement (EmitContext ec)
1885 stm.EmitStatement (ec);
1889 readonly Expression expr, orig_expr;
1891 private ReducedExpression (Expression expr, Expression orig_expr)
1894 this.eclass = expr.eclass;
1895 this.type = expr.Type;
1896 this.orig_expr = orig_expr;
1897 this.loc = orig_expr.Location;
1902 public Expression OriginalExpression {
1911 // Creates fully resolved expression switcher
1913 public static Constant Create (Constant expr, Expression original_expr)
1915 if (expr.eclass == ExprClass.Unresolved)
1916 throw new ArgumentException ("Unresolved expression");
1918 return new ReducedConstantExpression (expr, original_expr);
1921 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1923 return new ReducedExpressionStatement (s, orig);
1926 public static Expression Create (Expression expr, Expression original_expr)
1928 return Create (expr, original_expr, true);
1932 // Creates unresolved reduce expression. The original expression has to be
1933 // already resolved. Created expression is constant based based on `expr'
1934 // value unless canBeConstant is used
1936 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1938 if (canBeConstant) {
1939 Constant c = expr as Constant;
1941 return Create (c, original_expr);
1944 ExpressionStatement s = expr as ExpressionStatement;
1946 return Create (s, original_expr);
1948 if (expr.eclass == ExprClass.Unresolved)
1949 throw new ArgumentException ("Unresolved expression");
1951 return new ReducedExpression (expr, original_expr);
1954 public override Expression CreateExpressionTree (ResolveContext ec)
1956 return orig_expr.CreateExpressionTree (ec);
1959 protected override Expression DoResolve (ResolveContext ec)
1964 public override void Emit (EmitContext ec)
1969 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1971 expr.EmitBranchable (ec, target, on_true);
1974 public override SLE.Expression MakeExpression (BuilderContext ctx)
1976 return orig_expr.MakeExpression (ctx);
1981 // Standard composite pattern
1983 public abstract class CompositeExpression : Expression
1985 protected Expression expr;
1987 protected CompositeExpression (Expression expr)
1990 this.loc = expr.Location;
1993 public override Expression CreateExpressionTree (ResolveContext ec)
1995 return expr.CreateExpressionTree (ec);
1998 public Expression Child {
1999 get { return expr; }
2002 protected override Expression DoResolve (ResolveContext ec)
2004 expr = expr.Resolve (ec);
2007 eclass = expr.eclass;
2013 public override void Emit (EmitContext ec)
2018 public override bool IsNull {
2019 get { return expr.IsNull; }
2024 // Base of expressions used only to narrow resolve flow
2026 public abstract class ShimExpression : Expression
2028 protected Expression expr;
2030 protected ShimExpression (Expression expr)
2035 protected override void CloneTo (CloneContext clonectx, Expression t)
2040 ShimExpression target = (ShimExpression) t;
2041 target.expr = expr.Clone (clonectx);
2044 public override Expression CreateExpressionTree (ResolveContext ec)
2046 throw new NotSupportedException ("ET");
2049 public override void Emit (EmitContext ec)
2051 throw new InternalErrorException ("Missing Resolve call");
2054 public Expression Expr {
2055 get { return expr; }
2060 // Unresolved type name expressions
2062 public abstract class ATypeNameExpression : FullNamedExpression
2065 protected TypeArguments targs;
2067 protected ATypeNameExpression (string name, Location l)
2073 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2080 protected ATypeNameExpression (string name, int arity, Location l)
2081 : this (name, new UnboundTypeArguments (arity), l)
2087 protected int Arity {
2089 return targs == null ? 0 : targs.Count;
2093 public bool HasTypeArguments {
2095 return targs != null && !targs.IsEmpty;
2099 public string Name {
2108 public TypeArguments TypeArguments {
2116 public override bool Equals (object obj)
2118 ATypeNameExpression atne = obj as ATypeNameExpression;
2119 return atne != null && atne.Name == Name &&
2120 (targs == null || targs.Equals (atne.targs));
2123 public override int GetHashCode ()
2125 return Name.GetHashCode ();
2128 // TODO: Move it to MemberCore
2129 public static string GetMemberType (MemberCore mc)
2135 if (mc is FieldBase)
2137 if (mc is MethodCore)
2139 if (mc is EnumMember)
2147 public override string GetSignatureForError ()
2149 if (targs != null) {
2150 return Name + "<" + targs.GetSignatureForError () + ">";
2156 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2160 /// SimpleName expressions are formed of a single word and only happen at the beginning
2161 /// of a dotted-name.
2163 public class SimpleName : ATypeNameExpression
2165 public SimpleName (string name, Location l)
2170 public SimpleName (string name, TypeArguments args, Location l)
2171 : base (name, args, l)
2175 public SimpleName (string name, int arity, Location l)
2176 : base (name, arity, l)
2180 public SimpleName GetMethodGroup ()
2182 return new SimpleName (Name, targs, loc);
2185 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2187 if (ec.CurrentType != null) {
2188 if (ec.CurrentMemberDefinition != null) {
2189 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2191 Error_UnexpectedKind (ec.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2197 // TODO MemberCache: Implement
2199 string ns = ec.CurrentType.Namespace;
2200 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2201 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2202 var type = a.GetType (fullname);
2204 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2205 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2210 if (ec.CurrentTypeDefinition != null) {
2211 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2213 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2220 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2221 if (retval != null) {
2222 Error_TypeArgumentsCannotBeUsed (ec.Module.Compiler.Report, loc, retval.Type, Arity);
2224 var te = retval as TypeExpr;
2225 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2226 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2228 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2233 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Module.Compiler.Report);
2236 protected override Expression DoResolve (ResolveContext ec)
2238 return SimpleNameResolve (ec, null, false);
2241 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2243 return SimpleNameResolve (ec, right_side, false);
2246 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2248 int errors = ec.Module.Compiler.Report.Errors;
2249 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2252 if (fne.Type != null && Arity > 0) {
2253 if (HasTypeArguments) {
2254 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2255 return ct.ResolveAsTypeStep (ec, false);
2258 return new GenericOpenTypeExpr (fne.Type, loc);
2262 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2264 if (!(fne is Namespace))
2268 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2269 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2270 ec.Module.Compiler.Report.Error (1980, Location,
2271 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2272 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2275 return new DynamicTypeExpr (loc);
2281 if (silent || errors != ec.Module.Compiler.Report.Errors)
2284 Error_TypeOrNamespaceNotFound (ec);
2288 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2290 int lookup_arity = Arity;
2291 bool errorMode = false;
2293 Block current_block = rc.CurrentBlock;
2294 INamedBlockVariable variable = null;
2295 bool variable_found = false;
2299 // Stage 1: binding to local variables or parameters
2301 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2303 if (current_block != null && lookup_arity == 0) {
2304 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2305 if (!variable.IsDeclared) {
2306 // We found local name in accessible block but it's not
2307 // initialized yet, maybe the user wanted to bind to something else
2309 variable_found = true;
2311 e = variable.CreateReferenceExpression (rc, loc);
2314 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2323 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2325 TypeSpec member_type = rc.CurrentType;
2326 TypeSpec current_type = member_type;
2327 for (; member_type != null; member_type = member_type.DeclaringType) {
2328 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2332 var me = e as MemberExpr;
2334 // The name matches a type, defer to ResolveAsTypeStep
2342 if (variable != null) {
2343 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2344 rc.Report.Error (844, loc,
2345 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2346 Name, me.GetSignatureForError ());
2350 } else if (me is MethodGroupExpr) {
2351 // Leave it to overload resolution to report correct error
2353 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2354 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2357 // LAMESPEC: again, ignores InvocableOnly
2358 if (variable != null) {
2359 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2360 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2364 // MemberLookup does not check accessors availability, this is actually needed for properties only
2366 var pe = me as PropertyExpr;
2369 // Break as there is no other overload available anyway
2370 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2371 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2374 pe.Getter = pe.PropertyInfo.Get;
2376 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2379 pe.Setter = pe.PropertyInfo.Set;
2384 // TODO: It's used by EventExpr -> FieldExpr transformation only
2385 // TODO: Should go to MemberAccess
2386 me = me.ResolveMemberAccess (rc, null, null);
2390 me.SetTypeArguments (rc, targs);
2397 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2399 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2400 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2402 if (variable != null) {
2403 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2404 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2412 if (variable_found) {
2413 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2415 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2421 if (rc.Module.Compiler.IsEvalutor) {
2422 var fi = Evaluator.LookupField (Name);
2424 return new FieldExpr (fi.Item1, loc);
2428 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2433 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2435 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2440 if (right_side != null) {
2441 if (e is TypeExpr) {
2442 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2446 e = e.ResolveLValue (ec, right_side);
2451 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2457 /// Represents a namespace or a type. The name of the class was inspired by
2458 /// section 10.8.1 (Fully Qualified Names).
2460 public abstract class FullNamedExpression : Expression
2462 protected override void CloneTo (CloneContext clonectx, Expression target)
2464 // Do nothing, most unresolved type expressions cannot be
2465 // resolved to different type
2468 public override Expression CreateExpressionTree (ResolveContext ec)
2470 throw new NotSupportedException ("ET");
2473 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2478 public override void Emit (EmitContext ec)
2480 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2481 GetSignatureForError ());
2486 /// Expression that evaluates to a type
2488 public abstract class TypeExpr : FullNamedExpression {
2489 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2491 TypeExpr t = DoResolveAsTypeStep (ec);
2495 eclass = ExprClass.Type;
2499 protected override Expression DoResolve (ResolveContext ec)
2501 return ResolveAsTypeTerminal (ec, false);
2504 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2506 public override bool Equals (object obj)
2508 TypeExpr tobj = obj as TypeExpr;
2512 return Type == tobj.Type;
2515 public override int GetHashCode ()
2517 return Type.GetHashCode ();
2522 /// Fully resolved Expression that already evaluated to a type
2524 public class TypeExpression : TypeExpr {
2525 public TypeExpression (TypeSpec t, Location l)
2528 eclass = ExprClass.Type;
2532 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2537 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2544 /// This class denotes an expression which evaluates to a member
2545 /// of a struct or a class.
2547 public abstract class MemberExpr : Expression
2550 // An instance expression associated with this member, if it's a
2551 // non-static member
2553 public Expression InstanceExpression;
2556 /// The name of this member.
2558 public abstract string Name {
2563 // When base.member is used
2565 public bool IsBase {
2566 get { return InstanceExpression is BaseThis; }
2570 /// Whether this is an instance member.
2572 public abstract bool IsInstance {
2577 /// Whether this is a static member.
2579 public abstract bool IsStatic {
2584 protected abstract TypeSpec DeclaringType {
2589 // Converts best base candidate for virtual method starting from QueriedBaseType
2591 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2594 // Only when base.member is used and method is virtual
2600 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2601 // means for base.member access we have to find the closest match after we found best candidate
2603 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2605 // The method could already be what we are looking for
2607 TypeSpec[] targs = null;
2608 if (method.DeclaringType != InstanceExpression.Type) {
2609 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2610 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2611 if (base_override.IsGeneric)
2612 targs = method.TypeArguments;
2614 method = base_override;
2618 // TODO: For now we do it for any hoisted call even if it's needed for
2619 // hoisted stories only but that requires a new expression wrapper
2620 if (rc.CurrentAnonymousMethod != null) {
2621 if (targs == null && method.IsGeneric) {
2622 targs = method.TypeArguments;
2623 method = method.GetGenericMethodDefinition ();
2626 if (method.Parameters.HasArglist)
2627 throw new NotImplementedException ("__arglist base call proxy");
2629 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2631 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2632 // get/set member expressions second call would fail to proxy because left expression
2633 // would be of 'this' and not 'base'
2634 if (rc.CurrentType.IsStruct)
2635 InstanceExpression = new This (loc).Resolve (rc);
2639 method = method.MakeGenericMethod (rc, targs);
2643 // Only base will allow this invocation to happen.
2645 if (method.IsAbstract) {
2646 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2652 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2654 if (InstanceExpression == null)
2657 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2658 var ct = rc.CurrentType;
2659 var expr_type = InstanceExpression.Type;
2660 if (ct != expr_type) {
2661 expr_type = expr_type.GetDefinition ();
2662 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2663 rc.Report.SymbolRelatedToPreviousError (member);
2664 rc.Report.Error (1540, loc,
2665 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2666 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2672 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2675 type = type.GetDefinition ();
2677 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2680 type = type.DeclaringType;
2681 } while (type != null);
2686 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2688 if (InstanceExpression != null) {
2689 InstanceExpression = InstanceExpression.Resolve (rc);
2690 CheckProtectedMemberAccess (rc, member);
2693 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2694 UnsafeError (rc, loc);
2697 var dep = member.GetMissingDependencies ();
2699 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2702 if (!rc.IsObsolete) {
2703 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2705 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2708 if (!(member is FieldSpec))
2709 member.MemberDefinition.SetIsUsed ();
2712 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2714 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2718 // Implements identicial simple name and type-name
2720 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2723 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2726 // 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
2727 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2729 if (left is MemberExpr || left is VariableReference) {
2730 rc.Report.DisableReporting ();
2731 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2732 rc.Report.EnableReporting ();
2733 if (identical_type != null && identical_type.Type == left.Type)
2734 return identical_type;
2740 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2743 if (InstanceExpression != null) {
2744 if (InstanceExpression is TypeExpr) {
2745 var t = InstanceExpression.Type;
2747 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2748 if (oa != null && !rc.IsObsolete) {
2749 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2752 t = t.DeclaringType;
2753 } while (t != null);
2755 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2756 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2757 rc.Report.Error (176, loc,
2758 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2759 GetSignatureForError ());
2763 InstanceExpression = null;
2769 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2770 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2771 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2772 rc.Report.Error (236, loc,
2773 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2774 GetSignatureForError ());
2776 rc.Report.Error (120, loc,
2777 "An object reference is required to access non-static member `{0}'",
2778 GetSignatureForError ());
2783 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2784 rc.Report.Error (38, loc,
2785 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2786 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2789 InstanceExpression = new This (loc);
2790 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2791 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2792 InstanceExpression = InstanceExpression.Resolve (rc);
2795 InstanceExpression = InstanceExpression.Resolve (rc);
2801 var me = InstanceExpression as MemberExpr;
2803 me.ResolveInstanceExpression (rc, rhs);
2805 var fe = me as FieldExpr;
2806 if (fe != null && fe.IsMarshalByRefAccess ()) {
2807 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2808 rc.Report.Warning (1690, 1, loc,
2809 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2810 me.GetSignatureForError ());
2817 // Run member-access postponed check once we know that
2818 // the expression is not field expression which is the only
2819 // expression which can use uninitialized this
2821 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2822 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2826 // Additional checks for l-value member access
2830 // TODO: It should be recursive but that would break csc compatibility
2832 if (InstanceExpression is UnboxCast) {
2833 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2840 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2842 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2843 ec.Report.Warning (1720, 1, left.Location,
2844 "Expression will always cause a `{0}'", "System.NullReferenceException");
2847 InstanceExpression = left;
2851 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2853 TypeSpec instance_type = InstanceExpression.Type;
2854 if (TypeManager.IsValueType (instance_type)) {
2855 if (InstanceExpression is IMemoryLocation) {
2856 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2858 LocalTemporary t = new LocalTemporary (instance_type);
2859 InstanceExpression.Emit (ec);
2861 t.AddressOf (ec, AddressOp.Store);
2864 InstanceExpression.Emit (ec);
2866 // Only to make verifier happy
2867 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2868 ec.Emit (OpCodes.Box, instance_type);
2871 if (prepare_for_load)
2872 ec.Emit (OpCodes.Dup);
2875 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2879 // Represents a group of extension method candidates for whole namespace
2881 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2883 NamespaceEntry namespace_entry;
2884 public readonly Expression ExtensionExpression;
2886 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2887 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2889 this.namespace_entry = n;
2890 this.ExtensionExpression = extensionExpr;
2893 public override bool IsStatic {
2894 get { return true; }
2897 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2899 if (namespace_entry == null)
2903 // For extension methodgroup we are not looking for base members but parent
2904 // namespace extension methods
2906 int arity = type_arguments == null ? 0 : type_arguments.Count;
2907 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2911 return found.Cast<MemberSpec> ().ToList ();
2914 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2916 // We are already here
2920 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2922 if (arguments == null)
2923 arguments = new Arguments (1);
2925 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2926 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2928 // Store resolved argument and restore original arguments
2930 // Clean-up modified arguments for error reporting
2931 arguments.RemoveAt (0);
2935 var me = ExtensionExpression as MemberExpr;
2937 me.ResolveInstanceExpression (ec, null);
2939 InstanceExpression = null;
2943 #region IErrorHandler Members
2945 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2950 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2952 rc.Report.SymbolRelatedToPreviousError (best);
2953 rc.Report.Error (1928, loc,
2954 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2955 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2958 rc.Report.Error (1929, loc,
2959 "Extension method instance type `{0}' cannot be converted to `{1}'",
2960 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2966 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2971 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2980 /// MethodGroupExpr represents a group of method candidates which
2981 /// can be resolved to the best method overload
2983 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2985 protected IList<MemberSpec> Methods;
2986 MethodSpec best_candidate;
2987 TypeSpec best_candidate_return;
2988 protected TypeArguments type_arguments;
2990 SimpleName simple_name;
2991 protected TypeSpec queried_type;
2993 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2997 this.type = InternalType.MethodGroup;
2999 eclass = ExprClass.MethodGroup;
3000 queried_type = type;
3003 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3004 : this (new MemberSpec[] { m }, type, loc)
3010 public MethodSpec BestCandidate {
3012 return best_candidate;
3016 public TypeSpec BestCandidateReturnType {
3018 return best_candidate_return;
3022 protected override TypeSpec DeclaringType {
3024 return queried_type;
3028 public override bool IsInstance {
3030 if (best_candidate != null)
3031 return !best_candidate.IsStatic;
3037 public override bool IsStatic {
3039 if (best_candidate != null)
3040 return best_candidate.IsStatic;
3046 public override string Name {
3048 if (best_candidate != null)
3049 return best_candidate.Name;
3052 return Methods.First ().Name;
3059 // When best candidate is already know this factory can be used
3060 // to avoid expensive overload resolution to be called
3062 // NOTE: InstanceExpression has to be set manually
3064 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3066 return new MethodGroupExpr (best, queriedType, loc) {
3067 best_candidate = best,
3068 best_candidate_return = best.ReturnType
3072 public override string GetSignatureForError ()
3074 if (best_candidate != null)
3075 return best_candidate.GetSignatureForError ();
3077 return Methods.First ().GetSignatureForError ();
3080 public override Expression CreateExpressionTree (ResolveContext ec)
3082 if (best_candidate == null) {
3083 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3087 if (best_candidate.IsConditionallyExcluded (loc))
3088 ec.Report.Error (765, loc,
3089 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3091 return new TypeOfMethod (best_candidate, loc);
3094 protected override Expression DoResolve (ResolveContext ec)
3096 this.eclass = ExprClass.MethodGroup;
3098 if (InstanceExpression != null) {
3099 InstanceExpression = InstanceExpression.Resolve (ec);
3100 if (InstanceExpression == null)
3107 public override void Emit (EmitContext ec)
3109 throw new NotSupportedException ();
3112 public void EmitCall (EmitContext ec, Arguments arguments)
3114 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3117 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3119 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3120 Name, TypeManager.CSharpName (target));
3123 public static bool IsExtensionMethodArgument (Expression expr)
3126 // LAMESPEC: No details about which expressions are not allowed
3128 return !(expr is TypeExpr) && !(expr is BaseThis);
3132 /// Find the Applicable Function Members (7.4.2.1)
3134 /// me: Method Group expression with the members to select.
3135 /// it might contain constructors or methods (or anything
3136 /// that maps to a method).
3138 /// Arguments: ArrayList containing resolved Argument objects.
3140 /// loc: The location if we want an error to be reported, or a Null
3141 /// location for "probing" purposes.
3143 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3144 /// that is the best match of me on Arguments.
3147 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3149 // TODO: causes issues with probing mode, remove explicit Kind check
3150 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3153 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3154 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3155 r.BaseMembersProvider = this;
3158 if (cerrors != null)
3159 r.CustomErrors = cerrors;
3161 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3162 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3163 if (best_candidate == null)
3164 return r.BestCandidateIsDynamic ? this : null;
3166 // Overload resolver had to create a new method group, all checks bellow have already been executed
3167 if (r.BestCandidateNewMethodGroup != null)
3168 return r.BestCandidateNewMethodGroup;
3170 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3171 if (InstanceExpression != null) {
3172 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3173 InstanceExpression = null;
3175 if (best_candidate.IsStatic && simple_name != null) {
3176 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3179 InstanceExpression.Resolve (ec);
3183 ResolveInstanceExpression (ec, null);
3184 if (InstanceExpression != null)
3185 CheckProtectedMemberAccess (ec, best_candidate);
3188 var base_override = CandidateToBaseOverride (ec, best_candidate);
3189 if (base_override == best_candidate) {
3190 best_candidate_return = r.BestCandidateReturnType;
3192 best_candidate = base_override;
3193 best_candidate_return = best_candidate.ReturnType;
3199 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3201 simple_name = original;
3202 return base.ResolveMemberAccess (ec, left, original);
3205 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3207 type_arguments = ta;
3210 #region IBaseMembersProvider Members
3212 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3214 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3217 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3219 if (queried_type == member.DeclaringType)
3222 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3223 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3227 // Extension methods lookup after ordinary methods candidates failed to apply
3229 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3231 if (InstanceExpression == null)
3234 InstanceExpression = InstanceExpression.Resolve (rc);
3235 if (!IsExtensionMethodArgument (InstanceExpression))
3238 int arity = type_arguments == null ? 0 : type_arguments.Count;
3239 NamespaceEntry methods_scope = null;
3240 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3241 if (methods == null)
3244 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3245 emg.SetTypeArguments (rc, type_arguments);
3252 public struct OverloadResolver
3255 public enum Restrictions
3259 ProbingOnly = 1 << 1,
3260 CovariantDelegate = 1 << 2,
3261 NoBaseMembers = 1 << 3,
3262 BaseMembersIncluded = 1 << 4
3265 public interface IBaseMembersProvider
3267 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3268 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3269 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3272 public interface IErrorHandler
3274 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3275 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3276 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3277 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3280 sealed class NoBaseMembers : IBaseMembersProvider
3282 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3284 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3289 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3294 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3300 struct AmbiguousCandidate
3302 public readonly MemberSpec Member;
3303 public readonly bool Expanded;
3304 public readonly AParametersCollection Parameters;
3306 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3309 Parameters = parameters;
3310 Expanded = expanded;
3315 IList<MemberSpec> members;
3316 TypeArguments type_arguments;
3317 IBaseMembersProvider base_provider;
3318 IErrorHandler custom_errors;
3319 Restrictions restrictions;
3320 MethodGroupExpr best_candidate_extension_group;
3321 TypeSpec best_candidate_return_type;
3323 SessionReportPrinter lambda_conv_msgs;
3324 ReportPrinter prev_recorder;
3326 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3327 : this (members, null, restrictions, loc)
3331 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3334 if (members == null || members.Count == 0)
3335 throw new ArgumentException ("empty members set");
3337 this.members = members;
3339 type_arguments = targs;
3340 this.restrictions = restrictions;
3341 if (IsDelegateInvoke)
3342 this.restrictions |= Restrictions.NoBaseMembers;
3344 base_provider = NoBaseMembers.Instance;
3349 public IBaseMembersProvider BaseMembersProvider {
3351 return base_provider;
3354 base_provider = value;
3358 public bool BestCandidateIsDynamic { get; set; }
3361 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3363 public MethodGroupExpr BestCandidateNewMethodGroup {
3365 return best_candidate_extension_group;
3370 // Return type can be different between best candidate and closest override
3372 public TypeSpec BestCandidateReturnType {
3374 return best_candidate_return_type;
3378 public IErrorHandler CustomErrors {
3380 return custom_errors;
3383 custom_errors = value;
3387 TypeSpec DelegateType {
3389 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3390 throw new InternalErrorException ("Not running in delegate mode", loc);
3392 return members [0].DeclaringType;
3396 bool IsProbingOnly {
3398 return (restrictions & Restrictions.ProbingOnly) != 0;
3402 bool IsDelegateInvoke {
3404 return (restrictions & Restrictions.DelegateInvoke) != 0;
3411 // 7.4.3.3 Better conversion from expression
3412 // Returns : 1 if a->p is better,
3413 // 2 if a->q is better,
3414 // 0 if neither is better
3416 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3418 TypeSpec argument_type = a.Type;
3421 // If argument is an anonymous function
3423 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3425 // p and q are delegate types or expression tree types
3427 if (p.GetDefinition () == TypeManager.expression_type || q.GetDefinition () == TypeManager.expression_type) {
3428 if (q.MemberDefinition != p.MemberDefinition) {
3433 // Uwrap delegate from Expression<T>
3435 q = TypeManager.GetTypeArguments (q)[0];
3436 p = TypeManager.GetTypeArguments (p)[0];
3439 var p_m = Delegate.GetInvokeMethod (p);
3440 var q_m = Delegate.GetInvokeMethod (q);
3443 // With identical parameter lists
3445 if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
3452 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3454 if (p == TypeManager.void_type) {
3455 return q != TypeManager.void_type ? 2 : 0;
3459 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3461 if (q == TypeManager.void_type) {
3462 return p != TypeManager.void_type ? 1: 0;
3465 if (argument_type == p)
3468 if (argument_type == q)
3472 return BetterTypeConversion (ec, p, q);
3476 // 7.4.3.4 Better conversion from type
3478 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3480 if (p == null || q == null)
3481 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3483 if (p == TypeManager.int32_type) {
3484 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3486 } else if (p == TypeManager.int64_type) {
3487 if (q == TypeManager.uint64_type)
3489 } else if (p == TypeManager.sbyte_type) {
3490 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3491 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3493 } else if (p == TypeManager.short_type) {
3494 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3495 q == TypeManager.uint64_type)
3497 } else if (p == InternalType.Dynamic) {
3498 // Dynamic is never better
3502 if (q == TypeManager.int32_type) {
3503 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3505 } if (q == TypeManager.int64_type) {
3506 if (p == TypeManager.uint64_type)
3508 } else if (q == TypeManager.sbyte_type) {
3509 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3510 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3512 } if (q == TypeManager.short_type) {
3513 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3514 p == TypeManager.uint64_type)
3516 } else if (q == InternalType.Dynamic) {
3517 // Dynamic is never better
3521 // FIXME: handle lifted operators
3523 // TODO: this is expensive
3524 Expression p_tmp = new EmptyExpression (p);
3525 Expression q_tmp = new EmptyExpression (q);
3527 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3528 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3530 if (p_to_q && !q_to_p)
3533 if (q_to_p && !p_to_q)
3540 /// Determines "Better function" between candidate
3541 /// and the current best match
3544 /// Returns a boolean indicating :
3545 /// false if candidate ain't better
3546 /// true if candidate is better than the current best match
3548 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3549 MemberSpec best, AParametersCollection bparam, bool best_params)
3551 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3552 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3554 bool better_at_least_one = false;
3556 int args_count = args == null ? 0 : args.Count;
3560 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3563 // Default arguments are ignored for better decision
3564 if (a.IsDefaultArgument)
3568 // When comparing named argument the parameter type index has to be looked up
3569 // in original parameter set (override version for virtual members)
3571 NamedArgument na = a as NamedArgument;
3573 int idx = cparam.GetParameterIndexByName (na.Name);
3574 ct = candidate_pd.Types[idx];
3575 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3576 ct = TypeManager.GetElementType (ct);
3578 idx = bparam.GetParameterIndexByName (na.Name);
3579 bt = best_pd.Types[idx];
3580 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3581 bt = TypeManager.GetElementType (bt);
3583 ct = candidate_pd.Types[c_idx];
3584 bt = best_pd.Types[b_idx];
3586 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3587 ct = TypeManager.GetElementType (ct);
3591 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3592 bt = TypeManager.GetElementType (bt);
3597 if (TypeSpecComparer.IsEqual (ct, bt))
3601 int result = BetterExpressionConversion (ec, a, ct, bt);
3603 // for each argument, the conversion to 'ct' should be no worse than
3604 // the conversion to 'bt'.
3608 // for at least one argument, the conversion to 'ct' should be better than
3609 // the conversion to 'bt'.
3611 better_at_least_one = true;
3614 if (better_at_least_one)
3618 // This handles the case
3620 // Add (float f1, float f2, float f3);
3621 // Add (params decimal [] foo);
3623 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3624 // first candidate would've chosen as better.
3626 if (!same && !a.IsDefaultArgument)
3630 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3634 // This handles the following cases:
3636 // Foo (int i) is better than Foo (int i, long l = 0)
3637 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3639 // Prefer non-optional version
3641 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3643 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3644 if (candidate_pd.Count >= best_pd.Count)
3647 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3654 // One is a non-generic method and second is a generic method, then non-generic is better
3656 if (best.IsGeneric != candidate.IsGeneric)
3657 return best.IsGeneric;
3660 // This handles the following cases:
3662 // Trim () is better than Trim (params char[] chars)
3663 // Concat (string s1, string s2, string s3) is better than
3664 // Concat (string s1, params string [] srest)
3665 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3667 // Prefer non-expanded version
3669 if (candidate_params != best_params)
3672 int candidate_param_count = candidate_pd.Count;
3673 int best_param_count = best_pd.Count;
3675 if (candidate_param_count != best_param_count)
3676 // can only happen if (candidate_params && best_params)
3677 return candidate_param_count > best_param_count && best_pd.HasParams;
3680 // Both methods have the same number of parameters, and the parameters have equal types
3681 // Pick the "more specific" signature using rules over original (non-inflated) types
3683 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3684 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3686 bool specific_at_least_once = false;
3687 for (j = 0; j < args_count; ++j) {
3688 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3690 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3691 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3693 ct = candidate_def_pd.Types[j];
3694 bt = best_def_pd.Types[j];
3699 TypeSpec specific = MoreSpecific (ct, bt);
3703 specific_at_least_once = true;
3706 if (specific_at_least_once)
3712 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3714 rc.Report.Error (1729, loc,
3715 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3716 type.GetSignatureForError (), argCount.ToString ());
3720 // Determines if the candidate method is applicable to the given set of arguments
3721 // There could be two different set of parameters for same candidate where one
3722 // is the closest override for default values and named arguments checks and second
3723 // one being the virtual base for the parameter types and modifiers.
3725 // A return value rates candidate method compatibility,
3726 // 0 = the best, int.MaxValue = the worst
3728 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)
3730 // Parameters of most-derived type used mainly for named and optional parameters
3731 var pd = pm.Parameters;
3733 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3734 // params modifier instead of most-derived type
3735 var cpd = ((IParametersMember) candidate).Parameters;
3736 int param_count = pd.Count;
3737 int optional_count = 0;
3739 Arguments orig_args = arguments;
3741 if (arg_count != param_count) {
3742 for (int i = 0; i < pd.Count; ++i) {
3743 if (pd.FixedParameters[i].HasDefaultValue) {
3744 optional_count = pd.Count - i;
3749 if (optional_count != 0) {
3750 // Readjust expected number when params used
3751 if (cpd.HasParams) {
3753 if (arg_count < param_count)
3755 } else if (arg_count > param_count) {
3756 int args_gap = System.Math.Abs (arg_count - param_count);
3757 return int.MaxValue - 10000 + args_gap;
3759 } else if (arg_count != param_count) {
3760 int args_gap = System.Math.Abs (arg_count - param_count);
3762 return int.MaxValue - 10000 + args_gap;
3763 if (arg_count < param_count - 1)
3764 return int.MaxValue - 10000 + args_gap;
3767 // Resize to fit optional arguments
3768 if (optional_count != 0) {
3769 if (arguments == null) {
3770 arguments = new Arguments (optional_count);
3772 // Have to create a new container, so the next run can do same
3773 var resized = new Arguments (param_count);
3774 resized.AddRange (arguments);
3775 arguments = resized;
3778 for (int i = arg_count; i < param_count; ++i)
3779 arguments.Add (null);
3783 if (arg_count > 0) {
3785 // Shuffle named arguments to the right positions if there are any
3787 if (arguments[arg_count - 1] is NamedArgument) {
3788 arg_count = arguments.Count;
3790 for (int i = 0; i < arg_count; ++i) {
3791 bool arg_moved = false;
3793 NamedArgument na = arguments[i] as NamedArgument;
3797 int index = pd.GetParameterIndexByName (na.Name);
3799 // Named parameter not found
3803 // already reordered
3808 if (index >= param_count) {
3809 // When using parameters which should not be available to the user
3810 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3813 arguments.Add (null);
3817 temp = arguments[index];
3819 // The slot has been taken by positional argument
3820 if (temp != null && !(temp is NamedArgument))
3825 arguments = arguments.MarkOrderedArgument (na);
3829 arguments[index] = arguments[i];
3830 arguments[i] = temp;
3837 arg_count = arguments.Count;
3839 } else if (arguments != null) {
3840 arg_count = arguments.Count;
3844 // 1. Handle generic method using type arguments when specified or type inference
3847 var ms = candidate as MethodSpec;
3848 if (ms != null && ms.IsGeneric) {
3849 // Setup constraint checker for probing only
3850 ConstraintChecker cc = new ConstraintChecker (null);
3852 if (type_arguments != null) {
3853 var g_args_count = ms.Arity;
3854 if (g_args_count != type_arguments.Count)
3855 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3857 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3859 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3860 // for now it simplifies things. I should probably add a callback to ResolveContext
3861 if (lambda_conv_msgs == null) {
3862 lambda_conv_msgs = new SessionReportPrinter ();
3863 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3866 var ti = new TypeInference (arguments);
3867 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3868 lambda_conv_msgs.EndSession ();
3871 return ti.InferenceScore - 20000;
3873 if (i_args.Length != 0) {
3874 ms = ms.MakeGenericMethod (ec, i_args);
3877 cc.IgnoreInferredDynamic = true;
3881 // Type arguments constraints have to match for the method to be applicable
3883 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3885 return int.MaxValue - 25000;
3889 // We have a generic return type and at same time the method is override which
3890 // means we have to also inflate override return type in case the candidate is
3891 // best candidate and override return type is different to base return type.
3893 // virtual Foo<T, object> with override Foo<T, dynamic>
3895 if (candidate != pm) {
3896 MethodSpec override_ms = (MethodSpec) pm;
3897 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3898 returnType = inflator.Inflate (returnType);
3900 returnType = ms.ReturnType;
3904 ptypes = ms.Parameters.Types;
3906 if (type_arguments != null)
3907 return int.MaxValue - 15000;
3913 // 2. Each argument has to be implicitly convertible to method parameter
3915 Parameter.Modifier p_mod = 0;
3918 for (int i = 0; i < arg_count; i++) {
3919 Argument a = arguments[i];
3921 if (!pd.FixedParameters[i].HasDefaultValue) {
3922 arguments = orig_args;
3923 return arg_count * 2 + 2;
3927 // Get the default value expression, we can use the same expression
3928 // if the type matches
3930 Expression e = pd.FixedParameters[i].DefaultValue;
3931 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3933 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3935 if (e == EmptyExpression.MissingValue && ptypes[i] == TypeManager.object_type || ptypes[i] == InternalType.Dynamic) {
3936 e = new MemberAccess (new MemberAccess (new MemberAccess (
3937 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3939 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3945 arguments[i] = new Argument (e, Argument.AType.Default);
3949 if (p_mod != Parameter.Modifier.PARAMS) {
3950 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3952 } else if (!params_expanded_form) {
3953 params_expanded_form = true;
3954 pt = ((ElementTypeSpec) pt).Element;
3960 if (!params_expanded_form) {
3961 if (a.ArgType == Argument.AType.ExtensionType) {
3963 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3966 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3967 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3968 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3973 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3976 dynamicArgument = true;
3981 // It can be applicable in expanded form (when not doing exact match like for delegates)
3983 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3984 if (!params_expanded_form)
3985 pt = ((ElementTypeSpec) pt).Element;
3988 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3991 params_expanded_form = true;
3992 } else if (score < 0) {
3993 params_expanded_form = true;
3994 dynamicArgument = true;
3999 if (params_expanded_form)
4001 return (arg_count - i) * 2 + score;
4006 // When params parameter has no argument it will be provided later if the method is the best candidate
4008 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4009 params_expanded_form = true;
4012 // Restore original arguments for dynamic binder to keep the intention of original source code
4014 if (dynamicArgument)
4015 arguments = orig_args;
4021 // Tests argument compatibility with the parameter
4022 // The possible return values are
4024 // 1 - modifier mismatch
4025 // 2 - type mismatch
4026 // -1 - dynamic binding required
4028 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4031 // Types have to be identical when ref or out modifer
4032 // is used and argument is not of dynamic type
4034 if ((argument.Modifier | param_mod) != 0) {
4035 if (argument.Type != parameter) {
4037 // Do full equality check after quick path
4039 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4041 // Using dynamic for ref/out parameter can still succeed at runtime
4043 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4050 if (argument.Modifier != param_mod) {
4052 // Using dynamic for ref/out parameter can still succeed at runtime
4054 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4061 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4065 // Deploy custom error reporting for lambda methods. When probing lambda methods
4066 // keep all errors reported in separate set and once we are done and no best
4067 // candidate found, this set is used to report more details about what was wrong
4070 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4071 if (lambda_conv_msgs == null) {
4072 lambda_conv_msgs = new SessionReportPrinter ();
4073 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4077 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4078 if (lambda_conv_msgs != null) {
4079 lambda_conv_msgs.EndSession ();
4089 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4091 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4093 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4096 var ac_p = p as ArrayContainer;
4098 var ac_q = ((ArrayContainer) q);
4099 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4100 if (specific == ac_p.Element)
4102 if (specific == ac_q.Element)
4104 } else if (TypeManager.IsGenericType (p)) {
4105 var pargs = TypeManager.GetTypeArguments (p);
4106 var qargs = TypeManager.GetTypeArguments (q);
4108 bool p_specific_at_least_once = false;
4109 bool q_specific_at_least_once = false;
4111 for (int i = 0; i < pargs.Length; i++) {
4112 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4113 if (specific == pargs[i])
4114 p_specific_at_least_once = true;
4115 if (specific == qargs[i])
4116 q_specific_at_least_once = true;
4119 if (p_specific_at_least_once && !q_specific_at_least_once)
4121 if (!p_specific_at_least_once && q_specific_at_least_once)
4129 // Find the best method from candidate list
4131 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4133 List<AmbiguousCandidate> ambiguous_candidates = null;
4135 MemberSpec best_candidate;
4136 Arguments best_candidate_args = null;
4137 bool best_candidate_params = false;
4138 bool best_candidate_dynamic = false;
4139 int best_candidate_rate;
4140 IParametersMember best_parameter_member = null;
4142 int args_count = args != null ? args.Count : 0;
4144 Arguments candidate_args = args;
4145 bool error_mode = false;
4146 var current_type = rc.CurrentType;
4147 MemberSpec invocable_member = null;
4149 // Be careful, cannot return until error reporter is restored
4151 best_candidate = null;
4152 best_candidate_rate = int.MaxValue;
4154 var type_members = members;
4158 for (int i = 0; i < type_members.Count; ++i) {
4159 var member = type_members[i];
4162 // Methods in a base class are not candidates if any method in a derived
4163 // class is applicable
4165 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4169 if (!member.IsAccessible (current_type))
4172 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4176 IParametersMember pm = member as IParametersMember;
4179 // Will use it later to report ambiguity between best method and invocable member
4181 if (Invocation.IsMemberInvocable (member))
4182 invocable_member = member;
4188 // Overload resolution is looking for base member but using parameter names
4189 // and default values from the closest member. That means to do expensive lookup
4190 // for the closest override for virtual or abstract members
4192 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4193 var override_params = base_provider.GetOverrideMemberParameters (member);
4194 if (override_params != null)
4195 pm = override_params;
4199 // Check if the member candidate is applicable
4201 bool params_expanded_form = false;
4202 bool dynamic_argument = false;
4203 TypeSpec rt = pm.MemberType;
4204 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4207 // How does it score compare to others
4209 if (candidate_rate < best_candidate_rate) {
4210 best_candidate_rate = candidate_rate;
4211 best_candidate = member;
4212 best_candidate_args = candidate_args;
4213 best_candidate_params = params_expanded_form;
4214 best_candidate_dynamic = dynamic_argument;
4215 best_parameter_member = pm;
4216 best_candidate_return_type = rt;
4217 } else if (candidate_rate == 0) {
4219 // The member look is done per type for most operations but sometimes
4220 // it's not possible like for binary operators overload because they
4221 // are unioned between 2 sides
4223 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4224 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4229 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4231 // We pack all interface members into top level type which makes the overload resolution
4232 // more complicated for interfaces. We compensate it by removing methods with same
4233 // signature when building the cache hence this path should not really be hit often
4236 // interface IA { void Foo (int arg); }
4237 // interface IB : IA { void Foo (params int[] args); }
4239 // IB::Foo is the best overload when calling IB.Foo (1)
4242 if (ambiguous_candidates != null) {
4243 foreach (var amb_cand in ambiguous_candidates) {
4244 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4253 ambiguous_candidates = null;
4256 // Is the new candidate better
4257 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4261 best_candidate = member;
4262 best_candidate_args = candidate_args;
4263 best_candidate_params = params_expanded_form;
4264 best_candidate_dynamic = dynamic_argument;
4265 best_parameter_member = pm;
4266 best_candidate_return_type = rt;
4268 // It's not better but any other found later could be but we are not sure yet
4269 if (ambiguous_candidates == null)
4270 ambiguous_candidates = new List<AmbiguousCandidate> ();
4272 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4276 // Restore expanded arguments
4277 if (candidate_args != args)
4278 candidate_args = args;
4280 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4282 if (prev_recorder != null)
4283 rc.Report.SetPrinter (prev_recorder);
4287 // We've found exact match
4289 if (best_candidate_rate == 0)
4293 // Try extension methods lookup when no ordinary method match was found and provider enables it
4296 var emg = base_provider.LookupExtensionMethod (rc);
4298 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4300 best_candidate_extension_group = emg;
4301 return (T) (MemberSpec) emg.BestCandidate;
4306 // Don't run expensive error reporting mode for probing
4313 lambda_conv_msgs = null;
4318 // No best member match found, report an error
4320 if (best_candidate_rate != 0 || error_mode) {
4321 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4325 if (best_candidate_dynamic) {
4326 if (args[0].ArgType == Argument.AType.ExtensionType) {
4327 rc.Report.Error (1973, loc,
4328 "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",
4329 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4332 BestCandidateIsDynamic = true;
4336 if (ambiguous_candidates != null) {
4338 // Now check that there are no ambiguities i.e the selected method
4339 // should be better than all the others
4341 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4342 var candidate = ambiguous_candidates [ix];
4344 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4345 var ambiguous = candidate.Member;
4346 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4347 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4348 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4349 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4350 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4353 return (T) best_candidate;
4358 if (invocable_member != null) {
4359 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4360 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4361 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4362 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4366 // And now check if the arguments are all
4367 // compatible, perform conversions if
4368 // necessary etc. and return if everything is
4371 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4374 if (best_candidate == null)
4378 // Check ObsoleteAttribute on the best method
4380 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4381 if (oa != null && !rc.IsObsolete)
4382 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4384 var dep = best_candidate.GetMissingDependencies ();
4386 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4389 best_candidate.MemberDefinition.SetIsUsed ();
4391 args = best_candidate_args;
4392 return (T) best_candidate;
4395 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4397 return ResolveMember<MethodSpec> (rc, ref args);
4400 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4401 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4403 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4406 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4407 ec.Report.SymbolRelatedToPreviousError (method);
4408 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4409 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4410 TypeManager.CSharpSignature (method));
4413 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4414 TypeManager.CSharpSignature (method));
4415 } else if (IsDelegateInvoke) {
4416 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4417 DelegateType.GetSignatureForError ());
4419 ec.Report.SymbolRelatedToPreviousError (method);
4420 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4421 method.GetSignatureForError ());
4424 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4426 string index = (idx + 1).ToString ();
4427 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4428 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4429 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4430 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4431 index, Parameter.GetModifierSignature (a.Modifier));
4433 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4434 index, Parameter.GetModifierSignature (mod));
4436 string p1 = a.GetSignatureForError ();
4437 string p2 = TypeManager.CSharpName (paramType);
4440 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4441 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4442 ec.Report.SymbolRelatedToPreviousError (paramType);
4445 ec.Report.Error (1503, loc,
4446 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4451 // We have failed to find exact match so we return error info about the closest match
4453 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4455 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4456 int arg_count = args == null ? 0 : args.Count;
4458 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4459 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4460 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4464 if (lambda_conv_msgs != null) {
4465 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4470 // For candidates which match on parameters count report more details about incorrect arguments
4473 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4474 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4475 // Reject any inaccessible member
4476 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4477 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4478 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4482 var ms = best_candidate as MethodSpec;
4483 if (ms != null && ms.IsGeneric) {
4484 bool constr_ok = true;
4485 if (ms.TypeArguments != null)
4486 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4488 if (ta_count == 0) {
4489 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4493 rc.Report.Error (411, loc,
4494 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4495 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4502 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4508 // We failed to find any method with correct argument count, report best candidate
4510 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4513 if (best_candidate.Kind == MemberKind.Constructor) {
4514 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4515 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4516 } else if (IsDelegateInvoke) {
4517 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4518 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4519 DelegateType.GetSignatureForError (), arg_count.ToString ());
4521 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4522 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4523 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4524 name, arg_count.ToString ());
4528 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4530 var pd = pm.Parameters;
4531 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4533 Parameter.Modifier p_mod = 0;
4535 int a_idx = 0, a_pos = 0;
4537 ArrayInitializer params_initializers = null;
4538 bool has_unsafe_arg = pm.MemberType.IsPointer;
4539 int arg_count = args == null ? 0 : args.Count;
4541 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4543 if (p_mod != Parameter.Modifier.PARAMS) {
4544 p_mod = pd.FixedParameters[a_idx].ModFlags;
4546 has_unsafe_arg |= pt.IsPointer;
4548 if (p_mod == Parameter.Modifier.PARAMS) {
4549 if (chose_params_expanded) {
4550 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4551 pt = TypeManager.GetElementType (pt);
4557 // Types have to be identical when ref or out modifer is used
4559 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4560 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4563 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4569 NamedArgument na = a as NamedArgument;
4571 int name_index = pd.GetParameterIndexByName (na.Name);
4572 if (name_index < 0 || name_index >= pd.Count) {
4573 if (IsDelegateInvoke) {
4574 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4575 ec.Report.Error (1746, na.Location,
4576 "The delegate `{0}' does not contain a parameter named `{1}'",
4577 DelegateType.GetSignatureForError (), na.Name);
4579 ec.Report.SymbolRelatedToPreviousError (member);
4580 ec.Report.Error (1739, na.Location,
4581 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4582 TypeManager.CSharpSignature (member), na.Name);
4584 } else if (args[name_index] != a) {
4585 if (IsDelegateInvoke)
4586 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4588 ec.Report.SymbolRelatedToPreviousError (member);
4590 ec.Report.Error (1744, na.Location,
4591 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4596 if (a.Expr.Type == InternalType.Dynamic)
4599 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr, pt)) {
4600 custom_errors.NoArgumentMatch (ec, member);
4604 Expression conv = null;
4605 if (a.ArgType == Argument.AType.ExtensionType) {
4606 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4609 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4611 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4614 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4621 // Convert params arguments to an array initializer
4623 if (params_initializers != null) {
4624 // we choose to use 'a.Expr' rather than 'conv' so that
4625 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4626 params_initializers.Add (a.Expr);
4627 args.RemoveAt (a_idx--);
4632 // Update the argument with the implicit conversion
4636 if (a_idx != arg_count) {
4637 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4642 // Fill not provided arguments required by params modifier
4644 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4646 args = new Arguments (1);
4648 pt = ptypes[pd.Count - 1];
4649 pt = TypeManager.GetElementType (pt);
4650 has_unsafe_arg |= pt.IsPointer;
4651 params_initializers = new ArrayInitializer (0, loc);
4655 // Append an array argument with all params arguments
4657 if (params_initializers != null) {
4658 args.Add (new Argument (
4659 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4663 if (has_unsafe_arg && !ec.IsUnsafe) {
4664 Expression.UnsafeError (ec, loc);
4668 // We could infer inaccesible type arguments
4670 if (type_arguments == null && member.IsGeneric) {
4671 var ms = (MethodSpec) member;
4672 foreach (var ta in ms.TypeArguments) {
4673 if (!ta.IsAccessible (ec.CurrentType)) {
4674 ec.Report.SymbolRelatedToPreviousError (ta);
4675 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4685 public class ConstantExpr : MemberExpr
4689 public ConstantExpr (ConstSpec constant, Location loc)
4691 this.constant = constant;
4695 public override string Name {
4696 get { throw new NotImplementedException (); }
4699 public override bool IsInstance {
4700 get { return !IsStatic; }
4703 public override bool IsStatic {
4704 get { return true; }
4707 protected override TypeSpec DeclaringType {
4708 get { return constant.DeclaringType; }
4711 public override Expression CreateExpressionTree (ResolveContext ec)
4713 throw new NotSupportedException ("ET");
4716 protected override Expression DoResolve (ResolveContext rc)
4718 ResolveInstanceExpression (rc, null);
4719 DoBestMemberChecks (rc, constant);
4721 var c = constant.GetConstant (rc);
4723 // Creates reference expression to the constant value
4724 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4727 public override void Emit (EmitContext ec)
4729 throw new NotSupportedException ();
4732 public override string GetSignatureForError ()
4734 return constant.GetSignatureForError ();
4737 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4739 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4744 /// Fully resolved expression that evaluates to a Field
4746 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4747 protected FieldSpec spec;
4748 VariableInfo variable_info;
4750 LocalTemporary temp;
4753 protected FieldExpr (Location l)
4758 public FieldExpr (FieldSpec spec, Location loc)
4763 type = spec.MemberType;
4766 public FieldExpr (FieldBase fi, Location l)
4773 public override string Name {
4779 public bool IsHoisted {
4781 IVariableReference hv = InstanceExpression as IVariableReference;
4782 return hv != null && hv.IsHoisted;
4786 public override bool IsInstance {
4788 return !spec.IsStatic;
4792 public override bool IsStatic {
4794 return spec.IsStatic;
4798 public FieldSpec Spec {
4804 protected override TypeSpec DeclaringType {
4806 return spec.DeclaringType;
4810 public VariableInfo VariableInfo {
4812 return variable_info;
4818 public override string GetSignatureForError ()
4820 return TypeManager.GetFullNameSignature (spec);
4823 public bool IsMarshalByRefAccess ()
4825 // Checks possible ldflda of field access expression
4826 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4827 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4828 !(InstanceExpression is This);
4831 public void SetHasAddressTaken ()
4833 IVariableReference vr = InstanceExpression as IVariableReference;
4835 vr.SetHasAddressTaken ();
4838 public override Expression CreateExpressionTree (ResolveContext ec)
4840 Expression instance;
4841 if (InstanceExpression == null) {
4842 instance = new NullLiteral (loc);
4844 instance = InstanceExpression.CreateExpressionTree (ec);
4847 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4849 CreateTypeOfExpression ());
4851 return CreateExpressionFactoryCall (ec, "Field", args);
4854 public Expression CreateTypeOfExpression ()
4856 return new TypeOfField (spec, loc);
4859 protected override Expression DoResolve (ResolveContext ec)
4861 return DoResolve (ec, null);
4864 Expression DoResolve (ResolveContext ec, Expression rhs)
4866 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4868 if (ResolveInstanceExpression (ec, rhs)) {
4869 // Resolve the field's instance expression while flow analysis is turned
4870 // off: when accessing a field "a.b", we must check whether the field
4871 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4873 if (lvalue_instance) {
4874 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4875 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4877 Expression right_side =
4878 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4880 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4883 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4884 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4888 if (InstanceExpression == null)
4892 DoBestMemberChecks (ec, spec);
4894 var fb = spec as FixedFieldSpec;
4895 IVariableReference var = InstanceExpression as IVariableReference;
4897 if (lvalue_instance && var != null && var.VariableInfo != null) {
4898 var.VariableInfo.SetFieldAssigned (ec, Name);
4902 IFixedExpression fe = InstanceExpression as IFixedExpression;
4903 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4904 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4907 if (InstanceExpression.eclass != ExprClass.Variable) {
4908 ec.Report.SymbolRelatedToPreviousError (spec);
4909 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4910 TypeManager.GetFullNameSignature (spec));
4911 } else if (var != null && var.IsHoisted) {
4912 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4915 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4918 eclass = ExprClass.Variable;
4920 // If the instance expression is a local variable or parameter.
4921 if (var == null || var.VariableInfo == null)
4924 VariableInfo vi = var.VariableInfo;
4925 if (!vi.IsFieldAssigned (ec, Name, loc))
4928 variable_info = vi.GetSubStruct (Name);
4932 static readonly int [] codes = {
4933 191, // instance, write access
4934 192, // instance, out access
4935 198, // static, write access
4936 199, // static, out access
4937 1648, // member of value instance, write access
4938 1649, // member of value instance, out access
4939 1650, // member of value static, write access
4940 1651 // member of value static, out access
4943 static readonly string [] msgs = {
4944 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4945 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4946 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4947 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4948 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4949 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4950 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4951 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4954 // The return value is always null. Returning a value simplifies calling code.
4955 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4958 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4962 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4964 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4969 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4971 Expression e = DoResolve (ec, right_side);
4976 spec.MemberDefinition.SetIsAssigned ();
4978 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4979 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4980 ec.Report.Warning (420, 1, loc,
4981 "`{0}': A volatile field references will not be treated as volatile",
4982 spec.GetSignatureForError ());
4985 if (spec.IsReadOnly) {
4986 // InitOnly fields can only be assigned in constructors or initializers
4987 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4988 return Report_AssignToReadonly (ec, right_side);
4990 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4992 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4993 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
4994 return Report_AssignToReadonly (ec, right_side);
4995 // static InitOnly fields cannot be assigned-to in an instance constructor
4996 if (IsStatic && !ec.IsStatic)
4997 return Report_AssignToReadonly (ec, right_side);
4998 // instance constructors can't modify InitOnly fields of other instances of the same type
4999 if (!IsStatic && !(InstanceExpression is This))
5000 return Report_AssignToReadonly (ec, right_side);
5004 if (right_side == EmptyExpression.OutAccess.Instance &&
5005 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
5006 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5007 ec.Report.Warning (197, 1, loc,
5008 "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",
5009 GetSignatureForError ());
5012 eclass = ExprClass.Variable;
5016 public override int GetHashCode ()
5018 return spec.GetHashCode ();
5021 public bool IsFixed {
5024 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5026 IVariableReference variable = InstanceExpression as IVariableReference;
5027 if (variable != null)
5028 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5030 IFixedExpression fe = InstanceExpression as IFixedExpression;
5031 return fe != null && fe.IsFixed;
5035 public override bool Equals (object obj)
5037 FieldExpr fe = obj as FieldExpr;
5041 if (spec != fe.spec)
5044 if (InstanceExpression == null || fe.InstanceExpression == null)
5047 return InstanceExpression.Equals (fe.InstanceExpression);
5050 public void Emit (EmitContext ec, bool leave_copy)
5052 bool is_volatile = false;
5054 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5057 spec.MemberDefinition.SetIsUsed ();
5061 ec.Emit (OpCodes.Volatile);
5063 ec.Emit (OpCodes.Ldsfld, spec);
5066 EmitInstance (ec, false);
5068 // Optimization for build-in types
5069 if (TypeManager.IsStruct (type) && type == ec.CurrentType && InstanceExpression.Type == type) {
5070 ec.EmitLoadFromPtr (type);
5072 var ff = spec as FixedFieldSpec;
5074 ec.Emit (OpCodes.Ldflda, spec);
5075 ec.Emit (OpCodes.Ldflda, ff.Element);
5078 ec.Emit (OpCodes.Volatile);
5080 ec.Emit (OpCodes.Ldfld, spec);
5086 ec.Emit (OpCodes.Dup);
5088 temp = new LocalTemporary (this.Type);
5094 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5096 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5098 EmitInstance (ec, prepared);
5102 ec.Emit (OpCodes.Dup);
5104 temp = new LocalTemporary (this.Type);
5109 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5110 ec.Emit (OpCodes.Volatile);
5112 spec.MemberDefinition.SetIsAssigned ();
5115 ec.Emit (OpCodes.Stsfld, spec);
5117 ec.Emit (OpCodes.Stfld, spec);
5126 public override void Emit (EmitContext ec)
5131 public override void EmitSideEffect (EmitContext ec)
5133 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5135 if (is_volatile) // || is_marshal_by_ref ())
5136 base.EmitSideEffect (ec);
5139 public void AddressOf (EmitContext ec, AddressOp mode)
5141 if ((mode & AddressOp.Store) != 0)
5142 spec.MemberDefinition.SetIsAssigned ();
5143 if ((mode & AddressOp.Load) != 0)
5144 spec.MemberDefinition.SetIsUsed ();
5147 // Handle initonly fields specially: make a copy and then
5148 // get the address of the copy.
5151 if (spec.IsReadOnly){
5153 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5166 local = ec.DeclareLocal (type, false);
5167 ec.Emit (OpCodes.Stloc, local);
5168 ec.Emit (OpCodes.Ldloca, local);
5174 ec.Emit (OpCodes.Ldsflda, spec);
5177 EmitInstance (ec, false);
5178 ec.Emit (OpCodes.Ldflda, spec);
5182 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5184 return MakeExpression (ctx);
5187 public override SLE.Expression MakeExpression (BuilderContext ctx)
5190 return base.MakeExpression (ctx);
5192 return SLE.Expression.Field (
5193 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5194 spec.GetMetaInfo ());
5198 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5200 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5206 /// Expression that evaluates to a Property. The Assign class
5207 /// might set the `Value' expression if we are in an assignment.
5209 /// This is not an LValue because we need to re-write the expression, we
5210 /// can not take data from the stack and store it.
5212 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5214 public PropertyExpr (PropertySpec spec, Location l)
5217 best_candidate = spec;
5218 type = spec.MemberType;
5223 protected override TypeSpec DeclaringType {
5225 return best_candidate.DeclaringType;
5229 public override string Name {
5231 return best_candidate.Name;
5235 public override bool IsInstance {
5241 public override bool IsStatic {
5243 return best_candidate.IsStatic;
5247 public PropertySpec PropertyInfo {
5249 return best_candidate;
5255 public override Expression CreateExpressionTree (ResolveContext ec)
5258 if (IsSingleDimensionalArrayLength ()) {
5259 args = new Arguments (1);
5260 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5261 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5264 args = new Arguments (2);
5265 if (InstanceExpression == null)
5266 args.Add (new Argument (new NullLiteral (loc)));
5268 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5269 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5270 return CreateExpressionFactoryCall (ec, "Property", args);
5273 public Expression CreateSetterTypeOfExpression ()
5275 return new TypeOfMethod (Setter, loc);
5278 public override string GetSignatureForError ()
5280 return best_candidate.GetSignatureForError ();
5283 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5286 return base.MakeExpression (ctx);
5288 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5292 public override SLE.Expression MakeExpression (BuilderContext ctx)
5295 return base.MakeExpression (ctx);
5297 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5301 void Error_PropertyNotValid (ResolveContext ec)
5303 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5304 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5305 GetSignatureForError ());
5308 bool IsSingleDimensionalArrayLength ()
5310 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
5313 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5314 return ac != null && ac.Rank == 1;
5317 public override void Emit (EmitContext ec, bool leave_copy)
5320 // Special case: length of single dimension array property is turned into ldlen
5322 if (IsSingleDimensionalArrayLength ()) {
5324 EmitInstance (ec, false);
5325 ec.Emit (OpCodes.Ldlen);
5326 ec.Emit (OpCodes.Conv_I4);
5330 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5333 ec.Emit (OpCodes.Dup);
5335 temp = new LocalTemporary (this.Type);
5341 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5345 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5346 args = new Arguments (0);
5351 ec.Emit (OpCodes.Dup);
5353 temp = new LocalTemporary (this.Type);
5358 args = new Arguments (1);
5362 temp = new LocalTemporary (this.Type);
5364 args.Add (new Argument (temp));
5366 args.Add (new Argument (source));
5370 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5378 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5380 eclass = ExprClass.PropertyAccess;
5382 if (best_candidate.IsNotRealProperty) {
5383 Error_PropertyNotValid (rc);
5386 ResolveInstanceExpression (rc, right_side);
5388 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5389 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5390 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5392 type = p.MemberType;
5396 DoBestMemberChecks (rc, best_candidate);
5400 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5402 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5406 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5408 // getter and setter can be different for base calls
5409 MethodSpec getter, setter;
5410 protected T best_candidate;
5412 protected LocalTemporary temp;
5413 protected bool prepared;
5415 protected PropertyOrIndexerExpr (Location l)
5422 public MethodSpec Getter {
5431 public MethodSpec Setter {
5442 protected override Expression DoResolve (ResolveContext ec)
5444 if (eclass == ExprClass.Unresolved) {
5445 var expr = OverloadResolve (ec, null);
5450 return expr.Resolve (ec);
5453 if (!ResolveGetter (ec))
5459 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5461 if (right_side == EmptyExpression.OutAccess.Instance) {
5462 // TODO: best_candidate can be null at this point
5463 INamedBlockVariable variable = null;
5464 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5465 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5466 best_candidate.Name);
5468 right_side.DoResolveLValue (ec, this);
5473 // if the property/indexer returns a value type, and we try to set a field in it
5474 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5475 Error_CannotModifyIntermediateExpressionValue (ec);
5478 if (eclass == ExprClass.Unresolved) {
5479 var expr = OverloadResolve (ec, right_side);
5484 return expr.ResolveLValue (ec, right_side);
5487 if (!ResolveSetter (ec))
5494 // Implements the IAssignMethod interface for assignments
5496 public abstract void Emit (EmitContext ec, bool leave_copy);
5497 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5499 public override void Emit (EmitContext ec)
5504 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5506 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5508 bool ResolveGetter (ResolveContext rc)
5510 if (!best_candidate.HasGet) {
5511 if (InstanceExpression != EmptyExpression.Null) {
5512 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5513 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5514 best_candidate.GetSignatureForError ());
5517 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5518 if (best_candidate.HasDifferentAccessibility) {
5519 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5520 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5521 TypeManager.CSharpSignature (best_candidate));
5523 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5524 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5528 if (best_candidate.HasDifferentAccessibility) {
5529 CheckProtectedMemberAccess (rc, best_candidate.Get);
5532 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5536 bool ResolveSetter (ResolveContext rc)
5538 if (!best_candidate.HasSet) {
5539 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5540 GetSignatureForError ());
5544 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5545 if (best_candidate.HasDifferentAccessibility) {
5546 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5547 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5548 GetSignatureForError ());
5550 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5551 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5555 if (best_candidate.HasDifferentAccessibility)
5556 CheckProtectedMemberAccess (rc, best_candidate.Set);
5558 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5564 /// Fully resolved expression that evaluates to an Event
5566 public class EventExpr : MemberExpr, IAssignMethod
5568 readonly EventSpec spec;
5571 public EventExpr (EventSpec spec, Location loc)
5579 protected override TypeSpec DeclaringType {
5581 return spec.DeclaringType;
5585 public override string Name {
5591 public override bool IsInstance {
5593 return !spec.IsStatic;
5597 public override bool IsStatic {
5599 return spec.IsStatic;
5603 public MethodSpec Operator {
5611 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5614 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5616 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5617 if (spec.BackingField != null &&
5618 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5620 spec.MemberDefinition.SetIsUsed ();
5622 if (!ec.IsObsolete) {
5623 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5625 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5628 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5629 Error_AssignmentEventOnly (ec);
5631 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5633 InstanceExpression = null;
5635 return ml.ResolveMemberAccess (ec, left, original);
5639 return base.ResolveMemberAccess (ec, left, original);
5642 public override Expression CreateExpressionTree (ResolveContext ec)
5644 throw new NotSupportedException ("ET");
5647 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5649 if (right_side == EmptyExpression.EventAddition) {
5650 op = spec.AccessorAdd;
5651 } else if (right_side == EmptyExpression.EventSubtraction) {
5652 op = spec.AccessorRemove;
5656 Error_AssignmentEventOnly (ec);
5660 op = CandidateToBaseOverride (ec, op);
5664 protected override Expression DoResolve (ResolveContext ec)
5666 eclass = ExprClass.EventAccess;
5667 type = spec.MemberType;
5669 ResolveInstanceExpression (ec, null);
5671 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5672 Error_AssignmentEventOnly (ec);
5675 DoBestMemberChecks (ec, spec);
5679 public override void Emit (EmitContext ec)
5681 throw new NotSupportedException ();
5682 //Error_CannotAssign ();
5685 #region IAssignMethod Members
5687 public void Emit (EmitContext ec, bool leave_copy)
5689 throw new NotImplementedException ();
5692 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5694 if (leave_copy || !prepare_for_load)
5695 throw new NotImplementedException ("EventExpr::EmitAssign");
5697 Arguments args = new Arguments (1);
5698 args.Add (new Argument (source));
5699 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5704 void Error_AssignmentEventOnly (ResolveContext ec)
5706 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5707 ec.Report.Error (79, loc,
5708 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5709 GetSignatureForError ());
5711 ec.Report.Error (70, loc,
5712 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5713 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5717 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5719 name = name.Substring (0, name.LastIndexOf ('.'));
5720 base.Error_CannotCallAbstractBase (rc, name);
5723 public override string GetSignatureForError ()
5725 return TypeManager.CSharpSignature (spec);
5728 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5730 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5734 public class TemporaryVariableReference : VariableReference
5736 public class Declarator : Statement
5738 TemporaryVariableReference variable;
5740 public Declarator (TemporaryVariableReference variable)
5742 this.variable = variable;
5746 protected override void DoEmit (EmitContext ec)
5748 variable.li.CreateBuilder (ec);
5751 protected override void CloneTo (CloneContext clonectx, Statement target)
5759 public TemporaryVariableReference (LocalVariable li, Location loc)
5762 this.type = li.Type;
5766 public override bool IsLockedByStatement {
5774 public LocalVariable LocalInfo {
5780 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5782 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5783 return new TemporaryVariableReference (li, loc);
5786 public override Expression CreateExpressionTree (ResolveContext ec)
5788 throw new NotSupportedException ("ET");
5791 protected override Expression DoResolve (ResolveContext ec)
5793 eclass = ExprClass.Variable;
5796 // Don't capture temporary variables except when using
5797 // iterator redirection
5799 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5800 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5801 storey.CaptureLocalVariable (ec, li);
5807 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5809 return Resolve (ec);
5812 public override void Emit (EmitContext ec)
5814 li.CreateBuilder (ec);
5819 public void EmitAssign (EmitContext ec, Expression source)
5821 li.CreateBuilder (ec);
5823 EmitAssign (ec, source, false, false);
5826 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5828 return li.HoistedVariant;
5831 public override bool IsFixed {
5832 get { return true; }
5835 public override bool IsRef {
5836 get { return false; }
5839 public override string Name {
5840 get { throw new NotImplementedException (); }
5843 public override void SetHasAddressTaken ()
5845 throw new NotImplementedException ();
5848 protected override ILocalVariable Variable {
5852 public override VariableInfo VariableInfo {
5853 get { throw new NotImplementedException (); }
5858 /// Handles `var' contextual keyword; var becomes a keyword only
5859 /// if no type called var exists in a variable scope
5861 class VarExpr : SimpleName
5863 public VarExpr (Location loc)
5868 public bool InferType (ResolveContext ec, Expression right_side)
5871 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5873 type = right_side.Type;
5874 if (type == InternalType.Null || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5875 ec.Report.Error (815, loc,
5876 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5877 type.GetSignatureForError ());
5881 eclass = ExprClass.Variable;
5885 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5887 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5888 base.Error_TypeOrNamespaceNotFound (ec);
5890 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");