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");
802 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
804 ec.Report.SymbolRelatedToPreviousError (type);
805 if (ec.CurrentInitializerVariable != null) {
806 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
807 TypeManager.CSharpName (type), GetSignatureForError ());
809 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
810 GetSignatureForError ());
815 // Converts `source' to an int, uint, long or ulong.
817 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
819 var btypes = ec.BuildinTypes;
821 if (source.type == InternalType.Dynamic) {
822 Arguments args = new Arguments (1);
823 args.Add (new Argument (source));
824 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
827 Expression converted;
829 using (ec.Set (ResolveContext.Options.CheckedScope)) {
830 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
831 if (converted == null)
832 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
833 if (converted == null)
834 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
835 if (converted == null)
836 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
838 if (converted == null) {
839 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
845 // Only positive constants are allowed at compile time
847 Constant c = converted as Constant;
848 if (c != null && c.IsNegative)
849 Error_NegativeArrayIndex (ec, source.loc);
851 // No conversion needed to array index
852 if (converted.Type.BuildinType == BuildinTypeSpec.Type.Int)
855 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
859 // Derived classes implement this method by cloning the fields that
860 // could become altered during the Resolve stage
862 // Only expressions that are created for the parser need to implement
865 protected virtual void CloneTo (CloneContext clonectx, Expression target)
867 throw new NotImplementedException (
869 "CloneTo not implemented for expression {0}", this.GetType ()));
873 // Clones an expression created by the parser.
875 // We only support expressions created by the parser so far, not
876 // expressions that have been resolved (many more classes would need
877 // to implement CloneTo).
879 // This infrastructure is here merely for Lambda expressions which
880 // compile the same code using different type values for the same
881 // arguments to find the correct overload
883 public virtual Expression Clone (CloneContext clonectx)
885 Expression cloned = (Expression) MemberwiseClone ();
886 CloneTo (clonectx, cloned);
892 // Implementation of expression to expression tree conversion
894 public abstract Expression CreateExpressionTree (ResolveContext ec);
896 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
898 return CreateExpressionFactoryCall (ec, name, null, args, loc);
901 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
903 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
906 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
908 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
911 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
913 var t = ec.Module.PredefinedTypes.Expression.Resolve (loc);
917 return new TypeExpression (t, loc);
921 // Implemented by all expressions which support conversion from
922 // compiler expression to invokable runtime expression. Used by
923 // dynamic C# binder.
925 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
927 throw new NotImplementedException ("MakeExpression for " + GetType ());
932 /// This is just a base class for expressions that can
933 /// appear on statements (invocations, object creation,
934 /// assignments, post/pre increment and decrement). The idea
935 /// being that they would support an extra Emition interface that
936 /// does not leave a result on the stack.
938 public abstract class ExpressionStatement : Expression {
940 public ExpressionStatement ResolveStatement (BlockContext ec)
942 Expression e = Resolve (ec);
946 ExpressionStatement es = e as ExpressionStatement;
948 Error_InvalidExpressionStatement (ec);
954 /// Requests the expression to be emitted in a `statement'
955 /// context. This means that no new value is left on the
956 /// stack after invoking this method (constrasted with
957 /// Emit that will always leave a value on the stack).
959 public abstract void EmitStatement (EmitContext ec);
961 public override void EmitSideEffect (EmitContext ec)
968 /// This kind of cast is used to encapsulate the child
969 /// whose type is child.Type into an expression that is
970 /// reported to return "return_type". This is used to encapsulate
971 /// expressions which have compatible types, but need to be dealt
972 /// at higher levels with.
974 /// For example, a "byte" expression could be encapsulated in one
975 /// of these as an "unsigned int". The type for the expression
976 /// would be "unsigned int".
979 public abstract class TypeCast : Expression
981 protected readonly Expression child;
983 protected TypeCast (Expression child, TypeSpec return_type)
985 eclass = child.eclass;
986 loc = child.Location;
991 public Expression Child {
997 public override Expression CreateExpressionTree (ResolveContext ec)
999 Arguments args = new Arguments (2);
1000 args.Add (new Argument (child.CreateExpressionTree (ec)));
1001 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1003 if (type.IsPointer || child.Type.IsPointer)
1004 Error_PointerInsideExpressionTree (ec);
1006 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1009 protected override Expression DoResolve (ResolveContext ec)
1011 // This should never be invoked, we are born in fully
1012 // initialized state.
1017 public override void Emit (EmitContext ec)
1022 public override SLE.Expression MakeExpression (BuilderContext ctx)
1025 return base.MakeExpression (ctx);
1027 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1028 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1029 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1033 protected override void CloneTo (CloneContext clonectx, Expression t)
1038 public override bool IsNull {
1039 get { return child.IsNull; }
1043 public class EmptyCast : TypeCast {
1044 EmptyCast (Expression child, TypeSpec target_type)
1045 : base (child, target_type)
1049 public static Expression Create (Expression child, TypeSpec type)
1051 Constant c = child as Constant;
1053 return new EmptyConstantCast (c, type);
1055 EmptyCast e = child as EmptyCast;
1057 return new EmptyCast (e.child, type);
1059 return new EmptyCast (child, type);
1062 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1064 child.EmitBranchable (ec, label, on_true);
1067 public override void EmitSideEffect (EmitContext ec)
1069 child.EmitSideEffect (ec);
1074 // Used for predefined class library user casts (no obsolete check, etc.)
1076 public class OperatorCast : TypeCast {
1077 MethodSpec conversion_operator;
1079 public OperatorCast (Expression child, TypeSpec target_type)
1080 : this (child, target_type, false)
1084 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1085 : base (child, target_type)
1087 conversion_operator = GetConversionOperator (find_explicit);
1088 if (conversion_operator == null)
1089 throw new InternalErrorException ("Outer conversion routine is out of sync");
1092 // Returns the implicit operator that converts from
1093 // 'child.Type' to our target type (type)
1094 MethodSpec GetConversionOperator (bool find_explicit)
1096 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1098 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1100 mi = MemberCache.GetUserOperator (type, op, true);
1103 foreach (MethodSpec oper in mi) {
1104 if (oper.ReturnType != type)
1107 if (oper.Parameters.Types [0] == child.Type)
1114 public override void Emit (EmitContext ec)
1117 ec.Emit (OpCodes.Call, conversion_operator);
1122 /// This is a numeric cast to a Decimal
1124 public class CastToDecimal : OperatorCast {
1125 public CastToDecimal (Expression child)
1126 : this (child, false)
1130 public CastToDecimal (Expression child, bool find_explicit)
1131 : base (child, TypeManager.decimal_type, find_explicit)
1137 /// This is an explicit numeric cast from a Decimal
1139 public class CastFromDecimal : TypeCast
1141 static Dictionary<TypeSpec, MethodSpec> operators;
1143 public CastFromDecimal (Expression child, TypeSpec return_type)
1144 : base (child, return_type)
1146 if (child.Type.BuildinType != BuildinTypeSpec.Type.Decimal)
1147 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1150 // Returns the explicit operator that converts from an
1151 // express of type System.Decimal to 'type'.
1152 public Expression Resolve ()
1154 if (operators == null) {
1155 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1157 operators = new Dictionary<TypeSpec, MethodSpec> ();
1158 foreach (MethodSpec oper in all_oper) {
1159 AParametersCollection pd = oper.Parameters;
1160 if (pd.Types [0].BuildinType == BuildinTypeSpec.Type.Decimal)
1161 operators.Add (oper.ReturnType, oper);
1165 return operators.ContainsKey (type) ? this : null;
1168 public override void Emit (EmitContext ec)
1172 ec.Emit (OpCodes.Call, operators [type]);
1175 public static void Reset ()
1183 // Constant specialization of EmptyCast.
1184 // We need to special case this since an empty cast of
1185 // a constant is still a constant.
1187 public class EmptyConstantCast : Constant
1189 public readonly Constant child;
1191 public EmptyConstantCast (Constant child, TypeSpec type)
1192 : base (child.Location)
1195 throw new ArgumentNullException ("child");
1198 this.eclass = child.eclass;
1202 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1204 if (child.Type == target_type)
1207 // FIXME: check that 'type' can be converted to 'target_type' first
1208 return child.ConvertExplicitly (in_checked_context, target_type);
1211 public override Expression CreateExpressionTree (ResolveContext ec)
1213 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1214 child.CreateExpressionTree (ec),
1215 new TypeOf (new TypeExpression (type, loc), loc));
1218 Error_PointerInsideExpressionTree (ec);
1220 return CreateExpressionFactoryCall (ec, "Convert", args);
1223 public override bool IsDefaultValue {
1224 get { return child.IsDefaultValue; }
1227 public override bool IsNegative {
1228 get { return child.IsNegative; }
1231 public override bool IsNull {
1232 get { return child.IsNull; }
1235 public override bool IsOneInteger {
1236 get { return child.IsOneInteger; }
1239 public override bool IsZeroInteger {
1240 get { return child.IsZeroInteger; }
1243 public override void Emit (EmitContext ec)
1248 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1250 child.EmitBranchable (ec, label, on_true);
1252 // Only to make verifier happy
1253 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1254 ec.Emit (OpCodes.Unbox_Any, type);
1257 public override void EmitSideEffect (EmitContext ec)
1259 child.EmitSideEffect (ec);
1262 public override object GetValue ()
1264 return child.GetValue ();
1267 public override string GetValueAsLiteral ()
1269 return child.GetValueAsLiteral ();
1272 public override long GetValueAsLong ()
1274 return child.GetValueAsLong ();
1277 public override Constant ConvertImplicitly (TypeSpec target_type)
1279 if (type == target_type)
1282 // FIXME: Do we need to check user conversions?
1283 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1286 return child.ConvertImplicitly (target_type);
1291 /// This class is used to wrap literals which belong inside Enums
1293 public class EnumConstant : Constant
1295 public Constant Child;
1297 public EnumConstant (Constant child, TypeSpec enum_type)
1298 : base (child.Location)
1302 this.eclass = ExprClass.Value;
1303 this.type = enum_type;
1306 protected EnumConstant (Location loc)
1311 public override void Emit (EmitContext ec)
1316 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1318 Child.EncodeAttributeValue (rc, enc, Child.Type);
1321 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1323 Child.EmitBranchable (ec, label, on_true);
1326 public override void EmitSideEffect (EmitContext ec)
1328 Child.EmitSideEffect (ec);
1331 public override string GetSignatureForError()
1333 return TypeManager.CSharpName (Type);
1336 public override object GetValue ()
1338 return Child.GetValue ();
1342 public override object GetTypedValue ()
1345 // The method can be used in dynamic context only (on closed types)
1347 // System.Enum.ToObject cannot be called on dynamic types
1348 // EnumBuilder has to be used, but we cannot use EnumBuilder
1349 // because it does not properly support generics
1351 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1355 public override string GetValueAsLiteral ()
1357 return Child.GetValueAsLiteral ();
1360 public override long GetValueAsLong ()
1362 return Child.GetValueAsLong ();
1365 public EnumConstant Increment()
1367 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1370 public override bool IsDefaultValue {
1372 return Child.IsDefaultValue;
1376 public override bool IsZeroInteger {
1377 get { return Child.IsZeroInteger; }
1380 public override bool IsNegative {
1382 return Child.IsNegative;
1386 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1388 if (Child.Type == target_type)
1391 return Child.ConvertExplicitly (in_checked_context, target_type);
1394 public override Constant ConvertImplicitly (TypeSpec type)
1396 if (this.type == type) {
1400 if (!Convert.ImplicitStandardConversionExists (this, type)){
1404 return Child.ConvertImplicitly (type);
1409 /// This kind of cast is used to encapsulate Value Types in objects.
1411 /// The effect of it is to box the value type emitted by the previous
1414 public class BoxedCast : TypeCast {
1416 public BoxedCast (Expression expr, TypeSpec target_type)
1417 : base (expr, target_type)
1419 eclass = ExprClass.Value;
1422 protected override Expression DoResolve (ResolveContext ec)
1424 // This should never be invoked, we are born in fully
1425 // initialized state.
1430 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1432 // Only boxing to object type is supported
1433 if (targetType.BuildinType != BuildinTypeSpec.Type.Object) {
1434 base.EncodeAttributeValue (rc, enc, targetType);
1438 enc.Encode (child.Type);
1439 child.EncodeAttributeValue (rc, enc, child.Type);
1442 public override void Emit (EmitContext ec)
1446 ec.Emit (OpCodes.Box, child.Type);
1449 public override void EmitSideEffect (EmitContext ec)
1451 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1452 // so, we need to emit the box+pop instructions in most cases
1453 if (TypeManager.IsStruct (child.Type) &&
1454 (type.BuildinType == BuildinTypeSpec.Type.Object || type.BuildinType == BuildinTypeSpec.Type.ValueType))
1455 child.EmitSideEffect (ec);
1457 base.EmitSideEffect (ec);
1461 public class UnboxCast : TypeCast {
1462 public UnboxCast (Expression expr, TypeSpec return_type)
1463 : base (expr, return_type)
1467 protected override Expression DoResolve (ResolveContext ec)
1469 // This should never be invoked, we are born in fully
1470 // initialized state.
1475 public override void Emit (EmitContext ec)
1479 ec.Emit (OpCodes.Unbox_Any, type);
1484 /// This is used to perform explicit numeric conversions.
1486 /// Explicit numeric conversions might trigger exceptions in a checked
1487 /// context, so they should generate the conv.ovf opcodes instead of
1490 public class ConvCast : TypeCast {
1491 public enum Mode : byte {
1492 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1494 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1495 U2_I1, U2_U1, U2_I2, U2_CH,
1496 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1497 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1498 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1499 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1500 CH_I1, CH_U1, CH_I2,
1501 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1502 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1508 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1509 : base (child, return_type)
1514 protected override Expression DoResolve (ResolveContext ec)
1516 // This should never be invoked, we are born in fully
1517 // initialized state.
1522 public override string ToString ()
1524 return String.Format ("ConvCast ({0}, {1})", mode, child);
1527 public override void Emit (EmitContext ec)
1531 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1533 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1534 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1535 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1536 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1537 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1539 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1540 case Mode.U1_CH: /* nothing */ break;
1542 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1543 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1544 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1545 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1546 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1547 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1549 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1550 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1551 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1552 case Mode.U2_CH: /* nothing */ break;
1554 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1555 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1556 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1557 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1558 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1560 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1562 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1563 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1564 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1565 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1566 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1567 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1569 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1570 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1571 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1572 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1573 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1574 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1575 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1576 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1577 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1579 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1580 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1581 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1582 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1583 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1584 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1585 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1586 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1587 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1589 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1590 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1591 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1593 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1594 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1595 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1596 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1598 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1599 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1600 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1601 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1603 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1604 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1605 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1606 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1607 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1608 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1609 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1610 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1611 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1612 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1614 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1618 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1619 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1620 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1621 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1622 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1624 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1625 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1627 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1628 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1629 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1630 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1631 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1632 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1634 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1635 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1636 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1637 case Mode.U2_CH: /* nothing */ break;
1639 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1640 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1641 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1642 case Mode.I4_U4: /* nothing */ break;
1643 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1645 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1647 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1648 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1649 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1650 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1651 case Mode.U4_I4: /* nothing */ break;
1652 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1655 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1656 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1657 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1658 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1659 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1660 case Mode.I8_U8: /* nothing */ break;
1661 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1662 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1664 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1665 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1666 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1667 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1669 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1670 case Mode.U8_I8: /* nothing */ break;
1671 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1674 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1675 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1676 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1678 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1683 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1684 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1685 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1686 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1689 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1690 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1691 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1693 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1694 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1695 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1696 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1697 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1699 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1705 class OpcodeCast : TypeCast
1709 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1710 : base (child, return_type)
1715 protected override Expression DoResolve (ResolveContext ec)
1717 // This should never be invoked, we are born in fully
1718 // initialized state.
1723 public override void Emit (EmitContext ec)
1729 public TypeSpec UnderlyingType {
1730 get { return child.Type; }
1735 // Opcode casts expression with 2 opcodes but only
1736 // single expression tree node
1738 class OpcodeCastDuplex : OpcodeCast
1740 readonly OpCode second;
1742 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1743 : base (child, returnType, first)
1745 this.second = second;
1748 public override void Emit (EmitContext ec)
1756 /// This kind of cast is used to encapsulate a child and cast it
1757 /// to the class requested
1759 public sealed class ClassCast : TypeCast {
1760 readonly bool forced;
1762 public ClassCast (Expression child, TypeSpec return_type)
1763 : base (child, return_type)
1767 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1768 : base (child, return_type)
1770 this.forced = forced;
1773 public override void Emit (EmitContext ec)
1777 bool gen = TypeManager.IsGenericParameter (child.Type);
1779 ec.Emit (OpCodes.Box, child.Type);
1781 if (type.IsGenericParameter) {
1782 ec.Emit (OpCodes.Unbox_Any, type);
1789 ec.Emit (OpCodes.Castclass, type);
1794 // Created during resolving pahse when an expression is wrapped or constantified
1795 // and original expression can be used later (e.g. for expression trees)
1797 public class ReducedExpression : Expression
1799 sealed class ReducedConstantExpression : EmptyConstantCast
1801 readonly Expression orig_expr;
1803 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1804 : base (expr, expr.Type)
1806 this.orig_expr = orig_expr;
1809 public override Constant ConvertImplicitly (TypeSpec target_type)
1811 Constant c = base.ConvertImplicitly (target_type);
1813 c = new ReducedConstantExpression (c, orig_expr);
1818 public override Expression CreateExpressionTree (ResolveContext ec)
1820 return orig_expr.CreateExpressionTree (ec);
1823 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1825 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1827 c = new ReducedConstantExpression (c, orig_expr);
1832 sealed class ReducedExpressionStatement : ExpressionStatement
1834 readonly Expression orig_expr;
1835 readonly ExpressionStatement stm;
1837 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1839 this.orig_expr = orig;
1841 this.eclass = stm.eclass;
1842 this.type = stm.Type;
1844 this.loc = orig.Location;
1847 public override Expression CreateExpressionTree (ResolveContext ec)
1849 return orig_expr.CreateExpressionTree (ec);
1852 protected override Expression DoResolve (ResolveContext ec)
1857 public override void Emit (EmitContext ec)
1862 public override void EmitStatement (EmitContext ec)
1864 stm.EmitStatement (ec);
1868 readonly Expression expr, orig_expr;
1870 private ReducedExpression (Expression expr, Expression orig_expr)
1873 this.eclass = expr.eclass;
1874 this.type = expr.Type;
1875 this.orig_expr = orig_expr;
1876 this.loc = orig_expr.Location;
1881 public Expression OriginalExpression {
1890 // Creates fully resolved expression switcher
1892 public static Constant Create (Constant expr, Expression original_expr)
1894 if (expr.eclass == ExprClass.Unresolved)
1895 throw new ArgumentException ("Unresolved expression");
1897 return new ReducedConstantExpression (expr, original_expr);
1900 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1902 return new ReducedExpressionStatement (s, orig);
1905 public static Expression Create (Expression expr, Expression original_expr)
1907 return Create (expr, original_expr, true);
1911 // Creates unresolved reduce expression. The original expression has to be
1912 // already resolved. Created expression is constant based based on `expr'
1913 // value unless canBeConstant is used
1915 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1917 if (canBeConstant) {
1918 Constant c = expr as Constant;
1920 return Create (c, original_expr);
1923 ExpressionStatement s = expr as ExpressionStatement;
1925 return Create (s, original_expr);
1927 if (expr.eclass == ExprClass.Unresolved)
1928 throw new ArgumentException ("Unresolved expression");
1930 return new ReducedExpression (expr, original_expr);
1933 public override Expression CreateExpressionTree (ResolveContext ec)
1935 return orig_expr.CreateExpressionTree (ec);
1938 protected override Expression DoResolve (ResolveContext ec)
1943 public override void Emit (EmitContext ec)
1948 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1950 expr.EmitBranchable (ec, target, on_true);
1953 public override SLE.Expression MakeExpression (BuilderContext ctx)
1955 return orig_expr.MakeExpression (ctx);
1960 // Standard composite pattern
1962 public abstract class CompositeExpression : Expression
1964 protected Expression expr;
1966 protected CompositeExpression (Expression expr)
1969 this.loc = expr.Location;
1972 public override Expression CreateExpressionTree (ResolveContext ec)
1974 return expr.CreateExpressionTree (ec);
1977 public Expression Child {
1978 get { return expr; }
1981 protected override Expression DoResolve (ResolveContext ec)
1983 expr = expr.Resolve (ec);
1986 eclass = expr.eclass;
1992 public override void Emit (EmitContext ec)
1997 public override bool IsNull {
1998 get { return expr.IsNull; }
2003 // Base of expressions used only to narrow resolve flow
2005 public abstract class ShimExpression : Expression
2007 protected Expression expr;
2009 protected ShimExpression (Expression expr)
2014 protected override void CloneTo (CloneContext clonectx, Expression t)
2019 ShimExpression target = (ShimExpression) t;
2020 target.expr = expr.Clone (clonectx);
2023 public override Expression CreateExpressionTree (ResolveContext ec)
2025 throw new NotSupportedException ("ET");
2028 public override void Emit (EmitContext ec)
2030 throw new InternalErrorException ("Missing Resolve call");
2033 public Expression Expr {
2034 get { return expr; }
2039 // Unresolved type name expressions
2041 public abstract class ATypeNameExpression : FullNamedExpression
2044 protected TypeArguments targs;
2046 protected ATypeNameExpression (string name, Location l)
2052 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2059 protected ATypeNameExpression (string name, int arity, Location l)
2060 : this (name, new UnboundTypeArguments (arity), l)
2066 protected int Arity {
2068 return targs == null ? 0 : targs.Count;
2072 public bool HasTypeArguments {
2074 return targs != null && !targs.IsEmpty;
2078 public string Name {
2087 public TypeArguments TypeArguments {
2095 public override bool Equals (object obj)
2097 ATypeNameExpression atne = obj as ATypeNameExpression;
2098 return atne != null && atne.Name == Name &&
2099 (targs == null || targs.Equals (atne.targs));
2102 public override int GetHashCode ()
2104 return Name.GetHashCode ();
2107 // TODO: Move it to MemberCore
2108 public static string GetMemberType (MemberCore mc)
2114 if (mc is FieldBase)
2116 if (mc is MethodCore)
2118 if (mc is EnumMember)
2126 public override string GetSignatureForError ()
2128 if (targs != null) {
2129 return Name + "<" + targs.GetSignatureForError () + ">";
2135 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2139 /// SimpleName expressions are formed of a single word and only happen at the beginning
2140 /// of a dotted-name.
2142 public class SimpleName : ATypeNameExpression
2144 public SimpleName (string name, Location l)
2149 public SimpleName (string name, TypeArguments args, Location l)
2150 : base (name, args, l)
2154 public SimpleName (string name, int arity, Location l)
2155 : base (name, arity, l)
2159 public SimpleName GetMethodGroup ()
2161 return new SimpleName (Name, targs, loc);
2164 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2166 if (ec.CurrentType != null) {
2167 if (ec.CurrentMemberDefinition != null) {
2168 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2170 Error_UnexpectedKind (ec.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2176 // TODO MemberCache: Implement
2178 string ns = ec.CurrentType.Namespace;
2179 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2180 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2181 var type = a.GetType (fullname);
2183 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2184 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2189 if (ec.CurrentTypeDefinition != null) {
2190 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2192 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2199 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2200 if (retval != null) {
2201 Error_TypeArgumentsCannotBeUsed (ec.Module.Compiler.Report, loc, retval.Type, Arity);
2203 var te = retval as TypeExpr;
2204 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2205 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2207 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2212 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Module.Compiler.Report);
2215 protected override Expression DoResolve (ResolveContext ec)
2217 return SimpleNameResolve (ec, null, false);
2220 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2222 return SimpleNameResolve (ec, right_side, false);
2225 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2227 int errors = ec.Module.Compiler.Report.Errors;
2228 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2231 if (fne.Type != null && Arity > 0) {
2232 if (HasTypeArguments) {
2233 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2234 return ct.ResolveAsTypeStep (ec, false);
2237 return new GenericOpenTypeExpr (fne.Type, loc);
2241 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2243 if (!(fne is Namespace))
2247 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2248 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2249 ec.Module.Compiler.Report.Error (1980, Location,
2250 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2251 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2254 return new DynamicTypeExpr (loc);
2260 if (silent || errors != ec.Module.Compiler.Report.Errors)
2263 Error_TypeOrNamespaceNotFound (ec);
2267 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2269 int lookup_arity = Arity;
2270 bool errorMode = false;
2272 Block current_block = rc.CurrentBlock;
2273 INamedBlockVariable variable = null;
2274 bool variable_found = false;
2278 // Stage 1: binding to local variables or parameters
2280 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2282 if (current_block != null && lookup_arity == 0) {
2283 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2284 if (!variable.IsDeclared) {
2285 // We found local name in accessible block but it's not
2286 // initialized yet, maybe the user wanted to bind to something else
2288 variable_found = true;
2290 e = variable.CreateReferenceExpression (rc, loc);
2293 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2302 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2304 TypeSpec member_type = rc.CurrentType;
2305 TypeSpec current_type = member_type;
2306 for (; member_type != null; member_type = member_type.DeclaringType) {
2307 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2311 var me = e as MemberExpr;
2313 // The name matches a type, defer to ResolveAsTypeStep
2321 if (variable != null) {
2322 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2323 rc.Report.Error (844, loc,
2324 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2325 Name, me.GetSignatureForError ());
2329 } else if (me is MethodGroupExpr) {
2330 // Leave it to overload resolution to report correct error
2332 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2333 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2336 // LAMESPEC: again, ignores InvocableOnly
2337 if (variable != null) {
2338 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2339 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2343 // MemberLookup does not check accessors availability, this is actually needed for properties only
2345 var pe = me as PropertyExpr;
2348 // Break as there is no other overload available anyway
2349 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2350 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2353 pe.Getter = pe.PropertyInfo.Get;
2355 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2358 pe.Setter = pe.PropertyInfo.Set;
2363 // TODO: It's used by EventExpr -> FieldExpr transformation only
2364 // TODO: Should go to MemberAccess
2365 me = me.ResolveMemberAccess (rc, null, null);
2369 me.SetTypeArguments (rc, targs);
2376 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2378 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2379 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2381 if (variable != null) {
2382 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2383 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2391 if (variable_found) {
2392 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2394 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2400 if (rc.Module.Evaluator != null) {
2401 var fi = rc.Module.Evaluator.LookupField (Name);
2403 return new FieldExpr (fi.Item1, loc);
2407 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2412 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2414 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2419 if (right_side != null) {
2420 if (e is TypeExpr) {
2421 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2425 e = e.ResolveLValue (ec, right_side);
2430 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2436 /// Represents a namespace or a type. The name of the class was inspired by
2437 /// section 10.8.1 (Fully Qualified Names).
2439 public abstract class FullNamedExpression : Expression
2441 protected override void CloneTo (CloneContext clonectx, Expression target)
2443 // Do nothing, most unresolved type expressions cannot be
2444 // resolved to different type
2447 public override Expression CreateExpressionTree (ResolveContext ec)
2449 throw new NotSupportedException ("ET");
2452 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2457 public override void Emit (EmitContext ec)
2459 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2460 GetSignatureForError ());
2465 /// Expression that evaluates to a type
2467 public abstract class TypeExpr : FullNamedExpression {
2468 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2470 TypeExpr t = DoResolveAsTypeStep (ec);
2474 eclass = ExprClass.Type;
2478 protected override Expression DoResolve (ResolveContext ec)
2480 return ResolveAsTypeTerminal (ec, false);
2483 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2485 public override bool Equals (object obj)
2487 TypeExpr tobj = obj as TypeExpr;
2491 return Type == tobj.Type;
2494 public override int GetHashCode ()
2496 return Type.GetHashCode ();
2501 /// Fully resolved Expression that already evaluated to a type
2503 public class TypeExpression : TypeExpr {
2504 public TypeExpression (TypeSpec t, Location l)
2507 eclass = ExprClass.Type;
2511 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2516 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2523 /// This class denotes an expression which evaluates to a member
2524 /// of a struct or a class.
2526 public abstract class MemberExpr : Expression
2529 // An instance expression associated with this member, if it's a
2530 // non-static member
2532 public Expression InstanceExpression;
2535 /// The name of this member.
2537 public abstract string Name {
2542 // When base.member is used
2544 public bool IsBase {
2545 get { return InstanceExpression is BaseThis; }
2549 /// Whether this is an instance member.
2551 public abstract bool IsInstance {
2556 /// Whether this is a static member.
2558 public abstract bool IsStatic {
2563 protected abstract TypeSpec DeclaringType {
2568 // Converts best base candidate for virtual method starting from QueriedBaseType
2570 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2573 // Only when base.member is used and method is virtual
2579 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2580 // means for base.member access we have to find the closest match after we found best candidate
2582 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2584 // The method could already be what we are looking for
2586 TypeSpec[] targs = null;
2587 if (method.DeclaringType != InstanceExpression.Type) {
2588 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2589 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2590 if (base_override.IsGeneric)
2591 targs = method.TypeArguments;
2593 method = base_override;
2597 // TODO: For now we do it for any hoisted call even if it's needed for
2598 // hoisted stories only but that requires a new expression wrapper
2599 if (rc.CurrentAnonymousMethod != null) {
2600 if (targs == null && method.IsGeneric) {
2601 targs = method.TypeArguments;
2602 method = method.GetGenericMethodDefinition ();
2605 if (method.Parameters.HasArglist)
2606 throw new NotImplementedException ("__arglist base call proxy");
2608 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2610 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2611 // get/set member expressions second call would fail to proxy because left expression
2612 // would be of 'this' and not 'base'
2613 if (rc.CurrentType.IsStruct)
2614 InstanceExpression = new This (loc).Resolve (rc);
2618 method = method.MakeGenericMethod (rc, targs);
2622 // Only base will allow this invocation to happen.
2624 if (method.IsAbstract) {
2625 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2631 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2633 if (InstanceExpression == null)
2636 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2637 var ct = rc.CurrentType;
2638 var expr_type = InstanceExpression.Type;
2639 if (ct == expr_type)
2642 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && expr_type.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2645 expr_type = expr_type.GetDefinition ();
2646 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2647 rc.Report.SymbolRelatedToPreviousError (member);
2648 rc.Report.Error (1540, loc,
2649 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2650 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2655 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2658 type = type.GetDefinition ();
2660 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2663 type = type.DeclaringType;
2664 } while (type != null);
2669 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2671 if (InstanceExpression != null) {
2672 InstanceExpression = InstanceExpression.Resolve (rc);
2673 CheckProtectedMemberAccess (rc, member);
2676 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2677 UnsafeError (rc, loc);
2680 var dep = member.GetMissingDependencies ();
2682 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2685 if (!rc.IsObsolete) {
2686 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2688 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2691 if (!(member is FieldSpec))
2692 member.MemberDefinition.SetIsUsed ();
2695 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2697 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2701 // Implements identicial simple name and type-name
2703 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2706 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2709 // 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
2710 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2712 if (left is MemberExpr || left is VariableReference) {
2713 rc.Report.DisableReporting ();
2714 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2715 rc.Report.EnableReporting ();
2716 if (identical_type != null && identical_type.Type == left.Type)
2717 return identical_type;
2723 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2726 if (InstanceExpression != null) {
2727 if (InstanceExpression is TypeExpr) {
2728 var t = InstanceExpression.Type;
2730 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2731 if (oa != null && !rc.IsObsolete) {
2732 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2735 t = t.DeclaringType;
2736 } while (t != null);
2738 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2739 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2740 rc.Report.Error (176, loc,
2741 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2742 GetSignatureForError ());
2746 InstanceExpression = null;
2752 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2753 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2754 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2755 rc.Report.Error (236, loc,
2756 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2757 GetSignatureForError ());
2759 rc.Report.Error (120, loc,
2760 "An object reference is required to access non-static member `{0}'",
2761 GetSignatureForError ());
2766 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2767 rc.Report.Error (38, loc,
2768 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2769 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2772 InstanceExpression = new This (loc);
2773 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2774 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2775 InstanceExpression = InstanceExpression.Resolve (rc);
2778 InstanceExpression = InstanceExpression.Resolve (rc);
2784 var me = InstanceExpression as MemberExpr;
2786 me.ResolveInstanceExpression (rc, rhs);
2788 var fe = me as FieldExpr;
2789 if (fe != null && fe.IsMarshalByRefAccess ()) {
2790 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2791 rc.Report.Warning (1690, 1, loc,
2792 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2793 me.GetSignatureForError ());
2800 // Run member-access postponed check once we know that
2801 // the expression is not field expression which is the only
2802 // expression which can use uninitialized this
2804 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2805 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2809 // Additional checks for l-value member access
2813 // TODO: It should be recursive but that would break csc compatibility
2815 if (InstanceExpression is UnboxCast) {
2816 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2823 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2825 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2826 ec.Report.Warning (1720, 1, left.Location,
2827 "Expression will always cause a `{0}'", "System.NullReferenceException");
2830 InstanceExpression = left;
2834 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2836 TypeSpec instance_type = InstanceExpression.Type;
2837 if (TypeManager.IsValueType (instance_type)) {
2838 if (InstanceExpression is IMemoryLocation) {
2839 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2841 LocalTemporary t = new LocalTemporary (instance_type);
2842 InstanceExpression.Emit (ec);
2844 t.AddressOf (ec, AddressOp.Store);
2847 InstanceExpression.Emit (ec);
2849 // Only to make verifier happy
2850 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2851 ec.Emit (OpCodes.Box, instance_type);
2854 if (prepare_for_load)
2855 ec.Emit (OpCodes.Dup);
2858 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2862 // Represents a group of extension method candidates for whole namespace
2864 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2866 NamespaceEntry namespace_entry;
2867 public readonly Expression ExtensionExpression;
2869 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2870 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2872 this.namespace_entry = n;
2873 this.ExtensionExpression = extensionExpr;
2876 public override bool IsStatic {
2877 get { return true; }
2880 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2882 if (namespace_entry == null)
2886 // For extension methodgroup we are not looking for base members but parent
2887 // namespace extension methods
2889 int arity = type_arguments == null ? 0 : type_arguments.Count;
2890 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2894 return found.Cast<MemberSpec> ().ToList ();
2897 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2899 // We are already here
2903 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2905 if (arguments == null)
2906 arguments = new Arguments (1);
2908 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2909 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2911 // Store resolved argument and restore original arguments
2913 // Clean-up modified arguments for error reporting
2914 arguments.RemoveAt (0);
2918 var me = ExtensionExpression as MemberExpr;
2920 me.ResolveInstanceExpression (ec, null);
2922 InstanceExpression = null;
2926 #region IErrorHandler Members
2928 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2933 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2935 rc.Report.SymbolRelatedToPreviousError (best);
2936 rc.Report.Error (1928, loc,
2937 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2938 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2941 rc.Report.Error (1929, loc,
2942 "Extension method instance type `{0}' cannot be converted to `{1}'",
2943 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2949 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2954 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2963 /// MethodGroupExpr represents a group of method candidates which
2964 /// can be resolved to the best method overload
2966 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2968 protected IList<MemberSpec> Methods;
2969 MethodSpec best_candidate;
2970 TypeSpec best_candidate_return;
2971 protected TypeArguments type_arguments;
2973 SimpleName simple_name;
2974 protected TypeSpec queried_type;
2976 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2980 this.type = InternalType.MethodGroup;
2982 eclass = ExprClass.MethodGroup;
2983 queried_type = type;
2986 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2987 : this (new MemberSpec[] { m }, type, loc)
2993 public MethodSpec BestCandidate {
2995 return best_candidate;
2999 public TypeSpec BestCandidateReturnType {
3001 return best_candidate_return;
3005 protected override TypeSpec DeclaringType {
3007 return queried_type;
3011 public override bool IsInstance {
3013 if (best_candidate != null)
3014 return !best_candidate.IsStatic;
3020 public override bool IsStatic {
3022 if (best_candidate != null)
3023 return best_candidate.IsStatic;
3029 public override string Name {
3031 if (best_candidate != null)
3032 return best_candidate.Name;
3035 return Methods.First ().Name;
3042 // When best candidate is already know this factory can be used
3043 // to avoid expensive overload resolution to be called
3045 // NOTE: InstanceExpression has to be set manually
3047 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3049 return new MethodGroupExpr (best, queriedType, loc) {
3050 best_candidate = best,
3051 best_candidate_return = best.ReturnType
3055 public override string GetSignatureForError ()
3057 if (best_candidate != null)
3058 return best_candidate.GetSignatureForError ();
3060 return Methods.First ().GetSignatureForError ();
3063 public override Expression CreateExpressionTree (ResolveContext ec)
3065 if (best_candidate == null) {
3066 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3070 if (best_candidate.IsConditionallyExcluded (loc))
3071 ec.Report.Error (765, loc,
3072 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3074 return new TypeOfMethod (best_candidate, loc);
3077 protected override Expression DoResolve (ResolveContext ec)
3079 this.eclass = ExprClass.MethodGroup;
3081 if (InstanceExpression != null) {
3082 InstanceExpression = InstanceExpression.Resolve (ec);
3083 if (InstanceExpression == null)
3090 public override void Emit (EmitContext ec)
3092 throw new NotSupportedException ();
3095 public void EmitCall (EmitContext ec, Arguments arguments)
3097 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3100 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3102 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3103 Name, TypeManager.CSharpName (target));
3106 public static bool IsExtensionMethodArgument (Expression expr)
3109 // LAMESPEC: No details about which expressions are not allowed
3111 return !(expr is TypeExpr) && !(expr is BaseThis);
3115 /// Find the Applicable Function Members (7.4.2.1)
3117 /// me: Method Group expression with the members to select.
3118 /// it might contain constructors or methods (or anything
3119 /// that maps to a method).
3121 /// Arguments: ArrayList containing resolved Argument objects.
3123 /// loc: The location if we want an error to be reported, or a Null
3124 /// location for "probing" purposes.
3126 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3127 /// that is the best match of me on Arguments.
3130 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3132 // TODO: causes issues with probing mode, remove explicit Kind check
3133 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3136 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3137 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3138 r.BaseMembersProvider = this;
3141 if (cerrors != null)
3142 r.CustomErrors = cerrors;
3144 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3145 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3146 if (best_candidate == null)
3147 return r.BestCandidateIsDynamic ? this : null;
3149 // Overload resolver had to create a new method group, all checks bellow have already been executed
3150 if (r.BestCandidateNewMethodGroup != null)
3151 return r.BestCandidateNewMethodGroup;
3153 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3154 if (InstanceExpression != null) {
3155 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3156 InstanceExpression = null;
3158 if (best_candidate.IsStatic && simple_name != null) {
3159 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3162 InstanceExpression.Resolve (ec);
3166 ResolveInstanceExpression (ec, null);
3167 if (InstanceExpression != null)
3168 CheckProtectedMemberAccess (ec, best_candidate);
3171 var base_override = CandidateToBaseOverride (ec, best_candidate);
3172 if (base_override == best_candidate) {
3173 best_candidate_return = r.BestCandidateReturnType;
3175 best_candidate = base_override;
3176 best_candidate_return = best_candidate.ReturnType;
3182 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3184 simple_name = original;
3185 return base.ResolveMemberAccess (ec, left, original);
3188 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3190 type_arguments = ta;
3193 #region IBaseMembersProvider Members
3195 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3197 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3200 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3202 if (queried_type == member.DeclaringType)
3205 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3206 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3210 // Extension methods lookup after ordinary methods candidates failed to apply
3212 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3214 if (InstanceExpression == null)
3217 InstanceExpression = InstanceExpression.Resolve (rc);
3218 if (!IsExtensionMethodArgument (InstanceExpression))
3221 int arity = type_arguments == null ? 0 : type_arguments.Count;
3222 NamespaceEntry methods_scope = null;
3223 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3224 if (methods == null)
3227 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3228 emg.SetTypeArguments (rc, type_arguments);
3235 public struct OverloadResolver
3238 public enum Restrictions
3242 ProbingOnly = 1 << 1,
3243 CovariantDelegate = 1 << 2,
3244 NoBaseMembers = 1 << 3,
3245 BaseMembersIncluded = 1 << 4
3248 public interface IBaseMembersProvider
3250 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3251 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3252 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3255 public interface IErrorHandler
3257 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3258 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3259 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3260 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3263 sealed class NoBaseMembers : IBaseMembersProvider
3265 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3267 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3272 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3277 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3283 struct AmbiguousCandidate
3285 public readonly MemberSpec Member;
3286 public readonly bool Expanded;
3287 public readonly AParametersCollection Parameters;
3289 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3292 Parameters = parameters;
3293 Expanded = expanded;
3298 IList<MemberSpec> members;
3299 TypeArguments type_arguments;
3300 IBaseMembersProvider base_provider;
3301 IErrorHandler custom_errors;
3302 Restrictions restrictions;
3303 MethodGroupExpr best_candidate_extension_group;
3304 TypeSpec best_candidate_return_type;
3306 SessionReportPrinter lambda_conv_msgs;
3307 ReportPrinter prev_recorder;
3309 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3310 : this (members, null, restrictions, loc)
3314 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3317 if (members == null || members.Count == 0)
3318 throw new ArgumentException ("empty members set");
3320 this.members = members;
3322 type_arguments = targs;
3323 this.restrictions = restrictions;
3324 if (IsDelegateInvoke)
3325 this.restrictions |= Restrictions.NoBaseMembers;
3327 base_provider = NoBaseMembers.Instance;
3332 public IBaseMembersProvider BaseMembersProvider {
3334 return base_provider;
3337 base_provider = value;
3341 public bool BestCandidateIsDynamic { get; set; }
3344 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3346 public MethodGroupExpr BestCandidateNewMethodGroup {
3348 return best_candidate_extension_group;
3353 // Return type can be different between best candidate and closest override
3355 public TypeSpec BestCandidateReturnType {
3357 return best_candidate_return_type;
3361 public IErrorHandler CustomErrors {
3363 return custom_errors;
3366 custom_errors = value;
3370 TypeSpec DelegateType {
3372 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3373 throw new InternalErrorException ("Not running in delegate mode", loc);
3375 return members [0].DeclaringType;
3379 bool IsProbingOnly {
3381 return (restrictions & Restrictions.ProbingOnly) != 0;
3385 bool IsDelegateInvoke {
3387 return (restrictions & Restrictions.DelegateInvoke) != 0;
3394 // 7.4.3.3 Better conversion from expression
3395 // Returns : 1 if a->p is better,
3396 // 2 if a->q is better,
3397 // 0 if neither is better
3399 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3401 TypeSpec argument_type = a.Type;
3404 // If argument is an anonymous function
3406 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3408 // p and q are delegate types or expression tree types
3410 if (p.GetDefinition () == TypeManager.expression_type || q.GetDefinition () == TypeManager.expression_type) {
3411 if (q.MemberDefinition != p.MemberDefinition) {
3416 // Uwrap delegate from Expression<T>
3418 q = TypeManager.GetTypeArguments (q)[0];
3419 p = TypeManager.GetTypeArguments (p)[0];
3422 var p_m = Delegate.GetInvokeMethod (p);
3423 var q_m = Delegate.GetInvokeMethod (q);
3426 // With identical parameter lists
3428 if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
3435 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3437 if (p.Kind == MemberKind.Void) {
3438 return q.Kind != MemberKind.Void ? 2 : 0;
3442 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3444 if (q.Kind == MemberKind.Void) {
3445 return p.Kind != MemberKind.Void ? 1: 0;
3448 if (argument_type == p)
3451 if (argument_type == q)
3455 return BetterTypeConversion (ec, p, q);
3459 // 7.4.3.4 Better conversion from type
3461 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3463 if (p == null || q == null)
3464 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3466 switch (p.BuildinType) {
3467 case BuildinTypeSpec.Type.Int:
3468 if (q.BuildinType == BuildinTypeSpec.Type.UInt || q.BuildinType == BuildinTypeSpec.Type.ULong)
3471 case BuildinTypeSpec.Type.Long:
3472 if (q.BuildinType == BuildinTypeSpec.Type.ULong)
3475 case BuildinTypeSpec.Type.SByte:
3476 switch (q.BuildinType) {
3477 case BuildinTypeSpec.Type.Byte:
3478 case BuildinTypeSpec.Type.UShort:
3479 case BuildinTypeSpec.Type.UInt:
3480 case BuildinTypeSpec.Type.ULong:
3484 case BuildinTypeSpec.Type.Short:
3485 switch (q.BuildinType) {
3486 case BuildinTypeSpec.Type.UShort:
3487 case BuildinTypeSpec.Type.UInt:
3488 case BuildinTypeSpec.Type.ULong:
3492 case BuildinTypeSpec.Type.Dynamic:
3493 // Dynamic is never better
3497 switch (q.BuildinType) {
3498 case BuildinTypeSpec.Type.Int:
3499 if (p.BuildinType == BuildinTypeSpec.Type.UInt || p.BuildinType == BuildinTypeSpec.Type.ULong)
3502 case BuildinTypeSpec.Type.Long:
3503 if (p.BuildinType == BuildinTypeSpec.Type.ULong)
3506 case BuildinTypeSpec.Type.SByte:
3507 switch (p.BuildinType) {
3508 case BuildinTypeSpec.Type.Byte:
3509 case BuildinTypeSpec.Type.UShort:
3510 case BuildinTypeSpec.Type.UInt:
3511 case BuildinTypeSpec.Type.ULong:
3515 case BuildinTypeSpec.Type.Short:
3516 switch (p.BuildinType) {
3517 case BuildinTypeSpec.Type.UShort:
3518 case BuildinTypeSpec.Type.UInt:
3519 case BuildinTypeSpec.Type.ULong:
3523 case BuildinTypeSpec.Type.Dynamic:
3524 // Dynamic is never better
3528 // FIXME: handle lifted operators
3530 // TODO: this is expensive
3531 Expression p_tmp = new EmptyExpression (p);
3532 Expression q_tmp = new EmptyExpression (q);
3534 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3535 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3537 if (p_to_q && !q_to_p)
3540 if (q_to_p && !p_to_q)
3547 /// Determines "Better function" between candidate
3548 /// and the current best match
3551 /// Returns a boolean indicating :
3552 /// false if candidate ain't better
3553 /// true if candidate is better than the current best match
3555 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3556 MemberSpec best, AParametersCollection bparam, bool best_params)
3558 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3559 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3561 bool better_at_least_one = false;
3563 int args_count = args == null ? 0 : args.Count;
3567 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3570 // Default arguments are ignored for better decision
3571 if (a.IsDefaultArgument)
3575 // When comparing named argument the parameter type index has to be looked up
3576 // in original parameter set (override version for virtual members)
3578 NamedArgument na = a as NamedArgument;
3580 int idx = cparam.GetParameterIndexByName (na.Name);
3581 ct = candidate_pd.Types[idx];
3582 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3583 ct = TypeManager.GetElementType (ct);
3585 idx = bparam.GetParameterIndexByName (na.Name);
3586 bt = best_pd.Types[idx];
3587 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3588 bt = TypeManager.GetElementType (bt);
3590 ct = candidate_pd.Types[c_idx];
3591 bt = best_pd.Types[b_idx];
3593 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3594 ct = TypeManager.GetElementType (ct);
3598 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3599 bt = TypeManager.GetElementType (bt);
3604 if (TypeSpecComparer.IsEqual (ct, bt))
3608 int result = BetterExpressionConversion (ec, a, ct, bt);
3610 // for each argument, the conversion to 'ct' should be no worse than
3611 // the conversion to 'bt'.
3615 // for at least one argument, the conversion to 'ct' should be better than
3616 // the conversion to 'bt'.
3618 better_at_least_one = true;
3621 if (better_at_least_one)
3625 // This handles the case
3627 // Add (float f1, float f2, float f3);
3628 // Add (params decimal [] foo);
3630 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3631 // first candidate would've chosen as better.
3633 if (!same && !a.IsDefaultArgument)
3637 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3641 // This handles the following cases:
3643 // Foo (int i) is better than Foo (int i, long l = 0)
3644 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3646 // Prefer non-optional version
3648 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3650 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3651 if (candidate_pd.Count >= best_pd.Count)
3654 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3661 // One is a non-generic method and second is a generic method, then non-generic is better
3663 if (best.IsGeneric != candidate.IsGeneric)
3664 return best.IsGeneric;
3667 // This handles the following cases:
3669 // Trim () is better than Trim (params char[] chars)
3670 // Concat (string s1, string s2, string s3) is better than
3671 // Concat (string s1, params string [] srest)
3672 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3674 // Prefer non-expanded version
3676 if (candidate_params != best_params)
3679 int candidate_param_count = candidate_pd.Count;
3680 int best_param_count = best_pd.Count;
3682 if (candidate_param_count != best_param_count)
3683 // can only happen if (candidate_params && best_params)
3684 return candidate_param_count > best_param_count && best_pd.HasParams;
3687 // Both methods have the same number of parameters, and the parameters have equal types
3688 // Pick the "more specific" signature using rules over original (non-inflated) types
3690 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3691 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3693 bool specific_at_least_once = false;
3694 for (j = 0; j < args_count; ++j) {
3695 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3697 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3698 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3700 ct = candidate_def_pd.Types[j];
3701 bt = best_def_pd.Types[j];
3706 TypeSpec specific = MoreSpecific (ct, bt);
3710 specific_at_least_once = true;
3713 if (specific_at_least_once)
3719 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3721 rc.Report.Error (1729, loc,
3722 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3723 type.GetSignatureForError (), argCount.ToString ());
3727 // Determines if the candidate method is applicable to the given set of arguments
3728 // There could be two different set of parameters for same candidate where one
3729 // is the closest override for default values and named arguments checks and second
3730 // one being the virtual base for the parameter types and modifiers.
3732 // A return value rates candidate method compatibility,
3733 // 0 = the best, int.MaxValue = the worst
3735 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)
3737 // Parameters of most-derived type used mainly for named and optional parameters
3738 var pd = pm.Parameters;
3740 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3741 // params modifier instead of most-derived type
3742 var cpd = ((IParametersMember) candidate).Parameters;
3743 int param_count = pd.Count;
3744 int optional_count = 0;
3746 Arguments orig_args = arguments;
3748 if (arg_count != param_count) {
3749 for (int i = 0; i < pd.Count; ++i) {
3750 if (pd.FixedParameters[i].HasDefaultValue) {
3751 optional_count = pd.Count - i;
3756 if (optional_count != 0) {
3757 // Readjust expected number when params used
3758 if (cpd.HasParams) {
3760 if (arg_count < param_count)
3762 } else if (arg_count > param_count) {
3763 int args_gap = System.Math.Abs (arg_count - param_count);
3764 return int.MaxValue - 10000 + args_gap;
3766 } else if (arg_count != param_count) {
3767 int args_gap = System.Math.Abs (arg_count - param_count);
3769 return int.MaxValue - 10000 + args_gap;
3770 if (arg_count < param_count - 1)
3771 return int.MaxValue - 10000 + args_gap;
3774 // Resize to fit optional arguments
3775 if (optional_count != 0) {
3776 if (arguments == null) {
3777 arguments = new Arguments (optional_count);
3779 // Have to create a new container, so the next run can do same
3780 var resized = new Arguments (param_count);
3781 resized.AddRange (arguments);
3782 arguments = resized;
3785 for (int i = arg_count; i < param_count; ++i)
3786 arguments.Add (null);
3790 if (arg_count > 0) {
3792 // Shuffle named arguments to the right positions if there are any
3794 if (arguments[arg_count - 1] is NamedArgument) {
3795 arg_count = arguments.Count;
3797 for (int i = 0; i < arg_count; ++i) {
3798 bool arg_moved = false;
3800 NamedArgument na = arguments[i] as NamedArgument;
3804 int index = pd.GetParameterIndexByName (na.Name);
3806 // Named parameter not found
3810 // already reordered
3815 if (index >= param_count) {
3816 // When using parameters which should not be available to the user
3817 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3820 arguments.Add (null);
3824 temp = arguments[index];
3826 // The slot has been taken by positional argument
3827 if (temp != null && !(temp is NamedArgument))
3832 arguments = arguments.MarkOrderedArgument (na);
3836 arguments[index] = arguments[i];
3837 arguments[i] = temp;
3844 arg_count = arguments.Count;
3846 } else if (arguments != null) {
3847 arg_count = arguments.Count;
3851 // 1. Handle generic method using type arguments when specified or type inference
3854 var ms = candidate as MethodSpec;
3855 if (ms != null && ms.IsGeneric) {
3856 // Setup constraint checker for probing only
3857 ConstraintChecker cc = new ConstraintChecker (null);
3859 if (type_arguments != null) {
3860 var g_args_count = ms.Arity;
3861 if (g_args_count != type_arguments.Count)
3862 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3864 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3866 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3867 // for now it simplifies things. I should probably add a callback to ResolveContext
3868 if (lambda_conv_msgs == null) {
3869 lambda_conv_msgs = new SessionReportPrinter ();
3870 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3873 var ti = new TypeInference (arguments);
3874 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3875 lambda_conv_msgs.EndSession ();
3878 return ti.InferenceScore - 20000;
3880 if (i_args.Length != 0) {
3881 ms = ms.MakeGenericMethod (ec, i_args);
3884 cc.IgnoreInferredDynamic = true;
3888 // Type arguments constraints have to match for the method to be applicable
3890 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3892 return int.MaxValue - 25000;
3896 // We have a generic return type and at same time the method is override which
3897 // means we have to also inflate override return type in case the candidate is
3898 // best candidate and override return type is different to base return type.
3900 // virtual Foo<T, object> with override Foo<T, dynamic>
3902 if (candidate != pm) {
3903 MethodSpec override_ms = (MethodSpec) pm;
3904 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3905 returnType = inflator.Inflate (returnType);
3907 returnType = ms.ReturnType;
3911 ptypes = ms.Parameters.Types;
3913 if (type_arguments != null)
3914 return int.MaxValue - 15000;
3920 // 2. Each argument has to be implicitly convertible to method parameter
3922 Parameter.Modifier p_mod = 0;
3925 for (int i = 0; i < arg_count; i++) {
3926 Argument a = arguments[i];
3928 if (!pd.FixedParameters[i].HasDefaultValue) {
3929 arguments = orig_args;
3930 return arg_count * 2 + 2;
3934 // Get the default value expression, we can use the same expression
3935 // if the type matches
3937 Expression e = pd.FixedParameters[i].DefaultValue;
3938 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3940 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3942 if (e == EmptyExpression.MissingValue && ptypes[i].BuildinType == BuildinTypeSpec.Type.Object || ptypes[i] == InternalType.Dynamic) {
3943 e = new MemberAccess (new MemberAccess (new MemberAccess (
3944 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3946 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3952 arguments[i] = new Argument (e, Argument.AType.Default);
3956 if (p_mod != Parameter.Modifier.PARAMS) {
3957 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3959 } else if (!params_expanded_form) {
3960 params_expanded_form = true;
3961 pt = ((ElementTypeSpec) pt).Element;
3967 if (!params_expanded_form) {
3968 if (a.ArgType == Argument.AType.ExtensionType) {
3970 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3973 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3974 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3975 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3980 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3983 dynamicArgument = true;
3988 // It can be applicable in expanded form (when not doing exact match like for delegates)
3990 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3991 if (!params_expanded_form)
3992 pt = ((ElementTypeSpec) pt).Element;
3995 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
3998 params_expanded_form = true;
3999 } else if (score < 0) {
4000 params_expanded_form = true;
4001 dynamicArgument = true;
4006 if (params_expanded_form)
4008 return (arg_count - i) * 2 + score;
4013 // When params parameter has no argument it will be provided later if the method is the best candidate
4015 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4016 params_expanded_form = true;
4019 // Restore original arguments for dynamic binder to keep the intention of original source code
4021 if (dynamicArgument)
4022 arguments = orig_args;
4028 // Tests argument compatibility with the parameter
4029 // The possible return values are
4031 // 1 - modifier mismatch
4032 // 2 - type mismatch
4033 // -1 - dynamic binding required
4035 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4038 // Types have to be identical when ref or out modifer
4039 // is used and argument is not of dynamic type
4041 if ((argument.Modifier | param_mod) != 0) {
4042 if (argument.Type != parameter) {
4044 // Do full equality check after quick path
4046 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4048 // Using dynamic for ref/out parameter can still succeed at runtime
4050 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4057 if (argument.Modifier != param_mod) {
4059 // Using dynamic for ref/out parameter can still succeed at runtime
4061 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4068 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4072 // Deploy custom error reporting for lambda methods. When probing lambda methods
4073 // keep all errors reported in separate set and once we are done and no best
4074 // candidate found, this set is used to report more details about what was wrong
4077 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4078 if (lambda_conv_msgs == null) {
4079 lambda_conv_msgs = new SessionReportPrinter ();
4080 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4084 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4085 if (lambda_conv_msgs != null) {
4086 lambda_conv_msgs.EndSession ();
4096 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4098 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4100 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4103 var ac_p = p as ArrayContainer;
4105 var ac_q = ((ArrayContainer) q);
4106 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4107 if (specific == ac_p.Element)
4109 if (specific == ac_q.Element)
4111 } else if (TypeManager.IsGenericType (p)) {
4112 var pargs = TypeManager.GetTypeArguments (p);
4113 var qargs = TypeManager.GetTypeArguments (q);
4115 bool p_specific_at_least_once = false;
4116 bool q_specific_at_least_once = false;
4118 for (int i = 0; i < pargs.Length; i++) {
4119 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4120 if (specific == pargs[i])
4121 p_specific_at_least_once = true;
4122 if (specific == qargs[i])
4123 q_specific_at_least_once = true;
4126 if (p_specific_at_least_once && !q_specific_at_least_once)
4128 if (!p_specific_at_least_once && q_specific_at_least_once)
4136 // Find the best method from candidate list
4138 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4140 List<AmbiguousCandidate> ambiguous_candidates = null;
4142 MemberSpec best_candidate;
4143 Arguments best_candidate_args = null;
4144 bool best_candidate_params = false;
4145 bool best_candidate_dynamic = false;
4146 int best_candidate_rate;
4147 IParametersMember best_parameter_member = null;
4149 int args_count = args != null ? args.Count : 0;
4151 Arguments candidate_args = args;
4152 bool error_mode = false;
4153 var current_type = rc.CurrentType;
4154 MemberSpec invocable_member = null;
4156 // Be careful, cannot return until error reporter is restored
4158 best_candidate = null;
4159 best_candidate_rate = int.MaxValue;
4161 var type_members = members;
4165 for (int i = 0; i < type_members.Count; ++i) {
4166 var member = type_members[i];
4169 // Methods in a base class are not candidates if any method in a derived
4170 // class is applicable
4172 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4176 if (!member.IsAccessible (current_type))
4179 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4183 IParametersMember pm = member as IParametersMember;
4186 // Will use it later to report ambiguity between best method and invocable member
4188 if (Invocation.IsMemberInvocable (member))
4189 invocable_member = member;
4195 // Overload resolution is looking for base member but using parameter names
4196 // and default values from the closest member. That means to do expensive lookup
4197 // for the closest override for virtual or abstract members
4199 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4200 var override_params = base_provider.GetOverrideMemberParameters (member);
4201 if (override_params != null)
4202 pm = override_params;
4206 // Check if the member candidate is applicable
4208 bool params_expanded_form = false;
4209 bool dynamic_argument = false;
4210 TypeSpec rt = pm.MemberType;
4211 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4214 // How does it score compare to others
4216 if (candidate_rate < best_candidate_rate) {
4217 best_candidate_rate = candidate_rate;
4218 best_candidate = member;
4219 best_candidate_args = candidate_args;
4220 best_candidate_params = params_expanded_form;
4221 best_candidate_dynamic = dynamic_argument;
4222 best_parameter_member = pm;
4223 best_candidate_return_type = rt;
4224 } else if (candidate_rate == 0) {
4226 // The member look is done per type for most operations but sometimes
4227 // it's not possible like for binary operators overload because they
4228 // are unioned between 2 sides
4230 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4231 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4236 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4238 // We pack all interface members into top level type which makes the overload resolution
4239 // more complicated for interfaces. We compensate it by removing methods with same
4240 // signature when building the cache hence this path should not really be hit often
4243 // interface IA { void Foo (int arg); }
4244 // interface IB : IA { void Foo (params int[] args); }
4246 // IB::Foo is the best overload when calling IB.Foo (1)
4249 if (ambiguous_candidates != null) {
4250 foreach (var amb_cand in ambiguous_candidates) {
4251 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4260 ambiguous_candidates = null;
4263 // Is the new candidate better
4264 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4268 best_candidate = member;
4269 best_candidate_args = candidate_args;
4270 best_candidate_params = params_expanded_form;
4271 best_candidate_dynamic = dynamic_argument;
4272 best_parameter_member = pm;
4273 best_candidate_return_type = rt;
4275 // It's not better but any other found later could be but we are not sure yet
4276 if (ambiguous_candidates == null)
4277 ambiguous_candidates = new List<AmbiguousCandidate> ();
4279 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4283 // Restore expanded arguments
4284 if (candidate_args != args)
4285 candidate_args = args;
4287 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4289 if (prev_recorder != null)
4290 rc.Report.SetPrinter (prev_recorder);
4294 // We've found exact match
4296 if (best_candidate_rate == 0)
4300 // Try extension methods lookup when no ordinary method match was found and provider enables it
4303 var emg = base_provider.LookupExtensionMethod (rc);
4305 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4307 best_candidate_extension_group = emg;
4308 return (T) (MemberSpec) emg.BestCandidate;
4313 // Don't run expensive error reporting mode for probing
4320 lambda_conv_msgs = null;
4325 // No best member match found, report an error
4327 if (best_candidate_rate != 0 || error_mode) {
4328 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4332 if (best_candidate_dynamic) {
4333 if (args[0].ArgType == Argument.AType.ExtensionType) {
4334 rc.Report.Error (1973, loc,
4335 "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",
4336 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4339 BestCandidateIsDynamic = true;
4343 if (ambiguous_candidates != null) {
4345 // Now check that there are no ambiguities i.e the selected method
4346 // should be better than all the others
4348 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4349 var candidate = ambiguous_candidates [ix];
4351 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4352 var ambiguous = candidate.Member;
4353 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4354 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4355 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4356 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4357 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4360 return (T) best_candidate;
4365 if (invocable_member != null) {
4366 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4367 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4368 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4369 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4373 // And now check if the arguments are all
4374 // compatible, perform conversions if
4375 // necessary etc. and return if everything is
4378 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4381 if (best_candidate == null)
4385 // Check ObsoleteAttribute on the best method
4387 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4388 if (oa != null && !rc.IsObsolete)
4389 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4391 var dep = best_candidate.GetMissingDependencies ();
4393 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4396 best_candidate.MemberDefinition.SetIsUsed ();
4398 args = best_candidate_args;
4399 return (T) best_candidate;
4402 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4404 return ResolveMember<MethodSpec> (rc, ref args);
4407 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4408 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4410 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4413 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4414 ec.Report.SymbolRelatedToPreviousError (method);
4415 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4416 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4417 TypeManager.CSharpSignature (method));
4420 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4421 TypeManager.CSharpSignature (method));
4422 } else if (IsDelegateInvoke) {
4423 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4424 DelegateType.GetSignatureForError ());
4426 ec.Report.SymbolRelatedToPreviousError (method);
4427 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4428 method.GetSignatureForError ());
4431 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4433 string index = (idx + 1).ToString ();
4434 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4435 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4436 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4437 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4438 index, Parameter.GetModifierSignature (a.Modifier));
4440 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4441 index, Parameter.GetModifierSignature (mod));
4443 string p1 = a.GetSignatureForError ();
4444 string p2 = TypeManager.CSharpName (paramType);
4447 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4448 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4449 ec.Report.SymbolRelatedToPreviousError (paramType);
4452 ec.Report.Error (1503, loc,
4453 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4458 // We have failed to find exact match so we return error info about the closest match
4460 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4462 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4463 int arg_count = args == null ? 0 : args.Count;
4465 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4466 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4467 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4471 if (lambda_conv_msgs != null) {
4472 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4477 // For candidates which match on parameters count report more details about incorrect arguments
4480 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4481 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4482 // Reject any inaccessible member
4483 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4484 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4485 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4489 var ms = best_candidate as MethodSpec;
4490 if (ms != null && ms.IsGeneric) {
4491 bool constr_ok = true;
4492 if (ms.TypeArguments != null)
4493 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4495 if (ta_count == 0) {
4496 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4500 rc.Report.Error (411, loc,
4501 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4502 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4509 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4515 // We failed to find any method with correct argument count, report best candidate
4517 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4520 if (best_candidate.Kind == MemberKind.Constructor) {
4521 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4522 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4523 } else if (IsDelegateInvoke) {
4524 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4525 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4526 DelegateType.GetSignatureForError (), arg_count.ToString ());
4528 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4529 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4530 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4531 name, arg_count.ToString ());
4535 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4537 var pd = pm.Parameters;
4538 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4540 Parameter.Modifier p_mod = 0;
4542 int a_idx = 0, a_pos = 0;
4544 ArrayInitializer params_initializers = null;
4545 bool has_unsafe_arg = pm.MemberType.IsPointer;
4546 int arg_count = args == null ? 0 : args.Count;
4548 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4550 if (p_mod != Parameter.Modifier.PARAMS) {
4551 p_mod = pd.FixedParameters[a_idx].ModFlags;
4553 has_unsafe_arg |= pt.IsPointer;
4555 if (p_mod == Parameter.Modifier.PARAMS) {
4556 if (chose_params_expanded) {
4557 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4558 pt = TypeManager.GetElementType (pt);
4564 // Types have to be identical when ref or out modifer is used
4566 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4567 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4570 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4576 NamedArgument na = a as NamedArgument;
4578 int name_index = pd.GetParameterIndexByName (na.Name);
4579 if (name_index < 0 || name_index >= pd.Count) {
4580 if (IsDelegateInvoke) {
4581 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4582 ec.Report.Error (1746, na.Location,
4583 "The delegate `{0}' does not contain a parameter named `{1}'",
4584 DelegateType.GetSignatureForError (), na.Name);
4586 ec.Report.SymbolRelatedToPreviousError (member);
4587 ec.Report.Error (1739, na.Location,
4588 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4589 TypeManager.CSharpSignature (member), na.Name);
4591 } else if (args[name_index] != a) {
4592 if (IsDelegateInvoke)
4593 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4595 ec.Report.SymbolRelatedToPreviousError (member);
4597 ec.Report.Error (1744, na.Location,
4598 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4603 if (a.Expr.Type == InternalType.Dynamic)
4606 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr, pt)) {
4607 custom_errors.NoArgumentMatch (ec, member);
4611 Expression conv = null;
4612 if (a.ArgType == Argument.AType.ExtensionType) {
4613 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4616 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4618 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4621 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4628 // Convert params arguments to an array initializer
4630 if (params_initializers != null) {
4631 // we choose to use 'a.Expr' rather than 'conv' so that
4632 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4633 params_initializers.Add (a.Expr);
4634 args.RemoveAt (a_idx--);
4639 // Update the argument with the implicit conversion
4643 if (a_idx != arg_count) {
4644 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4649 // Fill not provided arguments required by params modifier
4651 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4653 args = new Arguments (1);
4655 pt = ptypes[pd.Count - 1];
4656 pt = TypeManager.GetElementType (pt);
4657 has_unsafe_arg |= pt.IsPointer;
4658 params_initializers = new ArrayInitializer (0, loc);
4662 // Append an array argument with all params arguments
4664 if (params_initializers != null) {
4665 args.Add (new Argument (
4666 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4670 if (has_unsafe_arg && !ec.IsUnsafe) {
4671 Expression.UnsafeError (ec, loc);
4675 // We could infer inaccesible type arguments
4677 if (type_arguments == null && member.IsGeneric) {
4678 var ms = (MethodSpec) member;
4679 foreach (var ta in ms.TypeArguments) {
4680 if (!ta.IsAccessible (ec.CurrentType)) {
4681 ec.Report.SymbolRelatedToPreviousError (ta);
4682 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4692 public class ConstantExpr : MemberExpr
4696 public ConstantExpr (ConstSpec constant, Location loc)
4698 this.constant = constant;
4702 public override string Name {
4703 get { throw new NotImplementedException (); }
4706 public override bool IsInstance {
4707 get { return !IsStatic; }
4710 public override bool IsStatic {
4711 get { return true; }
4714 protected override TypeSpec DeclaringType {
4715 get { return constant.DeclaringType; }
4718 public override Expression CreateExpressionTree (ResolveContext ec)
4720 throw new NotSupportedException ("ET");
4723 protected override Expression DoResolve (ResolveContext rc)
4725 ResolveInstanceExpression (rc, null);
4726 DoBestMemberChecks (rc, constant);
4728 var c = constant.GetConstant (rc);
4730 // Creates reference expression to the constant value
4731 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4734 public override void Emit (EmitContext ec)
4736 throw new NotSupportedException ();
4739 public override string GetSignatureForError ()
4741 return constant.GetSignatureForError ();
4744 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4746 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4751 /// Fully resolved expression that evaluates to a Field
4753 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4754 protected FieldSpec spec;
4755 VariableInfo variable_info;
4757 LocalTemporary temp;
4760 protected FieldExpr (Location l)
4765 public FieldExpr (FieldSpec spec, Location loc)
4770 type = spec.MemberType;
4773 public FieldExpr (FieldBase fi, Location l)
4780 public override string Name {
4786 public bool IsHoisted {
4788 IVariableReference hv = InstanceExpression as IVariableReference;
4789 return hv != null && hv.IsHoisted;
4793 public override bool IsInstance {
4795 return !spec.IsStatic;
4799 public override bool IsStatic {
4801 return spec.IsStatic;
4805 public FieldSpec Spec {
4811 protected override TypeSpec DeclaringType {
4813 return spec.DeclaringType;
4817 public VariableInfo VariableInfo {
4819 return variable_info;
4825 public override string GetSignatureForError ()
4827 return TypeManager.GetFullNameSignature (spec);
4830 public bool IsMarshalByRefAccess ()
4832 // Checks possible ldflda of field access expression
4833 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4834 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4835 !(InstanceExpression is This);
4838 public void SetHasAddressTaken ()
4840 IVariableReference vr = InstanceExpression as IVariableReference;
4842 vr.SetHasAddressTaken ();
4845 public override Expression CreateExpressionTree (ResolveContext ec)
4847 Expression instance;
4848 if (InstanceExpression == null) {
4849 instance = new NullLiteral (loc);
4851 instance = InstanceExpression.CreateExpressionTree (ec);
4854 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4856 CreateTypeOfExpression ());
4858 return CreateExpressionFactoryCall (ec, "Field", args);
4861 public Expression CreateTypeOfExpression ()
4863 return new TypeOfField (spec, loc);
4866 protected override Expression DoResolve (ResolveContext ec)
4868 return DoResolve (ec, null);
4871 Expression DoResolve (ResolveContext ec, Expression rhs)
4873 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4875 if (ResolveInstanceExpression (ec, rhs)) {
4876 // Resolve the field's instance expression while flow analysis is turned
4877 // off: when accessing a field "a.b", we must check whether the field
4878 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4880 if (lvalue_instance) {
4881 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4882 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4884 Expression right_side =
4885 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4887 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4890 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4891 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4895 if (InstanceExpression == null)
4899 DoBestMemberChecks (ec, spec);
4901 var fb = spec as FixedFieldSpec;
4902 IVariableReference var = InstanceExpression as IVariableReference;
4904 if (lvalue_instance && var != null && var.VariableInfo != null) {
4905 var.VariableInfo.SetFieldAssigned (ec, Name);
4909 IFixedExpression fe = InstanceExpression as IFixedExpression;
4910 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4911 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4914 if (InstanceExpression.eclass != ExprClass.Variable) {
4915 ec.Report.SymbolRelatedToPreviousError (spec);
4916 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4917 TypeManager.GetFullNameSignature (spec));
4918 } else if (var != null && var.IsHoisted) {
4919 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4922 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4925 eclass = ExprClass.Variable;
4927 // If the instance expression is a local variable or parameter.
4928 if (var == null || var.VariableInfo == null)
4931 VariableInfo vi = var.VariableInfo;
4932 if (!vi.IsFieldAssigned (ec, Name, loc))
4935 variable_info = vi.GetSubStruct (Name);
4939 static readonly int [] codes = {
4940 191, // instance, write access
4941 192, // instance, out access
4942 198, // static, write access
4943 199, // static, out access
4944 1648, // member of value instance, write access
4945 1649, // member of value instance, out access
4946 1650, // member of value static, write access
4947 1651 // member of value static, out access
4950 static readonly string [] msgs = {
4951 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4952 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4953 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4954 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4955 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4956 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4957 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4958 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4961 // The return value is always null. Returning a value simplifies calling code.
4962 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4965 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4969 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4971 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4976 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4978 Expression e = DoResolve (ec, right_side);
4983 spec.MemberDefinition.SetIsAssigned ();
4985 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4986 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4987 ec.Report.Warning (420, 1, loc,
4988 "`{0}': A volatile field references will not be treated as volatile",
4989 spec.GetSignatureForError ());
4992 if (spec.IsReadOnly) {
4993 // InitOnly fields can only be assigned in constructors or initializers
4994 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4995 return Report_AssignToReadonly (ec, right_side);
4997 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4999 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5000 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5001 return Report_AssignToReadonly (ec, right_side);
5002 // static InitOnly fields cannot be assigned-to in an instance constructor
5003 if (IsStatic && !ec.IsStatic)
5004 return Report_AssignToReadonly (ec, right_side);
5005 // instance constructors can't modify InitOnly fields of other instances of the same type
5006 if (!IsStatic && !(InstanceExpression is This))
5007 return Report_AssignToReadonly (ec, right_side);
5011 if (right_side == EmptyExpression.OutAccess.Instance &&
5012 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
5013 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5014 ec.Report.Warning (197, 1, loc,
5015 "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",
5016 GetSignatureForError ());
5019 eclass = ExprClass.Variable;
5023 public override int GetHashCode ()
5025 return spec.GetHashCode ();
5028 public bool IsFixed {
5031 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5033 IVariableReference variable = InstanceExpression as IVariableReference;
5034 if (variable != null)
5035 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5037 IFixedExpression fe = InstanceExpression as IFixedExpression;
5038 return fe != null && fe.IsFixed;
5042 public override bool Equals (object obj)
5044 FieldExpr fe = obj as FieldExpr;
5048 if (spec != fe.spec)
5051 if (InstanceExpression == null || fe.InstanceExpression == null)
5054 return InstanceExpression.Equals (fe.InstanceExpression);
5057 public void Emit (EmitContext ec, bool leave_copy)
5059 bool is_volatile = false;
5061 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5064 spec.MemberDefinition.SetIsUsed ();
5068 ec.Emit (OpCodes.Volatile);
5070 ec.Emit (OpCodes.Ldsfld, spec);
5073 EmitInstance (ec, false);
5075 // Optimization for build-in types
5076 if (TypeManager.IsStruct (type) && type == ec.CurrentType && InstanceExpression.Type == type) {
5077 ec.EmitLoadFromPtr (type);
5079 var ff = spec as FixedFieldSpec;
5081 ec.Emit (OpCodes.Ldflda, spec);
5082 ec.Emit (OpCodes.Ldflda, ff.Element);
5085 ec.Emit (OpCodes.Volatile);
5087 ec.Emit (OpCodes.Ldfld, spec);
5093 ec.Emit (OpCodes.Dup);
5095 temp = new LocalTemporary (this.Type);
5101 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5103 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5105 EmitInstance (ec, prepared);
5109 ec.Emit (OpCodes.Dup);
5111 temp = new LocalTemporary (this.Type);
5116 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5117 ec.Emit (OpCodes.Volatile);
5119 spec.MemberDefinition.SetIsAssigned ();
5122 ec.Emit (OpCodes.Stsfld, spec);
5124 ec.Emit (OpCodes.Stfld, spec);
5133 public override void Emit (EmitContext ec)
5138 public override void EmitSideEffect (EmitContext ec)
5140 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5142 if (is_volatile) // || is_marshal_by_ref ())
5143 base.EmitSideEffect (ec);
5146 public void AddressOf (EmitContext ec, AddressOp mode)
5148 if ((mode & AddressOp.Store) != 0)
5149 spec.MemberDefinition.SetIsAssigned ();
5150 if ((mode & AddressOp.Load) != 0)
5151 spec.MemberDefinition.SetIsUsed ();
5154 // Handle initonly fields specially: make a copy and then
5155 // get the address of the copy.
5158 if (spec.IsReadOnly){
5160 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5173 local = ec.DeclareLocal (type, false);
5174 ec.Emit (OpCodes.Stloc, local);
5175 ec.Emit (OpCodes.Ldloca, local);
5181 ec.Emit (OpCodes.Ldsflda, spec);
5184 EmitInstance (ec, false);
5185 ec.Emit (OpCodes.Ldflda, spec);
5189 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5191 return MakeExpression (ctx);
5194 public override SLE.Expression MakeExpression (BuilderContext ctx)
5197 return base.MakeExpression (ctx);
5199 return SLE.Expression.Field (
5200 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5201 spec.GetMetaInfo ());
5205 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5207 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5213 /// Expression that evaluates to a Property. The Assign class
5214 /// might set the `Value' expression if we are in an assignment.
5216 /// This is not an LValue because we need to re-write the expression, we
5217 /// can not take data from the stack and store it.
5219 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5221 public PropertyExpr (PropertySpec spec, Location l)
5224 best_candidate = spec;
5225 type = spec.MemberType;
5230 protected override TypeSpec DeclaringType {
5232 return best_candidate.DeclaringType;
5236 public override string Name {
5238 return best_candidate.Name;
5242 public override bool IsInstance {
5248 public override bool IsStatic {
5250 return best_candidate.IsStatic;
5254 public PropertySpec PropertyInfo {
5256 return best_candidate;
5262 public override Expression CreateExpressionTree (ResolveContext ec)
5265 if (IsSingleDimensionalArrayLength ()) {
5266 args = new Arguments (1);
5267 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5268 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5271 args = new Arguments (2);
5272 if (InstanceExpression == null)
5273 args.Add (new Argument (new NullLiteral (loc)));
5275 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5276 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5277 return CreateExpressionFactoryCall (ec, "Property", args);
5280 public Expression CreateSetterTypeOfExpression ()
5282 return new TypeOfMethod (Setter, loc);
5285 public override string GetSignatureForError ()
5287 return best_candidate.GetSignatureForError ();
5290 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5293 return base.MakeExpression (ctx);
5295 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5299 public override SLE.Expression MakeExpression (BuilderContext ctx)
5302 return base.MakeExpression (ctx);
5304 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5308 void Error_PropertyNotValid (ResolveContext ec)
5310 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5311 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5312 GetSignatureForError ());
5315 bool IsSingleDimensionalArrayLength ()
5317 if (best_candidate.DeclaringType.BuildinType != BuildinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5320 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5321 return ac != null && ac.Rank == 1;
5324 public override void Emit (EmitContext ec, bool leave_copy)
5327 // Special case: length of single dimension array property is turned into ldlen
5329 if (IsSingleDimensionalArrayLength ()) {
5331 EmitInstance (ec, false);
5332 ec.Emit (OpCodes.Ldlen);
5333 ec.Emit (OpCodes.Conv_I4);
5337 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5340 ec.Emit (OpCodes.Dup);
5342 temp = new LocalTemporary (this.Type);
5348 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5352 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5353 args = new Arguments (0);
5358 ec.Emit (OpCodes.Dup);
5360 temp = new LocalTemporary (this.Type);
5365 args = new Arguments (1);
5369 temp = new LocalTemporary (this.Type);
5371 args.Add (new Argument (temp));
5373 args.Add (new Argument (source));
5377 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5385 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5387 eclass = ExprClass.PropertyAccess;
5389 if (best_candidate.IsNotRealProperty) {
5390 Error_PropertyNotValid (rc);
5393 ResolveInstanceExpression (rc, right_side);
5395 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5396 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5397 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5399 type = p.MemberType;
5403 DoBestMemberChecks (rc, best_candidate);
5407 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5409 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5413 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5415 // getter and setter can be different for base calls
5416 MethodSpec getter, setter;
5417 protected T best_candidate;
5419 protected LocalTemporary temp;
5420 protected bool prepared;
5422 protected PropertyOrIndexerExpr (Location l)
5429 public MethodSpec Getter {
5438 public MethodSpec Setter {
5449 protected override Expression DoResolve (ResolveContext ec)
5451 if (eclass == ExprClass.Unresolved) {
5452 var expr = OverloadResolve (ec, null);
5457 return expr.Resolve (ec);
5460 if (!ResolveGetter (ec))
5466 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5468 if (right_side == EmptyExpression.OutAccess.Instance) {
5469 // TODO: best_candidate can be null at this point
5470 INamedBlockVariable variable = null;
5471 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5472 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5473 best_candidate.Name);
5475 right_side.DoResolveLValue (ec, this);
5480 // if the property/indexer returns a value type, and we try to set a field in it
5481 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5482 Error_CannotModifyIntermediateExpressionValue (ec);
5485 if (eclass == ExprClass.Unresolved) {
5486 var expr = OverloadResolve (ec, right_side);
5491 return expr.ResolveLValue (ec, right_side);
5494 if (!ResolveSetter (ec))
5501 // Implements the IAssignMethod interface for assignments
5503 public abstract void Emit (EmitContext ec, bool leave_copy);
5504 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5506 public override void Emit (EmitContext ec)
5511 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5513 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5515 bool ResolveGetter (ResolveContext rc)
5517 if (!best_candidate.HasGet) {
5518 if (InstanceExpression != EmptyExpression.Null) {
5519 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5520 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5521 best_candidate.GetSignatureForError ());
5524 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5525 if (best_candidate.HasDifferentAccessibility) {
5526 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5527 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5528 TypeManager.CSharpSignature (best_candidate));
5530 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5531 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5535 if (best_candidate.HasDifferentAccessibility) {
5536 CheckProtectedMemberAccess (rc, best_candidate.Get);
5539 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5543 bool ResolveSetter (ResolveContext rc)
5545 if (!best_candidate.HasSet) {
5546 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5547 GetSignatureForError ());
5551 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5552 if (best_candidate.HasDifferentAccessibility) {
5553 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5554 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5555 GetSignatureForError ());
5557 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5558 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5562 if (best_candidate.HasDifferentAccessibility)
5563 CheckProtectedMemberAccess (rc, best_candidate.Set);
5565 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5571 /// Fully resolved expression that evaluates to an Event
5573 public class EventExpr : MemberExpr, IAssignMethod
5575 readonly EventSpec spec;
5578 public EventExpr (EventSpec spec, Location loc)
5586 protected override TypeSpec DeclaringType {
5588 return spec.DeclaringType;
5592 public override string Name {
5598 public override bool IsInstance {
5600 return !spec.IsStatic;
5604 public override bool IsStatic {
5606 return spec.IsStatic;
5610 public MethodSpec Operator {
5618 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5621 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5623 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5624 if (spec.BackingField != null &&
5625 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5627 spec.MemberDefinition.SetIsUsed ();
5629 if (!ec.IsObsolete) {
5630 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5632 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5635 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5636 Error_AssignmentEventOnly (ec);
5638 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5640 InstanceExpression = null;
5642 return ml.ResolveMemberAccess (ec, left, original);
5646 return base.ResolveMemberAccess (ec, left, original);
5649 public override Expression CreateExpressionTree (ResolveContext ec)
5651 throw new NotSupportedException ("ET");
5654 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5656 if (right_side == EmptyExpression.EventAddition) {
5657 op = spec.AccessorAdd;
5658 } else if (right_side == EmptyExpression.EventSubtraction) {
5659 op = spec.AccessorRemove;
5663 Error_AssignmentEventOnly (ec);
5667 op = CandidateToBaseOverride (ec, op);
5671 protected override Expression DoResolve (ResolveContext ec)
5673 eclass = ExprClass.EventAccess;
5674 type = spec.MemberType;
5676 ResolveInstanceExpression (ec, null);
5678 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5679 Error_AssignmentEventOnly (ec);
5682 DoBestMemberChecks (ec, spec);
5686 public override void Emit (EmitContext ec)
5688 throw new NotSupportedException ();
5689 //Error_CannotAssign ();
5692 #region IAssignMethod Members
5694 public void Emit (EmitContext ec, bool leave_copy)
5696 throw new NotImplementedException ();
5699 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5701 if (leave_copy || !prepare_for_load)
5702 throw new NotImplementedException ("EventExpr::EmitAssign");
5704 Arguments args = new Arguments (1);
5705 args.Add (new Argument (source));
5706 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5711 void Error_AssignmentEventOnly (ResolveContext ec)
5713 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5714 ec.Report.Error (79, loc,
5715 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5716 GetSignatureForError ());
5718 ec.Report.Error (70, loc,
5719 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5720 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5724 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5726 name = name.Substring (0, name.LastIndexOf ('.'));
5727 base.Error_CannotCallAbstractBase (rc, name);
5730 public override string GetSignatureForError ()
5732 return TypeManager.CSharpSignature (spec);
5735 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5737 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5741 public class TemporaryVariableReference : VariableReference
5743 public class Declarator : Statement
5745 TemporaryVariableReference variable;
5747 public Declarator (TemporaryVariableReference variable)
5749 this.variable = variable;
5753 protected override void DoEmit (EmitContext ec)
5755 variable.li.CreateBuilder (ec);
5758 protected override void CloneTo (CloneContext clonectx, Statement target)
5766 public TemporaryVariableReference (LocalVariable li, Location loc)
5769 this.type = li.Type;
5773 public override bool IsLockedByStatement {
5781 public LocalVariable LocalInfo {
5787 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5789 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5790 return new TemporaryVariableReference (li, loc);
5793 public override Expression CreateExpressionTree (ResolveContext ec)
5795 throw new NotSupportedException ("ET");
5798 protected override Expression DoResolve (ResolveContext ec)
5800 eclass = ExprClass.Variable;
5803 // Don't capture temporary variables except when using
5804 // iterator redirection
5806 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5807 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5808 storey.CaptureLocalVariable (ec, li);
5814 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5816 return Resolve (ec);
5819 public override void Emit (EmitContext ec)
5821 li.CreateBuilder (ec);
5826 public void EmitAssign (EmitContext ec, Expression source)
5828 li.CreateBuilder (ec);
5830 EmitAssign (ec, source, false, false);
5833 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5835 return li.HoistedVariant;
5838 public override bool IsFixed {
5839 get { return true; }
5842 public override bool IsRef {
5843 get { return false; }
5846 public override string Name {
5847 get { throw new NotImplementedException (); }
5850 public override void SetHasAddressTaken ()
5852 throw new NotImplementedException ();
5855 protected override ILocalVariable Variable {
5859 public override VariableInfo VariableInfo {
5860 get { throw new NotImplementedException (); }
5865 /// Handles `var' contextual keyword; var becomes a keyword only
5866 /// if no type called var exists in a variable scope
5868 class VarExpr : SimpleName
5870 public VarExpr (Location loc)
5875 public bool InferType (ResolveContext ec, Expression right_side)
5878 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5880 type = right_side.Type;
5881 if (type == InternalType.Null || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5882 ec.Report.Error (815, loc,
5883 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5884 type.GetSignatureForError ());
5888 eclass = ExprClass.Variable;
5892 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5894 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5895 base.Error_TypeOrNamespaceNotFound (ec);
5897 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");