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).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 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 protected override Expression DoResolve (ResolveContext rc)
1248 public override void Emit (EmitContext ec)
1253 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1255 child.EmitBranchable (ec, label, on_true);
1257 // Only to make verifier happy
1258 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1259 ec.Emit (OpCodes.Unbox_Any, type);
1262 public override void EmitSideEffect (EmitContext ec)
1264 child.EmitSideEffect (ec);
1267 public override object GetValue ()
1269 return child.GetValue ();
1272 public override string GetValueAsLiteral ()
1274 return child.GetValueAsLiteral ();
1277 public override long GetValueAsLong ()
1279 return child.GetValueAsLong ();
1282 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1284 if (type == target_type)
1287 // FIXME: Do we need to check user conversions?
1288 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1291 return child.ConvertImplicitly (rc, target_type);
1296 /// This class is used to wrap literals which belong inside Enums
1298 public class EnumConstant : Constant
1300 public Constant Child;
1302 public EnumConstant (Constant child, TypeSpec enum_type)
1303 : base (child.Location)
1306 this.type = enum_type;
1309 protected EnumConstant (Location loc)
1314 protected override Expression DoResolve (ResolveContext rc)
1316 Child = Child.Resolve (rc);
1317 this.eclass = ExprClass.Value;
1321 public override void Emit (EmitContext ec)
1326 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1328 Child.EncodeAttributeValue (rc, enc, Child.Type);
1331 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1333 Child.EmitBranchable (ec, label, on_true);
1336 public override void EmitSideEffect (EmitContext ec)
1338 Child.EmitSideEffect (ec);
1341 public override string GetSignatureForError()
1343 return TypeManager.CSharpName (Type);
1346 public override object GetValue ()
1348 return Child.GetValue ();
1352 public override object GetTypedValue ()
1355 // The method can be used in dynamic context only (on closed types)
1357 // System.Enum.ToObject cannot be called on dynamic types
1358 // EnumBuilder has to be used, but we cannot use EnumBuilder
1359 // because it does not properly support generics
1361 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1365 public override string GetValueAsLiteral ()
1367 return Child.GetValueAsLiteral ();
1370 public override long GetValueAsLong ()
1372 return Child.GetValueAsLong ();
1375 public EnumConstant Increment()
1377 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1380 public override bool IsDefaultValue {
1382 return Child.IsDefaultValue;
1386 public override bool IsZeroInteger {
1387 get { return Child.IsZeroInteger; }
1390 public override bool IsNegative {
1392 return Child.IsNegative;
1396 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1398 if (Child.Type == target_type)
1401 return Child.ConvertExplicitly (in_checked_context, target_type);
1404 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1406 if (this.type == type) {
1410 if (!Convert.ImplicitStandardConversionExists (this, type)){
1414 return Child.ConvertImplicitly (rc, type);
1419 /// This kind of cast is used to encapsulate Value Types in objects.
1421 /// The effect of it is to box the value type emitted by the previous
1424 public class BoxedCast : TypeCast {
1426 public BoxedCast (Expression expr, TypeSpec target_type)
1427 : base (expr, target_type)
1429 eclass = ExprClass.Value;
1432 protected override Expression DoResolve (ResolveContext ec)
1434 // This should never be invoked, we are born in fully
1435 // initialized state.
1440 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1442 // Only boxing to object type is supported
1443 if (targetType.BuildinType != BuildinTypeSpec.Type.Object) {
1444 base.EncodeAttributeValue (rc, enc, targetType);
1448 enc.Encode (child.Type);
1449 child.EncodeAttributeValue (rc, enc, child.Type);
1452 public override void Emit (EmitContext ec)
1456 ec.Emit (OpCodes.Box, child.Type);
1459 public override void EmitSideEffect (EmitContext ec)
1461 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1462 // so, we need to emit the box+pop instructions in most cases
1463 if (TypeManager.IsStruct (child.Type) &&
1464 (type.BuildinType == BuildinTypeSpec.Type.Object || type.BuildinType == BuildinTypeSpec.Type.ValueType))
1465 child.EmitSideEffect (ec);
1467 base.EmitSideEffect (ec);
1471 public class UnboxCast : TypeCast {
1472 public UnboxCast (Expression expr, TypeSpec return_type)
1473 : base (expr, return_type)
1477 protected override Expression DoResolve (ResolveContext ec)
1479 // This should never be invoked, we are born in fully
1480 // initialized state.
1485 public override void Emit (EmitContext ec)
1489 ec.Emit (OpCodes.Unbox_Any, type);
1494 /// This is used to perform explicit numeric conversions.
1496 /// Explicit numeric conversions might trigger exceptions in a checked
1497 /// context, so they should generate the conv.ovf opcodes instead of
1500 public class ConvCast : TypeCast {
1501 public enum Mode : byte {
1502 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1504 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1505 U2_I1, U2_U1, U2_I2, U2_CH,
1506 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1507 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1508 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1509 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1510 CH_I1, CH_U1, CH_I2,
1511 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1512 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1518 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1519 : base (child, return_type)
1524 protected override Expression DoResolve (ResolveContext ec)
1526 // This should never be invoked, we are born in fully
1527 // initialized state.
1532 public override string ToString ()
1534 return String.Format ("ConvCast ({0}, {1})", mode, child);
1537 public override void Emit (EmitContext ec)
1541 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1543 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1544 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1545 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1546 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1547 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1549 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1550 case Mode.U1_CH: /* nothing */ break;
1552 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1553 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1554 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1555 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1556 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1557 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1560 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1561 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1562 case Mode.U2_CH: /* nothing */ break;
1564 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1565 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1566 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1567 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1568 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1570 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1572 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1573 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1574 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1575 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1576 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1577 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1579 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1580 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1581 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1582 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1584 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1585 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1586 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1587 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1589 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1590 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1591 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1592 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1593 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1594 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1595 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1596 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1597 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1599 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1600 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1601 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1603 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1604 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1605 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1606 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1607 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1608 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1609 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1610 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1611 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1613 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1614 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1615 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1616 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1617 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1618 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1619 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1620 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1621 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1622 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1624 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1628 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1629 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1630 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1631 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1632 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1634 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1635 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1637 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1638 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1639 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1640 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1641 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1642 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1645 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1646 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1647 case Mode.U2_CH: /* nothing */ break;
1649 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1650 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1651 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1652 case Mode.I4_U4: /* nothing */ break;
1653 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1655 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1657 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1659 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1660 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1661 case Mode.U4_I4: /* nothing */ break;
1662 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1665 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1666 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1667 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1669 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1670 case Mode.I8_U8: /* nothing */ break;
1671 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1672 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1674 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1675 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1676 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1677 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1679 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1680 case Mode.U8_I8: /* nothing */ break;
1681 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1684 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1685 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1686 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1688 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1689 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1690 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1691 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1693 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1694 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1695 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1696 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1698 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1705 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1706 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1707 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1709 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1715 class OpcodeCast : TypeCast
1719 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1720 : base (child, return_type)
1725 protected override Expression DoResolve (ResolveContext ec)
1727 // This should never be invoked, we are born in fully
1728 // initialized state.
1733 public override void Emit (EmitContext ec)
1739 public TypeSpec UnderlyingType {
1740 get { return child.Type; }
1745 // Opcode casts expression with 2 opcodes but only
1746 // single expression tree node
1748 class OpcodeCastDuplex : OpcodeCast
1750 readonly OpCode second;
1752 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1753 : base (child, returnType, first)
1755 this.second = second;
1758 public override void Emit (EmitContext ec)
1766 /// This kind of cast is used to encapsulate a child and cast it
1767 /// to the class requested
1769 public sealed class ClassCast : TypeCast {
1770 readonly bool forced;
1772 public ClassCast (Expression child, TypeSpec return_type)
1773 : base (child, return_type)
1777 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1778 : base (child, return_type)
1780 this.forced = forced;
1783 public override void Emit (EmitContext ec)
1787 bool gen = TypeManager.IsGenericParameter (child.Type);
1789 ec.Emit (OpCodes.Box, child.Type);
1791 if (type.IsGenericParameter) {
1792 ec.Emit (OpCodes.Unbox_Any, type);
1799 ec.Emit (OpCodes.Castclass, type);
1804 // Created during resolving pahse when an expression is wrapped or constantified
1805 // and original expression can be used later (e.g. for expression trees)
1807 public class ReducedExpression : Expression
1809 sealed class ReducedConstantExpression : EmptyConstantCast
1811 readonly Expression orig_expr;
1813 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1814 : base (expr, expr.Type)
1816 this.orig_expr = orig_expr;
1819 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1821 Constant c = base.ConvertImplicitly (rc, target_type);
1823 c = new ReducedConstantExpression (c, orig_expr);
1828 public override Expression CreateExpressionTree (ResolveContext ec)
1830 return orig_expr.CreateExpressionTree (ec);
1833 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1835 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1837 c = new ReducedConstantExpression (c, orig_expr);
1842 sealed class ReducedExpressionStatement : ExpressionStatement
1844 readonly Expression orig_expr;
1845 readonly ExpressionStatement stm;
1847 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1849 this.orig_expr = orig;
1851 this.loc = orig.Location;
1854 public override Expression CreateExpressionTree (ResolveContext ec)
1856 return orig_expr.CreateExpressionTree (ec);
1859 protected override Expression DoResolve (ResolveContext ec)
1861 eclass = stm.eclass;
1866 public override void Emit (EmitContext ec)
1871 public override void EmitStatement (EmitContext ec)
1873 stm.EmitStatement (ec);
1877 readonly Expression expr, orig_expr;
1879 private ReducedExpression (Expression expr, Expression orig_expr)
1882 this.eclass = expr.eclass;
1883 this.type = expr.Type;
1884 this.orig_expr = orig_expr;
1885 this.loc = orig_expr.Location;
1890 public Expression OriginalExpression {
1899 // Creates fully resolved expression switcher
1901 public static Constant Create (Constant expr, Expression original_expr)
1903 if (expr.eclass == ExprClass.Unresolved)
1904 throw new ArgumentException ("Unresolved expression");
1906 return new ReducedConstantExpression (expr, original_expr);
1909 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1911 return new ReducedExpressionStatement (s, orig);
1914 public static Expression Create (Expression expr, Expression original_expr)
1916 return Create (expr, original_expr, true);
1920 // Creates unresolved reduce expression. The original expression has to be
1921 // already resolved. Created expression is constant based based on `expr'
1922 // value unless canBeConstant is used
1924 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1926 if (canBeConstant) {
1927 Constant c = expr as Constant;
1929 return Create (c, original_expr);
1932 ExpressionStatement s = expr as ExpressionStatement;
1934 return Create (s, original_expr);
1936 if (expr.eclass == ExprClass.Unresolved)
1937 throw new ArgumentException ("Unresolved expression");
1939 return new ReducedExpression (expr, original_expr);
1942 public override Expression CreateExpressionTree (ResolveContext ec)
1944 return orig_expr.CreateExpressionTree (ec);
1947 protected override Expression DoResolve (ResolveContext ec)
1952 public override void Emit (EmitContext ec)
1957 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1959 expr.EmitBranchable (ec, target, on_true);
1962 public override SLE.Expression MakeExpression (BuilderContext ctx)
1964 return orig_expr.MakeExpression (ctx);
1969 // Standard composite pattern
1971 public abstract class CompositeExpression : Expression
1973 protected Expression expr;
1975 protected CompositeExpression (Expression expr)
1978 this.loc = expr.Location;
1981 public override Expression CreateExpressionTree (ResolveContext ec)
1983 return expr.CreateExpressionTree (ec);
1986 public Expression Child {
1987 get { return expr; }
1990 protected override Expression DoResolve (ResolveContext ec)
1992 expr = expr.Resolve (ec);
1995 eclass = expr.eclass;
2001 public override void Emit (EmitContext ec)
2006 public override bool IsNull {
2007 get { return expr.IsNull; }
2012 // Base of expressions used only to narrow resolve flow
2014 public abstract class ShimExpression : Expression
2016 protected Expression expr;
2018 protected ShimExpression (Expression expr)
2023 protected override void CloneTo (CloneContext clonectx, Expression t)
2028 ShimExpression target = (ShimExpression) t;
2029 target.expr = expr.Clone (clonectx);
2032 public override Expression CreateExpressionTree (ResolveContext ec)
2034 throw new NotSupportedException ("ET");
2037 public override void Emit (EmitContext ec)
2039 throw new InternalErrorException ("Missing Resolve call");
2042 public Expression Expr {
2043 get { return expr; }
2048 // Unresolved type name expressions
2050 public abstract class ATypeNameExpression : FullNamedExpression
2053 protected TypeArguments targs;
2055 protected ATypeNameExpression (string name, Location l)
2061 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2068 protected ATypeNameExpression (string name, int arity, Location l)
2069 : this (name, new UnboundTypeArguments (arity), l)
2075 protected int Arity {
2077 return targs == null ? 0 : targs.Count;
2081 public bool HasTypeArguments {
2083 return targs != null && !targs.IsEmpty;
2087 public string Name {
2096 public TypeArguments TypeArguments {
2104 public override bool Equals (object obj)
2106 ATypeNameExpression atne = obj as ATypeNameExpression;
2107 return atne != null && atne.Name == Name &&
2108 (targs == null || targs.Equals (atne.targs));
2111 public override int GetHashCode ()
2113 return Name.GetHashCode ();
2116 // TODO: Move it to MemberCore
2117 public static string GetMemberType (MemberCore mc)
2123 if (mc is FieldBase)
2125 if (mc is MethodCore)
2127 if (mc is EnumMember)
2135 public override string GetSignatureForError ()
2137 if (targs != null) {
2138 return Name + "<" + targs.GetSignatureForError () + ">";
2144 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2148 /// SimpleName expressions are formed of a single word and only happen at the beginning
2149 /// of a dotted-name.
2151 public class SimpleName : ATypeNameExpression
2153 public SimpleName (string name, Location l)
2158 public SimpleName (string name, TypeArguments args, Location l)
2159 : base (name, args, l)
2163 public SimpleName (string name, int arity, Location l)
2164 : base (name, arity, l)
2168 public SimpleName GetMethodGroup ()
2170 return new SimpleName (Name, targs, loc);
2173 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2175 if (ec.CurrentType != null) {
2176 if (ec.CurrentMemberDefinition != null) {
2177 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2179 Error_UnexpectedKind (ec.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2185 // TODO MemberCache: Implement
2187 string ns = ec.CurrentType.Namespace;
2188 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2189 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2190 var type = a.GetType (fullname);
2192 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2193 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2198 if (ec.CurrentTypeDefinition != null) {
2199 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2201 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2208 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2209 if (retval != null) {
2210 Error_TypeArgumentsCannotBeUsed (ec.Module.Compiler.Report, loc, retval.Type, Arity);
2212 var te = retval as TypeExpr;
2213 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2214 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2216 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2221 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Module.Compiler.Report);
2224 protected override Expression DoResolve (ResolveContext ec)
2226 return SimpleNameResolve (ec, null, false);
2229 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2231 return SimpleNameResolve (ec, right_side, false);
2234 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2236 int errors = ec.Module.Compiler.Report.Errors;
2237 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2240 if (fne.Type != null && Arity > 0) {
2241 if (HasTypeArguments) {
2242 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2243 return ct.ResolveAsTypeStep (ec, false);
2246 return new GenericOpenTypeExpr (fne.Type, loc);
2250 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2252 if (!(fne is Namespace))
2256 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2257 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2258 ec.Module.Compiler.Report.Error (1980, Location,
2259 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2260 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2263 return new DynamicTypeExpr (loc);
2269 if (silent || errors != ec.Module.Compiler.Report.Errors)
2272 Error_TypeOrNamespaceNotFound (ec);
2276 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2278 int lookup_arity = Arity;
2279 bool errorMode = false;
2281 Block current_block = rc.CurrentBlock;
2282 INamedBlockVariable variable = null;
2283 bool variable_found = false;
2287 // Stage 1: binding to local variables or parameters
2289 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2291 if (current_block != null && lookup_arity == 0) {
2292 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2293 if (!variable.IsDeclared) {
2294 // We found local name in accessible block but it's not
2295 // initialized yet, maybe the user wanted to bind to something else
2297 variable_found = true;
2299 e = variable.CreateReferenceExpression (rc, loc);
2302 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2311 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2313 TypeSpec member_type = rc.CurrentType;
2314 TypeSpec current_type = member_type;
2315 for (; member_type != null; member_type = member_type.DeclaringType) {
2316 e = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, restrictions, loc);
2320 var me = e as MemberExpr;
2322 // The name matches a type, defer to ResolveAsTypeStep
2330 if (variable != null) {
2331 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2332 rc.Report.Error (844, loc,
2333 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2334 Name, me.GetSignatureForError ());
2338 } else if (me is MethodGroupExpr) {
2339 // Leave it to overload resolution to report correct error
2341 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2342 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2345 // LAMESPEC: again, ignores InvocableOnly
2346 if (variable != null) {
2347 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2348 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2352 // MemberLookup does not check accessors availability, this is actually needed for properties only
2354 var pe = me as PropertyExpr;
2357 // Break as there is no other overload available anyway
2358 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2359 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2362 pe.Getter = pe.PropertyInfo.Get;
2364 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2367 pe.Setter = pe.PropertyInfo.Set;
2372 // TODO: It's used by EventExpr -> FieldExpr transformation only
2373 // TODO: Should go to MemberAccess
2374 me = me.ResolveMemberAccess (rc, null, null);
2378 me.SetTypeArguments (rc, targs);
2385 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2387 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2388 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2390 if (variable != null) {
2391 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2392 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2400 if (variable_found) {
2401 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2403 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2409 if (rc.Module.Evaluator != null) {
2410 var fi = rc.Module.Evaluator.LookupField (Name);
2412 return new FieldExpr (fi.Item1, loc);
2416 restrictions &= ~MemberLookupRestrictions.InvocableOnly;
2421 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2423 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2428 if (right_side != null) {
2429 if (e is TypeExpr) {
2430 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2434 e = e.ResolveLValue (ec, right_side);
2439 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2445 /// Represents a namespace or a type. The name of the class was inspired by
2446 /// section 10.8.1 (Fully Qualified Names).
2448 public abstract class FullNamedExpression : Expression
2450 protected override void CloneTo (CloneContext clonectx, Expression target)
2452 // Do nothing, most unresolved type expressions cannot be
2453 // resolved to different type
2456 public override Expression CreateExpressionTree (ResolveContext ec)
2458 throw new NotSupportedException ("ET");
2461 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2466 public override void Emit (EmitContext ec)
2468 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2469 GetSignatureForError ());
2474 /// Expression that evaluates to a type
2476 public abstract class TypeExpr : FullNamedExpression {
2477 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2479 TypeExpr t = DoResolveAsTypeStep (ec);
2483 eclass = ExprClass.Type;
2487 protected override Expression DoResolve (ResolveContext ec)
2489 return ResolveAsTypeTerminal (ec, false);
2492 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2494 public override bool Equals (object obj)
2496 TypeExpr tobj = obj as TypeExpr;
2500 return Type == tobj.Type;
2503 public override int GetHashCode ()
2505 return Type.GetHashCode ();
2510 /// Fully resolved Expression that already evaluated to a type
2512 public class TypeExpression : TypeExpr {
2513 public TypeExpression (TypeSpec t, Location l)
2516 eclass = ExprClass.Type;
2520 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2525 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2532 /// This class denotes an expression which evaluates to a member
2533 /// of a struct or a class.
2535 public abstract class MemberExpr : Expression
2538 // An instance expression associated with this member, if it's a
2539 // non-static member
2541 public Expression InstanceExpression;
2544 /// The name of this member.
2546 public abstract string Name {
2551 // When base.member is used
2553 public bool IsBase {
2554 get { return InstanceExpression is BaseThis; }
2558 /// Whether this is an instance member.
2560 public abstract bool IsInstance {
2565 /// Whether this is a static member.
2567 public abstract bool IsStatic {
2572 protected abstract TypeSpec DeclaringType {
2577 // Converts best base candidate for virtual method starting from QueriedBaseType
2579 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2582 // Only when base.member is used and method is virtual
2588 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2589 // means for base.member access we have to find the closest match after we found best candidate
2591 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2593 // The method could already be what we are looking for
2595 TypeSpec[] targs = null;
2596 if (method.DeclaringType != InstanceExpression.Type) {
2597 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2598 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2599 if (base_override.IsGeneric)
2600 targs = method.TypeArguments;
2602 method = base_override;
2606 // TODO: For now we do it for any hoisted call even if it's needed for
2607 // hoisted stories only but that requires a new expression wrapper
2608 if (rc.CurrentAnonymousMethod != null) {
2609 if (targs == null && method.IsGeneric) {
2610 targs = method.TypeArguments;
2611 method = method.GetGenericMethodDefinition ();
2614 if (method.Parameters.HasArglist)
2615 throw new NotImplementedException ("__arglist base call proxy");
2617 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2619 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2620 // get/set member expressions second call would fail to proxy because left expression
2621 // would be of 'this' and not 'base'
2622 if (rc.CurrentType.IsStruct)
2623 InstanceExpression = new This (loc).Resolve (rc);
2627 method = method.MakeGenericMethod (rc, targs);
2631 // Only base will allow this invocation to happen.
2633 if (method.IsAbstract) {
2634 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2640 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2642 if (InstanceExpression == null)
2645 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2646 var ct = rc.CurrentType;
2647 var expr_type = InstanceExpression.Type;
2648 if (ct != expr_type) {
2649 expr_type = expr_type.GetDefinition ();
2650 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2651 rc.Report.SymbolRelatedToPreviousError (member);
2652 rc.Report.Error (1540, loc,
2653 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2654 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2660 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2663 type = type.GetDefinition ();
2665 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2668 type = type.DeclaringType;
2669 } while (type != null);
2674 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2676 if (InstanceExpression != null) {
2677 InstanceExpression = InstanceExpression.Resolve (rc);
2678 CheckProtectedMemberAccess (rc, member);
2681 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2682 UnsafeError (rc, loc);
2685 var dep = member.GetMissingDependencies ();
2687 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2690 if (!rc.IsObsolete) {
2691 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2693 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2696 if (!(member is FieldSpec))
2697 member.MemberDefinition.SetIsUsed ();
2700 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2702 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2706 // Implements identicial simple name and type-name
2708 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2711 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2714 // 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
2715 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2717 if (left is MemberExpr || left is VariableReference) {
2718 rc.Report.DisableReporting ();
2719 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2720 rc.Report.EnableReporting ();
2721 if (identical_type != null && identical_type.Type == left.Type)
2722 return identical_type;
2728 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2731 if (InstanceExpression != null) {
2732 if (InstanceExpression is TypeExpr) {
2733 var t = InstanceExpression.Type;
2735 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2736 if (oa != null && !rc.IsObsolete) {
2737 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2740 t = t.DeclaringType;
2741 } while (t != null);
2743 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2744 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2745 rc.Report.Error (176, loc,
2746 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2747 GetSignatureForError ());
2751 InstanceExpression = null;
2757 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2758 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2759 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2760 rc.Report.Error (236, loc,
2761 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2762 GetSignatureForError ());
2764 rc.Report.Error (120, loc,
2765 "An object reference is required to access non-static member `{0}'",
2766 GetSignatureForError ());
2771 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2772 rc.Report.Error (38, loc,
2773 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2774 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2777 InstanceExpression = new This (loc);
2778 if (this is FieldExpr && rc.CurrentType.IsStruct) {
2779 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2780 InstanceExpression = InstanceExpression.Resolve (rc);
2783 InstanceExpression = InstanceExpression.Resolve (rc);
2789 var me = InstanceExpression as MemberExpr;
2791 me.ResolveInstanceExpression (rc, rhs);
2793 var fe = me as FieldExpr;
2794 if (fe != null && fe.IsMarshalByRefAccess ()) {
2795 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2796 rc.Report.Warning (1690, 1, loc,
2797 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2798 me.GetSignatureForError ());
2805 // Run member-access postponed check once we know that
2806 // the expression is not field expression which is the only
2807 // expression which can use uninitialized this
2809 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentType.IsStruct) {
2810 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2814 // Additional checks for l-value member access
2818 // TODO: It should be recursive but that would break csc compatibility
2820 if (InstanceExpression is UnboxCast) {
2821 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2828 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2830 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2831 ec.Report.Warning (1720, 1, left.Location,
2832 "Expression will always cause a `{0}'", "System.NullReferenceException");
2835 InstanceExpression = left;
2839 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2841 TypeSpec instance_type = InstanceExpression.Type;
2842 if (TypeManager.IsValueType (instance_type)) {
2843 if (InstanceExpression is IMemoryLocation) {
2844 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2846 LocalTemporary t = new LocalTemporary (instance_type);
2847 InstanceExpression.Emit (ec);
2849 t.AddressOf (ec, AddressOp.Store);
2852 InstanceExpression.Emit (ec);
2854 // Only to make verifier happy
2855 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeManager.IsReferenceType (instance_type))
2856 ec.Emit (OpCodes.Box, instance_type);
2859 if (prepare_for_load)
2860 ec.Emit (OpCodes.Dup);
2863 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2867 // Represents a group of extension method candidates for whole namespace
2869 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2871 NamespaceEntry namespace_entry;
2872 public readonly Expression ExtensionExpression;
2874 public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceEntry n, Expression extensionExpr, Location l)
2875 : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
2877 this.namespace_entry = n;
2878 this.ExtensionExpression = extensionExpr;
2881 public override bool IsStatic {
2882 get { return true; }
2885 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
2887 if (namespace_entry == null)
2891 // For extension methodgroup we are not looking for base members but parent
2892 // namespace extension methods
2894 int arity = type_arguments == null ? 0 : type_arguments.Count;
2895 var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
2899 return found.Cast<MemberSpec> ().ToList ();
2902 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
2904 // We are already here
2908 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2910 if (arguments == null)
2911 arguments = new Arguments (1);
2913 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
2914 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
2916 // Store resolved argument and restore original arguments
2918 // Clean-up modified arguments for error reporting
2919 arguments.RemoveAt (0);
2923 var me = ExtensionExpression as MemberExpr;
2925 me.ResolveInstanceExpression (ec, null);
2927 InstanceExpression = null;
2931 #region IErrorHandler Members
2933 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2938 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2940 rc.Report.SymbolRelatedToPreviousError (best);
2941 rc.Report.Error (1928, loc,
2942 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2943 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2946 rc.Report.Error (1929, loc,
2947 "Extension method instance type `{0}' cannot be converted to `{1}'",
2948 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2954 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2959 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2968 /// MethodGroupExpr represents a group of method candidates which
2969 /// can be resolved to the best method overload
2971 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2973 protected IList<MemberSpec> Methods;
2974 MethodSpec best_candidate;
2975 TypeSpec best_candidate_return;
2976 protected TypeArguments type_arguments;
2978 SimpleName simple_name;
2979 protected TypeSpec queried_type;
2981 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2985 this.type = InternalType.MethodGroup;
2987 eclass = ExprClass.MethodGroup;
2988 queried_type = type;
2991 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2992 : this (new MemberSpec[] { m }, type, loc)
2998 public MethodSpec BestCandidate {
3000 return best_candidate;
3004 public TypeSpec BestCandidateReturnType {
3006 return best_candidate_return;
3010 protected override TypeSpec DeclaringType {
3012 return queried_type;
3016 public override bool IsInstance {
3018 if (best_candidate != null)
3019 return !best_candidate.IsStatic;
3025 public override bool IsStatic {
3027 if (best_candidate != null)
3028 return best_candidate.IsStatic;
3034 public override string Name {
3036 if (best_candidate != null)
3037 return best_candidate.Name;
3040 return Methods.First ().Name;
3047 // When best candidate is already know this factory can be used
3048 // to avoid expensive overload resolution to be called
3050 // NOTE: InstanceExpression has to be set manually
3052 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3054 return new MethodGroupExpr (best, queriedType, loc) {
3055 best_candidate = best,
3056 best_candidate_return = best.ReturnType
3060 public override string GetSignatureForError ()
3062 if (best_candidate != null)
3063 return best_candidate.GetSignatureForError ();
3065 return Methods.First ().GetSignatureForError ();
3068 public override Expression CreateExpressionTree (ResolveContext ec)
3070 if (best_candidate == null) {
3071 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3075 if (best_candidate.IsConditionallyExcluded (loc))
3076 ec.Report.Error (765, loc,
3077 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3079 return new TypeOfMethod (best_candidate, loc);
3082 protected override Expression DoResolve (ResolveContext ec)
3084 this.eclass = ExprClass.MethodGroup;
3086 if (InstanceExpression != null) {
3087 InstanceExpression = InstanceExpression.Resolve (ec);
3088 if (InstanceExpression == null)
3095 public override void Emit (EmitContext ec)
3097 throw new NotSupportedException ();
3100 public void EmitCall (EmitContext ec, Arguments arguments)
3102 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3105 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3107 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3108 Name, TypeManager.CSharpName (target));
3111 public static bool IsExtensionMethodArgument (Expression expr)
3114 // LAMESPEC: No details about which expressions are not allowed
3116 return !(expr is TypeExpr) && !(expr is BaseThis);
3120 /// Find the Applicable Function Members (7.4.2.1)
3122 /// me: Method Group expression with the members to select.
3123 /// it might contain constructors or methods (or anything
3124 /// that maps to a method).
3126 /// Arguments: ArrayList containing resolved Argument objects.
3128 /// loc: The location if we want an error to be reported, or a Null
3129 /// location for "probing" purposes.
3131 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3132 /// that is the best match of me on Arguments.
3135 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3137 // TODO: causes issues with probing mode, remove explicit Kind check
3138 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3141 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3142 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3143 r.BaseMembersProvider = this;
3146 if (cerrors != null)
3147 r.CustomErrors = cerrors;
3149 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3150 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3151 if (best_candidate == null)
3152 return r.BestCandidateIsDynamic ? this : null;
3154 // Overload resolver had to create a new method group, all checks bellow have already been executed
3155 if (r.BestCandidateNewMethodGroup != null)
3156 return r.BestCandidateNewMethodGroup;
3158 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3159 if (InstanceExpression != null) {
3160 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3161 InstanceExpression = null;
3163 if (best_candidate.IsStatic && simple_name != null) {
3164 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3167 InstanceExpression.Resolve (ec);
3171 ResolveInstanceExpression (ec, null);
3172 if (InstanceExpression != null)
3173 CheckProtectedMemberAccess (ec, best_candidate);
3176 var base_override = CandidateToBaseOverride (ec, best_candidate);
3177 if (base_override == best_candidate) {
3178 best_candidate_return = r.BestCandidateReturnType;
3180 best_candidate = base_override;
3181 best_candidate_return = best_candidate.ReturnType;
3187 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3189 simple_name = original;
3190 return base.ResolveMemberAccess (ec, left, original);
3193 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3195 type_arguments = ta;
3198 #region IBaseMembersProvider Members
3200 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3202 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3205 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3207 if (queried_type == member.DeclaringType)
3210 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3211 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3215 // Extension methods lookup after ordinary methods candidates failed to apply
3217 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3219 if (InstanceExpression == null)
3222 InstanceExpression = InstanceExpression.Resolve (rc);
3223 if (!IsExtensionMethodArgument (InstanceExpression))
3226 int arity = type_arguments == null ? 0 : type_arguments.Count;
3227 NamespaceEntry methods_scope = null;
3228 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
3229 if (methods == null)
3232 var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
3233 emg.SetTypeArguments (rc, type_arguments);
3240 public struct OverloadResolver
3243 public enum Restrictions
3247 ProbingOnly = 1 << 1,
3248 CovariantDelegate = 1 << 2,
3249 NoBaseMembers = 1 << 3,
3250 BaseMembersIncluded = 1 << 4
3253 public interface IBaseMembersProvider
3255 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3256 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3257 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3260 public interface IErrorHandler
3262 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3263 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3264 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3265 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3268 sealed class NoBaseMembers : IBaseMembersProvider
3270 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3272 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3277 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3282 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3288 struct AmbiguousCandidate
3290 public readonly MemberSpec Member;
3291 public readonly bool Expanded;
3292 public readonly AParametersCollection Parameters;
3294 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3297 Parameters = parameters;
3298 Expanded = expanded;
3303 IList<MemberSpec> members;
3304 TypeArguments type_arguments;
3305 IBaseMembersProvider base_provider;
3306 IErrorHandler custom_errors;
3307 Restrictions restrictions;
3308 MethodGroupExpr best_candidate_extension_group;
3309 TypeSpec best_candidate_return_type;
3311 SessionReportPrinter lambda_conv_msgs;
3312 ReportPrinter prev_recorder;
3314 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3315 : this (members, null, restrictions, loc)
3319 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3322 if (members == null || members.Count == 0)
3323 throw new ArgumentException ("empty members set");
3325 this.members = members;
3327 type_arguments = targs;
3328 this.restrictions = restrictions;
3329 if (IsDelegateInvoke)
3330 this.restrictions |= Restrictions.NoBaseMembers;
3332 base_provider = NoBaseMembers.Instance;
3337 public IBaseMembersProvider BaseMembersProvider {
3339 return base_provider;
3342 base_provider = value;
3346 public bool BestCandidateIsDynamic { get; set; }
3349 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3351 public MethodGroupExpr BestCandidateNewMethodGroup {
3353 return best_candidate_extension_group;
3358 // Return type can be different between best candidate and closest override
3360 public TypeSpec BestCandidateReturnType {
3362 return best_candidate_return_type;
3366 public IErrorHandler CustomErrors {
3368 return custom_errors;
3371 custom_errors = value;
3375 TypeSpec DelegateType {
3377 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3378 throw new InternalErrorException ("Not running in delegate mode", loc);
3380 return members [0].DeclaringType;
3384 bool IsProbingOnly {
3386 return (restrictions & Restrictions.ProbingOnly) != 0;
3390 bool IsDelegateInvoke {
3392 return (restrictions & Restrictions.DelegateInvoke) != 0;
3399 // 7.4.3.3 Better conversion from expression
3400 // Returns : 1 if a->p is better,
3401 // 2 if a->q is better,
3402 // 0 if neither is better
3404 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3406 TypeSpec argument_type = a.Type;
3409 // If argument is an anonymous function
3411 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3413 // p and q are delegate types or expression tree types
3415 if (p.GetDefinition () == TypeManager.expression_type || q.GetDefinition () == TypeManager.expression_type) {
3416 if (q.MemberDefinition != p.MemberDefinition) {
3421 // Uwrap delegate from Expression<T>
3423 q = TypeManager.GetTypeArguments (q)[0];
3424 p = TypeManager.GetTypeArguments (p)[0];
3427 var p_m = Delegate.GetInvokeMethod (p);
3428 var q_m = Delegate.GetInvokeMethod (q);
3431 // With identical parameter lists
3433 if (!TypeSpecComparer.Equals (p_m.Parameters.Types,q_m.Parameters.Types))
3440 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3442 if (p.Kind == MemberKind.Void) {
3443 return q.Kind != MemberKind.Void ? 2 : 0;
3447 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3449 if (q.Kind == MemberKind.Void) {
3450 return p.Kind != MemberKind.Void ? 1: 0;
3453 if (argument_type == p)
3456 if (argument_type == q)
3460 return BetterTypeConversion (ec, p, q);
3464 // 7.4.3.4 Better conversion from type
3466 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3468 if (p == null || q == null)
3469 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3471 switch (p.BuildinType) {
3472 case BuildinTypeSpec.Type.Int:
3473 if (q.BuildinType == BuildinTypeSpec.Type.UInt || q.BuildinType == BuildinTypeSpec.Type.ULong)
3476 case BuildinTypeSpec.Type.Long:
3477 if (q.BuildinType == BuildinTypeSpec.Type.ULong)
3480 case BuildinTypeSpec.Type.SByte:
3481 switch (q.BuildinType) {
3482 case BuildinTypeSpec.Type.Byte:
3483 case BuildinTypeSpec.Type.UShort:
3484 case BuildinTypeSpec.Type.UInt:
3485 case BuildinTypeSpec.Type.ULong:
3489 case BuildinTypeSpec.Type.Short:
3490 switch (q.BuildinType) {
3491 case BuildinTypeSpec.Type.UShort:
3492 case BuildinTypeSpec.Type.UInt:
3493 case BuildinTypeSpec.Type.ULong:
3497 case BuildinTypeSpec.Type.Dynamic:
3498 // Dynamic is never better
3502 switch (q.BuildinType) {
3503 case BuildinTypeSpec.Type.Int:
3504 if (p.BuildinType == BuildinTypeSpec.Type.UInt || p.BuildinType == BuildinTypeSpec.Type.ULong)
3507 case BuildinTypeSpec.Type.Long:
3508 if (p.BuildinType == BuildinTypeSpec.Type.ULong)
3511 case BuildinTypeSpec.Type.SByte:
3512 switch (p.BuildinType) {
3513 case BuildinTypeSpec.Type.Byte:
3514 case BuildinTypeSpec.Type.UShort:
3515 case BuildinTypeSpec.Type.UInt:
3516 case BuildinTypeSpec.Type.ULong:
3520 case BuildinTypeSpec.Type.Short:
3521 switch (p.BuildinType) {
3522 case BuildinTypeSpec.Type.UShort:
3523 case BuildinTypeSpec.Type.UInt:
3524 case BuildinTypeSpec.Type.ULong:
3528 case BuildinTypeSpec.Type.Dynamic:
3529 // Dynamic is never better
3533 // FIXME: handle lifted operators
3535 // TODO: this is expensive
3536 Expression p_tmp = new EmptyExpression (p);
3537 Expression q_tmp = new EmptyExpression (q);
3539 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3540 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3542 if (p_to_q && !q_to_p)
3545 if (q_to_p && !p_to_q)
3552 /// Determines "Better function" between candidate
3553 /// and the current best match
3556 /// Returns a boolean indicating :
3557 /// false if candidate ain't better
3558 /// true if candidate is better than the current best match
3560 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3561 MemberSpec best, AParametersCollection bparam, bool best_params)
3563 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3564 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3566 bool better_at_least_one = false;
3568 int args_count = args == null ? 0 : args.Count;
3572 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3575 // Default arguments are ignored for better decision
3576 if (a.IsDefaultArgument)
3580 // When comparing named argument the parameter type index has to be looked up
3581 // in original parameter set (override version for virtual members)
3583 NamedArgument na = a as NamedArgument;
3585 int idx = cparam.GetParameterIndexByName (na.Name);
3586 ct = candidate_pd.Types[idx];
3587 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3588 ct = TypeManager.GetElementType (ct);
3590 idx = bparam.GetParameterIndexByName (na.Name);
3591 bt = best_pd.Types[idx];
3592 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3593 bt = TypeManager.GetElementType (bt);
3595 ct = candidate_pd.Types[c_idx];
3596 bt = best_pd.Types[b_idx];
3598 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3599 ct = TypeManager.GetElementType (ct);
3603 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3604 bt = TypeManager.GetElementType (bt);
3609 if (TypeSpecComparer.IsEqual (ct, bt))
3613 int result = BetterExpressionConversion (ec, a, ct, bt);
3615 // for each argument, the conversion to 'ct' should be no worse than
3616 // the conversion to 'bt'.
3620 // for at least one argument, the conversion to 'ct' should be better than
3621 // the conversion to 'bt'.
3623 better_at_least_one = true;
3626 if (better_at_least_one)
3630 // This handles the case
3632 // Add (float f1, float f2, float f3);
3633 // Add (params decimal [] foo);
3635 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3636 // first candidate would've chosen as better.
3638 if (!same && !a.IsDefaultArgument)
3642 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3646 // This handles the following cases:
3648 // Foo (int i) is better than Foo (int i, long l = 0)
3649 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3651 // Prefer non-optional version
3653 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3655 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3656 if (candidate_pd.Count >= best_pd.Count)
3659 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3666 // One is a non-generic method and second is a generic method, then non-generic is better
3668 if (best.IsGeneric != candidate.IsGeneric)
3669 return best.IsGeneric;
3672 // This handles the following cases:
3674 // Trim () is better than Trim (params char[] chars)
3675 // Concat (string s1, string s2, string s3) is better than
3676 // Concat (string s1, params string [] srest)
3677 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3679 // Prefer non-expanded version
3681 if (candidate_params != best_params)
3684 int candidate_param_count = candidate_pd.Count;
3685 int best_param_count = best_pd.Count;
3687 if (candidate_param_count != best_param_count)
3688 // can only happen if (candidate_params && best_params)
3689 return candidate_param_count > best_param_count && best_pd.HasParams;
3692 // Both methods have the same number of parameters, and the parameters have equal types
3693 // Pick the "more specific" signature using rules over original (non-inflated) types
3695 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3696 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3698 bool specific_at_least_once = false;
3699 for (j = 0; j < args_count; ++j) {
3700 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3702 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3703 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3705 ct = candidate_def_pd.Types[j];
3706 bt = best_def_pd.Types[j];
3711 TypeSpec specific = MoreSpecific (ct, bt);
3715 specific_at_least_once = true;
3718 if (specific_at_least_once)
3724 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3726 rc.Report.Error (1729, loc,
3727 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3728 type.GetSignatureForError (), argCount.ToString ());
3732 // Determines if the candidate method is applicable to the given set of arguments
3733 // There could be two different set of parameters for same candidate where one
3734 // is the closest override for default values and named arguments checks and second
3735 // one being the virtual base for the parameter types and modifiers.
3737 // A return value rates candidate method compatibility,
3738 // 0 = the best, int.MaxValue = the worst
3740 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)
3742 // Parameters of most-derived type used mainly for named and optional parameters
3743 var pd = pm.Parameters;
3745 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3746 // params modifier instead of most-derived type
3747 var cpd = ((IParametersMember) candidate).Parameters;
3748 int param_count = pd.Count;
3749 int optional_count = 0;
3751 Arguments orig_args = arguments;
3753 if (arg_count != param_count) {
3754 for (int i = 0; i < pd.Count; ++i) {
3755 if (pd.FixedParameters[i].HasDefaultValue) {
3756 optional_count = pd.Count - i;
3761 if (optional_count != 0) {
3762 // Readjust expected number when params used
3763 if (cpd.HasParams) {
3765 if (arg_count < param_count)
3767 } else if (arg_count > param_count) {
3768 int args_gap = System.Math.Abs (arg_count - param_count);
3769 return int.MaxValue - 10000 + args_gap;
3771 } else if (arg_count != param_count) {
3772 int args_gap = System.Math.Abs (arg_count - param_count);
3774 return int.MaxValue - 10000 + args_gap;
3775 if (arg_count < param_count - 1)
3776 return int.MaxValue - 10000 + args_gap;
3779 // Resize to fit optional arguments
3780 if (optional_count != 0) {
3781 if (arguments == null) {
3782 arguments = new Arguments (optional_count);
3784 // Have to create a new container, so the next run can do same
3785 var resized = new Arguments (param_count);
3786 resized.AddRange (arguments);
3787 arguments = resized;
3790 for (int i = arg_count; i < param_count; ++i)
3791 arguments.Add (null);
3795 if (arg_count > 0) {
3797 // Shuffle named arguments to the right positions if there are any
3799 if (arguments[arg_count - 1] is NamedArgument) {
3800 arg_count = arguments.Count;
3802 for (int i = 0; i < arg_count; ++i) {
3803 bool arg_moved = false;
3805 NamedArgument na = arguments[i] as NamedArgument;
3809 int index = pd.GetParameterIndexByName (na.Name);
3811 // Named parameter not found
3815 // already reordered
3820 if (index >= param_count) {
3821 // When using parameters which should not be available to the user
3822 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
3825 arguments.Add (null);
3829 temp = arguments[index];
3831 // The slot has been taken by positional argument
3832 if (temp != null && !(temp is NamedArgument))
3837 arguments = arguments.MarkOrderedArgument (na);
3841 arguments[index] = arguments[i];
3842 arguments[i] = temp;
3849 arg_count = arguments.Count;
3851 } else if (arguments != null) {
3852 arg_count = arguments.Count;
3856 // 1. Handle generic method using type arguments when specified or type inference
3859 var ms = candidate as MethodSpec;
3860 if (ms != null && ms.IsGeneric) {
3861 // Setup constraint checker for probing only
3862 ConstraintChecker cc = new ConstraintChecker (null);
3864 if (type_arguments != null) {
3865 var g_args_count = ms.Arity;
3866 if (g_args_count != type_arguments.Count)
3867 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3869 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
3871 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3872 // for now it simplifies things. I should probably add a callback to ResolveContext
3873 if (lambda_conv_msgs == null) {
3874 lambda_conv_msgs = new SessionReportPrinter ();
3875 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3878 var ti = new TypeInference (arguments);
3879 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
3880 lambda_conv_msgs.EndSession ();
3883 return ti.InferenceScore - 20000;
3885 if (i_args.Length != 0) {
3886 ms = ms.MakeGenericMethod (ec, i_args);
3889 cc.IgnoreInferredDynamic = true;
3893 // Type arguments constraints have to match for the method to be applicable
3895 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
3897 return int.MaxValue - 25000;
3901 // We have a generic return type and at same time the method is override which
3902 // means we have to also inflate override return type in case the candidate is
3903 // best candidate and override return type is different to base return type.
3905 // virtual Foo<T, object> with override Foo<T, dynamic>
3907 if (candidate != pm) {
3908 MethodSpec override_ms = (MethodSpec) pm;
3909 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
3910 returnType = inflator.Inflate (returnType);
3912 returnType = ms.ReturnType;
3916 ptypes = ms.Parameters.Types;
3918 if (type_arguments != null)
3919 return int.MaxValue - 15000;
3925 // 2. Each argument has to be implicitly convertible to method parameter
3927 Parameter.Modifier p_mod = 0;
3930 for (int i = 0; i < arg_count; i++) {
3931 Argument a = arguments[i];
3933 if (!pd.FixedParameters[i].HasDefaultValue) {
3934 arguments = orig_args;
3935 return arg_count * 2 + 2;
3939 // Get the default value expression, we can use the same expression
3940 // if the type matches
3942 Expression e = pd.FixedParameters[i].DefaultValue;
3943 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
3945 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
3947 if (e == EmptyExpression.MissingValue && ptypes[i].BuildinType == BuildinTypeSpec.Type.Object || ptypes[i] == InternalType.Dynamic) {
3948 e = new MemberAccess (new MemberAccess (new MemberAccess (
3949 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
3951 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
3957 arguments[i] = new Argument (e, Argument.AType.Default);
3961 if (p_mod != Parameter.Modifier.PARAMS) {
3962 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
3964 } else if (!params_expanded_form) {
3965 params_expanded_form = true;
3966 pt = ((ElementTypeSpec) pt).Element;
3972 if (!params_expanded_form) {
3973 if (a.ArgType == Argument.AType.ExtensionType) {
3975 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
3978 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
3979 Convert.ImplicitReferenceConversionExists (a.Expr, pt) ||
3980 Convert.ImplicitBoxingConversion (EmptyExpression.Null, at, pt) != null) {
3985 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3988 dynamicArgument = true;
3993 // It can be applicable in expanded form (when not doing exact match like for delegates)
3995 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
3996 if (!params_expanded_form)
3997 pt = ((ElementTypeSpec) pt).Element;
4000 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4003 params_expanded_form = true;
4004 } else if (score < 0) {
4005 params_expanded_form = true;
4006 dynamicArgument = true;
4011 if (params_expanded_form)
4013 return (arg_count - i) * 2 + score;
4018 // When params parameter has no argument it will be provided later if the method is the best candidate
4020 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4021 params_expanded_form = true;
4024 // Restore original arguments for dynamic binder to keep the intention of original source code
4026 if (dynamicArgument)
4027 arguments = orig_args;
4033 // Tests argument compatibility with the parameter
4034 // The possible return values are
4036 // 1 - modifier mismatch
4037 // 2 - type mismatch
4038 // -1 - dynamic binding required
4040 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4043 // Types have to be identical when ref or out modifer
4044 // is used and argument is not of dynamic type
4046 if ((argument.Modifier | param_mod) != 0) {
4047 if (argument.Type != parameter) {
4049 // Do full equality check after quick path
4051 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4053 // Using dynamic for ref/out parameter can still succeed at runtime
4055 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4062 if (argument.Modifier != param_mod) {
4064 // Using dynamic for ref/out parameter can still succeed at runtime
4066 if (argument.Type == InternalType.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4073 if (argument.Type == InternalType.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4077 // Deploy custom error reporting for lambda methods. When probing lambda methods
4078 // keep all errors reported in separate set and once we are done and no best
4079 // candidate found, this set is used to report more details about what was wrong
4082 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4083 if (lambda_conv_msgs == null) {
4084 lambda_conv_msgs = new SessionReportPrinter ();
4085 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4089 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4090 if (lambda_conv_msgs != null) {
4091 lambda_conv_msgs.EndSession ();
4101 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4103 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4105 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4108 var ac_p = p as ArrayContainer;
4110 var ac_q = ((ArrayContainer) q);
4111 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4112 if (specific == ac_p.Element)
4114 if (specific == ac_q.Element)
4116 } else if (TypeManager.IsGenericType (p)) {
4117 var pargs = TypeManager.GetTypeArguments (p);
4118 var qargs = TypeManager.GetTypeArguments (q);
4120 bool p_specific_at_least_once = false;
4121 bool q_specific_at_least_once = false;
4123 for (int i = 0; i < pargs.Length; i++) {
4124 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4125 if (specific == pargs[i])
4126 p_specific_at_least_once = true;
4127 if (specific == qargs[i])
4128 q_specific_at_least_once = true;
4131 if (p_specific_at_least_once && !q_specific_at_least_once)
4133 if (!p_specific_at_least_once && q_specific_at_least_once)
4141 // Find the best method from candidate list
4143 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4145 List<AmbiguousCandidate> ambiguous_candidates = null;
4147 MemberSpec best_candidate;
4148 Arguments best_candidate_args = null;
4149 bool best_candidate_params = false;
4150 bool best_candidate_dynamic = false;
4151 int best_candidate_rate;
4152 IParametersMember best_parameter_member = null;
4154 int args_count = args != null ? args.Count : 0;
4156 Arguments candidate_args = args;
4157 bool error_mode = false;
4158 var current_type = rc.CurrentType;
4159 MemberSpec invocable_member = null;
4161 // Be careful, cannot return until error reporter is restored
4163 best_candidate = null;
4164 best_candidate_rate = int.MaxValue;
4166 var type_members = members;
4170 for (int i = 0; i < type_members.Count; ++i) {
4171 var member = type_members[i];
4174 // Methods in a base class are not candidates if any method in a derived
4175 // class is applicable
4177 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4181 if (!member.IsAccessible (current_type))
4184 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (current_type))
4188 IParametersMember pm = member as IParametersMember;
4191 // Will use it later to report ambiguity between best method and invocable member
4193 if (Invocation.IsMemberInvocable (member))
4194 invocable_member = member;
4200 // Overload resolution is looking for base member but using parameter names
4201 // and default values from the closest member. That means to do expensive lookup
4202 // for the closest override for virtual or abstract members
4204 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4205 var override_params = base_provider.GetOverrideMemberParameters (member);
4206 if (override_params != null)
4207 pm = override_params;
4211 // Check if the member candidate is applicable
4213 bool params_expanded_form = false;
4214 bool dynamic_argument = false;
4215 TypeSpec rt = pm.MemberType;
4216 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4219 // How does it score compare to others
4221 if (candidate_rate < best_candidate_rate) {
4222 best_candidate_rate = candidate_rate;
4223 best_candidate = member;
4224 best_candidate_args = candidate_args;
4225 best_candidate_params = params_expanded_form;
4226 best_candidate_dynamic = dynamic_argument;
4227 best_parameter_member = pm;
4228 best_candidate_return_type = rt;
4229 } else if (candidate_rate == 0) {
4231 // The member look is done per type for most operations but sometimes
4232 // it's not possible like for binary operators overload because they
4233 // are unioned between 2 sides
4235 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4236 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4241 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4243 // We pack all interface members into top level type which makes the overload resolution
4244 // more complicated for interfaces. We compensate it by removing methods with same
4245 // signature when building the cache hence this path should not really be hit often
4248 // interface IA { void Foo (int arg); }
4249 // interface IB : IA { void Foo (params int[] args); }
4251 // IB::Foo is the best overload when calling IB.Foo (1)
4254 if (ambiguous_candidates != null) {
4255 foreach (var amb_cand in ambiguous_candidates) {
4256 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4265 ambiguous_candidates = null;
4268 // Is the new candidate better
4269 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4273 best_candidate = member;
4274 best_candidate_args = candidate_args;
4275 best_candidate_params = params_expanded_form;
4276 best_candidate_dynamic = dynamic_argument;
4277 best_parameter_member = pm;
4278 best_candidate_return_type = rt;
4280 // It's not better but any other found later could be but we are not sure yet
4281 if (ambiguous_candidates == null)
4282 ambiguous_candidates = new List<AmbiguousCandidate> ();
4284 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4288 // Restore expanded arguments
4289 if (candidate_args != args)
4290 candidate_args = args;
4292 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4294 if (prev_recorder != null)
4295 rc.Report.SetPrinter (prev_recorder);
4299 // We've found exact match
4301 if (best_candidate_rate == 0)
4305 // Try extension methods lookup when no ordinary method match was found and provider enables it
4308 var emg = base_provider.LookupExtensionMethod (rc);
4310 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4312 best_candidate_extension_group = emg;
4313 return (T) (MemberSpec) emg.BestCandidate;
4318 // Don't run expensive error reporting mode for probing
4325 lambda_conv_msgs = null;
4330 // No best member match found, report an error
4332 if (best_candidate_rate != 0 || error_mode) {
4333 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4337 if (best_candidate_dynamic) {
4338 if (args[0].ArgType == Argument.AType.ExtensionType) {
4339 rc.Report.Error (1973, loc,
4340 "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",
4341 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4344 BestCandidateIsDynamic = true;
4348 if (ambiguous_candidates != null) {
4350 // Now check that there are no ambiguities i.e the selected method
4351 // should be better than all the others
4353 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4354 var candidate = ambiguous_candidates [ix];
4356 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4357 var ambiguous = candidate.Member;
4358 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4359 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4360 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4361 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4362 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4365 return (T) best_candidate;
4370 if (invocable_member != null) {
4371 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4372 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4373 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4374 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4378 // And now check if the arguments are all
4379 // compatible, perform conversions if
4380 // necessary etc. and return if everything is
4383 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4386 if (best_candidate == null)
4390 // Check ObsoleteAttribute on the best method
4392 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4393 if (oa != null && !rc.IsObsolete)
4394 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4396 var dep = best_candidate.GetMissingDependencies ();
4398 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4401 best_candidate.MemberDefinition.SetIsUsed ();
4403 args = best_candidate_args;
4404 return (T) best_candidate;
4407 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4409 return ResolveMember<MethodSpec> (rc, ref args);
4412 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4413 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4415 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4418 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4419 ec.Report.SymbolRelatedToPreviousError (method);
4420 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4421 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4422 TypeManager.CSharpSignature (method));
4425 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4426 TypeManager.CSharpSignature (method));
4427 } else if (IsDelegateInvoke) {
4428 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4429 DelegateType.GetSignatureForError ());
4431 ec.Report.SymbolRelatedToPreviousError (method);
4432 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4433 method.GetSignatureForError ());
4436 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4438 string index = (idx + 1).ToString ();
4439 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4440 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4441 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4442 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4443 index, Parameter.GetModifierSignature (a.Modifier));
4445 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4446 index, Parameter.GetModifierSignature (mod));
4448 string p1 = a.GetSignatureForError ();
4449 string p2 = TypeManager.CSharpName (paramType);
4452 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4453 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
4454 ec.Report.SymbolRelatedToPreviousError (paramType);
4457 ec.Report.Error (1503, loc,
4458 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4463 // We have failed to find exact match so we return error info about the closest match
4465 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4467 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4468 int arg_count = args == null ? 0 : args.Count;
4470 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4471 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4472 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4476 if (lambda_conv_msgs != null) {
4477 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4482 // For candidates which match on parameters count report more details about incorrect arguments
4485 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4486 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4487 // Reject any inaccessible member
4488 if (!best_candidate.IsAccessible (rc.CurrentType) || !best_candidate.DeclaringType.IsAccessible (rc.CurrentType)) {
4489 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4490 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4494 var ms = best_candidate as MethodSpec;
4495 if (ms != null && ms.IsGeneric) {
4496 bool constr_ok = true;
4497 if (ms.TypeArguments != null)
4498 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4500 if (ta_count == 0) {
4501 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4505 rc.Report.Error (411, loc,
4506 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4507 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4514 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4520 // We failed to find any method with correct argument count, report best candidate
4522 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4525 if (best_candidate.Kind == MemberKind.Constructor) {
4526 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4527 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4528 } else if (IsDelegateInvoke) {
4529 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4530 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4531 DelegateType.GetSignatureForError (), arg_count.ToString ());
4533 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4534 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4535 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4536 name, arg_count.ToString ());
4540 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4542 var pd = pm.Parameters;
4543 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4545 Parameter.Modifier p_mod = 0;
4547 int a_idx = 0, a_pos = 0;
4549 ArrayInitializer params_initializers = null;
4550 bool has_unsafe_arg = pm.MemberType.IsPointer;
4551 int arg_count = args == null ? 0 : args.Count;
4553 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4555 if (p_mod != Parameter.Modifier.PARAMS) {
4556 p_mod = pd.FixedParameters[a_idx].ModFlags;
4558 has_unsafe_arg |= pt.IsPointer;
4560 if (p_mod == Parameter.Modifier.PARAMS) {
4561 if (chose_params_expanded) {
4562 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4563 pt = TypeManager.GetElementType (pt);
4569 // Types have to be identical when ref or out modifer is used
4571 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4572 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4575 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4581 NamedArgument na = a as NamedArgument;
4583 int name_index = pd.GetParameterIndexByName (na.Name);
4584 if (name_index < 0 || name_index >= pd.Count) {
4585 if (IsDelegateInvoke) {
4586 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4587 ec.Report.Error (1746, na.Location,
4588 "The delegate `{0}' does not contain a parameter named `{1}'",
4589 DelegateType.GetSignatureForError (), na.Name);
4591 ec.Report.SymbolRelatedToPreviousError (member);
4592 ec.Report.Error (1739, na.Location,
4593 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4594 TypeManager.CSharpSignature (member), na.Name);
4596 } else if (args[name_index] != a) {
4597 if (IsDelegateInvoke)
4598 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4600 ec.Report.SymbolRelatedToPreviousError (member);
4602 ec.Report.Error (1744, na.Location,
4603 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4608 if (a.Expr.Type == InternalType.Dynamic)
4611 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr, pt)) {
4612 custom_errors.NoArgumentMatch (ec, member);
4616 Expression conv = null;
4617 if (a.ArgType == Argument.AType.ExtensionType) {
4618 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4621 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4623 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4626 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4633 // Convert params arguments to an array initializer
4635 if (params_initializers != null) {
4636 // we choose to use 'a.Expr' rather than 'conv' so that
4637 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4638 params_initializers.Add (a.Expr);
4639 args.RemoveAt (a_idx--);
4644 // Update the argument with the implicit conversion
4648 if (a_idx != arg_count) {
4649 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4654 // Fill not provided arguments required by params modifier
4656 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4658 args = new Arguments (1);
4660 pt = ptypes[pd.Count - 1];
4661 pt = TypeManager.GetElementType (pt);
4662 has_unsafe_arg |= pt.IsPointer;
4663 params_initializers = new ArrayInitializer (0, loc);
4667 // Append an array argument with all params arguments
4669 if (params_initializers != null) {
4670 args.Add (new Argument (
4671 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4675 if (has_unsafe_arg && !ec.IsUnsafe) {
4676 Expression.UnsafeError (ec, loc);
4680 // We could infer inaccesible type arguments
4682 if (type_arguments == null && member.IsGeneric) {
4683 var ms = (MethodSpec) member;
4684 foreach (var ta in ms.TypeArguments) {
4685 if (!ta.IsAccessible (ec.CurrentType)) {
4686 ec.Report.SymbolRelatedToPreviousError (ta);
4687 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4697 public class ConstantExpr : MemberExpr
4701 public ConstantExpr (ConstSpec constant, Location loc)
4703 this.constant = constant;
4707 public override string Name {
4708 get { throw new NotImplementedException (); }
4711 public override bool IsInstance {
4712 get { return !IsStatic; }
4715 public override bool IsStatic {
4716 get { return true; }
4719 protected override TypeSpec DeclaringType {
4720 get { return constant.DeclaringType; }
4723 public override Expression CreateExpressionTree (ResolveContext ec)
4725 throw new NotSupportedException ("ET");
4728 protected override Expression DoResolve (ResolveContext rc)
4730 ResolveInstanceExpression (rc, null);
4731 DoBestMemberChecks (rc, constant);
4733 var c = constant.GetConstant (rc);
4735 // Creates reference expression to the constant value
4736 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4739 public override void Emit (EmitContext ec)
4741 throw new NotSupportedException ();
4744 public override string GetSignatureForError ()
4746 return constant.GetSignatureForError ();
4749 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4751 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4756 /// Fully resolved expression that evaluates to a Field
4758 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4759 protected FieldSpec spec;
4760 VariableInfo variable_info;
4762 LocalTemporary temp;
4765 protected FieldExpr (Location l)
4770 public FieldExpr (FieldSpec spec, Location loc)
4775 type = spec.MemberType;
4778 public FieldExpr (FieldBase fi, Location l)
4785 public override string Name {
4791 public bool IsHoisted {
4793 IVariableReference hv = InstanceExpression as IVariableReference;
4794 return hv != null && hv.IsHoisted;
4798 public override bool IsInstance {
4800 return !spec.IsStatic;
4804 public override bool IsStatic {
4806 return spec.IsStatic;
4810 public FieldSpec Spec {
4816 protected override TypeSpec DeclaringType {
4818 return spec.DeclaringType;
4822 public VariableInfo VariableInfo {
4824 return variable_info;
4830 public override string GetSignatureForError ()
4832 return TypeManager.GetFullNameSignature (spec);
4835 public bool IsMarshalByRefAccess ()
4837 // Checks possible ldflda of field access expression
4838 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4839 TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false) &&
4840 !(InstanceExpression is This);
4843 public void SetHasAddressTaken ()
4845 IVariableReference vr = InstanceExpression as IVariableReference;
4847 vr.SetHasAddressTaken ();
4850 public override Expression CreateExpressionTree (ResolveContext ec)
4852 Expression instance;
4853 if (InstanceExpression == null) {
4854 instance = new NullLiteral (loc);
4856 instance = InstanceExpression.CreateExpressionTree (ec);
4859 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4861 CreateTypeOfExpression ());
4863 return CreateExpressionFactoryCall (ec, "Field", args);
4866 public Expression CreateTypeOfExpression ()
4868 return new TypeOfField (spec, loc);
4871 protected override Expression DoResolve (ResolveContext ec)
4873 return DoResolve (ec, null);
4876 Expression DoResolve (ResolveContext ec, Expression rhs)
4878 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
4880 if (ResolveInstanceExpression (ec, rhs)) {
4881 // Resolve the field's instance expression while flow analysis is turned
4882 // off: when accessing a field "a.b", we must check whether the field
4883 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4885 if (lvalue_instance) {
4886 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4887 bool out_access = rhs == EmptyExpression.OutAccess.Instance || rhs == EmptyExpression.LValueMemberOutAccess;
4889 Expression right_side =
4890 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4892 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4895 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4896 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4900 if (InstanceExpression == null)
4904 DoBestMemberChecks (ec, spec);
4906 var fb = spec as FixedFieldSpec;
4907 IVariableReference var = InstanceExpression as IVariableReference;
4909 if (lvalue_instance && var != null && var.VariableInfo != null) {
4910 var.VariableInfo.SetFieldAssigned (ec, Name);
4914 IFixedExpression fe = InstanceExpression as IFixedExpression;
4915 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4916 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4919 if (InstanceExpression.eclass != ExprClass.Variable) {
4920 ec.Report.SymbolRelatedToPreviousError (spec);
4921 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4922 TypeManager.GetFullNameSignature (spec));
4923 } else if (var != null && var.IsHoisted) {
4924 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4927 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4930 eclass = ExprClass.Variable;
4932 // If the instance expression is a local variable or parameter.
4933 if (var == null || var.VariableInfo == null)
4936 VariableInfo vi = var.VariableInfo;
4937 if (!vi.IsFieldAssigned (ec, Name, loc))
4940 variable_info = vi.GetSubStruct (Name);
4944 static readonly int [] codes = {
4945 191, // instance, write access
4946 192, // instance, out access
4947 198, // static, write access
4948 199, // static, out access
4949 1648, // member of value instance, write access
4950 1649, // member of value instance, out access
4951 1650, // member of value static, write access
4952 1651 // member of value static, out access
4955 static readonly string [] msgs = {
4956 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4957 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4958 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4959 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4960 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4961 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4962 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4963 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4966 // The return value is always null. Returning a value simplifies calling code.
4967 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4970 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4974 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4976 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4981 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4983 Expression e = DoResolve (ec, right_side);
4988 spec.MemberDefinition.SetIsAssigned ();
4990 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4991 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4992 ec.Report.Warning (420, 1, loc,
4993 "`{0}': A volatile field references will not be treated as volatile",
4994 spec.GetSignatureForError ());
4997 if (spec.IsReadOnly) {
4998 // InitOnly fields can only be assigned in constructors or initializers
4999 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5000 return Report_AssignToReadonly (ec, right_side);
5002 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5004 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5005 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5006 return Report_AssignToReadonly (ec, right_side);
5007 // static InitOnly fields cannot be assigned-to in an instance constructor
5008 if (IsStatic && !ec.IsStatic)
5009 return Report_AssignToReadonly (ec, right_side);
5010 // instance constructors can't modify InitOnly fields of other instances of the same type
5011 if (!IsStatic && !(InstanceExpression is This))
5012 return Report_AssignToReadonly (ec, right_side);
5016 if (right_side == EmptyExpression.OutAccess.Instance &&
5017 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeSpec.IsBaseClass (spec.DeclaringType, TypeManager.mbr_type, false)) {
5018 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5019 ec.Report.Warning (197, 1, loc,
5020 "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",
5021 GetSignatureForError ());
5024 eclass = ExprClass.Variable;
5028 public override int GetHashCode ()
5030 return spec.GetHashCode ();
5033 public bool IsFixed {
5036 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5038 IVariableReference variable = InstanceExpression as IVariableReference;
5039 if (variable != null)
5040 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5042 IFixedExpression fe = InstanceExpression as IFixedExpression;
5043 return fe != null && fe.IsFixed;
5047 public override bool Equals (object obj)
5049 FieldExpr fe = obj as FieldExpr;
5053 if (spec != fe.spec)
5056 if (InstanceExpression == null || fe.InstanceExpression == null)
5059 return InstanceExpression.Equals (fe.InstanceExpression);
5062 public void Emit (EmitContext ec, bool leave_copy)
5064 bool is_volatile = false;
5066 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5069 spec.MemberDefinition.SetIsUsed ();
5073 ec.Emit (OpCodes.Volatile);
5075 ec.Emit (OpCodes.Ldsfld, spec);
5078 EmitInstance (ec, false);
5080 // Optimization for build-in types
5081 if (TypeManager.IsStruct (type) && type == ec.CurrentType && InstanceExpression.Type == type) {
5082 ec.EmitLoadFromPtr (type);
5084 var ff = spec as FixedFieldSpec;
5086 ec.Emit (OpCodes.Ldflda, spec);
5087 ec.Emit (OpCodes.Ldflda, ff.Element);
5090 ec.Emit (OpCodes.Volatile);
5092 ec.Emit (OpCodes.Ldfld, spec);
5098 ec.Emit (OpCodes.Dup);
5100 temp = new LocalTemporary (this.Type);
5106 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5108 prepared = prepare_for_load && !(source is DynamicExpressionStatement);
5110 EmitInstance (ec, prepared);
5114 ec.Emit (OpCodes.Dup);
5116 temp = new LocalTemporary (this.Type);
5121 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5122 ec.Emit (OpCodes.Volatile);
5124 spec.MemberDefinition.SetIsAssigned ();
5127 ec.Emit (OpCodes.Stsfld, spec);
5129 ec.Emit (OpCodes.Stfld, spec);
5138 public override void Emit (EmitContext ec)
5143 public override void EmitSideEffect (EmitContext ec)
5145 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5147 if (is_volatile) // || is_marshal_by_ref ())
5148 base.EmitSideEffect (ec);
5151 public void AddressOf (EmitContext ec, AddressOp mode)
5153 if ((mode & AddressOp.Store) != 0)
5154 spec.MemberDefinition.SetIsAssigned ();
5155 if ((mode & AddressOp.Load) != 0)
5156 spec.MemberDefinition.SetIsUsed ();
5159 // Handle initonly fields specially: make a copy and then
5160 // get the address of the copy.
5163 if (spec.IsReadOnly){
5165 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5178 local = ec.DeclareLocal (type, false);
5179 ec.Emit (OpCodes.Stloc, local);
5180 ec.Emit (OpCodes.Ldloca, local);
5186 ec.Emit (OpCodes.Ldsflda, spec);
5189 EmitInstance (ec, false);
5190 ec.Emit (OpCodes.Ldflda, spec);
5194 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5196 return MakeExpression (ctx);
5199 public override SLE.Expression MakeExpression (BuilderContext ctx)
5202 return base.MakeExpression (ctx);
5204 return SLE.Expression.Field (
5205 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5206 spec.GetMetaInfo ());
5210 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5212 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
5218 /// Expression that evaluates to a Property. The Assign class
5219 /// might set the `Value' expression if we are in an assignment.
5221 /// This is not an LValue because we need to re-write the expression, we
5222 /// can not take data from the stack and store it.
5224 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5226 public PropertyExpr (PropertySpec spec, Location l)
5229 best_candidate = spec;
5230 type = spec.MemberType;
5235 protected override TypeSpec DeclaringType {
5237 return best_candidate.DeclaringType;
5241 public override string Name {
5243 return best_candidate.Name;
5247 public override bool IsInstance {
5253 public override bool IsStatic {
5255 return best_candidate.IsStatic;
5259 public PropertySpec PropertyInfo {
5261 return best_candidate;
5267 public override Expression CreateExpressionTree (ResolveContext ec)
5270 if (IsSingleDimensionalArrayLength ()) {
5271 args = new Arguments (1);
5272 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5273 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5276 args = new Arguments (2);
5277 if (InstanceExpression == null)
5278 args.Add (new Argument (new NullLiteral (loc)));
5280 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5281 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5282 return CreateExpressionFactoryCall (ec, "Property", args);
5285 public Expression CreateSetterTypeOfExpression ()
5287 return new TypeOfMethod (Setter, loc);
5290 public override string GetSignatureForError ()
5292 return best_candidate.GetSignatureForError ();
5295 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5298 return base.MakeExpression (ctx);
5300 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5304 public override SLE.Expression MakeExpression (BuilderContext ctx)
5307 return base.MakeExpression (ctx);
5309 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5313 void Error_PropertyNotValid (ResolveContext ec)
5315 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5316 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5317 GetSignatureForError ());
5320 bool IsSingleDimensionalArrayLength ()
5322 if (best_candidate.DeclaringType.BuildinType != BuildinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5325 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5326 return ac != null && ac.Rank == 1;
5329 public override void Emit (EmitContext ec, bool leave_copy)
5332 // Special case: length of single dimension array property is turned into ldlen
5334 if (IsSingleDimensionalArrayLength ()) {
5336 EmitInstance (ec, false);
5337 ec.Emit (OpCodes.Ldlen);
5338 ec.Emit (OpCodes.Conv_I4);
5342 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
5345 ec.Emit (OpCodes.Dup);
5347 temp = new LocalTemporary (this.Type);
5353 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5357 if (prepare_for_load && !(source is DynamicExpressionStatement)) {
5358 args = new Arguments (0);
5363 ec.Emit (OpCodes.Dup);
5365 temp = new LocalTemporary (this.Type);
5370 args = new Arguments (1);
5374 temp = new LocalTemporary (this.Type);
5376 args.Add (new Argument (temp));
5378 args.Add (new Argument (source));
5382 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
5390 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5392 eclass = ExprClass.PropertyAccess;
5394 if (best_candidate.IsNotRealProperty) {
5395 Error_PropertyNotValid (rc);
5398 ResolveInstanceExpression (rc, right_side);
5400 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5401 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5402 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5404 type = p.MemberType;
5408 DoBestMemberChecks (rc, best_candidate);
5412 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5414 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
5418 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5420 // getter and setter can be different for base calls
5421 MethodSpec getter, setter;
5422 protected T best_candidate;
5424 protected LocalTemporary temp;
5425 protected bool prepared;
5427 protected PropertyOrIndexerExpr (Location l)
5434 public MethodSpec Getter {
5443 public MethodSpec Setter {
5454 protected override Expression DoResolve (ResolveContext ec)
5456 if (eclass == ExprClass.Unresolved) {
5457 var expr = OverloadResolve (ec, null);
5462 return expr.Resolve (ec);
5465 if (!ResolveGetter (ec))
5471 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5473 if (right_side == EmptyExpression.OutAccess.Instance) {
5474 // TODO: best_candidate can be null at this point
5475 INamedBlockVariable variable = null;
5476 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5477 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5478 best_candidate.Name);
5480 right_side.DoResolveLValue (ec, this);
5485 // if the property/indexer returns a value type, and we try to set a field in it
5486 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5487 Error_CannotModifyIntermediateExpressionValue (ec);
5490 if (eclass == ExprClass.Unresolved) {
5491 var expr = OverloadResolve (ec, right_side);
5496 return expr.ResolveLValue (ec, right_side);
5499 if (!ResolveSetter (ec))
5506 // Implements the IAssignMethod interface for assignments
5508 public abstract void Emit (EmitContext ec, bool leave_copy);
5509 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
5511 public override void Emit (EmitContext ec)
5516 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5518 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5520 bool ResolveGetter (ResolveContext rc)
5522 if (!best_candidate.HasGet) {
5523 if (InstanceExpression != EmptyExpression.Null) {
5524 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5525 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5526 best_candidate.GetSignatureForError ());
5529 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5530 if (best_candidate.HasDifferentAccessibility) {
5531 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5532 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5533 TypeManager.CSharpSignature (best_candidate));
5535 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5536 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5540 if (best_candidate.HasDifferentAccessibility) {
5541 CheckProtectedMemberAccess (rc, best_candidate.Get);
5544 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5548 bool ResolveSetter (ResolveContext rc)
5550 if (!best_candidate.HasSet) {
5551 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5552 GetSignatureForError ());
5556 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5557 if (best_candidate.HasDifferentAccessibility) {
5558 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5559 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5560 GetSignatureForError ());
5562 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5563 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5567 if (best_candidate.HasDifferentAccessibility)
5568 CheckProtectedMemberAccess (rc, best_candidate.Set);
5570 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5576 /// Fully resolved expression that evaluates to an Event
5578 public class EventExpr : MemberExpr, IAssignMethod
5580 readonly EventSpec spec;
5583 public EventExpr (EventSpec spec, Location loc)
5591 protected override TypeSpec DeclaringType {
5593 return spec.DeclaringType;
5597 public override string Name {
5603 public override bool IsInstance {
5605 return !spec.IsStatic;
5609 public override bool IsStatic {
5611 return spec.IsStatic;
5615 public MethodSpec Operator {
5623 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5626 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5628 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5629 if (spec.BackingField != null &&
5630 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5632 spec.MemberDefinition.SetIsUsed ();
5634 if (!ec.IsObsolete) {
5635 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5637 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5640 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
5641 Error_AssignmentEventOnly (ec);
5643 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5645 InstanceExpression = null;
5647 return ml.ResolveMemberAccess (ec, left, original);
5651 return base.ResolveMemberAccess (ec, left, original);
5654 public override Expression CreateExpressionTree (ResolveContext ec)
5656 throw new NotSupportedException ("ET");
5659 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5661 if (right_side == EmptyExpression.EventAddition) {
5662 op = spec.AccessorAdd;
5663 } else if (right_side == EmptyExpression.EventSubtraction) {
5664 op = spec.AccessorRemove;
5668 Error_AssignmentEventOnly (ec);
5672 op = CandidateToBaseOverride (ec, op);
5676 protected override Expression DoResolve (ResolveContext ec)
5678 eclass = ExprClass.EventAccess;
5679 type = spec.MemberType;
5681 ResolveInstanceExpression (ec, null);
5683 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5684 Error_AssignmentEventOnly (ec);
5687 DoBestMemberChecks (ec, spec);
5691 public override void Emit (EmitContext ec)
5693 throw new NotSupportedException ();
5694 //Error_CannotAssign ();
5697 #region IAssignMethod Members
5699 public void Emit (EmitContext ec, bool leave_copy)
5701 throw new NotImplementedException ();
5704 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
5706 if (leave_copy || !prepare_for_load)
5707 throw new NotImplementedException ("EventExpr::EmitAssign");
5709 Arguments args = new Arguments (1);
5710 args.Add (new Argument (source));
5711 Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
5716 void Error_AssignmentEventOnly (ResolveContext ec)
5718 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
5719 ec.Report.Error (79, loc,
5720 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5721 GetSignatureForError ());
5723 ec.Report.Error (70, loc,
5724 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5725 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
5729 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
5731 name = name.Substring (0, name.LastIndexOf ('.'));
5732 base.Error_CannotCallAbstractBase (rc, name);
5735 public override string GetSignatureForError ()
5737 return TypeManager.CSharpSignature (spec);
5740 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5742 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5746 public class TemporaryVariableReference : VariableReference
5748 public class Declarator : Statement
5750 TemporaryVariableReference variable;
5752 public Declarator (TemporaryVariableReference variable)
5754 this.variable = variable;
5758 protected override void DoEmit (EmitContext ec)
5760 variable.li.CreateBuilder (ec);
5763 protected override void CloneTo (CloneContext clonectx, Statement target)
5771 public TemporaryVariableReference (LocalVariable li, Location loc)
5774 this.type = li.Type;
5778 public override bool IsLockedByStatement {
5786 public LocalVariable LocalInfo {
5792 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
5794 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
5795 return new TemporaryVariableReference (li, loc);
5798 public override Expression CreateExpressionTree (ResolveContext ec)
5800 throw new NotSupportedException ("ET");
5803 protected override Expression DoResolve (ResolveContext ec)
5805 eclass = ExprClass.Variable;
5808 // Don't capture temporary variables except when using
5809 // iterator redirection
5811 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5812 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5813 storey.CaptureLocalVariable (ec, li);
5819 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5821 return Resolve (ec);
5824 public override void Emit (EmitContext ec)
5826 li.CreateBuilder (ec);
5831 public void EmitAssign (EmitContext ec, Expression source)
5833 li.CreateBuilder (ec);
5835 EmitAssign (ec, source, false, false);
5838 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5840 return li.HoistedVariant;
5843 public override bool IsFixed {
5844 get { return true; }
5847 public override bool IsRef {
5848 get { return false; }
5851 public override string Name {
5852 get { throw new NotImplementedException (); }
5855 public override void SetHasAddressTaken ()
5857 throw new NotImplementedException ();
5860 protected override ILocalVariable Variable {
5864 public override VariableInfo VariableInfo {
5865 get { throw new NotImplementedException (); }
5870 /// Handles `var' contextual keyword; var becomes a keyword only
5871 /// if no type called var exists in a variable scope
5873 class VarExpr : SimpleName
5875 public VarExpr (Location loc)
5880 public bool InferType (ResolveContext ec, Expression right_side)
5883 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5885 type = right_side.Type;
5886 if (type == InternalType.Null || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5887 ec.Report.Error (815, loc,
5888 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5889 type.GetSignatureForError ());
5893 eclass = ExprClass.Variable;
5897 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5899 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
5900 base.Error_TypeOrNamespaceNotFound (ec);
5902 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");