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.
10 // Copyright 2011 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
122 /// Base class for expressions
124 public abstract class Expression {
125 public ExprClass eclass;
126 protected TypeSpec type;
127 protected Location loc;
129 public TypeSpec Type {
131 set { type = value; }
134 public virtual bool IsSideEffectFree {
140 public Location Location {
144 public virtual bool IsNull {
151 // Returns true when the expression during Emit phase breaks stack
152 // by using await expression
154 public virtual bool ContainsEmitWithAwait ()
160 /// Performs semantic analysis on the Expression
164 /// The Resolve method is invoked to perform the semantic analysis
167 /// The return value is an expression (it can be the
168 /// same expression in some cases) or a new
169 /// expression that better represents this node.
171 /// For example, optimizations of Unary (LiteralInt)
172 /// would return a new LiteralInt with a negated
175 /// If there is an error during semantic analysis,
176 /// then an error should be reported (using Report)
177 /// and a null value should be returned.
179 /// There are two side effects expected from calling
180 /// Resolve(): the the field variable "eclass" should
181 /// be set to any value of the enumeration
182 /// `ExprClass' and the type variable should be set
183 /// to a valid type (this is the type of the
186 protected abstract Expression DoResolve (ResolveContext rc);
188 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
194 // This is used if the expression should be resolved as a type or namespace name.
195 // the default implementation fails.
197 public virtual TypeSpec ResolveAsType (IMemberContext mc)
199 ResolveContext ec = new ResolveContext (mc);
200 Expression e = Resolve (ec);
202 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
207 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
209 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
212 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
214 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
217 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
219 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
220 name, TypeManager.CSharpName (type));
223 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
225 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
226 "expressions can be used as a statement");
229 public void Error_InvalidExpressionStatement (BlockContext ec)
231 Error_InvalidExpressionStatement (ec.Report, loc);
234 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
236 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
239 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
241 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
244 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
246 // The error was already reported as CS1660
247 if (type == InternalType.AnonymousMethod)
250 string from_type = type.GetSignatureForError ();
251 string to_type = target.GetSignatureForError ();
252 if (from_type == to_type) {
253 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
254 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
258 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
263 ec.Report.DisableReporting ();
264 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
265 ec.Report.EnableReporting ();
268 ec.Report.Error (266, loc,
269 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
272 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
277 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
279 // Better message for possible generic expressions
280 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
281 var report = context.Module.Compiler.Report;
282 report.SymbolRelatedToPreviousError (member);
283 if (member is TypeSpec)
284 member = ((TypeSpec) member).GetDefinition ();
286 member = ((MethodSpec) member).GetGenericMethodDefinition ();
288 string name = member.Kind == MemberKind.Method ? "method" : "type";
289 if (member.IsGeneric) {
290 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
291 name, member.GetSignatureForError (), member.Arity.ToString ());
293 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
294 name, member.GetSignatureForError ());
297 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
301 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
303 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
307 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
309 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
312 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
314 ec.Report.SymbolRelatedToPreviousError (type);
315 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
316 TypeManager.CSharpName (type), name);
319 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
321 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
324 protected void Error_VoidPointerOperation (ResolveContext rc)
326 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
329 public ResolveFlags ExprClassToResolveFlags {
333 case ExprClass.Namespace:
334 return ResolveFlags.Type;
336 case ExprClass.MethodGroup:
337 return ResolveFlags.MethodGroup;
339 case ExprClass.TypeParameter:
340 return ResolveFlags.TypeParameter;
342 case ExprClass.Value:
343 case ExprClass.Variable:
344 case ExprClass.PropertyAccess:
345 case ExprClass.EventAccess:
346 case ExprClass.IndexerAccess:
347 return ResolveFlags.VariableOrValue;
350 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
355 public virtual string GetSignatureForError ()
357 return type.GetDefinition ().GetSignatureForError ();
361 /// Resolves an expression and performs semantic analysis on it.
365 /// Currently Resolve wraps DoResolve to perform sanity
366 /// checking and assertion checking on what we expect from Resolve.
368 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
370 if (eclass != ExprClass.Unresolved)
380 if ((flags & e.ExprClassToResolveFlags) == 0) {
381 e.Error_UnexpectedKind (ec, flags, loc);
386 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
389 } catch (Exception ex) {
390 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
393 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
394 return EmptyExpression.Null; // TODO: Add location
399 /// Resolves an expression and performs semantic analysis on it.
401 public Expression Resolve (ResolveContext rc)
403 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
407 /// Resolves an expression for LValue assignment
411 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
412 /// checking and assertion checking on what we expect from Resolve
414 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
416 int errors = ec.Report.Errors;
417 bool out_access = right_side == EmptyExpression.OutAccess;
419 Expression e = DoResolveLValue (ec, right_side);
421 if (e != null && out_access && !(e is IMemoryLocation)) {
422 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
423 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
425 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
426 // e.GetType () + " " + e.GetSignatureForError ());
431 if (errors == ec.Report.Errors) {
433 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
435 Error_ValueAssignment (ec, loc);
440 if (e.eclass == ExprClass.Unresolved)
441 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
443 if ((e.type == null) && !(e is GenericTypeExpr))
444 throw new Exception ("Expression " + e + " did not set its type after Resolve");
449 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
451 rc.Module.Compiler.Report.Error (182, loc,
452 "An attribute argument must be a constant expression, typeof expression or array creation expression");
456 /// Emits the code for the expression
460 /// The Emit method is invoked to generate the code
461 /// for the expression.
463 public abstract void Emit (EmitContext ec);
466 // Emit code to branch to @target if this expression is equivalent to @on_true.
467 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
468 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
469 // including the use of conditional branches. Note also that a branch MUST be emitted
470 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
473 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
476 // Emit this expression for its side effects, not for its value.
477 // The default implementation is to emit the value, and then throw it away.
478 // Subclasses can provide more efficient implementations, but those MUST be equivalent
479 public virtual void EmitSideEffect (EmitContext ec)
482 ec.Emit (OpCodes.Pop);
486 // Emits the expression into temporary field variable. The method
487 // should be used for await expressions only
489 public virtual Expression EmitToField (EmitContext ec)
492 // This is the await prepare Emit method. When emitting code like
493 // a + b we emit code like
499 // For await a + await b we have to interfere the flow to keep the
500 // stack clean because await yields from the expression. The emit
503 // a = a.EmitToField () // a is changed to temporary field access
504 // b = b.EmitToField ()
510 // The idea is to emit expression and leave the stack empty with
511 // result value still available.
513 // Expressions should override this default implementation when
514 // optimized version can be provided (e.g. FieldExpr)
517 // We can optimize for side-effect free expressions, they can be
518 // emitted out of order
520 if (IsSideEffectFree)
523 bool needs_temporary = ContainsEmitWithAwait ();
524 if (!needs_temporary)
527 // Emit original code
528 EmitToFieldSource (ec);
531 // Store the result to temporary field when we
532 // cannot load this directly
534 var field = ec.GetTemporaryField (type);
535 if (needs_temporary) {
537 // Create temporary local (we cannot load this before Emit)
539 var temp = ec.GetTemporaryLocal (type);
540 ec.Emit (OpCodes.Stloc, temp);
543 ec.Emit (OpCodes.Ldloc, temp);
544 field.EmitAssignFromStack (ec);
546 ec.FreeTemporaryLocal (temp, type);
548 field.EmitAssignFromStack (ec);
554 protected virtual void EmitToFieldSource (EmitContext ec)
557 // Default implementation calls Emit method
562 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
564 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
565 bool contains_await = false;
567 for (int i = 1; i < expressions.Count; ++i) {
568 if (expressions[i].ContainsEmitWithAwait ()) {
569 contains_await = true;
574 if (contains_await) {
575 for (int i = 0; i < expressions.Count; ++i) {
576 expressions[i] = expressions[i].EmitToField (ec);
581 for (int i = 0; i < expressions.Count; ++i) {
582 expressions[i].Emit (ec);
587 /// Protected constructor. Only derivate types should
588 /// be able to be created
591 protected Expression ()
596 /// Returns a fully formed expression after a MemberLookup
599 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
601 if (spec is EventSpec)
602 return new EventExpr ((EventSpec) spec, loc);
603 if (spec is ConstSpec)
604 return new ConstantExpr ((ConstSpec) spec, loc);
605 if (spec is FieldSpec)
606 return new FieldExpr ((FieldSpec) spec, loc);
607 if (spec is PropertySpec)
608 return new PropertyExpr ((PropertySpec) spec, loc);
609 if (spec is TypeSpec)
610 return new TypeExpression (((TypeSpec) spec), loc);
615 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
617 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
619 rc.Report.SymbolRelatedToPreviousError (type);
621 // Report meaningful error for struct as they always have default ctor in C# context
622 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
624 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
625 type.GetSignatureForError ());
631 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
632 var ctor = r.ResolveMember<MethodSpec> (rc, ref args);
636 if ((ctor.Modifiers & Modifiers.PROTECTED) != 0 && !rc.HasSet (ResolveContext.Options.BaseInitializer)) {
637 MemberExpr.CheckProtectedMemberAccess (rc, ctor, ctor.DeclaringType, loc);
644 public enum MemberLookupRestrictions
653 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
654 // `qualifier_type' or null to lookup members in the current class.
656 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
658 var members = MemberCache.FindMembers (queried_type, name, false);
662 MemberSpec non_method = null;
663 MemberSpec ambig_non_method = null;
665 for (int i = 0; i < members.Count; ++i) {
666 var member = members[i];
668 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
669 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
672 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
675 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
679 if (!member.IsAccessible (rc))
683 // With runtime binder we can have a situation where queried type is inaccessible
684 // because it came via dynamic object, the check about inconsisted accessibility
685 // had no effect as the type was unknown during compilation
688 // private class N { }
690 // public dynamic Foo ()
696 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
700 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
701 if (member is MethodSpec)
702 return new MethodGroupExpr (members, queried_type, loc);
704 if (!Invocation.IsMemberInvocable (member))
708 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
710 } else if (!errorMode && !member.IsNotCSharpCompatible) {
711 ambig_non_method = member;
715 if (non_method != null) {
716 if (ambig_non_method != null && rc != null) {
717 var report = rc.Module.Compiler.Report;
718 report.SymbolRelatedToPreviousError (non_method);
719 report.SymbolRelatedToPreviousError (ambig_non_method);
720 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
721 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
724 if (non_method is MethodSpec)
725 return new MethodGroupExpr (members, queried_type, loc);
727 return ExprClassFromMemberInfo (non_method, loc);
730 if (members[0].DeclaringType.BaseType == null)
733 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
735 } while (members != null);
740 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
742 throw new NotImplementedException ();
745 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
747 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
751 /// Returns an expression that can be used to invoke operator true
752 /// on the expression if it exists.
754 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
756 return GetOperatorTrueOrFalse (ec, e, true, loc);
760 /// Returns an expression that can be used to invoke operator false
761 /// on the expression if it exists.
763 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
765 return GetOperatorTrueOrFalse (ec, e, false, loc);
768 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
770 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
771 var methods = MemberCache.GetUserOperator (e.type, op, false);
775 Arguments arguments = new Arguments (1);
776 arguments.Add (new Argument (e));
778 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
779 var oper = res.ResolveOperator (ec, ref arguments);
784 return new UserOperatorCall (oper, arguments, null, loc);
787 public virtual string ExprClassName
791 case ExprClass.Unresolved:
793 case ExprClass.Value:
795 case ExprClass.Variable:
797 case ExprClass.Namespace:
801 case ExprClass.MethodGroup:
802 return "method group";
803 case ExprClass.PropertyAccess:
804 return "property access";
805 case ExprClass.EventAccess:
806 return "event access";
807 case ExprClass.IndexerAccess:
808 return "indexer access";
809 case ExprClass.Nothing:
811 case ExprClass.TypeParameter:
812 return "type parameter";
814 throw new Exception ("Should not happen");
819 /// Reports that we were expecting `expr' to be of class `expected'
821 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
823 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
826 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
830 name = mc.GetSignatureForError ();
832 name = GetSignatureForError ();
834 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
835 name, was, expected);
838 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
840 string [] valid = new string [4];
843 if ((flags & ResolveFlags.VariableOrValue) != 0) {
844 valid [count++] = "variable";
845 valid [count++] = "value";
848 if ((flags & ResolveFlags.Type) != 0)
849 valid [count++] = "type";
851 if ((flags & ResolveFlags.MethodGroup) != 0)
852 valid [count++] = "method group";
855 valid [count++] = "unknown";
857 StringBuilder sb = new StringBuilder (valid [0]);
858 for (int i = 1; i < count - 1; i++) {
860 sb.Append (valid [i]);
863 sb.Append ("' or `");
864 sb.Append (valid [count - 1]);
867 ec.Report.Error (119, loc,
868 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
871 public static void UnsafeError (ResolveContext ec, Location loc)
873 UnsafeError (ec.Report, loc);
876 public static void UnsafeError (Report Report, Location loc)
878 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
881 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
883 ec.Report.SymbolRelatedToPreviousError (type);
884 if (ec.CurrentInitializerVariable != null) {
885 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
886 TypeManager.CSharpName (type), GetSignatureForError ());
888 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
889 GetSignatureForError ());
894 // Converts `source' to an int, uint, long or ulong.
896 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
898 var btypes = ec.BuiltinTypes;
900 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
901 Arguments args = new Arguments (1);
902 args.Add (new Argument (source));
903 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
906 Expression converted;
908 using (ec.Set (ResolveContext.Options.CheckedScope)) {
909 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
910 if (converted == null)
911 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
912 if (converted == null)
913 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
914 if (converted == null)
915 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
917 if (converted == null) {
918 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
924 // Only positive constants are allowed at compile time
926 Constant c = converted as Constant;
927 if (c != null && c.IsNegative)
928 Error_NegativeArrayIndex (ec, source.loc);
930 // No conversion needed to array index
931 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
934 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
938 // Derived classes implement this method by cloning the fields that
939 // could become altered during the Resolve stage
941 // Only expressions that are created for the parser need to implement
944 protected virtual void CloneTo (CloneContext clonectx, Expression target)
946 throw new NotImplementedException (
948 "CloneTo not implemented for expression {0}", this.GetType ()));
952 // Clones an expression created by the parser.
954 // We only support expressions created by the parser so far, not
955 // expressions that have been resolved (many more classes would need
956 // to implement CloneTo).
958 // This infrastructure is here merely for Lambda expressions which
959 // compile the same code using different type values for the same
960 // arguments to find the correct overload
962 public virtual Expression Clone (CloneContext clonectx)
964 Expression cloned = (Expression) MemberwiseClone ();
965 CloneTo (clonectx, cloned);
971 // Implementation of expression to expression tree conversion
973 public abstract Expression CreateExpressionTree (ResolveContext ec);
975 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
977 return CreateExpressionFactoryCall (ec, name, null, args, loc);
980 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
982 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
985 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
987 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
990 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
992 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
996 return new TypeExpression (t, loc);
1000 // Implemented by all expressions which support conversion from
1001 // compiler expression to invokable runtime expression. Used by
1002 // dynamic C# binder.
1004 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1006 throw new NotImplementedException ("MakeExpression for " + GetType ());
1011 /// This is just a base class for expressions that can
1012 /// appear on statements (invocations, object creation,
1013 /// assignments, post/pre increment and decrement). The idea
1014 /// being that they would support an extra Emition interface that
1015 /// does not leave a result on the stack.
1017 public abstract class ExpressionStatement : Expression {
1019 public ExpressionStatement ResolveStatement (BlockContext ec)
1021 Expression e = Resolve (ec);
1025 ExpressionStatement es = e as ExpressionStatement;
1027 Error_InvalidExpressionStatement (ec);
1033 /// Requests the expression to be emitted in a `statement'
1034 /// context. This means that no new value is left on the
1035 /// stack after invoking this method (constrasted with
1036 /// Emit that will always leave a value on the stack).
1038 public abstract void EmitStatement (EmitContext ec);
1040 public override void EmitSideEffect (EmitContext ec)
1047 /// This kind of cast is used to encapsulate the child
1048 /// whose type is child.Type into an expression that is
1049 /// reported to return "return_type". This is used to encapsulate
1050 /// expressions which have compatible types, but need to be dealt
1051 /// at higher levels with.
1053 /// For example, a "byte" expression could be encapsulated in one
1054 /// of these as an "unsigned int". The type for the expression
1055 /// would be "unsigned int".
1058 public abstract class TypeCast : Expression
1060 protected readonly Expression child;
1062 protected TypeCast (Expression child, TypeSpec return_type)
1064 eclass = child.eclass;
1065 loc = child.Location;
1070 public Expression Child {
1076 public override bool ContainsEmitWithAwait ()
1078 return child.ContainsEmitWithAwait ();
1081 public override Expression CreateExpressionTree (ResolveContext ec)
1083 Arguments args = new Arguments (2);
1084 args.Add (new Argument (child.CreateExpressionTree (ec)));
1085 args.Add (new Argument (new TypeOf (type, loc)));
1087 if (type.IsPointer || child.Type.IsPointer)
1088 Error_PointerInsideExpressionTree (ec);
1090 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1093 protected override Expression DoResolve (ResolveContext ec)
1095 // This should never be invoked, we are born in fully
1096 // initialized state.
1101 public override void Emit (EmitContext ec)
1106 public override SLE.Expression MakeExpression (BuilderContext ctx)
1109 return base.MakeExpression (ctx);
1111 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1112 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1113 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1117 protected override void CloneTo (CloneContext clonectx, Expression t)
1122 public override bool IsNull {
1123 get { return child.IsNull; }
1127 public class EmptyCast : TypeCast {
1128 EmptyCast (Expression child, TypeSpec target_type)
1129 : base (child, target_type)
1133 public static Expression Create (Expression child, TypeSpec type)
1135 Constant c = child as Constant;
1137 return new EmptyConstantCast (c, type);
1139 EmptyCast e = child as EmptyCast;
1141 return new EmptyCast (e.child, type);
1143 return new EmptyCast (child, type);
1146 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1148 child.EmitBranchable (ec, label, on_true);
1151 public override void EmitSideEffect (EmitContext ec)
1153 child.EmitSideEffect (ec);
1158 // Used for predefined type user operator (no obsolete check, etc.)
1160 public class OperatorCast : TypeCast
1162 readonly MethodSpec conversion_operator;
1164 public OperatorCast (Expression expr, TypeSpec target_type)
1165 : this (expr, target_type, target_type, false)
1169 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1170 : this (expr, target_type, target_type, find_explicit)
1174 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1175 : base (expr, returnType)
1177 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1178 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1181 foreach (MethodSpec oper in mi) {
1182 if (oper.ReturnType != returnType)
1185 if (oper.Parameters.Types[0] == expr.Type) {
1186 conversion_operator = oper;
1192 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1193 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1196 public override void Emit (EmitContext ec)
1199 ec.Emit (OpCodes.Call, conversion_operator);
1204 // Constant specialization of EmptyCast.
1205 // We need to special case this since an empty cast of
1206 // a constant is still a constant.
1208 public class EmptyConstantCast : Constant
1210 public readonly Constant child;
1212 public EmptyConstantCast (Constant child, TypeSpec type)
1213 : base (child.Location)
1216 throw new ArgumentNullException ("child");
1219 this.eclass = child.eclass;
1223 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1225 if (child.Type == target_type)
1228 // FIXME: check that 'type' can be converted to 'target_type' first
1229 return child.ConvertExplicitly (in_checked_context, target_type);
1232 public override Expression CreateExpressionTree (ResolveContext ec)
1234 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1235 child.CreateExpressionTree (ec),
1236 new TypeOf (type, loc));
1239 Error_PointerInsideExpressionTree (ec);
1241 return CreateExpressionFactoryCall (ec, "Convert", args);
1244 public override bool IsDefaultValue {
1245 get { return child.IsDefaultValue; }
1248 public override bool IsNegative {
1249 get { return child.IsNegative; }
1252 public override bool IsNull {
1253 get { return child.IsNull; }
1256 public override bool IsOneInteger {
1257 get { return child.IsOneInteger; }
1260 public override bool IsSideEffectFree {
1262 return child.IsSideEffectFree;
1266 public override bool IsZeroInteger {
1267 get { return child.IsZeroInteger; }
1270 public override void Emit (EmitContext ec)
1275 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1277 child.EmitBranchable (ec, label, on_true);
1279 // Only to make verifier happy
1280 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1281 ec.Emit (OpCodes.Unbox_Any, type);
1284 public override void EmitSideEffect (EmitContext ec)
1286 child.EmitSideEffect (ec);
1289 public override object GetValue ()
1291 return child.GetValue ();
1294 public override string GetValueAsLiteral ()
1296 return child.GetValueAsLiteral ();
1299 public override long GetValueAsLong ()
1301 return child.GetValueAsLong ();
1304 public override Constant ConvertImplicitly (TypeSpec target_type)
1306 if (type == target_type)
1309 // FIXME: Do we need to check user conversions?
1310 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1313 return child.ConvertImplicitly (target_type);
1318 /// This class is used to wrap literals which belong inside Enums
1320 public class EnumConstant : Constant
1322 public Constant Child;
1324 public EnumConstant (Constant child, TypeSpec enum_type)
1325 : base (child.Location)
1329 this.eclass = ExprClass.Value;
1330 this.type = enum_type;
1333 protected EnumConstant (Location loc)
1338 public override void Emit (EmitContext ec)
1343 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1345 Child.EncodeAttributeValue (rc, enc, Child.Type);
1348 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1350 Child.EmitBranchable (ec, label, on_true);
1353 public override void EmitSideEffect (EmitContext ec)
1355 Child.EmitSideEffect (ec);
1358 public override string GetSignatureForError()
1360 return TypeManager.CSharpName (Type);
1363 public override object GetValue ()
1365 return Child.GetValue ();
1369 public override object GetTypedValue ()
1372 // The method can be used in dynamic context only (on closed types)
1374 // System.Enum.ToObject cannot be called on dynamic types
1375 // EnumBuilder has to be used, but we cannot use EnumBuilder
1376 // because it does not properly support generics
1378 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1382 public override string GetValueAsLiteral ()
1384 return Child.GetValueAsLiteral ();
1387 public override long GetValueAsLong ()
1389 return Child.GetValueAsLong ();
1392 public EnumConstant Increment()
1394 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1397 public override bool IsDefaultValue {
1399 return Child.IsDefaultValue;
1403 public override bool IsSideEffectFree {
1405 return Child.IsSideEffectFree;
1409 public override bool IsZeroInteger {
1410 get { return Child.IsZeroInteger; }
1413 public override bool IsNegative {
1415 return Child.IsNegative;
1419 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1421 if (Child.Type == target_type)
1424 return Child.ConvertExplicitly (in_checked_context, target_type);
1427 public override Constant ConvertImplicitly (TypeSpec type)
1429 if (this.type == type) {
1433 if (!Convert.ImplicitStandardConversionExists (this, type)){
1437 return Child.ConvertImplicitly (type);
1442 /// This kind of cast is used to encapsulate Value Types in objects.
1444 /// The effect of it is to box the value type emitted by the previous
1447 public class BoxedCast : TypeCast {
1449 public BoxedCast (Expression expr, TypeSpec target_type)
1450 : base (expr, target_type)
1452 eclass = ExprClass.Value;
1455 protected override Expression DoResolve (ResolveContext ec)
1457 // This should never be invoked, we are born in fully
1458 // initialized state.
1463 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1465 // Only boxing to object type is supported
1466 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1467 base.EncodeAttributeValue (rc, enc, targetType);
1471 enc.Encode (child.Type);
1472 child.EncodeAttributeValue (rc, enc, child.Type);
1475 public override void Emit (EmitContext ec)
1479 ec.Emit (OpCodes.Box, child.Type);
1482 public override void EmitSideEffect (EmitContext ec)
1484 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1485 // so, we need to emit the box+pop instructions in most cases
1486 if (child.Type.IsStruct &&
1487 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1488 child.EmitSideEffect (ec);
1490 base.EmitSideEffect (ec);
1494 public class UnboxCast : TypeCast {
1495 public UnboxCast (Expression expr, TypeSpec return_type)
1496 : base (expr, return_type)
1500 protected override Expression DoResolve (ResolveContext ec)
1502 // This should never be invoked, we are born in fully
1503 // initialized state.
1508 public override void Emit (EmitContext ec)
1512 ec.Emit (OpCodes.Unbox_Any, type);
1517 /// This is used to perform explicit numeric conversions.
1519 /// Explicit numeric conversions might trigger exceptions in a checked
1520 /// context, so they should generate the conv.ovf opcodes instead of
1523 public class ConvCast : TypeCast {
1524 public enum Mode : byte {
1525 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1527 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1528 U2_I1, U2_U1, U2_I2, U2_CH,
1529 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1530 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1531 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1532 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1533 CH_I1, CH_U1, CH_I2,
1534 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1535 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1541 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1542 : base (child, return_type)
1547 protected override Expression DoResolve (ResolveContext ec)
1549 // This should never be invoked, we are born in fully
1550 // initialized state.
1555 public override string ToString ()
1557 return String.Format ("ConvCast ({0}, {1})", mode, child);
1560 public override void Emit (EmitContext ec)
1564 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1566 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1567 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1568 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1569 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1570 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1572 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1573 case Mode.U1_CH: /* nothing */ break;
1575 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1576 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1577 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1578 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1579 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1580 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1582 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1583 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1584 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1585 case Mode.U2_CH: /* nothing */ break;
1587 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1588 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1589 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1590 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1591 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1592 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1593 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1595 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1596 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1597 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1598 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1599 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1600 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1602 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1603 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1604 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1605 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1606 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1607 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1608 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1609 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1610 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1612 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1613 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1614 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1615 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1616 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1617 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1618 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1619 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1620 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1622 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1623 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1624 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1626 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1627 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1628 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1629 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1630 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1631 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1632 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1633 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1634 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1637 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1638 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1639 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1640 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1641 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1642 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1643 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1644 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1645 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1647 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1651 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1652 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1653 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1654 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1655 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1657 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1658 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1660 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1661 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1662 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1663 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1664 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1665 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1667 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1668 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1669 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1670 case Mode.U2_CH: /* nothing */ break;
1672 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1673 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1674 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1675 case Mode.I4_U4: /* nothing */ break;
1676 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1677 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1678 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1680 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1681 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1682 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1683 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1684 case Mode.U4_I4: /* nothing */ break;
1685 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1687 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1688 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1689 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1690 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1691 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1692 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1693 case Mode.I8_U8: /* nothing */ break;
1694 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1695 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1697 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1698 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1699 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1700 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1701 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1702 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1703 case Mode.U8_I8: /* nothing */ break;
1704 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1705 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1707 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1708 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1709 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1711 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1712 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1713 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1714 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1715 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1716 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1717 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1718 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1719 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1722 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1723 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1724 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1725 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1726 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1727 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1728 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1729 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1730 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1732 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1738 class OpcodeCast : TypeCast
1742 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1743 : base (child, return_type)
1748 protected override Expression DoResolve (ResolveContext ec)
1750 // This should never be invoked, we are born in fully
1751 // initialized state.
1756 public override void Emit (EmitContext ec)
1762 public TypeSpec UnderlyingType {
1763 get { return child.Type; }
1768 // Opcode casts expression with 2 opcodes but only
1769 // single expression tree node
1771 class OpcodeCastDuplex : OpcodeCast
1773 readonly OpCode second;
1775 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1776 : base (child, returnType, first)
1778 this.second = second;
1781 public override void Emit (EmitContext ec)
1789 /// This kind of cast is used to encapsulate a child and cast it
1790 /// to the class requested
1792 public sealed class ClassCast : TypeCast {
1793 readonly bool forced;
1795 public ClassCast (Expression child, TypeSpec return_type)
1796 : base (child, return_type)
1800 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1801 : base (child, return_type)
1803 this.forced = forced;
1806 public override void Emit (EmitContext ec)
1810 bool gen = TypeManager.IsGenericParameter (child.Type);
1812 ec.Emit (OpCodes.Box, child.Type);
1814 if (type.IsGenericParameter) {
1815 ec.Emit (OpCodes.Unbox_Any, type);
1822 ec.Emit (OpCodes.Castclass, type);
1827 // Created during resolving pahse when an expression is wrapped or constantified
1828 // and original expression can be used later (e.g. for expression trees)
1830 public class ReducedExpression : Expression
1832 sealed class ReducedConstantExpression : EmptyConstantCast
1834 readonly Expression orig_expr;
1836 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1837 : base (expr, expr.Type)
1839 this.orig_expr = orig_expr;
1842 public override Constant ConvertImplicitly (TypeSpec target_type)
1844 Constant c = base.ConvertImplicitly (target_type);
1846 c = new ReducedConstantExpression (c, orig_expr);
1851 public override Expression CreateExpressionTree (ResolveContext ec)
1853 return orig_expr.CreateExpressionTree (ec);
1856 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1858 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1860 c = new ReducedConstantExpression (c, orig_expr);
1864 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1867 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1869 if (orig_expr is Conditional)
1870 child.EncodeAttributeValue (rc, enc, targetType);
1872 base.EncodeAttributeValue (rc, enc, targetType);
1876 sealed class ReducedExpressionStatement : ExpressionStatement
1878 readonly Expression orig_expr;
1879 readonly ExpressionStatement stm;
1881 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1883 this.orig_expr = orig;
1885 this.eclass = stm.eclass;
1886 this.type = stm.Type;
1888 this.loc = orig.Location;
1891 public override bool ContainsEmitWithAwait ()
1893 return stm.ContainsEmitWithAwait ();
1896 public override Expression CreateExpressionTree (ResolveContext ec)
1898 return orig_expr.CreateExpressionTree (ec);
1901 protected override Expression DoResolve (ResolveContext ec)
1906 public override void Emit (EmitContext ec)
1911 public override void EmitStatement (EmitContext ec)
1913 stm.EmitStatement (ec);
1917 readonly Expression expr, orig_expr;
1919 private ReducedExpression (Expression expr, Expression orig_expr)
1922 this.eclass = expr.eclass;
1923 this.type = expr.Type;
1924 this.orig_expr = orig_expr;
1925 this.loc = orig_expr.Location;
1930 public Expression OriginalExpression {
1938 public override bool ContainsEmitWithAwait ()
1940 return expr.ContainsEmitWithAwait ();
1944 // Creates fully resolved expression switcher
1946 public static Constant Create (Constant expr, Expression original_expr)
1948 if (expr.eclass == ExprClass.Unresolved)
1949 throw new ArgumentException ("Unresolved expression");
1951 return new ReducedConstantExpression (expr, original_expr);
1954 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1956 return new ReducedExpressionStatement (s, orig);
1959 public static Expression Create (Expression expr, Expression original_expr)
1961 return Create (expr, original_expr, true);
1965 // Creates unresolved reduce expression. The original expression has to be
1966 // already resolved. Created expression is constant based based on `expr'
1967 // value unless canBeConstant is used
1969 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1971 if (canBeConstant) {
1972 Constant c = expr as Constant;
1974 return Create (c, original_expr);
1977 ExpressionStatement s = expr as ExpressionStatement;
1979 return Create (s, original_expr);
1981 if (expr.eclass == ExprClass.Unresolved)
1982 throw new ArgumentException ("Unresolved expression");
1984 return new ReducedExpression (expr, original_expr);
1987 public override Expression CreateExpressionTree (ResolveContext ec)
1989 return orig_expr.CreateExpressionTree (ec);
1992 protected override Expression DoResolve (ResolveContext ec)
1997 public override void Emit (EmitContext ec)
2002 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2004 expr.EmitBranchable (ec, target, on_true);
2007 public override SLE.Expression MakeExpression (BuilderContext ctx)
2009 return orig_expr.MakeExpression (ctx);
2014 // Standard composite pattern
2016 public abstract class CompositeExpression : Expression
2018 protected Expression expr;
2020 protected CompositeExpression (Expression expr)
2023 this.loc = expr.Location;
2026 public override bool ContainsEmitWithAwait ()
2028 return expr.ContainsEmitWithAwait ();
2031 public override Expression CreateExpressionTree (ResolveContext rc)
2033 return expr.CreateExpressionTree (rc);
2036 public Expression Child {
2037 get { return expr; }
2040 protected override Expression DoResolve (ResolveContext rc)
2042 expr = expr.Resolve (rc);
2045 eclass = expr.eclass;
2051 public override void Emit (EmitContext ec)
2056 public override bool IsNull {
2057 get { return expr.IsNull; }
2062 // Base of expressions used only to narrow resolve flow
2064 public abstract class ShimExpression : Expression
2066 protected Expression expr;
2068 protected ShimExpression (Expression expr)
2073 public Expression Expr {
2079 protected override void CloneTo (CloneContext clonectx, Expression t)
2084 ShimExpression target = (ShimExpression) t;
2085 target.expr = expr.Clone (clonectx);
2088 public override bool ContainsEmitWithAwait ()
2090 return expr.ContainsEmitWithAwait ();
2093 public override Expression CreateExpressionTree (ResolveContext ec)
2095 throw new NotSupportedException ("ET");
2098 public override void Emit (EmitContext ec)
2100 throw new InternalErrorException ("Missing Resolve call");
2106 // Unresolved type name expressions
2108 public abstract class ATypeNameExpression : FullNamedExpression
2111 protected TypeArguments targs;
2113 protected ATypeNameExpression (string name, Location l)
2119 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2126 protected ATypeNameExpression (string name, int arity, Location l)
2127 : this (name, new UnboundTypeArguments (arity), l)
2133 protected int Arity {
2135 return targs == null ? 0 : targs.Count;
2139 public bool HasTypeArguments {
2141 return targs != null && !targs.IsEmpty;
2145 public string Name {
2154 public TypeArguments TypeArguments {
2162 public override bool Equals (object obj)
2164 ATypeNameExpression atne = obj as ATypeNameExpression;
2165 return atne != null && atne.Name == Name &&
2166 (targs == null || targs.Equals (atne.targs));
2169 public override int GetHashCode ()
2171 return Name.GetHashCode ();
2174 // TODO: Move it to MemberCore
2175 public static string GetMemberType (MemberCore mc)
2181 if (mc is FieldBase)
2183 if (mc is MethodCore)
2185 if (mc is EnumMember)
2193 public override string GetSignatureForError ()
2195 if (targs != null) {
2196 return Name + "<" + targs.GetSignatureForError () + ">";
2202 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2206 /// SimpleName expressions are formed of a single word and only happen at the beginning
2207 /// of a dotted-name.
2209 public class SimpleName : ATypeNameExpression
2211 public SimpleName (string name, Location l)
2216 public SimpleName (string name, TypeArguments args, Location l)
2217 : base (name, args, l)
2221 public SimpleName (string name, int arity, Location l)
2222 : base (name, arity, l)
2226 public SimpleName GetMethodGroup ()
2228 return new SimpleName (Name, targs, loc);
2231 protected override Expression DoResolve (ResolveContext rc)
2233 var e = SimpleNameResolve (rc, null, false);
2235 var fe = e as FieldExpr;
2237 fe.VerifyAssignedStructField (rc, null);
2243 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2245 return SimpleNameResolve (ec, right_side, false);
2248 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2250 if (ctx.CurrentType != null) {
2251 if (ctx.CurrentMemberDefinition != null) {
2252 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2254 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2260 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2261 if (retval != null) {
2262 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2263 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2267 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2268 if (retval != null) {
2269 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2273 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2276 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2278 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2281 if (fne.Type != null && Arity > 0) {
2282 if (HasTypeArguments) {
2283 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2284 if (ct.ResolveAsType (ec) == null)
2290 return new GenericOpenTypeExpr (fne.Type, loc);
2294 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2296 if (!(fne is Namespace))
2300 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2301 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2302 ec.Module.Compiler.Report.Error (1980, Location,
2303 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2304 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2307 fne = new DynamicTypeExpr (loc);
2308 fne.ResolveAsType (ec);
2314 Error_TypeOrNamespaceNotFound (ec);
2318 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2320 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2323 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2325 int lookup_arity = Arity;
2326 bool errorMode = false;
2328 Block current_block = rc.CurrentBlock;
2329 INamedBlockVariable variable = null;
2330 bool variable_found = false;
2334 // Stage 1: binding to local variables or parameters
2336 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2338 if (current_block != null && lookup_arity == 0) {
2339 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2340 if (!variable.IsDeclared) {
2341 // We found local name in accessible block but it's not
2342 // initialized yet, maybe the user wanted to bind to something else
2344 variable_found = true;
2346 e = variable.CreateReferenceExpression (rc, loc);
2349 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2358 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2360 TypeSpec member_type = rc.CurrentType;
2361 for (; member_type != null; member_type = member_type.DeclaringType) {
2362 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2366 var me = e as MemberExpr;
2368 // The name matches a type, defer to ResolveAsTypeStep
2376 if (variable != null) {
2377 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2378 rc.Report.Error (844, loc,
2379 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2380 Name, me.GetSignatureForError ());
2384 } else if (me is MethodGroupExpr) {
2385 // Leave it to overload resolution to report correct error
2387 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2388 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2391 // LAMESPEC: again, ignores InvocableOnly
2392 if (variable != null) {
2393 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2394 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2398 // MemberLookup does not check accessors availability, this is actually needed for properties only
2400 var pe = me as PropertyExpr;
2403 // Break as there is no other overload available anyway
2404 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2405 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2408 pe.Getter = pe.PropertyInfo.Get;
2410 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2413 pe.Setter = pe.PropertyInfo.Set;
2418 // TODO: It's used by EventExpr -> FieldExpr transformation only
2419 // TODO: Should go to MemberAccess
2420 me = me.ResolveMemberAccess (rc, null, null);
2424 me.SetTypeArguments (rc, targs);
2431 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2433 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2434 if (IsPossibleTypeOrNamespace (rc)) {
2435 if (variable != null) {
2436 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2437 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2440 return ResolveAsTypeOrNamespace (rc);
2445 if (variable_found) {
2446 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2449 TypeParameter[] tparams = rc.CurrentTypeParameters;
2450 if (tparams != null) {
2451 foreach (var ctp in tparams) {
2452 if (ctp.Name == Name) {
2453 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2459 var ct = rc.CurrentType;
2461 if (ct.MemberDefinition.TypeParametersCount > 0) {
2462 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2463 if (ctp.Name == Name) {
2464 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2470 ct = ct.DeclaringType;
2471 } while (ct != null);
2474 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2475 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2477 rc.Report.SymbolRelatedToPreviousError (e.Type);
2478 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2483 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2485 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2486 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2491 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2494 return ErrorExpression.Instance;
2497 if (rc.Module.Evaluator != null) {
2498 var fi = rc.Module.Evaluator.LookupField (Name);
2500 return new FieldExpr (fi.Item1, loc);
2508 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2510 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2515 if (right_side != null) {
2516 if (e is TypeExpr) {
2517 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2521 e = e.ResolveLValue (ec, right_side);
2526 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2532 /// Represents a namespace or a type. The name of the class was inspired by
2533 /// section 10.8.1 (Fully Qualified Names).
2535 public abstract class FullNamedExpression : Expression
2537 protected override void CloneTo (CloneContext clonectx, Expression target)
2539 // Do nothing, most unresolved type expressions cannot be
2540 // resolved to different type
2543 public override bool ContainsEmitWithAwait ()
2548 public override Expression CreateExpressionTree (ResolveContext ec)
2550 throw new NotSupportedException ("ET");
2553 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2556 // This is used to resolve the expression as a type, a null
2557 // value will be returned if the expression is not a type
2560 public override TypeSpec ResolveAsType (IMemberContext mc)
2562 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2567 TypeExpr te = fne as TypeExpr;
2569 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2577 var dep = type.GetMissingDependencies ();
2579 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2583 // Obsolete checks cannot be done when resolving base context as they
2584 // require type dependencies to be set but we are in process of resolving them
2586 if (!(mc is TypeContainer.BaseContext)) {
2587 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2588 if (obsolete_attr != null && !mc.IsObsolete) {
2589 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2597 public override void Emit (EmitContext ec)
2599 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2600 GetSignatureForError ());
2605 /// Expression that evaluates to a type
2607 public abstract class TypeExpr : FullNamedExpression
2609 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2615 protected sealed override Expression DoResolve (ResolveContext ec)
2621 public override bool Equals (object obj)
2623 TypeExpr tobj = obj as TypeExpr;
2627 return Type == tobj.Type;
2630 public override int GetHashCode ()
2632 return Type.GetHashCode ();
2637 /// Fully resolved Expression that already evaluated to a type
2639 public class TypeExpression : TypeExpr
2641 public TypeExpression (TypeSpec t, Location l)
2644 eclass = ExprClass.Type;
2648 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2655 /// This class denotes an expression which evaluates to a member
2656 /// of a struct or a class.
2658 public abstract class MemberExpr : Expression
2661 // An instance expression associated with this member, if it's a
2662 // non-static member
2664 public Expression InstanceExpression;
2667 /// The name of this member.
2669 public abstract string Name {
2674 // When base.member is used
2676 public bool IsBase {
2677 get { return InstanceExpression is BaseThis; }
2681 /// Whether this is an instance member.
2683 public abstract bool IsInstance {
2688 /// Whether this is a static member.
2690 public abstract bool IsStatic {
2694 protected abstract TypeSpec DeclaringType {
2699 // Converts best base candidate for virtual method starting from QueriedBaseType
2701 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2704 // Only when base.member is used and method is virtual
2710 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2711 // means for base.member access we have to find the closest match after we found best candidate
2713 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2715 // The method could already be what we are looking for
2717 TypeSpec[] targs = null;
2718 if (method.DeclaringType != InstanceExpression.Type) {
2719 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2720 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2721 if (base_override.IsGeneric)
2722 targs = method.TypeArguments;
2724 method = base_override;
2728 // TODO: For now we do it for any hoisted call even if it's needed for
2729 // hoisted stories only but that requires a new expression wrapper
2730 if (rc.CurrentAnonymousMethod != null) {
2731 if (targs == null && method.IsGeneric) {
2732 targs = method.TypeArguments;
2733 method = method.GetGenericMethodDefinition ();
2736 if (method.Parameters.HasArglist)
2737 throw new NotImplementedException ("__arglist base call proxy");
2739 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2741 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2742 // get/set member expressions second call would fail to proxy because left expression
2743 // would be of 'this' and not 'base'
2744 if (rc.CurrentType.IsStruct)
2745 InstanceExpression = new This (loc).Resolve (rc);
2749 method = method.MakeGenericMethod (rc, targs);
2753 // Only base will allow this invocation to happen.
2755 if (method.IsAbstract) {
2756 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2762 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2764 if (InstanceExpression == null)
2767 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2768 CheckProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2772 public static void CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier, Location loc) where T : MemberSpec
2774 var ct = rc.CurrentType;
2775 if (ct == qualifier)
2778 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2781 qualifier = qualifier.GetDefinition ();
2782 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2783 rc.Report.SymbolRelatedToPreviousError (member);
2784 rc.Report.Error (1540, loc,
2785 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2786 member.GetSignatureForError (), qualifier.GetSignatureForError (), ct.GetSignatureForError ());
2790 public override bool ContainsEmitWithAwait ()
2792 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2795 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2798 type = type.GetDefinition ();
2800 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2803 type = type.DeclaringType;
2804 } while (type != null);
2809 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2811 if (InstanceExpression != null) {
2812 InstanceExpression = InstanceExpression.Resolve (rc);
2813 CheckProtectedMemberAccess (rc, member);
2816 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2817 UnsafeError (rc, loc);
2820 var dep = member.GetMissingDependencies ();
2822 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2825 if (!rc.IsObsolete) {
2826 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2828 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2831 if (!(member is FieldSpec))
2832 member.MemberDefinition.SetIsUsed ();
2835 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2837 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2841 // Implements identicial simple name and type-name
2843 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2846 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2849 // 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
2850 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2852 if (left is MemberExpr || left is VariableReference) {
2853 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2854 if (identical_type != null && identical_type.Type == left.Type)
2855 return identical_type;
2861 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2864 if (InstanceExpression != null) {
2865 if (InstanceExpression is TypeExpr) {
2866 var t = InstanceExpression.Type;
2868 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2869 if (oa != null && !rc.IsObsolete) {
2870 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2873 t = t.DeclaringType;
2874 } while (t != null);
2876 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2877 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2878 rc.Report.Error (176, loc,
2879 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2880 GetSignatureForError ());
2884 InstanceExpression = null;
2890 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2891 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2892 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2893 rc.Report.Error (236, loc,
2894 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2895 GetSignatureForError ());
2897 rc.Report.Error (120, loc,
2898 "An object reference is required to access non-static member `{0}'",
2899 GetSignatureForError ());
2904 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2905 rc.Report.Error (38, loc,
2906 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2907 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2910 InstanceExpression = new This (loc);
2911 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2912 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2913 InstanceExpression = InstanceExpression.Resolve (rc);
2916 InstanceExpression = InstanceExpression.Resolve (rc);
2922 var me = InstanceExpression as MemberExpr;
2924 me.ResolveInstanceExpression (rc, rhs);
2926 var fe = me as FieldExpr;
2927 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2928 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2929 rc.Report.Warning (1690, 1, loc,
2930 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2931 me.GetSignatureForError ());
2938 // Run member-access postponed check once we know that
2939 // the expression is not field expression which is the only
2940 // expression which can use uninitialized this
2942 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2943 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2947 // Additional checks for l-value member access
2951 // TODO: It should be recursive but that would break csc compatibility
2953 if (InstanceExpression is UnboxCast) {
2954 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2961 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2963 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2964 ec.Report.Warning (1720, 1, left.Location,
2965 "Expression will always cause a `{0}'", "System.NullReferenceException");
2968 InstanceExpression = left;
2972 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2974 TypeSpec instance_type = InstanceExpression.Type;
2975 if (TypeSpec.IsValueType (instance_type)) {
2976 if (InstanceExpression is IMemoryLocation) {
2977 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
2979 LocalTemporary t = new LocalTemporary (instance_type);
2980 InstanceExpression.Emit (ec);
2982 t.AddressOf (ec, AddressOp.Store);
2986 InstanceExpression.Emit (ec);
2988 // Only to make verifier happy
2989 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
2990 ec.Emit (OpCodes.Box, instance_type);
2993 if (prepare_for_load)
2994 ec.Emit (OpCodes.Dup);
2997 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3000 public class ExtensionMethodCandidates
3002 NamespaceContainer container;
3004 IList<MethodSpec> methods;
3006 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
3007 : this (methods, nsContainer, null)
3011 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
3013 this.methods = methods;
3014 this.container = nsContainer;
3018 public NamespaceContainer Container {
3024 public bool HasUninspectedMembers { get; set; }
3026 public Namespace Namespace {
3032 public IList<MethodSpec> Methods {
3040 // Represents a group of extension method candidates for whole namespace
3042 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3044 ExtensionMethodCandidates candidates;
3045 public readonly Expression ExtensionExpression;
3047 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3048 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3050 this.candidates = candidates;
3051 this.ExtensionExpression = extensionExpr;
3054 public override bool IsStatic {
3055 get { return true; }
3059 // For extension methodgroup we are not looking for base members but parent
3060 // namespace extension methods
3062 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3064 // TODO: candidates are null only when doing error reporting, that's
3065 // incorrect. We have to discover same extension methods in error mode
3066 if (candidates == null)
3069 int arity = type_arguments == null ? 0 : type_arguments.Count;
3072 // Here we try to resume the search for extension method at the point
3073 // where the last bunch of candidates was found. It's more tricky than
3074 // it seems as we have to check both namespace containers and namespace
3075 // in correct order.
3081 // namespace B.C.D {
3082 // <our first search found candidates in A.B.C.D
3086 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3087 // checked before we hit A.N1 using
3089 if (candidates.Namespace == null) {
3091 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3092 if (methods != null) {
3093 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3094 return methods.Cast<MemberSpec> ().ToList ();
3098 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3099 if (ns_container == null)
3102 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3103 if (candidates == null)
3106 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3109 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3111 // We are already here
3115 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3117 if (arguments == null)
3118 arguments = new Arguments (1);
3120 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3121 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3123 // Store resolved argument and restore original arguments
3125 // Clean-up modified arguments for error reporting
3126 arguments.RemoveAt (0);
3130 var me = ExtensionExpression as MemberExpr;
3132 me.ResolveInstanceExpression (ec, null);
3134 InstanceExpression = null;
3138 #region IErrorHandler Members
3140 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3145 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3147 rc.Report.SymbolRelatedToPreviousError (best);
3148 rc.Report.Error (1928, loc,
3149 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3150 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3153 rc.Report.Error (1929, loc,
3154 "Extension method instance type `{0}' cannot be converted to `{1}'",
3155 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3161 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3166 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3175 /// MethodGroupExpr represents a group of method candidates which
3176 /// can be resolved to the best method overload
3178 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3180 protected IList<MemberSpec> Methods;
3181 MethodSpec best_candidate;
3182 TypeSpec best_candidate_return;
3183 protected TypeArguments type_arguments;
3185 SimpleName simple_name;
3186 protected TypeSpec queried_type;
3188 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3192 this.type = InternalType.MethodGroup;
3194 eclass = ExprClass.MethodGroup;
3195 queried_type = type;
3198 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3199 : this (new MemberSpec[] { m }, type, loc)
3205 public MethodSpec BestCandidate {
3207 return best_candidate;
3211 public TypeSpec BestCandidateReturnType {
3213 return best_candidate_return;
3217 public IList<MemberSpec> Candidates {
3223 protected override TypeSpec DeclaringType {
3225 return queried_type;
3229 public override bool IsInstance {
3231 if (best_candidate != null)
3232 return !best_candidate.IsStatic;
3238 public override bool IsStatic {
3240 if (best_candidate != null)
3241 return best_candidate.IsStatic;
3247 public override string Name {
3249 if (best_candidate != null)
3250 return best_candidate.Name;
3253 return Methods.First ().Name;
3260 // When best candidate is already know this factory can be used
3261 // to avoid expensive overload resolution to be called
3263 // NOTE: InstanceExpression has to be set manually
3265 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3267 return new MethodGroupExpr (best, queriedType, loc) {
3268 best_candidate = best,
3269 best_candidate_return = best.ReturnType
3273 public override string GetSignatureForError ()
3275 if (best_candidate != null)
3276 return best_candidate.GetSignatureForError ();
3278 return Methods.First ().GetSignatureForError ();
3281 public override Expression CreateExpressionTree (ResolveContext ec)
3283 if (best_candidate == null) {
3284 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3288 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3289 ec.Report.Error (765, loc,
3290 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3292 return new TypeOfMethod (best_candidate, loc);
3295 protected override Expression DoResolve (ResolveContext ec)
3297 this.eclass = ExprClass.MethodGroup;
3299 if (InstanceExpression != null) {
3300 InstanceExpression = InstanceExpression.Resolve (ec);
3301 if (InstanceExpression == null)
3308 public override void Emit (EmitContext ec)
3310 throw new NotSupportedException ();
3313 public void EmitCall (EmitContext ec, Arguments arguments)
3315 var call = new CallEmitter ();
3316 call.InstanceExpression = InstanceExpression;
3317 call.Emit (ec, best_candidate, arguments, loc);
3320 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3322 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3323 Name, TypeManager.CSharpName (target));
3326 public static bool IsExtensionMethodArgument (Expression expr)
3329 // LAMESPEC: No details about which expressions are not allowed
3331 return !(expr is TypeExpr) && !(expr is BaseThis);
3335 /// Find the Applicable Function Members (7.4.2.1)
3337 /// me: Method Group expression with the members to select.
3338 /// it might contain constructors or methods (or anything
3339 /// that maps to a method).
3341 /// Arguments: ArrayList containing resolved Argument objects.
3343 /// loc: The location if we want an error to be reported, or a Null
3344 /// location for "probing" purposes.
3346 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3347 /// that is the best match of me on Arguments.
3350 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3352 // TODO: causes issues with probing mode, remove explicit Kind check
3353 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3356 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3357 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3358 r.BaseMembersProvider = this;
3361 if (cerrors != null)
3362 r.CustomErrors = cerrors;
3364 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3365 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3366 if (best_candidate == null)
3367 return r.BestCandidateIsDynamic ? this : null;
3369 // Overload resolver had to create a new method group, all checks bellow have already been executed
3370 if (r.BestCandidateNewMethodGroup != null)
3371 return r.BestCandidateNewMethodGroup;
3373 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3374 if (InstanceExpression != null) {
3375 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3376 InstanceExpression = null;
3378 if (best_candidate.IsStatic && simple_name != null) {
3379 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3382 InstanceExpression.Resolve (ec);
3386 ResolveInstanceExpression (ec, null);
3387 if (InstanceExpression != null)
3388 CheckProtectedMemberAccess (ec, best_candidate);
3391 var base_override = CandidateToBaseOverride (ec, best_candidate);
3392 if (base_override == best_candidate) {
3393 best_candidate_return = r.BestCandidateReturnType;
3395 best_candidate = base_override;
3396 best_candidate_return = best_candidate.ReturnType;
3402 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3404 simple_name = original;
3405 return base.ResolveMemberAccess (ec, left, original);
3408 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3410 type_arguments = ta;
3413 #region IBaseMembersProvider Members
3415 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3417 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3420 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3422 if (queried_type == member.DeclaringType)
3425 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3426 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3430 // Extension methods lookup after ordinary methods candidates failed to apply
3432 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3434 if (InstanceExpression == null)
3437 InstanceExpression = InstanceExpression.Resolve (rc);
3438 if (!IsExtensionMethodArgument (InstanceExpression))
3441 int arity = type_arguments == null ? 0 : type_arguments.Count;
3442 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3443 if (methods == null)
3446 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3447 emg.SetTypeArguments (rc, type_arguments);
3454 public struct OverloadResolver
3457 public enum Restrictions
3461 ProbingOnly = 1 << 1,
3462 CovariantDelegate = 1 << 2,
3463 NoBaseMembers = 1 << 3,
3464 BaseMembersIncluded = 1 << 4
3467 public interface IBaseMembersProvider
3469 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3470 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3471 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3474 public interface IErrorHandler
3476 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3477 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3478 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3479 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3482 sealed class NoBaseMembers : IBaseMembersProvider
3484 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3486 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3491 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3496 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3502 struct AmbiguousCandidate
3504 public readonly MemberSpec Member;
3505 public readonly bool Expanded;
3506 public readonly AParametersCollection Parameters;
3508 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3511 Parameters = parameters;
3512 Expanded = expanded;
3517 IList<MemberSpec> members;
3518 TypeArguments type_arguments;
3519 IBaseMembersProvider base_provider;
3520 IErrorHandler custom_errors;
3521 Restrictions restrictions;
3522 MethodGroupExpr best_candidate_extension_group;
3523 TypeSpec best_candidate_return_type;
3525 SessionReportPrinter lambda_conv_msgs;
3526 ReportPrinter prev_recorder;
3528 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3529 : this (members, null, restrictions, loc)
3533 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3536 if (members == null || members.Count == 0)
3537 throw new ArgumentException ("empty members set");
3539 this.members = members;
3541 type_arguments = targs;
3542 this.restrictions = restrictions;
3543 if (IsDelegateInvoke)
3544 this.restrictions |= Restrictions.NoBaseMembers;
3546 base_provider = NoBaseMembers.Instance;
3551 public IBaseMembersProvider BaseMembersProvider {
3553 return base_provider;
3556 base_provider = value;
3560 public bool BestCandidateIsDynamic { get; set; }
3563 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3565 public MethodGroupExpr BestCandidateNewMethodGroup {
3567 return best_candidate_extension_group;
3572 // Return type can be different between best candidate and closest override
3574 public TypeSpec BestCandidateReturnType {
3576 return best_candidate_return_type;
3580 public IErrorHandler CustomErrors {
3582 return custom_errors;
3585 custom_errors = value;
3589 TypeSpec DelegateType {
3591 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3592 throw new InternalErrorException ("Not running in delegate mode", loc);
3594 return members [0].DeclaringType;
3598 bool IsProbingOnly {
3600 return (restrictions & Restrictions.ProbingOnly) != 0;
3604 bool IsDelegateInvoke {
3606 return (restrictions & Restrictions.DelegateInvoke) != 0;
3613 // 7.4.3.3 Better conversion from expression
3614 // Returns : 1 if a->p is better,
3615 // 2 if a->q is better,
3616 // 0 if neither is better
3618 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3620 TypeSpec argument_type = a.Type;
3623 // If argument is an anonymous function
3625 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3627 // p and q are delegate types or expression tree types
3629 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3630 if (q.MemberDefinition != p.MemberDefinition) {
3635 // Uwrap delegate from Expression<T>
3637 q = TypeManager.GetTypeArguments (q)[0];
3638 p = TypeManager.GetTypeArguments (p)[0];
3641 var p_m = Delegate.GetInvokeMethod (p);
3642 var q_m = Delegate.GetInvokeMethod (q);
3645 // With identical parameter lists
3647 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3654 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3656 if (p.Kind == MemberKind.Void) {
3657 return q.Kind != MemberKind.Void ? 2 : 0;
3661 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3663 if (q.Kind == MemberKind.Void) {
3664 return p.Kind != MemberKind.Void ? 1: 0;
3668 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3669 // better conversion is performed between underlying types Y1 and Y2
3671 if (p.IsGenericTask || q.IsGenericTask) {
3672 if (p.IsGenericTask != q.IsGenericTask) {
3676 var async_am = a.Expr as AnonymousMethodExpression;
3677 if (async_am == null || !async_am.IsAsync)
3680 q = q.TypeArguments[0];
3681 p = p.TypeArguments[0];
3685 // The parameters are identicial and return type is not void, use better type conversion
3686 // on return type to determine better one
3689 if (argument_type == p)
3692 if (argument_type == q)
3696 return BetterTypeConversion (ec, p, q);
3700 // 7.4.3.4 Better conversion from type
3702 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3704 if (p == null || q == null)
3705 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3707 switch (p.BuiltinType) {
3708 case BuiltinTypeSpec.Type.Int:
3709 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3712 case BuiltinTypeSpec.Type.Long:
3713 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3716 case BuiltinTypeSpec.Type.SByte:
3717 switch (q.BuiltinType) {
3718 case BuiltinTypeSpec.Type.Byte:
3719 case BuiltinTypeSpec.Type.UShort:
3720 case BuiltinTypeSpec.Type.UInt:
3721 case BuiltinTypeSpec.Type.ULong:
3725 case BuiltinTypeSpec.Type.Short:
3726 switch (q.BuiltinType) {
3727 case BuiltinTypeSpec.Type.UShort:
3728 case BuiltinTypeSpec.Type.UInt:
3729 case BuiltinTypeSpec.Type.ULong:
3733 case BuiltinTypeSpec.Type.Dynamic:
3734 // Dynamic is never better
3738 switch (q.BuiltinType) {
3739 case BuiltinTypeSpec.Type.Int:
3740 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3743 case BuiltinTypeSpec.Type.Long:
3744 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3747 case BuiltinTypeSpec.Type.SByte:
3748 switch (p.BuiltinType) {
3749 case BuiltinTypeSpec.Type.Byte:
3750 case BuiltinTypeSpec.Type.UShort:
3751 case BuiltinTypeSpec.Type.UInt:
3752 case BuiltinTypeSpec.Type.ULong:
3756 case BuiltinTypeSpec.Type.Short:
3757 switch (p.BuiltinType) {
3758 case BuiltinTypeSpec.Type.UShort:
3759 case BuiltinTypeSpec.Type.UInt:
3760 case BuiltinTypeSpec.Type.ULong:
3764 case BuiltinTypeSpec.Type.Dynamic:
3765 // Dynamic is never better
3769 // FIXME: handle lifted operators
3771 // TODO: this is expensive
3772 Expression p_tmp = new EmptyExpression (p);
3773 Expression q_tmp = new EmptyExpression (q);
3775 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3776 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3778 if (p_to_q && !q_to_p)
3781 if (q_to_p && !p_to_q)
3788 /// Determines "Better function" between candidate
3789 /// and the current best match
3792 /// Returns a boolean indicating :
3793 /// false if candidate ain't better
3794 /// true if candidate is better than the current best match
3796 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3797 MemberSpec best, AParametersCollection bparam, bool best_params)
3799 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3800 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3802 bool better_at_least_one = false;
3804 int args_count = args == null ? 0 : args.Count;
3808 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3811 // Default arguments are ignored for better decision
3812 if (a.IsDefaultArgument)
3816 // When comparing named argument the parameter type index has to be looked up
3817 // in original parameter set (override version for virtual members)
3819 NamedArgument na = a as NamedArgument;
3821 int idx = cparam.GetParameterIndexByName (na.Name);
3822 ct = candidate_pd.Types[idx];
3823 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3824 ct = TypeManager.GetElementType (ct);
3826 idx = bparam.GetParameterIndexByName (na.Name);
3827 bt = best_pd.Types[idx];
3828 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3829 bt = TypeManager.GetElementType (bt);
3831 ct = candidate_pd.Types[c_idx];
3832 bt = best_pd.Types[b_idx];
3834 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3835 ct = TypeManager.GetElementType (ct);
3839 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3840 bt = TypeManager.GetElementType (bt);
3845 if (TypeSpecComparer.IsEqual (ct, bt))
3849 int result = BetterExpressionConversion (ec, a, ct, bt);
3851 // for each argument, the conversion to 'ct' should be no worse than
3852 // the conversion to 'bt'.
3856 // for at least one argument, the conversion to 'ct' should be better than
3857 // the conversion to 'bt'.
3859 better_at_least_one = true;
3862 if (better_at_least_one)
3866 // This handles the case
3868 // Add (float f1, float f2, float f3);
3869 // Add (params decimal [] foo);
3871 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3872 // first candidate would've chosen as better.
3874 if (!same && !a.IsDefaultArgument)
3878 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3882 // This handles the following cases:
3884 // Foo (int i) is better than Foo (int i, long l = 0)
3885 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3887 // Prefer non-optional version
3889 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3891 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3892 if (candidate_pd.Count >= best_pd.Count)
3895 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3902 // One is a non-generic method and second is a generic method, then non-generic is better
3904 if (best.IsGeneric != candidate.IsGeneric)
3905 return best.IsGeneric;
3908 // This handles the following cases:
3910 // Trim () is better than Trim (params char[] chars)
3911 // Concat (string s1, string s2, string s3) is better than
3912 // Concat (string s1, params string [] srest)
3913 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3915 // Prefer non-expanded version
3917 if (candidate_params != best_params)
3920 int candidate_param_count = candidate_pd.Count;
3921 int best_param_count = best_pd.Count;
3923 if (candidate_param_count != best_param_count)
3924 // can only happen if (candidate_params && best_params)
3925 return candidate_param_count > best_param_count && best_pd.HasParams;
3928 // Both methods have the same number of parameters, and the parameters have equal types
3929 // Pick the "more specific" signature using rules over original (non-inflated) types
3931 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3932 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3934 bool specific_at_least_once = false;
3935 for (j = 0; j < args_count; ++j) {
3936 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3938 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3939 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3941 ct = candidate_def_pd.Types[j];
3942 bt = best_def_pd.Types[j];
3947 TypeSpec specific = MoreSpecific (ct, bt);
3951 specific_at_least_once = true;
3954 if (specific_at_least_once)
3960 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3962 rc.Report.Error (1729, loc,
3963 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3964 type.GetSignatureForError (), argCount.ToString ());
3968 // Determines if the candidate method is applicable to the given set of arguments
3969 // There could be two different set of parameters for same candidate where one
3970 // is the closest override for default values and named arguments checks and second
3971 // one being the virtual base for the parameter types and modifiers.
3973 // A return value rates candidate method compatibility,
3974 // 0 = the best, int.MaxValue = the worst
3976 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)
3978 // Parameters of most-derived type used mainly for named and optional parameters
3979 var pd = pm.Parameters;
3981 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
3982 // params modifier instead of most-derived type
3983 var cpd = ((IParametersMember) candidate).Parameters;
3984 int param_count = pd.Count;
3985 int optional_count = 0;
3987 Arguments orig_args = arguments;
3989 if (arg_count != param_count) {
3990 for (int i = 0; i < pd.Count; ++i) {
3991 if (pd.FixedParameters[i].HasDefaultValue) {
3992 optional_count = pd.Count - i;
3997 if (optional_count != 0) {
3998 // Readjust expected number when params used
3999 if (cpd.HasParams) {
4001 if (arg_count < param_count)
4003 } else if (arg_count > param_count) {
4004 int args_gap = System.Math.Abs (arg_count - param_count);
4005 return int.MaxValue - 10000 + args_gap;
4007 } else if (arg_count != param_count) {
4008 int args_gap = System.Math.Abs (arg_count - param_count);
4010 return int.MaxValue - 10000 + args_gap;
4011 if (arg_count < param_count - 1)
4012 return int.MaxValue - 10000 + args_gap;
4015 // Resize to fit optional arguments
4016 if (optional_count != 0) {
4017 if (arguments == null) {
4018 arguments = new Arguments (optional_count);
4020 // Have to create a new container, so the next run can do same
4021 var resized = new Arguments (param_count);
4022 resized.AddRange (arguments);
4023 arguments = resized;
4026 for (int i = arg_count; i < param_count; ++i)
4027 arguments.Add (null);
4031 if (arg_count > 0) {
4033 // Shuffle named arguments to the right positions if there are any
4035 if (arguments[arg_count - 1] is NamedArgument) {
4036 arg_count = arguments.Count;
4038 for (int i = 0; i < arg_count; ++i) {
4039 bool arg_moved = false;
4041 NamedArgument na = arguments[i] as NamedArgument;
4045 int index = pd.GetParameterIndexByName (na.Name);
4047 // Named parameter not found
4051 // already reordered
4056 if (index >= param_count) {
4057 // When using parameters which should not be available to the user
4058 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4061 arguments.Add (null);
4065 temp = arguments[index];
4067 // The slot has been taken by positional argument
4068 if (temp != null && !(temp is NamedArgument))
4073 arguments = arguments.MarkOrderedArgument (na);
4077 arguments[index] = arguments[i];
4078 arguments[i] = temp;
4085 arg_count = arguments.Count;
4087 } else if (arguments != null) {
4088 arg_count = arguments.Count;
4092 // 1. Handle generic method using type arguments when specified or type inference
4095 var ms = candidate as MethodSpec;
4096 if (ms != null && ms.IsGeneric) {
4097 // Setup constraint checker for probing only
4098 ConstraintChecker cc = new ConstraintChecker (null);
4100 if (type_arguments != null) {
4101 var g_args_count = ms.Arity;
4102 if (g_args_count != type_arguments.Count)
4103 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4105 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4107 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4108 // for now it simplifies things. I should probably add a callback to ResolveContext
4109 if (lambda_conv_msgs == null) {
4110 lambda_conv_msgs = new SessionReportPrinter ();
4111 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4114 var ti = new TypeInference (arguments);
4115 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4116 lambda_conv_msgs.EndSession ();
4119 return ti.InferenceScore - 20000;
4121 if (i_args.Length != 0) {
4122 ms = ms.MakeGenericMethod (ec, i_args);
4125 cc.IgnoreInferredDynamic = true;
4129 // Type arguments constraints have to match for the method to be applicable
4131 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4133 return int.MaxValue - 25000;
4137 // We have a generic return type and at same time the method is override which
4138 // means we have to also inflate override return type in case the candidate is
4139 // best candidate and override return type is different to base return type.
4141 // virtual Foo<T, object> with override Foo<T, dynamic>
4143 if (candidate != pm) {
4144 MethodSpec override_ms = (MethodSpec) pm;
4145 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4146 returnType = inflator.Inflate (returnType);
4148 returnType = ms.ReturnType;
4152 ptypes = ms.Parameters.Types;
4154 if (type_arguments != null)
4155 return int.MaxValue - 15000;
4161 // 2. Each argument has to be implicitly convertible to method parameter
4163 Parameter.Modifier p_mod = 0;
4166 for (int i = 0; i < arg_count; i++) {
4167 Argument a = arguments[i];
4169 if (!pd.FixedParameters[i].HasDefaultValue) {
4170 arguments = orig_args;
4171 return arg_count * 2 + 2;
4175 // Get the default value expression, we can use the same expression
4176 // if the type matches
4178 Expression e = pd.FixedParameters[i].DefaultValue;
4179 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric) {
4181 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4183 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4184 e = new MemberAccess (new MemberAccess (new MemberAccess (
4185 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4187 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4193 arguments[i] = new Argument (e, Argument.AType.Default);
4197 if (p_mod != Parameter.Modifier.PARAMS) {
4198 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4200 } else if (!params_expanded_form) {
4201 params_expanded_form = true;
4202 pt = ((ElementTypeSpec) pt).Element;
4208 if (!params_expanded_form) {
4209 if (a.ArgType == Argument.AType.ExtensionType) {
4211 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4213 // LAMESPEC: or implicit type parameter conversion
4216 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4217 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4218 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4223 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4226 dynamicArgument = true;
4231 // It can be applicable in expanded form (when not doing exact match like for delegates)
4233 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4234 if (!params_expanded_form)
4235 pt = ((ElementTypeSpec) pt).Element;
4238 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4241 params_expanded_form = true;
4242 } else if (score < 0) {
4243 params_expanded_form = true;
4244 dynamicArgument = true;
4249 if (params_expanded_form)
4251 return (arg_count - i) * 2 + score;
4256 // When params parameter has no argument it will be provided later if the method is the best candidate
4258 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4259 params_expanded_form = true;
4262 // Restore original arguments for dynamic binder to keep the intention of original source code
4264 if (dynamicArgument)
4265 arguments = orig_args;
4271 // Tests argument compatibility with the parameter
4272 // The possible return values are
4274 // 1 - modifier mismatch
4275 // 2 - type mismatch
4276 // -1 - dynamic binding required
4278 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4281 // Types have to be identical when ref or out modifer
4282 // is used and argument is not of dynamic type
4284 if ((argument.Modifier | param_mod) != 0) {
4285 if (argument.Type != parameter) {
4287 // Do full equality check after quick path
4289 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4291 // Using dynamic for ref/out parameter can still succeed at runtime
4293 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4300 if (argument.Modifier != param_mod) {
4302 // Using dynamic for ref/out parameter can still succeed at runtime
4304 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4311 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4315 // Deploy custom error reporting for lambda methods. When probing lambda methods
4316 // keep all errors reported in separate set and once we are done and no best
4317 // candidate was found, this set is used to report more details about what was wrong
4320 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4321 if (lambda_conv_msgs == null) {
4322 lambda_conv_msgs = new SessionReportPrinter ();
4323 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4328 // Use implicit conversion in all modes to return same candidates when the expression
4329 // is used as argument or delegate conversion
4331 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4332 if (lambda_conv_msgs != null) {
4333 lambda_conv_msgs.EndSession ();
4343 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4345 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4347 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4350 var ac_p = p as ArrayContainer;
4352 var ac_q = ((ArrayContainer) q);
4353 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4354 if (specific == ac_p.Element)
4356 if (specific == ac_q.Element)
4358 } else if (TypeManager.IsGenericType (p)) {
4359 var pargs = TypeManager.GetTypeArguments (p);
4360 var qargs = TypeManager.GetTypeArguments (q);
4362 bool p_specific_at_least_once = false;
4363 bool q_specific_at_least_once = false;
4365 for (int i = 0; i < pargs.Length; i++) {
4366 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4367 if (specific == pargs[i])
4368 p_specific_at_least_once = true;
4369 if (specific == qargs[i])
4370 q_specific_at_least_once = true;
4373 if (p_specific_at_least_once && !q_specific_at_least_once)
4375 if (!p_specific_at_least_once && q_specific_at_least_once)
4383 // Find the best method from candidate list
4385 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4387 List<AmbiguousCandidate> ambiguous_candidates = null;
4389 MemberSpec best_candidate;
4390 Arguments best_candidate_args = null;
4391 bool best_candidate_params = false;
4392 bool best_candidate_dynamic = false;
4393 int best_candidate_rate;
4394 IParametersMember best_parameter_member = null;
4396 int args_count = args != null ? args.Count : 0;
4398 Arguments candidate_args = args;
4399 bool error_mode = false;
4400 MemberSpec invocable_member = null;
4402 // Be careful, cannot return until error reporter is restored
4404 best_candidate = null;
4405 best_candidate_rate = int.MaxValue;
4407 var type_members = members;
4411 for (int i = 0; i < type_members.Count; ++i) {
4412 var member = type_members[i];
4415 // Methods in a base class are not candidates if any method in a derived
4416 // class is applicable
4418 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4422 if (!member.IsAccessible (rc))
4425 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4429 IParametersMember pm = member as IParametersMember;
4432 // Will use it later to report ambiguity between best method and invocable member
4434 if (Invocation.IsMemberInvocable (member))
4435 invocable_member = member;
4441 // Overload resolution is looking for base member but using parameter names
4442 // and default values from the closest member. That means to do expensive lookup
4443 // for the closest override for virtual or abstract members
4445 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4446 var override_params = base_provider.GetOverrideMemberParameters (member);
4447 if (override_params != null)
4448 pm = override_params;
4452 // Check if the member candidate is applicable
4454 bool params_expanded_form = false;
4455 bool dynamic_argument = false;
4456 TypeSpec rt = pm.MemberType;
4457 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4460 // How does it score compare to others
4462 if (candidate_rate < best_candidate_rate) {
4463 best_candidate_rate = candidate_rate;
4464 best_candidate = member;
4465 best_candidate_args = candidate_args;
4466 best_candidate_params = params_expanded_form;
4467 best_candidate_dynamic = dynamic_argument;
4468 best_parameter_member = pm;
4469 best_candidate_return_type = rt;
4470 } else if (candidate_rate == 0) {
4472 // The member look is done per type for most operations but sometimes
4473 // it's not possible like for binary operators overload because they
4474 // are unioned between 2 sides
4476 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4477 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4482 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4484 // We pack all interface members into top level type which makes the overload resolution
4485 // more complicated for interfaces. We compensate it by removing methods with same
4486 // signature when building the cache hence this path should not really be hit often
4489 // interface IA { void Foo (int arg); }
4490 // interface IB : IA { void Foo (params int[] args); }
4492 // IB::Foo is the best overload when calling IB.Foo (1)
4495 if (ambiguous_candidates != null) {
4496 foreach (var amb_cand in ambiguous_candidates) {
4497 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4506 ambiguous_candidates = null;
4509 // Is the new candidate better
4510 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4514 best_candidate = member;
4515 best_candidate_args = candidate_args;
4516 best_candidate_params = params_expanded_form;
4517 best_candidate_dynamic = dynamic_argument;
4518 best_parameter_member = pm;
4519 best_candidate_return_type = rt;
4521 // It's not better but any other found later could be but we are not sure yet
4522 if (ambiguous_candidates == null)
4523 ambiguous_candidates = new List<AmbiguousCandidate> ();
4525 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4529 // Restore expanded arguments
4530 if (candidate_args != args)
4531 candidate_args = args;
4533 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4535 if (prev_recorder != null)
4536 rc.Report.SetPrinter (prev_recorder);
4540 // We've found exact match
4542 if (best_candidate_rate == 0)
4546 // Try extension methods lookup when no ordinary method match was found and provider enables it
4549 var emg = base_provider.LookupExtensionMethod (rc);
4551 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4553 best_candidate_extension_group = emg;
4554 return (T) (MemberSpec) emg.BestCandidate;
4559 // Don't run expensive error reporting mode for probing
4566 lambda_conv_msgs = null;
4571 // No best member match found, report an error
4573 if (best_candidate_rate != 0 || error_mode) {
4574 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4578 if (best_candidate_dynamic) {
4579 if (args[0].ArgType == Argument.AType.ExtensionType) {
4580 rc.Report.Error (1973, loc,
4581 "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",
4582 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4585 BestCandidateIsDynamic = true;
4590 // These flags indicates we are running delegate probing conversion. No need to
4591 // do more expensive checks
4593 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4594 return (T) best_candidate;
4596 if (ambiguous_candidates != null) {
4598 // Now check that there are no ambiguities i.e the selected method
4599 // should be better than all the others
4601 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4602 var candidate = ambiguous_candidates [ix];
4604 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4605 var ambiguous = candidate.Member;
4606 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4607 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4608 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4609 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4610 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4613 return (T) best_candidate;
4618 if (invocable_member != null) {
4619 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4620 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4621 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4622 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4626 // And now check if the arguments are all
4627 // compatible, perform conversions if
4628 // necessary etc. and return if everything is
4631 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4634 if (best_candidate == null)
4638 // Check ObsoleteAttribute on the best method
4640 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4641 if (oa != null && !rc.IsObsolete)
4642 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4644 var dep = best_candidate.GetMissingDependencies ();
4646 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4649 best_candidate.MemberDefinition.SetIsUsed ();
4651 args = best_candidate_args;
4652 return (T) best_candidate;
4655 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4657 return ResolveMember<MethodSpec> (rc, ref args);
4660 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4661 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4663 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4666 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4667 ec.Report.SymbolRelatedToPreviousError (method);
4668 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4669 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4670 TypeManager.CSharpSignature (method));
4673 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4674 TypeManager.CSharpSignature (method));
4675 } else if (IsDelegateInvoke) {
4676 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4677 DelegateType.GetSignatureForError ());
4679 ec.Report.SymbolRelatedToPreviousError (method);
4680 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4681 method.GetSignatureForError ());
4684 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4686 string index = (idx + 1).ToString ();
4687 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4688 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4689 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4690 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4691 index, Parameter.GetModifierSignature (a.Modifier));
4693 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4694 index, Parameter.GetModifierSignature (mod));
4695 } else if (a.Expr != ErrorExpression.Instance) {
4696 string p1 = a.GetSignatureForError ();
4697 string p2 = TypeManager.CSharpName (paramType);
4700 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4701 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4704 ec.Report.Error (1503, loc,
4705 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4710 // We have failed to find exact match so we return error info about the closest match
4712 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4714 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4715 int arg_count = args == null ? 0 : args.Count;
4717 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4718 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4719 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4723 if (lambda_conv_msgs != null) {
4724 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4729 // For candidates which match on parameters count report more details about incorrect arguments
4732 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4733 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4734 // Reject any inaccessible member
4735 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4736 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4737 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4741 var ms = best_candidate as MethodSpec;
4742 if (ms != null && ms.IsGeneric) {
4743 bool constr_ok = true;
4744 if (ms.TypeArguments != null)
4745 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4747 if (ta_count == 0) {
4748 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4752 rc.Report.Error (411, loc,
4753 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4754 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4761 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4767 // We failed to find any method with correct argument count, report best candidate
4769 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4772 if (best_candidate.Kind == MemberKind.Constructor) {
4773 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4774 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4775 } else if (IsDelegateInvoke) {
4776 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4777 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4778 DelegateType.GetSignatureForError (), arg_count.ToString ());
4780 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4781 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4782 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4783 name, arg_count.ToString ());
4787 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4789 var pd = pm.Parameters;
4790 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4792 Parameter.Modifier p_mod = 0;
4794 int a_idx = 0, a_pos = 0;
4796 ArrayInitializer params_initializers = null;
4797 bool has_unsafe_arg = pm.MemberType.IsPointer;
4798 int arg_count = args == null ? 0 : args.Count;
4800 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4802 if (p_mod != Parameter.Modifier.PARAMS) {
4803 p_mod = pd.FixedParameters[a_idx].ModFlags;
4805 has_unsafe_arg |= pt.IsPointer;
4807 if (p_mod == Parameter.Modifier.PARAMS) {
4808 if (chose_params_expanded) {
4809 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4810 pt = TypeManager.GetElementType (pt);
4816 // Types have to be identical when ref or out modifer is used
4818 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4819 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4822 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4828 NamedArgument na = a as NamedArgument;
4830 int name_index = pd.GetParameterIndexByName (na.Name);
4831 if (name_index < 0 || name_index >= pd.Count) {
4832 if (IsDelegateInvoke) {
4833 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4834 ec.Report.Error (1746, na.Location,
4835 "The delegate `{0}' does not contain a parameter named `{1}'",
4836 DelegateType.GetSignatureForError (), na.Name);
4838 ec.Report.SymbolRelatedToPreviousError (member);
4839 ec.Report.Error (1739, na.Location,
4840 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4841 TypeManager.CSharpSignature (member), na.Name);
4843 } else if (args[name_index] != a) {
4844 if (IsDelegateInvoke)
4845 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4847 ec.Report.SymbolRelatedToPreviousError (member);
4849 ec.Report.Error (1744, na.Location,
4850 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4855 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4858 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4859 custom_errors.NoArgumentMatch (ec, member);
4863 Expression conv = null;
4864 if (a.ArgType == Argument.AType.ExtensionType) {
4865 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4868 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4870 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4873 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4880 // Convert params arguments to an array initializer
4882 if (params_initializers != null) {
4883 // we choose to use 'a.Expr' rather than 'conv' so that
4884 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4885 params_initializers.Add (a.Expr);
4886 args.RemoveAt (a_idx--);
4891 // Update the argument with the implicit conversion
4895 if (a_idx != arg_count) {
4896 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4901 // Fill not provided arguments required by params modifier
4903 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4905 args = new Arguments (1);
4907 pt = ptypes[pd.Count - 1];
4908 pt = TypeManager.GetElementType (pt);
4909 has_unsafe_arg |= pt.IsPointer;
4910 params_initializers = new ArrayInitializer (0, loc);
4914 // Append an array argument with all params arguments
4916 if (params_initializers != null) {
4917 args.Add (new Argument (
4918 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4922 if (has_unsafe_arg && !ec.IsUnsafe) {
4923 Expression.UnsafeError (ec, loc);
4927 // We could infer inaccesible type arguments
4929 if (type_arguments == null && member.IsGeneric) {
4930 var ms = (MethodSpec) member;
4931 foreach (var ta in ms.TypeArguments) {
4932 if (!ta.IsAccessible (ec)) {
4933 ec.Report.SymbolRelatedToPreviousError (ta);
4934 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
4944 public class ConstantExpr : MemberExpr
4946 readonly ConstSpec constant;
4948 public ConstantExpr (ConstSpec constant, Location loc)
4950 this.constant = constant;
4954 public override string Name {
4955 get { throw new NotImplementedException (); }
4958 public override bool IsInstance {
4959 get { return !IsStatic; }
4962 public override bool IsStatic {
4963 get { return true; }
4966 protected override TypeSpec DeclaringType {
4967 get { return constant.DeclaringType; }
4970 public override Expression CreateExpressionTree (ResolveContext ec)
4972 throw new NotSupportedException ("ET");
4975 protected override Expression DoResolve (ResolveContext rc)
4977 ResolveInstanceExpression (rc, null);
4978 DoBestMemberChecks (rc, constant);
4980 var c = constant.GetConstant (rc);
4982 // Creates reference expression to the constant value
4983 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
4986 public override void Emit (EmitContext ec)
4988 throw new NotSupportedException ();
4991 public override string GetSignatureForError ()
4993 return constant.GetSignatureForError ();
4996 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4998 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5003 // Fully resolved expression that references a Field
5005 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5007 protected FieldSpec spec;
5008 VariableInfo variable_info;
5010 LocalTemporary temp;
5013 protected FieldExpr (Location l)
5018 public FieldExpr (FieldSpec spec, Location loc)
5023 type = spec.MemberType;
5026 public FieldExpr (FieldBase fi, Location l)
5033 public override string Name {
5039 public bool IsHoisted {
5041 IVariableReference hv = InstanceExpression as IVariableReference;
5042 return hv != null && hv.IsHoisted;
5046 public override bool IsInstance {
5048 return !spec.IsStatic;
5052 public override bool IsStatic {
5054 return spec.IsStatic;
5058 public FieldSpec Spec {
5064 protected override TypeSpec DeclaringType {
5066 return spec.DeclaringType;
5070 public VariableInfo VariableInfo {
5072 return variable_info;
5078 public override string GetSignatureForError ()
5080 return TypeManager.GetFullNameSignature (spec);
5083 public bool IsMarshalByRefAccess (ResolveContext rc)
5085 // Checks possible ldflda of field access expression
5086 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5087 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5088 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5091 public void SetHasAddressTaken ()
5093 IVariableReference vr = InstanceExpression as IVariableReference;
5095 vr.SetHasAddressTaken ();
5099 public override Expression CreateExpressionTree (ResolveContext ec)
5101 Expression instance;
5102 if (InstanceExpression == null) {
5103 instance = new NullLiteral (loc);
5105 instance = InstanceExpression.CreateExpressionTree (ec);
5108 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5110 CreateTypeOfExpression ());
5112 return CreateExpressionFactoryCall (ec, "Field", args);
5115 public Expression CreateTypeOfExpression ()
5117 return new TypeOfField (spec, loc);
5120 protected override Expression DoResolve (ResolveContext ec)
5122 return DoResolve (ec, null);
5125 Expression DoResolve (ResolveContext ec, Expression rhs)
5127 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5130 if (ResolveInstanceExpression (ec, rhs)) {
5131 // Resolve the field's instance expression while flow analysis is turned
5132 // off: when accessing a field "a.b", we must check whether the field
5133 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5135 if (lvalue_instance) {
5136 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5137 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5139 Expression right_side =
5140 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5142 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5145 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5146 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5150 if (InstanceExpression == null)
5154 DoBestMemberChecks (ec, spec);
5157 var fb = spec as FixedFieldSpec;
5158 IVariableReference var = InstanceExpression as IVariableReference;
5160 if (lvalue_instance && var != null && var.VariableInfo != null) {
5161 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5165 IFixedExpression fe = InstanceExpression as IFixedExpression;
5166 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5167 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5170 if (InstanceExpression.eclass != ExprClass.Variable) {
5171 ec.Report.SymbolRelatedToPreviousError (spec);
5172 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5173 TypeManager.GetFullNameSignature (spec));
5174 } else if (var != null && var.IsHoisted) {
5175 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5178 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5182 // Set flow-analysis variable info for struct member access. It will be check later
5183 // for precise error reporting
5185 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5186 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5187 if (rhs != null && variable_info != null)
5188 variable_info.SetStructFieldAssigned (ec, Name);
5191 eclass = ExprClass.Variable;
5195 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5200 var var = fe.InstanceExpression as IVariableReference;
5202 var vi = var.VariableInfo;
5204 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5206 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5208 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5215 fe = fe.InstanceExpression as FieldExpr;
5217 } while (fe != null);
5220 static readonly int [] codes = {
5221 191, // instance, write access
5222 192, // instance, out access
5223 198, // static, write access
5224 199, // static, out access
5225 1648, // member of value instance, write access
5226 1649, // member of value instance, out access
5227 1650, // member of value static, write access
5228 1651 // member of value static, out access
5231 static readonly string [] msgs = {
5232 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5233 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5234 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5235 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5236 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5237 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5238 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5239 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5242 // The return value is always null. Returning a value simplifies calling code.
5243 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5246 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5250 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5252 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5257 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5259 Expression e = DoResolve (ec, right_side);
5264 spec.MemberDefinition.SetIsAssigned ();
5266 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5267 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5268 ec.Report.Warning (420, 1, loc,
5269 "`{0}': A volatile field references will not be treated as volatile",
5270 spec.GetSignatureForError ());
5273 if (spec.IsReadOnly) {
5274 // InitOnly fields can only be assigned in constructors or initializers
5275 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5276 return Report_AssignToReadonly (ec, right_side);
5278 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5280 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5281 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5282 return Report_AssignToReadonly (ec, right_side);
5283 // static InitOnly fields cannot be assigned-to in an instance constructor
5284 if (IsStatic && !ec.IsStatic)
5285 return Report_AssignToReadonly (ec, right_side);
5286 // instance constructors can't modify InitOnly fields of other instances of the same type
5287 if (!IsStatic && !(InstanceExpression is This))
5288 return Report_AssignToReadonly (ec, right_side);
5292 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5293 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5294 ec.Report.Warning (197, 1, loc,
5295 "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",
5296 GetSignatureForError ());
5299 eclass = ExprClass.Variable;
5303 public override int GetHashCode ()
5305 return spec.GetHashCode ();
5308 public bool IsFixed {
5311 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5313 IVariableReference variable = InstanceExpression as IVariableReference;
5314 if (variable != null)
5315 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5317 IFixedExpression fe = InstanceExpression as IFixedExpression;
5318 return fe != null && fe.IsFixed;
5322 public override bool Equals (object obj)
5324 FieldExpr fe = obj as FieldExpr;
5328 if (spec != fe.spec)
5331 if (InstanceExpression == null || fe.InstanceExpression == null)
5334 return InstanceExpression.Equals (fe.InstanceExpression);
5337 public void Emit (EmitContext ec, bool leave_copy)
5339 bool is_volatile = false;
5341 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5344 spec.MemberDefinition.SetIsUsed ();
5348 ec.Emit (OpCodes.Volatile);
5350 ec.Emit (OpCodes.Ldsfld, spec);
5353 EmitInstance (ec, false);
5355 // Optimization for build-in types
5356 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5357 ec.EmitLoadFromPtr (type);
5359 var ff = spec as FixedFieldSpec;
5361 ec.Emit (OpCodes.Ldflda, spec);
5362 ec.Emit (OpCodes.Ldflda, ff.Element);
5365 ec.Emit (OpCodes.Volatile);
5367 ec.Emit (OpCodes.Ldfld, spec);
5373 ec.Emit (OpCodes.Dup);
5375 temp = new LocalTemporary (this.Type);
5381 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5383 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5384 if (isCompound && !(source is DynamicExpressionStatement)) {
5385 if (has_await_source) {
5387 InstanceExpression = InstanceExpression.EmitToField (ec);
5394 if (has_await_source)
5395 source = source.EmitToField (ec);
5397 EmitInstance (ec, prepared);
5403 ec.Emit (OpCodes.Dup);
5405 temp = new LocalTemporary (this.Type);
5410 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5411 ec.Emit (OpCodes.Volatile);
5413 spec.MemberDefinition.SetIsAssigned ();
5416 ec.Emit (OpCodes.Stsfld, spec);
5418 ec.Emit (OpCodes.Stfld, spec);
5428 // Emits store to field with prepared values on stack
5430 public void EmitAssignFromStack (EmitContext ec)
5433 ec.Emit (OpCodes.Stsfld, spec);
5435 ec.Emit (OpCodes.Stfld, spec);
5439 public override void Emit (EmitContext ec)
5444 public override void EmitSideEffect (EmitContext ec)
5446 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5448 if (is_volatile) // || is_marshal_by_ref ())
5449 base.EmitSideEffect (ec);
5452 public void AddressOf (EmitContext ec, AddressOp mode)
5454 if ((mode & AddressOp.Store) != 0)
5455 spec.MemberDefinition.SetIsAssigned ();
5456 if ((mode & AddressOp.Load) != 0)
5457 spec.MemberDefinition.SetIsUsed ();
5460 // Handle initonly fields specially: make a copy and then
5461 // get the address of the copy.
5464 if (spec.IsReadOnly){
5466 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5478 var temp = ec.GetTemporaryLocal (type);
5479 ec.Emit (OpCodes.Stloc, temp);
5480 ec.Emit (OpCodes.Ldloca, temp);
5481 ec.FreeTemporaryLocal (temp, type);
5487 ec.Emit (OpCodes.Ldsflda, spec);
5490 EmitInstance (ec, false);
5491 ec.Emit (OpCodes.Ldflda, spec);
5495 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5497 return MakeExpression (ctx);
5500 public override SLE.Expression MakeExpression (BuilderContext ctx)
5503 return base.MakeExpression (ctx);
5505 return SLE.Expression.Field (
5506 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5507 spec.GetMetaInfo ());
5511 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5513 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5519 // Expression that evaluates to a Property.
5521 // This is not an LValue because we need to re-write the expression. We
5522 // can not take data from the stack and store it.
5524 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5526 public PropertyExpr (PropertySpec spec, Location l)
5529 best_candidate = spec;
5530 type = spec.MemberType;
5535 protected override Arguments Arguments {
5543 protected override TypeSpec DeclaringType {
5545 return best_candidate.DeclaringType;
5549 public override string Name {
5551 return best_candidate.Name;
5555 public override bool IsInstance {
5561 public override bool IsStatic {
5563 return best_candidate.IsStatic;
5567 public PropertySpec PropertyInfo {
5569 return best_candidate;
5575 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5577 return new PropertyExpr (spec, loc) {
5583 public override Expression CreateExpressionTree (ResolveContext ec)
5586 if (IsSingleDimensionalArrayLength ()) {
5587 args = new Arguments (1);
5588 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5589 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5592 args = new Arguments (2);
5593 if (InstanceExpression == null)
5594 args.Add (new Argument (new NullLiteral (loc)));
5596 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5597 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5598 return CreateExpressionFactoryCall (ec, "Property", args);
5601 public Expression CreateSetterTypeOfExpression ()
5603 return new TypeOfMethod (Setter, loc);
5606 public override string GetSignatureForError ()
5608 return best_candidate.GetSignatureForError ();
5611 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5614 return base.MakeExpression (ctx);
5616 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5620 public override SLE.Expression MakeExpression (BuilderContext ctx)
5623 return base.MakeExpression (ctx);
5625 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5629 void Error_PropertyNotValid (ResolveContext ec)
5631 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5632 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5633 GetSignatureForError ());
5636 bool IsSingleDimensionalArrayLength ()
5638 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5641 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5642 return ac != null && ac.Rank == 1;
5645 public override void Emit (EmitContext ec, bool leave_copy)
5648 // Special case: length of single dimension array property is turned into ldlen
5650 if (IsSingleDimensionalArrayLength ()) {
5651 EmitInstance (ec, false);
5652 ec.Emit (OpCodes.Ldlen);
5653 ec.Emit (OpCodes.Conv_I4);
5657 base.Emit (ec, leave_copy);
5660 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5663 LocalTemporary await_source_arg = null;
5665 if (isCompound && !(source is DynamicExpressionStatement)) {
5666 emitting_compound_assignment = true;
5669 if (has_await_arguments) {
5670 await_source_arg = new LocalTemporary (Type);
5671 await_source_arg.Store (ec);
5673 args = new Arguments (1);
5674 args.Add (new Argument (await_source_arg));
5677 temp = await_source_arg;
5680 has_await_arguments = false;
5685 ec.Emit (OpCodes.Dup);
5686 temp = new LocalTemporary (this.Type);
5691 args = new Arguments (1);
5695 temp = new LocalTemporary (this.Type);
5697 args.Add (new Argument (temp));
5699 args.Add (new Argument (source));
5703 emitting_compound_assignment = false;
5705 var call = new CallEmitter ();
5706 call.InstanceExpression = InstanceExpression;
5708 call.InstanceExpressionOnStack = true;
5710 call.Emit (ec, Setter, args, loc);
5717 if (await_source_arg != null) {
5718 await_source_arg.Release (ec);
5722 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5724 eclass = ExprClass.PropertyAccess;
5726 if (best_candidate.IsNotCSharpCompatible) {
5727 Error_PropertyNotValid (rc);
5730 ResolveInstanceExpression (rc, right_side);
5732 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5733 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5734 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5736 type = p.MemberType;
5740 DoBestMemberChecks (rc, best_candidate);
5744 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5746 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5750 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5752 // getter and setter can be different for base calls
5753 MethodSpec getter, setter;
5754 protected T best_candidate;
5756 protected LocalTemporary temp;
5757 protected bool emitting_compound_assignment;
5758 protected bool has_await_arguments;
5760 protected PropertyOrIndexerExpr (Location l)
5767 protected abstract Arguments Arguments { get; set; }
5769 public MethodSpec Getter {
5778 public MethodSpec Setter {
5789 protected override Expression DoResolve (ResolveContext ec)
5791 if (eclass == ExprClass.Unresolved) {
5792 var expr = OverloadResolve (ec, null);
5797 return expr.Resolve (ec);
5800 if (!ResolveGetter (ec))
5806 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5808 if (right_side == EmptyExpression.OutAccess) {
5809 // TODO: best_candidate can be null at this point
5810 INamedBlockVariable variable = null;
5811 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5812 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5813 best_candidate.Name);
5815 right_side.DoResolveLValue (ec, this);
5820 // if the property/indexer returns a value type, and we try to set a field in it
5821 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5822 Error_CannotModifyIntermediateExpressionValue (ec);
5825 if (eclass == ExprClass.Unresolved) {
5826 var expr = OverloadResolve (ec, right_side);
5831 return expr.ResolveLValue (ec, right_side);
5834 if (!ResolveSetter (ec))
5841 // Implements the IAssignMethod interface for assignments
5843 public virtual void Emit (EmitContext ec, bool leave_copy)
5845 var call = new CallEmitter ();
5846 call.InstanceExpression = InstanceExpression;
5847 if (has_await_arguments)
5848 call.HasAwaitArguments = true;
5850 call.DuplicateArguments = emitting_compound_assignment;
5852 call.Emit (ec, Getter, Arguments, loc);
5854 if (call.HasAwaitArguments) {
5855 InstanceExpression = call.InstanceExpression;
5856 Arguments = call.EmittedArguments;
5857 has_await_arguments = true;
5861 ec.Emit (OpCodes.Dup);
5862 temp = new LocalTemporary (Type);
5867 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5869 public override void Emit (EmitContext ec)
5874 protected override void EmitToFieldSource (EmitContext ec)
5876 has_await_arguments = true;
5880 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5882 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5884 bool ResolveGetter (ResolveContext rc)
5886 if (!best_candidate.HasGet) {
5887 if (InstanceExpression != EmptyExpression.Null) {
5888 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5889 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5890 best_candidate.GetSignatureForError ());
5893 } else if (!best_candidate.Get.IsAccessible (rc)) {
5894 if (best_candidate.HasDifferentAccessibility) {
5895 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5896 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5897 TypeManager.CSharpSignature (best_candidate));
5899 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5900 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5904 if (best_candidate.HasDifferentAccessibility) {
5905 CheckProtectedMemberAccess (rc, best_candidate.Get);
5908 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5912 bool ResolveSetter (ResolveContext rc)
5914 if (!best_candidate.HasSet) {
5915 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5916 GetSignatureForError ());
5920 if (!best_candidate.Set.IsAccessible (rc)) {
5921 if (best_candidate.HasDifferentAccessibility) {
5922 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5923 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5924 GetSignatureForError ());
5926 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5927 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5931 if (best_candidate.HasDifferentAccessibility)
5932 CheckProtectedMemberAccess (rc, best_candidate.Set);
5934 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5940 /// Fully resolved expression that evaluates to an Event
5942 public class EventExpr : MemberExpr, IAssignMethod
5944 readonly EventSpec spec;
5947 public EventExpr (EventSpec spec, Location loc)
5955 protected override TypeSpec DeclaringType {
5957 return spec.DeclaringType;
5961 public override string Name {
5967 public override bool IsInstance {
5969 return !spec.IsStatic;
5973 public override bool IsStatic {
5975 return spec.IsStatic;
5979 public MethodSpec Operator {
5987 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5990 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
5992 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5993 if (spec.BackingField != null &&
5994 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
5996 spec.MemberDefinition.SetIsUsed ();
5998 if (!ec.IsObsolete) {
5999 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6001 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6004 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6005 Error_AssignmentEventOnly (ec);
6007 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6009 InstanceExpression = null;
6011 return ml.ResolveMemberAccess (ec, left, original);
6015 return base.ResolveMemberAccess (ec, left, original);
6018 public override Expression CreateExpressionTree (ResolveContext ec)
6020 throw new NotSupportedException ("ET");
6023 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6025 if (right_side == EmptyExpression.EventAddition) {
6026 op = spec.AccessorAdd;
6027 } else if (right_side == EmptyExpression.EventSubtraction) {
6028 op = spec.AccessorRemove;
6032 Error_AssignmentEventOnly (ec);
6036 op = CandidateToBaseOverride (ec, op);
6040 protected override Expression DoResolve (ResolveContext ec)
6042 eclass = ExprClass.EventAccess;
6043 type = spec.MemberType;
6045 ResolveInstanceExpression (ec, null);
6047 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6048 Error_AssignmentEventOnly (ec);
6051 DoBestMemberChecks (ec, spec);
6055 public override void Emit (EmitContext ec)
6057 throw new NotSupportedException ();
6058 //Error_CannotAssign ();
6061 #region IAssignMethod Members
6063 public void Emit (EmitContext ec, bool leave_copy)
6065 throw new NotImplementedException ();
6068 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6070 if (leave_copy || !isCompound)
6071 throw new NotImplementedException ("EventExpr::EmitAssign");
6073 Arguments args = new Arguments (1);
6074 args.Add (new Argument (source));
6076 var call = new CallEmitter ();
6077 call.InstanceExpression = InstanceExpression;
6078 call.Emit (ec, op, args, loc);
6083 void Error_AssignmentEventOnly (ResolveContext ec)
6085 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6086 ec.Report.Error (79, loc,
6087 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6088 GetSignatureForError ());
6090 ec.Report.Error (70, loc,
6091 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6092 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6096 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6098 name = name.Substring (0, name.LastIndexOf ('.'));
6099 base.Error_CannotCallAbstractBase (rc, name);
6102 public override string GetSignatureForError ()
6104 return TypeManager.CSharpSignature (spec);
6107 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6109 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6113 public class TemporaryVariableReference : VariableReference
6115 public class Declarator : Statement
6117 TemporaryVariableReference variable;
6119 public Declarator (TemporaryVariableReference variable)
6121 this.variable = variable;
6125 protected override void DoEmit (EmitContext ec)
6127 variable.li.CreateBuilder (ec);
6130 protected override void CloneTo (CloneContext clonectx, Statement target)
6138 public TemporaryVariableReference (LocalVariable li, Location loc)
6141 this.type = li.Type;
6145 public override bool IsLockedByStatement {
6153 public LocalVariable LocalInfo {
6159 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6161 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6162 return new TemporaryVariableReference (li, loc);
6165 protected override Expression DoResolve (ResolveContext ec)
6167 eclass = ExprClass.Variable;
6170 // Don't capture temporary variables except when using
6171 // state machine redirection
6173 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
6174 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6175 storey.CaptureLocalVariable (ec, li);
6181 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6183 return Resolve (ec);
6186 public override void Emit (EmitContext ec)
6188 li.CreateBuilder (ec);
6193 public void EmitAssign (EmitContext ec, Expression source)
6195 li.CreateBuilder (ec);
6197 EmitAssign (ec, source, false, false);
6200 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6202 return li.HoistedVariant;
6205 public override bool IsFixed {
6206 get { return true; }
6209 public override bool IsRef {
6210 get { return false; }
6213 public override string Name {
6214 get { throw new NotImplementedException (); }
6217 public override void SetHasAddressTaken ()
6219 throw new NotImplementedException ();
6222 protected override ILocalVariable Variable {
6226 public override VariableInfo VariableInfo {
6227 get { return null; }
6230 public override void VerifyAssigned (ResolveContext rc)
6236 /// Handles `var' contextual keyword; var becomes a keyword only
6237 /// if no type called var exists in a variable scope
6239 class VarExpr : SimpleName
6241 public VarExpr (Location loc)
6246 public bool InferType (ResolveContext ec, Expression right_side)
6249 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6251 type = right_side.Type;
6252 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6253 ec.Report.Error (815, loc,
6254 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6255 type.GetSignatureForError ());
6259 eclass = ExprClass.Variable;
6263 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6265 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6266 base.Error_TypeOrNamespaceNotFound (ec);
6268 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");