2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Diagnostics;
16 using System.Reflection;
17 using System.Reflection.Emit;
19 using SLE = System.Linq.Expressions;
22 namespace Mono.CSharp {
25 /// The ExprClass class contains the is used to pass the
26 /// classification of an expression (value, variable, namespace,
27 /// type, method group, property access, event access, indexer access,
30 public enum ExprClass : byte {
46 /// This is used to tell Resolve in which types of expressions we're
50 public enum ResolveFlags {
51 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
54 // Returns a type expression.
57 // Returns a method group.
60 TypeParameter = 1 << 3,
62 // Mask of all the expression class flags.
63 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
67 // This is just as a hint to AddressOf of what will be done with the
70 public enum AddressOp {
77 /// This interface is implemented by variables
79 public interface IMemoryLocation {
81 /// The AddressOf method should generate code that loads
82 /// the address of the object and leaves it on the stack.
84 /// The `mode' argument is used to notify the expression
85 /// of whether this will be used to read from the address or
86 /// write to the address.
88 /// This is just a hint that can be used to provide good error
89 /// reporting, and should have no other side effects.
91 void AddressOf (EmitContext ec, AddressOp mode);
95 // An expressions resolved as a direct variable reference
97 public interface IVariableReference : IFixedExpression
99 bool IsHoisted { get; }
101 VariableInfo VariableInfo { get; }
103 void SetHasAddressTaken ();
107 // Implemented by an expression which could be or is always
110 public interface IFixedExpression
112 bool IsFixed { get; }
116 /// Base class for expressions
118 public abstract class Expression {
119 public ExprClass eclass;
120 protected TypeSpec type;
121 protected Location loc;
123 public TypeSpec Type {
125 set { type = value; }
128 public Location Location {
132 // Not nice but we have broken hierarchy.
133 public virtual void CheckMarshalByRefAccess (ResolveContext ec)
137 public virtual string GetSignatureForError ()
139 return type.GetDefinition ().GetSignatureForError ();
142 public virtual bool IsNull {
149 /// Performs semantic analysis on the Expression
153 /// The Resolve method is invoked to perform the semantic analysis
156 /// The return value is an expression (it can be the
157 /// same expression in some cases) or a new
158 /// expression that better represents this node.
160 /// For example, optimizations of Unary (LiteralInt)
161 /// would return a new LiteralInt with a negated
164 /// If there is an error during semantic analysis,
165 /// then an error should be reported (using Report)
166 /// and a null value should be returned.
168 /// There are two side effects expected from calling
169 /// Resolve(): the the field variable "eclass" should
170 /// be set to any value of the enumeration
171 /// `ExprClass' and the type variable should be set
172 /// to a valid type (this is the type of the
175 protected abstract Expression DoResolve (ResolveContext rc);
177 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
183 // This is used if the expression should be resolved as a type or namespace name.
184 // the default implementation fails.
186 public virtual FullNamedExpression ResolveAsTypeStep (IMemberContext rc, bool silent)
189 ResolveContext ec = new ResolveContext (rc);
190 Expression e = Resolve (ec);
192 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
199 // C# 3.0 introduced contextual keywords (var) which behaves like a type if type with
200 // same name exists or as a keyword when no type was found
202 public virtual TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
204 return ResolveAsTypeTerminal (rc, silent);
208 // This is used to resolve the expression as a type, a null
209 // value will be returned if the expression is not a type
212 public virtual TypeExpr ResolveAsTypeTerminal (IMemberContext ec , bool silent)
214 int errors = ec.Compiler.Report.Errors;
216 FullNamedExpression fne = ResolveAsTypeStep (ec, silent);
221 TypeExpr te = fne as TypeExpr;
223 if (!silent && errors == ec.Compiler.Report.Errors)
224 fne.Error_UnexpectedKind (ec.Compiler.Report, null, "type", loc);
228 if (!te.CheckAccessLevel (ec)) {
229 ec.Compiler.Report.SymbolRelatedToPreviousError (te.Type);
230 ErrorIsInaccesible (ec, te.Type.GetSignatureForError (), loc);
236 // Obsolete checks cannot be done when resolving base context as they
237 // require type dependecies to be set but we are just resolving them
239 if (!silent && !(ec is TypeContainer.BaseContext)) {
240 ObsoleteAttribute obsolete_attr = te.Type.GetAttributeObsolete ();
241 if (obsolete_attr != null && !ec.IsObsolete) {
242 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, ec.Compiler.Report);
249 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
251 rc.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
254 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
256 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
259 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
261 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
262 name, TypeManager.CSharpName (type));
265 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
267 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
268 "expressions can be used as a statement");
271 public void Error_InvalidExpressionStatement (BlockContext ec)
273 Error_InvalidExpressionStatement (ec.Report, loc);
276 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
278 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
281 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
283 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
286 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
288 // The error was already reported as CS1660
289 if (type == InternalType.AnonymousMethod)
293 if (TypeManager.IsGenericParameter (Type) && TypeManager.IsGenericParameter (target) && type.Name == target.Name) {
294 string sig1 = type.DeclaringMethod == null ?
295 TypeManager.CSharpName (type.DeclaringType) :
296 TypeManager.CSharpSignature (type.DeclaringMethod);
297 string sig2 = target.DeclaringMethod == null ?
298 TypeManager.CSharpName (target.DeclaringType) :
299 TypeManager.CSharpSignature (target.DeclaringMethod);
300 ec.Report.ExtraInformation (loc,
302 "The generic parameter `{0}' of `{1}' cannot be converted to the generic parameter `{0}' of `{2}' (in the previous ",
303 Type.Name, sig1, sig2));
304 } else if (Type.MetaInfo.FullName == target.MetaInfo.FullName) {
305 ec.Report.ExtraInformation (loc,
307 "The type `{0}' has two conflicting definitions, one comes from `{1}' and the other from `{2}' (in the previous ",
308 Type.MetaInfo.FullName, Type.Assembly.FullName, target.Assembly.FullName));
312 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
313 TypeManager.CSharpName (type), TypeManager.CSharpName (target));
317 ec.Report.DisableReporting ();
318 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
319 ec.Report.EnableReporting ();
322 ec.Report.Error (266, loc, "Cannot implicitly convert type `{0}' to `{1}'. " +
323 "An explicit conversion exists (are you missing a cast?)",
324 TypeManager.CSharpName (Type), TypeManager.CSharpName (target));
328 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
329 type.GetSignatureForError (), target.GetSignatureForError ());
332 public virtual void Error_VariableIsUsedBeforeItIsDeclared (Report Report, string name)
334 Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", name);
337 public void Error_TypeArgumentsCannotBeUsed (Report report, Location loc, MemberSpec member, int arity)
339 // Better message for possible generic expressions
340 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
341 report.SymbolRelatedToPreviousError (member);
342 if (member is TypeSpec)
343 member = ((TypeSpec) member).GetDefinition ();
345 member = ((MethodSpec) member).GetGenericMethodDefinition ();
347 string name = member.Kind == MemberKind.Method ? "method" : "type";
348 if (member.IsGeneric) {
349 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
350 name, member.GetSignatureForError (), member.Arity.ToString ());
352 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
353 name, member.GetSignatureForError ());
356 Error_TypeArgumentsCannotBeUsed (report, ExprClassName, GetSignatureForError (), loc);
360 public void Error_TypeArgumentsCannotBeUsed (Report report, string exprType, string name, Location loc)
362 report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
366 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
368 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
371 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
373 ec.Report.SymbolRelatedToPreviousError (type);
374 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
375 TypeManager.CSharpName (type), name);
378 protected static void Error_ValueAssignment (ResolveContext ec, Location loc)
380 ec.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
383 public ResolveFlags ExprClassToResolveFlags {
387 case ExprClass.Namespace:
388 return ResolveFlags.Type;
390 case ExprClass.MethodGroup:
391 return ResolveFlags.MethodGroup;
393 case ExprClass.TypeParameter:
394 return ResolveFlags.TypeParameter;
396 case ExprClass.Value:
397 case ExprClass.Variable:
398 case ExprClass.PropertyAccess:
399 case ExprClass.EventAccess:
400 case ExprClass.IndexerAccess:
401 return ResolveFlags.VariableOrValue;
404 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
410 /// Resolves an expression and performs semantic analysis on it.
414 /// Currently Resolve wraps DoResolve to perform sanity
415 /// checking and assertion checking on what we expect from Resolve.
417 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
419 if (eclass != ExprClass.Unresolved)
429 if ((flags & e.ExprClassToResolveFlags) == 0) {
430 e.Error_UnexpectedKind (ec, flags, loc);
435 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
438 } catch (Exception ex) {
439 if (loc.IsNull || Report.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
442 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
443 return EmptyExpression.Null;
448 /// Resolves an expression and performs semantic analysis on it.
450 public Expression Resolve (ResolveContext rc)
452 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
456 /// Resolves an expression for LValue assignment
460 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
461 /// checking and assertion checking on what we expect from Resolve
463 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
465 int errors = ec.Report.Errors;
466 bool out_access = right_side == EmptyExpression.OutAccess.Instance;
468 Expression e = DoResolveLValue (ec, right_side);
470 if (e != null && out_access && !(e is IMemoryLocation)) {
471 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
472 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
474 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
475 // e.GetType () + " " + e.GetSignatureForError ());
480 if (errors == ec.Report.Errors) {
482 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
484 Error_ValueAssignment (ec, loc);
489 if (e.eclass == ExprClass.Unresolved)
490 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
492 if ((e.type == null) && !(e is GenericTypeExpr))
493 throw new Exception ("Expression " + e + " did not set its type after Resolve");
498 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
500 Attribute.Error_AttributeArgumentNotValid (rc, loc);
504 /// Emits the code for the expression
508 /// The Emit method is invoked to generate the code
509 /// for the expression.
511 public abstract void Emit (EmitContext ec);
514 // Emit code to branch to @target if this expression is equivalent to @on_true.
515 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
516 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
517 // including the use of conditional branches. Note also that a branch MUST be emitted
518 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
521 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
524 // Emit this expression for its side effects, not for its value.
525 // The default implementation is to emit the value, and then throw it away.
526 // Subclasses can provide more efficient implementations, but those MUST be equivalent
527 public virtual void EmitSideEffect (EmitContext ec)
530 ec.Emit (OpCodes.Pop);
534 /// Protected constructor. Only derivate types should
535 /// be able to be created
538 protected Expression ()
543 /// Returns a fully formed expression after a MemberLookup
546 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
548 if (spec is EventSpec)
549 return new EventExpr ((EventSpec) spec, loc);
550 if (spec is ConstSpec)
551 return new ConstantExpr ((ConstSpec) spec, loc);
552 if (spec is FieldSpec)
553 return new FieldExpr ((FieldSpec) spec, loc);
554 if (spec is PropertySpec)
555 return new PropertyExpr ((PropertySpec) spec, loc);
556 if (spec is TypeSpec)
557 return new TypeExpression (((TypeSpec) spec), loc);
562 protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
564 var ctors = MemberCache.FindMembers (type, ConstructorInfo.ConstructorName, true);
566 rc.Report.SymbolRelatedToPreviousError (type);
568 // Report meaningful error for struct as they always have default ctor in C# context
569 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
571 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
572 type.GetSignatureForError ());
578 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
579 return r.ResolveMember<MethodSpec> (rc, ref args);
583 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
584 // `qualifier_type' or null to lookup members in the current class.
586 public static Expression MemberLookup (ResolveContext rc, TypeSpec currentType, TypeSpec queried_type, string name, int arity, bool invocableOnly, Location loc)
588 var members = MemberCache.FindMembers (queried_type, name, false);
592 MemberSpec non_method = null;
593 MemberSpec ambig_non_method = null;
594 currentType = currentType ?? InternalType.FakeInternalType;
596 for (int i = 0; i < members.Count; ++i) {
597 var member = members[i];
599 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
600 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
603 if (arity > 0 && member.Arity != arity)
606 if (rc != null && !member.IsAccessible (currentType))
610 if (member is MethodSpec)
611 return new MethodGroupExpr (members, queried_type, loc);
613 if (!Invocation.IsMemberInvocable (member))
617 if (non_method == null || member is MethodSpec) {
619 } else if (currentType != null) {
620 ambig_non_method = member;
624 if (non_method != null) {
625 if (ambig_non_method != null && rc != null) {
626 rc.Report.SymbolRelatedToPreviousError (non_method);
627 rc.Report.SymbolRelatedToPreviousError (ambig_non_method);
628 rc.Report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
629 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
632 if (non_method is MethodSpec)
633 return new MethodGroupExpr (members, queried_type, loc);
635 return ExprClassFromMemberInfo (non_method, loc);
638 if (members[0].DeclaringType.BaseType == null)
641 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
643 } while (members != null);
648 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
650 throw new NotImplementedException ();
653 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
655 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
659 /// Returns an expression that can be used to invoke operator true
660 /// on the expression if it exists.
662 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
664 return GetOperatorTrueOrFalse (ec, e, true, loc);
668 /// Returns an expression that can be used to invoke operator false
669 /// on the expression if it exists.
671 static public Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
673 return GetOperatorTrueOrFalse (ec, e, false, loc);
676 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
678 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
679 var methods = MemberCache.GetUserOperator (e.type, op, false);
683 Arguments arguments = new Arguments (1);
684 arguments.Add (new Argument (e));
686 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
687 var oper = res.ResolveOperator (ec, ref arguments);
692 return new UserOperatorCall (oper, arguments, null, loc);
695 public virtual string ExprClassName
699 case ExprClass.Unresolved:
701 case ExprClass.Value:
703 case ExprClass.Variable:
705 case ExprClass.Namespace:
709 case ExprClass.MethodGroup:
710 return "method group";
711 case ExprClass.PropertyAccess:
712 return "property access";
713 case ExprClass.EventAccess:
714 return "event access";
715 case ExprClass.IndexerAccess:
716 return "indexer access";
717 case ExprClass.Nothing:
719 case ExprClass.TypeParameter:
720 return "type parameter";
722 throw new Exception ("Should not happen");
727 /// Reports that we were expecting `expr' to be of class `expected'
729 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
731 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
734 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
738 name = mc.GetSignatureForError ();
740 name = GetSignatureForError ();
742 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
743 name, was, expected);
746 public void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
748 string [] valid = new string [4];
751 if ((flags & ResolveFlags.VariableOrValue) != 0) {
752 valid [count++] = "variable";
753 valid [count++] = "value";
756 if ((flags & ResolveFlags.Type) != 0)
757 valid [count++] = "type";
759 if ((flags & ResolveFlags.MethodGroup) != 0)
760 valid [count++] = "method group";
763 valid [count++] = "unknown";
765 StringBuilder sb = new StringBuilder (valid [0]);
766 for (int i = 1; i < count - 1; i++) {
768 sb.Append (valid [i]);
771 sb.Append ("' or `");
772 sb.Append (valid [count - 1]);
775 ec.Report.Error (119, loc,
776 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
779 public static void UnsafeError (ResolveContext ec, Location loc)
781 UnsafeError (ec.Report, loc);
784 public static void UnsafeError (Report Report, Location loc)
786 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
791 // Returns the size of type `t' if known, otherwise, 0
793 public static int GetTypeSize (TypeSpec t)
795 if (t == TypeManager.int32_type ||
796 t == TypeManager.uint32_type ||
797 t == TypeManager.float_type)
799 else if (t == TypeManager.int64_type ||
800 t == TypeManager.uint64_type ||
801 t == TypeManager.double_type)
803 else if (t == TypeManager.byte_type ||
804 t == TypeManager.sbyte_type ||
805 t == TypeManager.bool_type)
807 else if (t == TypeManager.short_type ||
808 t == TypeManager.char_type ||
809 t == TypeManager.ushort_type)
811 else if (t == TypeManager.decimal_type)
817 protected void Error_CannotCallAbstractBase (ResolveContext ec, string name)
819 ec.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
822 protected void Error_CannotModifyIntermediateExpressionValue (ResolveContext ec)
824 ec.Report.SymbolRelatedToPreviousError (type);
825 if (ec.CurrentInitializerVariable != null) {
826 ec.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
827 TypeManager.CSharpName (type), GetSignatureForError ());
829 ec.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
830 GetSignatureForError ());
835 // Converts `source' to an int, uint, long or ulong.
837 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
839 if (source.type == InternalType.Dynamic) {
840 Arguments args = new Arguments (1);
841 args.Add (new Argument (source));
842 return new DynamicConversion (TypeManager.int32_type, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
845 Expression converted;
847 using (ec.Set (ResolveContext.Options.CheckedScope)) {
848 converted = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, source.loc);
849 if (converted == null)
850 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, source.loc);
851 if (converted == null)
852 converted = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, source.loc);
853 if (converted == null)
854 converted = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, source.loc);
856 if (converted == null) {
857 source.Error_ValueCannotBeConverted (ec, source.loc, TypeManager.int32_type, false);
863 // Only positive constants are allowed at compile time
865 Constant c = converted as Constant;
866 if (c != null && c.IsNegative)
867 Error_NegativeArrayIndex (ec, source.loc);
869 // No conversion needed to array index
870 if (converted.Type == TypeManager.int32_type)
873 return new ArrayIndexCast (converted).Resolve (ec);
877 // Derived classes implement this method by cloning the fields that
878 // could become altered during the Resolve stage
880 // Only expressions that are created for the parser need to implement
883 protected virtual void CloneTo (CloneContext clonectx, Expression target)
885 throw new NotImplementedException (
887 "CloneTo not implemented for expression {0}", this.GetType ()));
891 // Clones an expression created by the parser.
893 // We only support expressions created by the parser so far, not
894 // expressions that have been resolved (many more classes would need
895 // to implement CloneTo).
897 // This infrastructure is here merely for Lambda expressions which
898 // compile the same code using different type values for the same
899 // arguments to find the correct overload
901 public Expression Clone (CloneContext clonectx)
903 Expression cloned = (Expression) MemberwiseClone ();
904 CloneTo (clonectx, cloned);
910 // Implementation of expression to expression tree conversion
912 public abstract Expression CreateExpressionTree (ResolveContext ec);
914 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
916 return CreateExpressionFactoryCall (ec, name, null, args, loc);
919 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
921 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
924 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
926 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
929 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
931 TypeExpr texpr = TypeManager.expression_type_expr;
933 TypeSpec t = TypeManager.CoreLookupType (ec.Compiler, "System.Linq.Expressions", "Expression", MemberKind.Class, true);
937 TypeManager.expression_type_expr = texpr = new TypeExpression (t, Location.Null);
944 // Implemented by all expressions which support conversion from
945 // compiler expression to invokable runtime expression. Used by
946 // dynamic C# binder.
948 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
950 throw new NotImplementedException ("MakeExpression for " + GetType ());
955 /// This is just a base class for expressions that can
956 /// appear on statements (invocations, object creation,
957 /// assignments, post/pre increment and decrement). The idea
958 /// being that they would support an extra Emition interface that
959 /// does not leave a result on the stack.
961 public abstract class ExpressionStatement : Expression {
963 public ExpressionStatement ResolveStatement (BlockContext ec)
965 Expression e = Resolve (ec);
969 ExpressionStatement es = e as ExpressionStatement;
971 Error_InvalidExpressionStatement (ec);
977 /// Requests the expression to be emitted in a `statement'
978 /// context. This means that no new value is left on the
979 /// stack after invoking this method (constrasted with
980 /// Emit that will always leave a value on the stack).
982 public abstract void EmitStatement (EmitContext ec);
984 public override void EmitSideEffect (EmitContext ec)
991 /// This kind of cast is used to encapsulate the child
992 /// whose type is child.Type into an expression that is
993 /// reported to return "return_type". This is used to encapsulate
994 /// expressions which have compatible types, but need to be dealt
995 /// at higher levels with.
997 /// For example, a "byte" expression could be encapsulated in one
998 /// of these as an "unsigned int". The type for the expression
999 /// would be "unsigned int".
1002 public abstract class TypeCast : Expression
1004 protected readonly Expression child;
1006 protected TypeCast (Expression child, TypeSpec return_type)
1008 eclass = child.eclass;
1009 loc = child.Location;
1014 public Expression Child {
1020 public override Expression CreateExpressionTree (ResolveContext ec)
1022 Arguments args = new Arguments (2);
1023 args.Add (new Argument (child.CreateExpressionTree (ec)));
1024 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
1026 if (type.IsPointer || child.Type.IsPointer)
1027 Error_PointerInsideExpressionTree (ec);
1029 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1032 protected override Expression DoResolve (ResolveContext ec)
1034 // This should never be invoked, we are born in fully
1035 // initialized state.
1040 public override void Emit (EmitContext ec)
1045 public override SLE.Expression MakeExpression (BuilderContext ctx)
1047 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1048 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1049 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1052 protected override void CloneTo (CloneContext clonectx, Expression t)
1057 public override bool IsNull {
1058 get { return child.IsNull; }
1062 public class EmptyCast : TypeCast {
1063 EmptyCast (Expression child, TypeSpec target_type)
1064 : base (child, target_type)
1068 public static Expression Create (Expression child, TypeSpec type)
1070 Constant c = child as Constant;
1072 return new EmptyConstantCast (c, type);
1074 EmptyCast e = child as EmptyCast;
1076 return new EmptyCast (e.child, type);
1078 return new EmptyCast (child, type);
1081 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1083 child.EmitBranchable (ec, label, on_true);
1086 public override void EmitSideEffect (EmitContext ec)
1088 child.EmitSideEffect (ec);
1093 // Used for predefined class library user casts (no obsolete check, etc.)
1095 public class OperatorCast : TypeCast {
1096 MethodSpec conversion_operator;
1098 public OperatorCast (Expression child, TypeSpec target_type)
1099 : this (child, target_type, false)
1103 public OperatorCast (Expression child, TypeSpec target_type, bool find_explicit)
1104 : base (child, target_type)
1106 conversion_operator = GetConversionOperator (find_explicit);
1107 if (conversion_operator == null)
1108 throw new InternalErrorException ("Outer conversion routine is out of sync");
1111 // Returns the implicit operator that converts from
1112 // 'child.Type' to our target type (type)
1113 MethodSpec GetConversionOperator (bool find_explicit)
1115 var op = find_explicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1117 var mi = MemberCache.GetUserOperator (child.Type, op, true);
1119 mi = MemberCache.GetUserOperator (type, op, true);
1122 foreach (MethodSpec oper in mi) {
1123 if (oper.ReturnType != type)
1126 if (oper.Parameters.Types [0] == child.Type)
1133 public override void Emit (EmitContext ec)
1136 ec.Emit (OpCodes.Call, conversion_operator);
1141 /// This is a numeric cast to a Decimal
1143 public class CastToDecimal : OperatorCast {
1144 public CastToDecimal (Expression child)
1145 : this (child, false)
1149 public CastToDecimal (Expression child, bool find_explicit)
1150 : base (child, TypeManager.decimal_type, find_explicit)
1156 /// This is an explicit numeric cast from a Decimal
1158 public class CastFromDecimal : TypeCast
1160 static Dictionary<TypeSpec, MethodSpec> operators;
1162 public CastFromDecimal (Expression child, TypeSpec return_type)
1163 : base (child, return_type)
1165 if (child.Type != TypeManager.decimal_type)
1166 throw new ArgumentException ("Expected decimal child " + child.Type.GetSignatureForError ());
1169 // Returns the explicit operator that converts from an
1170 // express of type System.Decimal to 'type'.
1171 public Expression Resolve ()
1173 if (operators == null) {
1174 var all_oper = MemberCache.GetUserOperator (TypeManager.decimal_type, Operator.OpType.Explicit, true);
1176 operators = new Dictionary<TypeSpec, MethodSpec> ();
1177 foreach (MethodSpec oper in all_oper) {
1178 AParametersCollection pd = oper.Parameters;
1179 if (pd.Types [0] == TypeManager.decimal_type)
1180 operators.Add (oper.ReturnType, oper);
1184 return operators.ContainsKey (type) ? this : null;
1187 public override void Emit (EmitContext ec)
1191 ec.Emit (OpCodes.Call, operators [type]);
1194 public static void Reset ()
1202 // Constant specialization of EmptyCast.
1203 // We need to special case this since an empty cast of
1204 // a constant is still a constant.
1206 public class EmptyConstantCast : Constant
1208 public Constant child;
1210 public EmptyConstantCast (Constant child, TypeSpec type)
1211 : base (child.Location)
1214 throw new ArgumentNullException ("child");
1217 this.eclass = child.eclass;
1221 public override string AsString ()
1223 return child.AsString ();
1226 public override object GetValue ()
1228 return child.GetValue ();
1231 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1233 if (child.Type == target_type)
1236 // FIXME: check that 'type' can be converted to 'target_type' first
1237 return child.ConvertExplicitly (in_checked_context, target_type);
1240 public override Expression CreateExpressionTree (ResolveContext ec)
1242 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1243 child.CreateExpressionTree (ec),
1244 new TypeOf (new TypeExpression (type, loc), loc));
1247 Error_PointerInsideExpressionTree (ec);
1249 return CreateExpressionFactoryCall (ec, "Convert", args);
1252 public override bool IsDefaultValue {
1253 get { return child.IsDefaultValue; }
1256 public override bool IsNegative {
1257 get { return child.IsNegative; }
1260 public override bool IsNull {
1261 get { return child.IsNull; }
1264 public override bool IsOneInteger {
1265 get { return child.IsOneInteger; }
1268 public override bool IsZeroInteger {
1269 get { return child.IsZeroInteger; }
1272 protected override Expression DoResolve (ResolveContext rc)
1277 public override void Emit (EmitContext ec)
1282 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1284 child.EmitBranchable (ec, label, on_true);
1286 // Only to make verifier happy
1287 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1288 ec.Emit (OpCodes.Unbox_Any, type);
1291 public override void EmitSideEffect (EmitContext ec)
1293 child.EmitSideEffect (ec);
1296 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1298 // FIXME: Do we need to check user conversions?
1299 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1301 return child.ConvertImplicitly (rc, target_type);
1306 /// This class is used to wrap literals which belong inside Enums
1308 public class EnumConstant : Constant
1310 public Constant Child;
1312 public EnumConstant (Constant child, TypeSpec enum_type)
1313 : base (child.Location)
1316 this.type = enum_type;
1319 protected EnumConstant (Location loc)
1324 protected override Expression DoResolve (ResolveContext rc)
1326 Child = Child.Resolve (rc);
1327 this.eclass = ExprClass.Value;
1331 public override void Emit (EmitContext ec)
1336 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1338 Child.EncodeAttributeValue (rc, enc, Child.Type);
1341 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1343 Child.EmitBranchable (ec, label, on_true);
1346 public override void EmitSideEffect (EmitContext ec)
1348 Child.EmitSideEffect (ec);
1351 public override string GetSignatureForError()
1353 return TypeManager.CSharpName (Type);
1356 public override object GetValue ()
1358 return Child.GetValue ();
1361 public override object GetTypedValue ()
1363 // FIXME: runtime is not ready to work with just emited enums
1364 if (!RootContext.StdLib) {
1365 return Child.GetValue ();
1369 // Small workaround for big problem
1370 // System.Enum.ToObject cannot be called on dynamic types
1371 // EnumBuilder has to be used, but we cannot use EnumBuilder
1372 // because it does not properly support generics
1374 // This works only sometimes
1376 if (type.MemberDefinition is TypeContainer)
1377 return Child.GetValue ();
1380 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1383 public override string AsString ()
1385 return Child.AsString ();
1388 public EnumConstant Increment()
1390 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1393 public override bool IsDefaultValue {
1395 return Child.IsDefaultValue;
1399 public override bool IsZeroInteger {
1400 get { return Child.IsZeroInteger; }
1403 public override bool IsNegative {
1405 return Child.IsNegative;
1409 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1411 if (Child.Type == target_type)
1414 return Child.ConvertExplicitly (in_checked_context, target_type);
1417 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec type)
1419 if (this.type == type) {
1423 if (!Convert.ImplicitStandardConversionExists (this, type)){
1427 return Child.ConvertImplicitly (rc, type);
1432 /// This kind of cast is used to encapsulate Value Types in objects.
1434 /// The effect of it is to box the value type emitted by the previous
1437 public class BoxedCast : TypeCast {
1439 public BoxedCast (Expression expr, TypeSpec target_type)
1440 : base (expr, target_type)
1442 eclass = ExprClass.Value;
1445 protected override Expression DoResolve (ResolveContext ec)
1447 // This should never be invoked, we are born in fully
1448 // initialized state.
1453 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1455 enc.Encode (child.Type);
1456 child.EncodeAttributeValue (rc, enc, child.Type);
1459 public override void Emit (EmitContext ec)
1463 ec.Emit (OpCodes.Box, child.Type);
1466 public override void EmitSideEffect (EmitContext ec)
1468 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1469 // so, we need to emit the box+pop instructions in most cases
1470 if (TypeManager.IsStruct (child.Type) &&
1471 (type == TypeManager.object_type || type == TypeManager.value_type))
1472 child.EmitSideEffect (ec);
1474 base.EmitSideEffect (ec);
1478 public class UnboxCast : TypeCast {
1479 public UnboxCast (Expression expr, TypeSpec return_type)
1480 : base (expr, return_type)
1484 protected override Expression DoResolve (ResolveContext ec)
1486 // This should never be invoked, we are born in fully
1487 // initialized state.
1492 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
1494 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
1495 ec.Report.Error (445, loc, "Cannot modify the result of an unboxing conversion");
1496 return base.DoResolveLValue (ec, right_side);
1499 public override void Emit (EmitContext ec)
1503 ec.Emit (OpCodes.Unbox_Any, type);
1508 /// This is used to perform explicit numeric conversions.
1510 /// Explicit numeric conversions might trigger exceptions in a checked
1511 /// context, so they should generate the conv.ovf opcodes instead of
1514 public class ConvCast : TypeCast {
1515 public enum Mode : byte {
1516 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1518 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1519 U2_I1, U2_U1, U2_I2, U2_CH,
1520 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1521 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1522 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1523 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1524 CH_I1, CH_U1, CH_I2,
1525 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1526 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1532 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1533 : base (child, return_type)
1538 protected override Expression DoResolve (ResolveContext ec)
1540 // This should never be invoked, we are born in fully
1541 // initialized state.
1546 public override string ToString ()
1548 return String.Format ("ConvCast ({0}, {1})", mode, child);
1551 public override void Emit (EmitContext ec)
1555 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1557 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1558 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1559 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1560 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1561 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1563 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1564 case Mode.U1_CH: /* nothing */ break;
1566 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1567 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1568 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1570 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1571 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1573 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1574 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1575 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1576 case Mode.U2_CH: /* nothing */ break;
1578 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1579 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1580 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1581 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1582 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1584 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1586 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1587 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1588 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1589 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1590 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1591 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1593 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1594 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1595 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1596 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1597 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1598 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1599 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1600 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1601 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1603 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1604 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1605 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1606 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1607 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1608 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1609 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1610 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1611 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1613 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1614 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1615 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1617 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1618 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1619 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1620 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1621 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1622 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1623 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1624 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1625 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1627 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1628 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1629 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1630 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1631 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1632 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1633 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1634 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1635 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1636 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1638 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1642 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1643 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1644 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1645 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1646 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1648 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1649 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1651 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1652 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1653 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1655 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1656 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1658 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1659 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1660 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1661 case Mode.U2_CH: /* nothing */ break;
1663 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1664 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1665 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1666 case Mode.I4_U4: /* nothing */ break;
1667 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1669 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1671 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1672 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1673 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1674 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1675 case Mode.U4_I4: /* nothing */ break;
1676 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1679 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1680 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1681 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1682 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1683 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1684 case Mode.I8_U8: /* nothing */ break;
1685 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1686 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1688 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1689 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1690 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1691 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1693 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1694 case Mode.U8_I8: /* nothing */ break;
1695 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1696 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1698 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1702 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1703 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1704 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1705 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1707 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1708 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1709 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1710 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1712 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1713 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1714 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1715 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1716 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1717 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1718 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1719 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1720 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1721 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1723 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1729 public class OpcodeCast : TypeCast {
1732 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1733 : base (child, return_type)
1738 protected override Expression DoResolve (ResolveContext ec)
1740 // This should never be invoked, we are born in fully
1741 // initialized state.
1746 public override void Emit (EmitContext ec)
1752 public TypeSpec UnderlyingType {
1753 get { return child.Type; }
1758 /// This kind of cast is used to encapsulate a child and cast it
1759 /// to the class requested
1761 public sealed class ClassCast : TypeCast {
1762 readonly bool forced;
1764 public ClassCast (Expression child, TypeSpec return_type)
1765 : base (child, return_type)
1769 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1770 : base (child, return_type)
1772 this.forced = forced;
1775 public override void Emit (EmitContext ec)
1779 bool gen = TypeManager.IsGenericParameter (child.Type);
1781 ec.Emit (OpCodes.Box, child.Type);
1783 if (type.IsGenericParameter) {
1784 ec.Emit (OpCodes.Unbox_Any, type);
1791 ec.Emit (OpCodes.Castclass, type);
1796 // Created during resolving pahse when an expression is wrapped or constantified
1797 // and original expression can be used later (e.g. for expression trees)
1799 public class ReducedExpression : Expression
1801 sealed class ReducedConstantExpression : EmptyConstantCast
1803 readonly Expression orig_expr;
1805 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1806 : base (expr, expr.Type)
1808 this.orig_expr = orig_expr;
1811 public override Constant ConvertImplicitly (ResolveContext rc, TypeSpec target_type)
1813 Constant c = base.ConvertImplicitly (rc, target_type);
1815 c = new ReducedConstantExpression (c, orig_expr);
1820 public override Expression CreateExpressionTree (ResolveContext ec)
1822 return orig_expr.CreateExpressionTree (ec);
1825 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1827 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1829 c = new ReducedConstantExpression (c, orig_expr);
1834 sealed class ReducedExpressionStatement : ExpressionStatement
1836 readonly Expression orig_expr;
1837 readonly ExpressionStatement stm;
1839 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1841 this.orig_expr = orig;
1843 this.loc = orig.Location;
1846 public override Expression CreateExpressionTree (ResolveContext ec)
1848 return orig_expr.CreateExpressionTree (ec);
1851 protected override Expression DoResolve (ResolveContext ec)
1853 eclass = stm.eclass;
1858 public override void Emit (EmitContext ec)
1863 public override void EmitStatement (EmitContext ec)
1865 stm.EmitStatement (ec);
1869 readonly Expression expr, orig_expr;
1871 private ReducedExpression (Expression expr, Expression orig_expr)
1874 this.eclass = expr.eclass;
1875 this.type = expr.Type;
1876 this.orig_expr = orig_expr;
1877 this.loc = orig_expr.Location;
1881 // Creates fully resolved expression switcher
1883 public static Constant Create (Constant expr, Expression original_expr)
1885 if (expr.eclass == ExprClass.Unresolved)
1886 throw new ArgumentException ("Unresolved expression");
1888 return new ReducedConstantExpression (expr, original_expr);
1891 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1893 return new ReducedExpressionStatement (s, orig);
1897 // Creates unresolved reduce expression. The original expression has to be
1900 public static Expression Create (Expression expr, Expression original_expr)
1902 Constant c = expr as Constant;
1904 return Create (c, original_expr);
1906 ExpressionStatement s = expr as ExpressionStatement;
1908 return Create (s, original_expr);
1910 if (expr.eclass == ExprClass.Unresolved)
1911 throw new ArgumentException ("Unresolved expression");
1913 return new ReducedExpression (expr, original_expr);
1916 public override Expression CreateExpressionTree (ResolveContext ec)
1918 return orig_expr.CreateExpressionTree (ec);
1921 protected override Expression DoResolve (ResolveContext ec)
1926 public override void Emit (EmitContext ec)
1931 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
1933 expr.EmitBranchable (ec, target, on_true);
1936 public override SLE.Expression MakeExpression (BuilderContext ctx)
1938 return orig_expr.MakeExpression (ctx);
1943 // Standard composite pattern
1945 public abstract class CompositeExpression : Expression
1949 protected CompositeExpression (Expression expr)
1952 this.loc = expr.Location;
1955 public override Expression CreateExpressionTree (ResolveContext ec)
1957 return expr.CreateExpressionTree (ec);
1960 public Expression Child {
1961 get { return expr; }
1964 protected override Expression DoResolve (ResolveContext ec)
1966 expr = expr.Resolve (ec);
1969 eclass = expr.eclass;
1975 public override void Emit (EmitContext ec)
1980 public override bool IsNull {
1981 get { return expr.IsNull; }
1986 // Base of expressions used only to narrow resolve flow
1988 public abstract class ShimExpression : Expression
1990 protected Expression expr;
1992 protected ShimExpression (Expression expr)
1997 protected override void CloneTo (CloneContext clonectx, Expression t)
2002 ShimExpression target = (ShimExpression) t;
2003 target.expr = expr.Clone (clonectx);
2006 public override Expression CreateExpressionTree (ResolveContext ec)
2008 throw new NotSupportedException ("ET");
2011 public override void Emit (EmitContext ec)
2013 throw new InternalErrorException ("Missing Resolve call");
2016 public Expression Expr {
2017 get { return expr; }
2022 // Unresolved type name expressions
2024 public abstract class ATypeNameExpression : FullNamedExpression
2027 protected TypeArguments targs;
2029 protected ATypeNameExpression (string name, Location l)
2035 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2042 protected ATypeNameExpression (string name, int arity, Location l)
2043 : this (name, new UnboundTypeArguments (arity), l)
2049 protected int Arity {
2051 return targs == null ? 0 : targs.Count;
2055 public bool HasTypeArguments {
2057 return targs != null && !targs.IsEmpty;
2061 public string Name {
2070 public TypeArguments TypeArguments {
2078 public override bool Equals (object obj)
2080 ATypeNameExpression atne = obj as ATypeNameExpression;
2081 return atne != null && atne.Name == Name &&
2082 (targs == null || targs.Equals (atne.targs));
2085 public override int GetHashCode ()
2087 return Name.GetHashCode ();
2090 // TODO: Move it to MemberCore
2091 public static string GetMemberType (MemberCore mc)
2097 if (mc is FieldBase)
2099 if (mc is MethodCore)
2101 if (mc is EnumMember)
2109 public override string GetSignatureForError ()
2111 if (targs != null) {
2112 return Name + "<" + targs.GetSignatureForError () + ">";
2118 public abstract Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly);
2122 /// SimpleName expressions are formed of a single word and only happen at the beginning
2123 /// of a dotted-name.
2125 public class SimpleName : ATypeNameExpression
2127 public SimpleName (string name, Location l)
2132 public SimpleName (string name, TypeArguments args, Location l)
2133 : base (name, args, l)
2137 public SimpleName (string name, int arity, Location l)
2138 : base (name, arity, l)
2142 public SimpleName GetMethodGroup ()
2144 return new SimpleName (Name, targs, loc);
2147 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ec)
2149 if (ec.CurrentType != null) {
2150 if (ec.CurrentMemberDefinition != null) {
2151 MemberCore mc = ec.CurrentMemberDefinition.Parent.GetDefinition (Name);
2153 Error_UnexpectedKind (ec.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2159 // TODO MemberCache: Implement
2161 string ns = ec.CurrentType.Namespace;
2162 string fullname = (ns.Length > 0) ? ns + "." + Name : Name;
2163 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
2164 var type = a.GetType (fullname);
2166 ec.Compiler.Report.SymbolRelatedToPreviousError (type);
2167 Expression.ErrorIsInaccesible (loc, TypeManager.CSharpName (type), ec.Compiler.Report);
2172 if (ec.CurrentTypeDefinition != null) {
2173 TypeSpec t = ec.CurrentTypeDefinition.LookupAnyGeneric (Name);
2175 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, t, loc);
2182 FullNamedExpression retval = ec.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), loc, true);
2183 if (retval != null) {
2184 Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc, retval.Type, Arity);
2186 var te = retval as TypeExpr;
2187 if (HasTypeArguments && te != null && !te.Type.IsGeneric)
2188 retval.Error_TypeArgumentsCannotBeUsed (ec.Compiler.Report, loc);
2190 Namespace.Error_InvalidNumberOfTypeArguments (ec.Compiler.Report, retval.Type, loc);
2195 NamespaceEntry.Error_NamespaceNotFound (loc, Name, ec.Compiler.Report);
2198 protected override Expression DoResolve (ResolveContext ec)
2200 return SimpleNameResolve (ec, null, false);
2203 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2205 return SimpleNameResolve (ec, right_side, false);
2208 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2210 int errors = ec.Compiler.Report.Errors;
2211 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, loc, /*ignore_cs0104=*/ false);
2214 if (fne.Type != null && Arity > 0) {
2215 if (HasTypeArguments) {
2216 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2217 return ct.ResolveAsTypeStep (ec, false);
2220 return new GenericOpenTypeExpr (fne.Type, loc);
2224 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2226 if (!(fne is Namespace))
2230 if (Arity == 0 && Name == "dynamic" && RootContext.Version > LanguageVersion.V_3) {
2231 if (!PredefinedAttributes.Get.Dynamic.IsDefined) {
2232 ec.Compiler.Report.Error (1980, Location,
2233 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2234 PredefinedAttributes.Get.Dynamic.GetSignatureForError ());
2237 return new DynamicTypeExpr (loc);
2243 if (silent || errors != ec.Compiler.Report.Errors)
2246 Error_TypeOrNamespaceNotFound (ec);
2250 public override Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly)
2252 int lookup_arity = Arity;
2253 bool errorMode = false;
2255 Block current_block = rc.CurrentBlock;
2259 // Stage 1: binding to local variables or parameters
2261 if (current_block != null && lookup_arity == 0) {
2262 LocalInfo vi = current_block.GetLocalInfo (Name);
2264 // TODO: pass vi in to speed things up
2265 e = new LocalVariableReference (rc.CurrentBlock, Name, loc);
2267 e = current_block.Toplevel.GetParameterReference (Name, loc);
2272 Error_TypeArgumentsCannotBeUsed (rc.Report, "variable", Name, loc);
2278 current_block.CheckInvariantMeaningInBlock (Name, this, loc);
2282 IKnownVariable ikv = current_block.Explicit.GetKnownVariable (Name);
2284 LocalInfo li = ikv as LocalInfo;
2285 // Supress CS0219 warning
2289 Error_VariableIsUsedBeforeItIsDeclared (rc.Report, Name);
2297 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2299 TypeSpec member_type = rc.CurrentType;
2300 TypeSpec current_type = member_type;
2301 for (; member_type != null; member_type = member_type.DeclaringType) {
2302 var me = MemberLookup (errorMode ? null : rc, current_type, member_type, Name, lookup_arity, invocableOnly, loc) as MemberExpr;
2307 if (me is MethodGroupExpr) {
2308 // Leave it to overload resolution to report correct error
2310 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2311 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2315 // MemberLookup does not check accessors availability, this is actually needed for properties only
2317 var pe = me as PropertyExpr;
2320 // Break as there is no other overload available anyway
2322 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (current_type))
2325 pe.Getter = pe.PropertyInfo.Get;
2327 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (current_type))
2330 pe.Setter = pe.PropertyInfo.Set;
2335 // TODO: It's used by EventExpr -> FieldExpr transformation only
2336 // TODO: Should go to MemberAccess
2337 me = me.ResolveMemberAccess (rc, null, null);
2341 me.SetTypeArguments (rc, targs);
2348 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2350 if (!invocableOnly) {
2351 e = ResolveAsTypeStep (rc, lookup_arity == 0 || !errorMode);
2357 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2361 if (RootContext.EvalMode) {
2362 var fi = Evaluator.LookupField (Name);
2364 return new FieldExpr (fi.Item1, loc);
2368 invocableOnly = false;
2373 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2375 Expression e = LookupNameExpression (ec, right_side == null, false);
2380 if (right_side != null)
2381 e = e.ResolveLValue (ec, right_side);
2385 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2391 /// Represents a namespace or a type. The name of the class was inspired by
2392 /// section 10.8.1 (Fully Qualified Names).
2394 public abstract class FullNamedExpression : Expression
2396 protected override void CloneTo (CloneContext clonectx, Expression target)
2398 // Do nothing, most unresolved type expressions cannot be
2399 // resolved to different type
2402 public override Expression CreateExpressionTree (ResolveContext ec)
2404 throw new NotSupportedException ("ET");
2407 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2412 public override void Emit (EmitContext ec)
2414 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2415 GetSignatureForError ());
2420 /// Expression that evaluates to a type
2422 public abstract class TypeExpr : FullNamedExpression {
2423 public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
2425 TypeExpr t = DoResolveAsTypeStep (ec);
2429 eclass = ExprClass.Type;
2433 protected override Expression DoResolve (ResolveContext ec)
2435 return ResolveAsTypeTerminal (ec, false);
2438 public virtual bool CheckAccessLevel (IMemberContext mc)
2440 DeclSpace c = mc.CurrentMemberDefinition as DeclSpace;
2442 c = mc.CurrentMemberDefinition.Parent;
2444 return c.CheckAccessLevel (Type);
2447 protected abstract TypeExpr DoResolveAsTypeStep (IMemberContext ec);
2449 public override bool Equals (object obj)
2451 TypeExpr tobj = obj as TypeExpr;
2455 return Type == tobj.Type;
2458 public override int GetHashCode ()
2460 return Type.GetHashCode ();
2465 /// Fully resolved Expression that already evaluated to a type
2467 public class TypeExpression : TypeExpr {
2468 public TypeExpression (TypeSpec t, Location l)
2471 eclass = ExprClass.Type;
2475 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
2480 public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
2487 /// This class denotes an expression which evaluates to a member
2488 /// of a struct or a class.
2490 public abstract class MemberExpr : Expression
2493 // An instance expression associated with this member, if it's a
2494 // non-static member
2496 public Expression InstanceExpression;
2499 /// The name of this member.
2501 public abstract string Name {
2506 // When base.member is used
2508 public bool IsBase {
2509 get { return InstanceExpression is BaseThis; }
2513 /// Whether this is an instance member.
2515 public abstract bool IsInstance {
2520 /// Whether this is a static member.
2522 public abstract bool IsStatic {
2527 protected abstract TypeSpec DeclaringType {
2532 // Converts best base candidate for virtual method starting from QueriedBaseType
2534 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2537 // Only when base.member is used and method is virtual
2543 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2544 // means for base.member access we have to find the closest match after we found best candidate
2546 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.STATIC)) != Modifiers.STATIC) {
2548 // The method could already be what we are looking for
2550 TypeSpec[] targs = null;
2551 if (method.DeclaringType != InstanceExpression.Type) {
2552 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2553 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2554 if (base_override.IsGeneric)
2555 targs = method.TypeArguments;
2557 method = base_override;
2561 // TODO: For now we do it for any hoisted call even if it's needed for
2562 // hoisted stories only but that requires a new expression wrapper
2563 if (rc.CurrentAnonymousMethod != null) {
2564 if (targs == null && method.IsGeneric) {
2565 targs = method.TypeArguments;
2566 method = method.GetGenericMethodDefinition ();
2569 if (method.Parameters.HasArglist)
2570 throw new NotImplementedException ("__arglist base call proxy");
2572 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
\r
2574 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
\r
2575 // get/set member expressions second call would fail to proxy because left expression
\r
2576 // would be of 'this' and not 'base'
\r
2577 if (rc.CurrentType.IsStruct)
\r
2578 InstanceExpression = rc.GetThis (loc);
\r
2582 method = method.MakeGenericMethod (targs);
2586 // Only base will allow this invocation to happen.
2588 if (method.IsAbstract) {
2589 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2595 protected void CheckProtectedMemberAccess<T> (ResolveContext rc, T member) where T : MemberSpec
2597 if (InstanceExpression == null)
2600 if ((member.Modifiers & Modifiers.AccessibilityMask) == Modifiers.PROTECTED && !(InstanceExpression is This)) {
2601 var ct = rc.CurrentType;
2602 var expr_type = InstanceExpression.Type;
2603 if (ct != expr_type && !TypeManager.IsSubclassOf (expr_type, ct)) {
2604 expr_type = expr_type.GetDefinition ();
2605 if (ct != expr_type && !IsSameOrBaseQualifier (ct, expr_type)) {
2606 rc.Report.SymbolRelatedToPreviousError (member);
2607 rc.Report.Error (1540, loc,
2608 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2609 member.GetSignatureForError (), expr_type.GetSignatureForError (), ct.GetSignatureForError ());
2615 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2618 type = type.GetDefinition ();
2620 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2623 type = type.DeclaringType;
2624 } while (type != null);
2629 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2631 if (InstanceExpression != null) {
2632 InstanceExpression = InstanceExpression.Resolve (rc);
2633 CheckProtectedMemberAccess (rc, member);
2636 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2637 UnsafeError (rc, loc);
2640 if (!rc.IsObsolete) {
2641 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2643 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2646 if (!(member is FieldSpec))
2647 member.MemberDefinition.SetIsUsed ();
2651 // Implements identicial simple name and type-name
2653 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2656 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2659 // 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
2660 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2662 if (left is MemberExpr || left is VariableReference) {
2663 rc.Report.DisableReporting ();
2664 Expression identical_type = rc.LookupNamespaceOrType (name.Name, 0, loc, true) as TypeExpr;
2665 rc.Report.EnableReporting ();
2666 if (identical_type != null && identical_type.Type == left.Type)
2667 return identical_type;
2673 public bool ResolveInstanceExpression (ResolveContext rc)
2676 if (InstanceExpression != null) {
2677 if (InstanceExpression is TypeExpr) {
2678 ObsoleteAttribute oa = InstanceExpression.Type.GetAttributeObsolete ();
2679 if (oa != null && !rc.IsObsolete) {
2680 AttributeTester.Report_ObsoleteMessage (oa, InstanceExpression.GetSignatureForError (), loc, rc.Report);
2683 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2684 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2685 rc.Report.Error (176, loc,
2686 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2687 GetSignatureForError ());
2691 InstanceExpression = null;
2697 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2698 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2699 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2700 rc.Report.Error (236, loc,
2701 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2702 GetSignatureForError ());
2704 rc.Report.Error (120, loc,
2705 "An object reference is required to access non-static member `{0}'",
2706 GetSignatureForError ());
2711 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2712 rc.Report.Error (38, loc,
2713 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2714 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2717 InstanceExpression = rc.GetThis (loc);
2721 var me = InstanceExpression as MemberExpr;
2723 me.ResolveInstanceExpression (rc);
2725 var fe = me as FieldExpr;
2726 if (fe != null && fe.IsMarshalByRefAccess ()) {
2727 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2728 rc.Report.Warning (1690, 1, loc,
2729 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2730 me.GetSignatureForError ());
2737 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2739 if (left != null && left.IsNull && TypeManager.IsReferenceType (left.Type)) {
2740 ec.Report.Warning (1720, 1, left.Location,
2741 "Expression will always cause a `{0}'", "System.NullReferenceException");
2744 InstanceExpression = left;
2748 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2750 if (TypeManager.IsValueType (InstanceExpression.Type)) {
2751 if (InstanceExpression is IMemoryLocation) {
2752 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.LoadStore);
2754 LocalTemporary t = new LocalTemporary (InstanceExpression.Type);
2755 InstanceExpression.Emit (ec);
2757 t.AddressOf (ec, AddressOp.Store);
2760 InstanceExpression.Emit (ec);
2762 if (prepare_for_load)
2763 ec.Emit (OpCodes.Dup);
2766 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
2770 /// Represents group of extension method candidates
2772 public class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
2774 readonly NamespaceEntry namespace_entry;
2775 public Expression ExtensionExpression;
2777 public ExtensionMethodGroupExpr (List<MethodSpec> list, NamespaceEntry n, TypeSpec extensionType, Location l)
2778 : base (list.Cast<MemberSpec>().ToList (), extensionType, l)
2780 this.namespace_entry = n;
2783 public override bool IsStatic {
2784 get { return true; }
2787 public bool IsTopLevel {
2788 get { return namespace_entry == null; }
2791 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
2793 if (arguments == null)
2794 arguments = new Arguments (1);
2796 arguments.Insert (0, new Argument (ExtensionExpression));
2797 MethodGroupExpr mg = ResolveOverloadExtensions (ec, ref arguments, ehandler ?? this, namespace_entry, loc);
2799 // Store resolved argument and restore original arguments
2801 arguments.RemoveAt (0); // Clean-up modified arguments for error reporting
2803 var me = ExtensionExpression as MemberExpr;
2805 me.ResolveInstanceExpression (ec);
2811 MethodGroupExpr ResolveOverloadExtensions (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, NamespaceEntry ns, Location loc)
2813 // Use normal resolve rules
2814 MethodGroupExpr mg = base.OverloadResolve (ec, ref arguments, ehandler, ns != null ? OverloadResolver.Restrictions.ProbingOnly : OverloadResolver.Restrictions.None);
2822 int arity = type_arguments == null ? 0 : type_arguments.Count;
2823 ExtensionMethodGroupExpr e = ns.LookupExtensionMethod (type, Name, arity, loc);
2825 return base.OverloadResolve (ec, ref arguments, ehandler, OverloadResolver.Restrictions.None);
2827 e.ExtensionExpression = ExtensionExpression;
2828 e.SetTypeArguments (ec, type_arguments);
2829 return e.ResolveOverloadExtensions (ec, ref arguments, ehandler, e.namespace_entry, loc);
2832 #region IErrorHandler Members
2834 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
2839 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
2841 rc.Report.SymbolRelatedToPreviousError (best);
2842 rc.Report.Error (1928, loc,
2843 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
2844 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
2847 rc.Report.Error (1929, loc,
2848 "Extension method instance type `{0}' cannot be converted to `{1}'",
2849 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
2855 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
2860 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
2869 /// MethodGroupExpr represents a group of method candidates which
2870 /// can be resolved to the best method overload
2872 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
2874 protected IList<MemberSpec> Methods;
2875 MethodSpec best_candidate;
2876 protected TypeArguments type_arguments;
2878 SimpleName simple_name;
2879 protected TypeSpec queried_type;
2881 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
2885 this.type = InternalType.MethodGroup;
2887 eclass = ExprClass.MethodGroup;
2888 queried_type = type;
2891 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
2892 : this (new MemberSpec[] { m }, type, loc)
2898 public MethodSpec BestCandidate {
2900 return best_candidate;
2904 protected override TypeSpec DeclaringType {
2906 return queried_type;
2910 public override bool IsInstance {
2912 if (best_candidate != null)
2913 return !best_candidate.IsStatic;
2919 public override bool IsStatic {
2921 if (best_candidate != null)
2922 return best_candidate.IsStatic;
2928 public override string Name {
2930 if (best_candidate != null)
2931 return best_candidate.Name;
2934 return Methods.First ().Name;
2941 // When best candidate is already know this factory can be used
2942 // to avoid expensive overload resolution to be called
2944 // NOTE: InstanceExpression has to be set manually
2946 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
2948 return new MethodGroupExpr (best, queriedType, loc) {
2949 best_candidate = best
2953 public override string GetSignatureForError ()
2955 if (best_candidate != null)
2956 return best_candidate.GetSignatureForError ();
2958 return Methods.First ().GetSignatureForError ();
2961 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2963 simple_name = original;
2965 return base.ResolveMemberAccess (ec, left, original);
2968 public override Expression CreateExpressionTree (ResolveContext ec)
2970 if (best_candidate == null) {
2971 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
2975 if (best_candidate.IsConditionallyExcluded (loc))
2976 ec.Report.Error (765, loc,
2977 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
2979 return new TypeOfMethod (best_candidate, loc);
2982 protected override Expression DoResolve (ResolveContext ec)
2984 this.eclass = ExprClass.MethodGroup;
2986 if (InstanceExpression != null) {
2987 InstanceExpression = InstanceExpression.Resolve (ec);
2988 if (InstanceExpression == null)
2995 public override void Emit (EmitContext ec)
2997 throw new NotSupportedException ();
3000 public void EmitCall (EmitContext ec, Arguments arguments)
3002 Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
3005 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3007 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3008 Name, TypeManager.CSharpName (target));
3011 public static bool IsExtensionMethodArgument (Expression expr)
3014 // LAMESPEC: No details about which expressions are not allowed
3016 return !(expr is BaseThis);
3020 /// Find the Applicable Function Members (7.4.2.1)
3022 /// me: Method Group expression with the members to select.
3023 /// it might contain constructors or methods (or anything
3024 /// that maps to a method).
3026 /// Arguments: ArrayList containing resolved Argument objects.
3028 /// loc: The location if we want an error to be reported, or a Null
3029 /// location for "probing" purposes.
3031 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3032 /// that is the best match of me on Arguments.
3035 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3037 // TODO: causes issues with probing mode, remove explicit Kind check
3038 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3041 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3042 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3043 r.BaseMembersProvider = this;
3046 if (cerrors != null)
3047 r.CustomErrors = cerrors;
3049 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3050 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3051 if (best_candidate == null)
3052 return r.BestCandidateIsDynamic ? this : null;
3054 if (best_candidate.Kind == MemberKind.Method) {
3055 if (InstanceExpression != null) {
3056 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3057 InstanceExpression = null;
3059 if (best_candidate.IsStatic && simple_name != null) {
3060 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3063 InstanceExpression.Resolve (ec);
3067 ResolveInstanceExpression (ec);
3068 if (InstanceExpression != null)
3069 CheckProtectedMemberAccess (ec, best_candidate);
3071 if (best_candidate.IsGeneric) {
3072 ConstraintChecker.CheckAll (ec.MemberContext, best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments,
3073 best_candidate.Constraints, loc);
3077 best_candidate = CandidateToBaseOverride (ec, best_candidate);
3081 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3083 type_arguments = ta;
3086 #region IBaseMembersProvider Members
3088 IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
3090 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3093 MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc, int arity)
3095 if (InstanceExpression == null)
3098 InstanceExpression = InstanceExpression.Resolve (rc);
3099 if (!IsExtensionMethodArgument (InstanceExpression))
3102 var emg = rc.LookupExtensionMethod (InstanceExpression.Type, Methods [0].Name, arity, loc);
3104 emg.ExtensionExpression = InstanceExpression;
3105 emg.SetTypeArguments (rc, type_arguments);
3114 public struct OverloadResolver
3117 public enum Restrictions
3121 ProbingOnly = 1 << 1,
3123 NoBaseMembers = 1 << 3
3126 public interface IBaseMembersProvider
3128 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3129 MethodGroupExpr LookupExtensionMethod (ResolveContext rc, int arity);
3132 public interface IErrorHandler
3134 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3135 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3136 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3137 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3140 sealed class NoBaseMembers : IBaseMembersProvider
3142 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3144 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3149 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc, int arity)
3155 struct AmbiguousCandidate
3157 public readonly MemberSpec Member;
3158 public readonly bool Expanded;
3160 public AmbiguousCandidate (MemberSpec member, bool expanded)
3163 Expanded = expanded;
3168 IList<MemberSpec> members;
3169 TypeArguments type_arguments;
3170 IBaseMembersProvider base_provider;
3171 IErrorHandler custom_errors;
3172 Restrictions restrictions;
3174 SessionReportPrinter lambda_conv_msgs;
3175 ReportPrinter prev_recorder;
3177 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3178 : this (members, null, restrictions, loc)
3182 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3185 if (members == null || members.Count == 0)
3186 throw new ArgumentException ("empty members set");
3188 this.members = members;
3190 type_arguments = targs;
3191 this.restrictions = restrictions;
3192 if (IsDelegateInvoke)
3193 this.restrictions |= Restrictions.NoBaseMembers;
3195 base_provider = NoBaseMembers.Instance;
3200 public IBaseMembersProvider BaseMembersProvider {
3202 return base_provider;
3205 base_provider = value;
3209 public bool BestCandidateIsDynamic { get; set; }
3211 public IErrorHandler CustomErrors {
3213 return custom_errors;
3216 custom_errors = value;
3220 TypeSpec DelegateType {
3222 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3223 throw new InternalErrorException ("Not running in delegate mode", loc);
3225 return members [0].DeclaringType;
3229 bool IsProbingOnly {
3231 return (restrictions & Restrictions.ProbingOnly) != 0;
3235 bool IsDelegateInvoke {
3237 return (restrictions & Restrictions.DelegateInvoke) != 0;
3244 // 7.4.3.3 Better conversion from expression
3245 // Returns : 1 if a->p is better,
3246 // 2 if a->q is better,
3247 // 0 if neither is better
3249 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3251 TypeSpec argument_type = a.Type;
3252 if (argument_type == InternalType.AnonymousMethod && RootContext.Version > LanguageVersion.ISO_2) {
3254 // Uwrap delegate from Expression<T>
3256 if (p.GetDefinition () == TypeManager.expression_type) {
3257 p = TypeManager.GetTypeArguments (p)[0];
3259 if (q.GetDefinition () == TypeManager.expression_type) {
3260 q = TypeManager.GetTypeArguments (q)[0];
3263 p = Delegate.GetInvokeMethod (ec.Compiler, p).ReturnType;
3264 q = Delegate.GetInvokeMethod (ec.Compiler, q).ReturnType;
3265 if (p == TypeManager.void_type && q != TypeManager.void_type)
3267 if (q == TypeManager.void_type && p != TypeManager.void_type)
3270 if (argument_type == p)
3273 if (argument_type == q)
3277 return BetterTypeConversion (ec, p, q);
3281 // 7.4.3.4 Better conversion from type
3283 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3285 if (p == null || q == null)
3286 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3288 if (p == TypeManager.int32_type) {
3289 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3291 } else if (p == TypeManager.int64_type) {
3292 if (q == TypeManager.uint64_type)
3294 } else if (p == TypeManager.sbyte_type) {
3295 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3296 q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3298 } else if (p == TypeManager.short_type) {
3299 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3300 q == TypeManager.uint64_type)
3302 } else if (p == InternalType.Dynamic) {
3303 if (q == TypeManager.object_type)
3307 if (q == TypeManager.int32_type) {
3308 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3310 } if (q == TypeManager.int64_type) {
3311 if (p == TypeManager.uint64_type)
3313 } else if (q == TypeManager.sbyte_type) {
3314 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
3315 p == TypeManager.uint32_type || p == TypeManager.uint64_type)
3317 } if (q == TypeManager.short_type) {
3318 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
3319 p == TypeManager.uint64_type)
3321 } else if (q == InternalType.Dynamic) {
3322 if (p == TypeManager.object_type)
3326 // TODO: this is expensive
3327 Expression p_tmp = new EmptyExpression (p);
3328 Expression q_tmp = new EmptyExpression (q);
3330 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3331 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3333 if (p_to_q && !q_to_p)
3336 if (q_to_p && !p_to_q)
3343 /// Determines "Better function" between candidate
3344 /// and the current best match
3347 /// Returns a boolean indicating :
3348 /// false if candidate ain't better
3349 /// true if candidate is better than the current best match
3351 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, bool candidate_params,
3352 MemberSpec best, bool best_params)
3354 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3355 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3357 bool better_at_least_one = false;
3359 int args_count = args == null ? 0 : args.Count;
3360 for (int j = 0, c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3361 Argument a = args[j];
3363 // Provided default argument value is never better
3364 if (a.IsDefaultArgument && candidate_params == best_params)
3367 TypeSpec ct = candidate_pd.Types[c_idx];
3368 TypeSpec bt = best_pd.Types[b_idx];
3370 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3371 ct = TypeManager.GetElementType (ct);
3375 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3376 bt = TypeManager.GetElementType (bt);
3380 if (TypeManager.IsEqual (ct, bt))
3384 int result = BetterExpressionConversion (ec, a, ct, bt);
3386 // for each argument, the conversion to 'ct' should be no worse than
3387 // the conversion to 'bt'.
3391 // for at least one argument, the conversion to 'ct' should be better than
3392 // the conversion to 'bt'.
3394 better_at_least_one = true;
3397 if (better_at_least_one)
3401 // This handles the case
3403 // Add (float f1, float f2, float f3);
3404 // Add (params decimal [] foo);
3406 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3407 // first candidate would've chosen as better.
3413 // The two methods have equal parameter types. Now apply tie-breaking rules
3415 if (best.IsGeneric) {
3416 if (!candidate.IsGeneric)
3418 } else if (candidate.IsGeneric) {
3423 // This handles the following cases:
3425 // Trim () is better than Trim (params char[] chars)
3426 // Concat (string s1, string s2, string s3) is better than
3427 // Concat (string s1, params string [] srest)
3428 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3430 if (!candidate_params && best_params)
3432 if (candidate_params && !best_params)
3435 int candidate_param_count = candidate_pd.Count;
3436 int best_param_count = best_pd.Count;
3438 if (candidate_param_count != best_param_count)
3439 // can only happen if (candidate_params && best_params)
3440 return candidate_param_count > best_param_count && best_pd.HasParams;
3443 // Both methods have the same number of parameters, and the parameters have equal types
3444 // Pick the "more specific" signature using rules over original (non-inflated) types
3446 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3447 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3449 bool specific_at_least_once = false;
3450 for (int j = 0; j < candidate_param_count; ++j) {
3451 var ct = candidate_def_pd.Types[j];
3452 var bt = best_def_pd.Types[j];
3455 TypeSpec specific = MoreSpecific (ct, bt);
3459 specific_at_least_once = true;
3462 if (specific_at_least_once)
3465 // FIXME: handle lifted operators
3471 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
3473 rc.Report.Error (1729, loc,
3474 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
3475 type.GetSignatureForError (), argCount.ToString ());
3479 /// Determines if the candidate method is applicable (section 14.4.2.1)
3480 /// to the given set of arguments
3481 /// A return value rates candidate method compatibility,
3482 /// 0 = the best, int.MaxValue = the worst
3484 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, ref bool params_expanded_form)
3486 AParametersCollection pd = ((IParametersMember) candidate).Parameters;
3487 int param_count = pd.Count;
3488 int optional_count = 0;
3490 if (arg_count != param_count) {
3491 for (int i = 0; i < pd.Count; ++i) {
3492 if (pd.FixedParameters[i].HasDefaultValue) {
3493 optional_count = pd.Count - i;
3498 int args_gap = System.Math.Abs (arg_count - param_count);
3499 if (optional_count != 0) {
3500 if (args_gap > optional_count)
3501 return int.MaxValue - 10000 + args_gap - optional_count;
3503 // Readjust expected number when params used
3506 if (arg_count < param_count)
3508 } else if (arg_count > param_count) {
3509 return int.MaxValue - 10000 + args_gap;
3511 } else if (arg_count != param_count) {
3513 return int.MaxValue - 10000 + args_gap;
3514 if (arg_count < param_count - 1)
3515 return int.MaxValue - 10000 + args_gap;
3518 // Initialize expanded form of a method with 1 params parameter
3519 params_expanded_form = param_count == 1 && pd.HasParams;
3521 // Resize to fit optional arguments
3522 if (optional_count != 0) {
3524 if (arguments == null) {
3525 resized = new Arguments (optional_count);
3527 resized = new Arguments (param_count);
3528 resized.AddRange (arguments);
3531 for (int i = arg_count; i < param_count; ++i)
3533 arguments = resized;
3537 if (arg_count > 0) {
3539 // Shuffle named arguments to the right positions if there are any
3541 if (arguments[arg_count - 1] is NamedArgument) {
3542 arg_count = arguments.Count;
3544 for (int i = 0; i < arg_count; ++i) {
3545 bool arg_moved = false;
3547 NamedArgument na = arguments[i] as NamedArgument;
3551 int index = pd.GetParameterIndexByName (na.Name);
3553 // Named parameter not found or already reordered
3557 // When using parameters which should not be available to the user
3558 if (index >= param_count)
3562 arguments.MarkReorderedArgument (na);
3566 Argument temp = arguments[index];
3567 arguments[index] = arguments[i];
3568 arguments[i] = temp;
3575 arg_count = arguments.Count;
3577 } else if (arguments != null) {
3578 arg_count = arguments.Count;
3582 // 1. Handle generic method using type arguments when specified or type inference
3584 var ms = candidate as MethodSpec;
3585 if (ms != null && ms.IsGeneric) {
3586 if (type_arguments != null) {
3587 var g_args_count = ms.Arity;
3588 if (g_args_count != type_arguments.Count)
3589 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
3591 candidate = ms = ms.MakeGenericMethod (type_arguments.Arguments);
3594 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
3595 // for now it simplifies things. I should probably add a callback to ResolveContext
3596 if (lambda_conv_msgs == null) {
3597 lambda_conv_msgs = new SessionReportPrinter ();
3598 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3601 int score = TypeManager.InferTypeArguments (ec, arguments, ref ms);
3602 lambda_conv_msgs.EndSession ();
3605 return score - 20000;
3611 if (type_arguments != null)
3612 return int.MaxValue - 15000;
3616 // 2. Each argument has to be implicitly convertible to method parameter
3618 Parameter.Modifier p_mod = 0;
3620 for (int i = 0; i < arg_count; i++) {
3621 Argument a = arguments[i];
3623 if (!pd.FixedParameters[i].HasDefaultValue)
3624 throw new InternalErrorException ();
3626 Expression e = pd.FixedParameters[i].DefaultValue as Constant;
3628 e = new DefaultValueExpression (new TypeExpression (pd.Types[i], loc), loc).Resolve (ec);
3630 arguments[i] = new Argument (e, Argument.AType.Default);
3634 if (p_mod != Parameter.Modifier.PARAMS) {
3635 p_mod = pd.FixedParameters[i].ModFlags & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3638 params_expanded_form = true;
3641 Parameter.Modifier a_mod = a.Modifier & ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
3643 if (!params_expanded_form)
3644 score = IsArgumentCompatible (ec, a_mod, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
3647 // It can be applicable in expanded form (when not doing exact match like for delegates)
3649 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.Covariant) == 0) {
3650 score = IsArgumentCompatible (ec, a_mod, a, 0, TypeManager.GetElementType (pt));
3652 params_expanded_form = true;
3656 if (params_expanded_form)
3658 return (arg_count - i) * 2 + score;
3662 if (arg_count != param_count)
3663 params_expanded_form = true;
3668 int IsArgumentCompatible (ResolveContext ec, Parameter.Modifier arg_mod, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
3671 // Types have to be identical when ref or out modifer is used
3673 if ((arg_mod | param_mod) != 0) {
3674 if (argument.Type != parameter) {
3675 if (argument.Type == InternalType.Dynamic)
3682 // Deploy custom error reporting for lambda methods. When probing lambda methods
3683 // keep all errors reported in separate set and once we are done and no best
3684 // candidate found, this set is used to report more details about what was wrong
3687 if (argument.Expr.Type == InternalType.AnonymousMethod) {
3688 if (lambda_conv_msgs == null) {
3689 lambda_conv_msgs = new SessionReportPrinter ();
3690 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
3694 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
3695 if (lambda_conv_msgs != null) {
3696 lambda_conv_msgs.EndSession ();
3699 if (argument.Type == InternalType.Dynamic)
3706 if (arg_mod != param_mod)
3712 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
3714 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
3716 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
3719 var ac_p = p as ArrayContainer;
3721 var ac_q = ((ArrayContainer) q);
3722 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
3723 if (specific == ac_p.Element)
3725 if (specific == ac_q.Element)
3727 } else if (TypeManager.IsGenericType (p)) {
3728 var pargs = TypeManager.GetTypeArguments (p);
3729 var qargs = TypeManager.GetTypeArguments (q);
3731 bool p_specific_at_least_once = false;
3732 bool q_specific_at_least_once = false;
3734 for (int i = 0; i < pargs.Length; i++) {
3735 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
3736 if (specific == pargs[i])
3737 p_specific_at_least_once = true;
3738 if (specific == qargs[i])
3739 q_specific_at_least_once = true;
3742 if (p_specific_at_least_once && !q_specific_at_least_once)
3744 if (!p_specific_at_least_once && q_specific_at_least_once)
3752 // Find the best method from candidate list
3754 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
3756 List<AmbiguousCandidate> ambiguous_candidates = null;
3758 MemberSpec best_candidate;
3759 Arguments best_candidate_args = null;
3760 bool best_candidate_params = false;
3761 int best_candidate_rate;
3763 int args_count = args != null ? args.Count : 0;
3764 Arguments candidate_args = args;
3765 bool error_mode = false;
3766 var current_type = rc.CurrentType;
3767 MemberSpec invocable_member = null;
3769 // Cannot return until error reporter is restored
3771 best_candidate = null;
3772 best_candidate_rate = int.MaxValue;
3774 var type_members = members;
3777 for (int i = 0; i < type_members.Count; ++i) {
3778 var member = type_members [i];
3781 // Methods in a base class are not candidates if any method in a derived
3782 // class is applicable
3784 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
3787 if (!member.IsAccessible (current_type) && !error_mode)
3790 if (!(member is IParametersMember)) {
3792 // Will use it later to report ambiguity between best method and invocable member
3794 if (Invocation.IsMemberInvocable (member))
3795 invocable_member = member;
3801 // Check if candidate is applicable
3803 bool params_expanded_form = false;
3804 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, ref params_expanded_form);
3807 // How does it score compare to others
3809 if (candidate_rate < best_candidate_rate) {
3810 best_candidate_rate = candidate_rate;
3811 best_candidate = member;
3812 best_candidate_args = candidate_args;
3813 best_candidate_params = params_expanded_form;
3814 } else if (candidate_rate == 0) {
3815 // Is new candidate better
3816 if (BetterFunction (rc, candidate_args, member, params_expanded_form, best_candidate, best_candidate_params)) {
3817 best_candidate = member;
3818 best_candidate_args = candidate_args;
3819 best_candidate_params = params_expanded_form;
3821 // It's not better but any other found later could be but we are not sure yet
3822 if (ambiguous_candidates == null)
3823 ambiguous_candidates = new List<AmbiguousCandidate> ();
3825 ambiguous_candidates.Add (new AmbiguousCandidate (member, params_expanded_form));
3829 // Restore expanded arguments
3830 if (candidate_args != args)
3831 candidate_args = args;
3833 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
3835 if (prev_recorder != null)
3836 rc.Report.SetPrinter (prev_recorder);
3839 // We've found exact match
3841 if (best_candidate_rate == 0)
3845 // Extension methods lookup when no ordinary method match was found
3848 var emg = base_provider.LookupExtensionMethod (rc, type_arguments == null ? 0 : type_arguments.Count);
3850 emg = emg.OverloadResolve (rc, ref args, custom_errors, error_mode ? Restrictions.ProbingOnly : Restrictions.None);
3852 return (T) (MemberSpec) emg.BestCandidate;
3856 // Don't run expensive error reporting mode for probing
3863 lambda_conv_msgs = null;
3868 // No best member match found, report an error
3870 if (best_candidate_rate != 0 || error_mode) {
3871 ReportOverloadError (rc, best_candidate, best_candidate_args, best_candidate_params);
3876 if (args_count != 0 && args.HasDynamic) {
3877 BestCandidateIsDynamic = true;
3881 if (ambiguous_candidates != null) {
3883 // Now check that there are no ambiguities i.e the selected method
3884 // should be better than all the others
3886 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
3887 var candidate = ambiguous_candidates [ix];
3889 if (!BetterFunction (rc, candidate_args, best_candidate, best_candidate_params, candidate.Member, candidate.Expanded)) {
3890 var ambiguous = candidate.Member;
3891 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
3892 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3893 rc.Report.SymbolRelatedToPreviousError (ambiguous);
3894 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
3895 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
3898 return (T) best_candidate;
3903 if (invocable_member != null) {
3904 rc.Report.SymbolRelatedToPreviousError (best_candidate);
3905 rc.Report.SymbolRelatedToPreviousError (invocable_member);
3906 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
3907 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
3911 // And now check if the arguments are all
3912 // compatible, perform conversions if
3913 // necessary etc. and return if everything is
3916 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_candidate_params))
3919 if (best_candidate == null)
3923 // Check ObsoleteAttribute on the best method
3925 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
3926 if (oa != null && !rc.IsObsolete)
3927 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
3929 best_candidate.MemberDefinition.SetIsUsed ();
3931 args = best_candidate_args;
3932 return (T) best_candidate;
3935 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
3937 return ResolveMember<MethodSpec> (rc, ref args);
3940 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
3941 Argument a, AParametersCollection expected_par, TypeSpec paramType)
3943 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
3946 if (a is CollectionElementInitializer.ElementInitializerArgument) {
3947 ec.Report.SymbolRelatedToPreviousError (method);
3948 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
3949 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
3950 TypeManager.CSharpSignature (method));
3953 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
3954 TypeManager.CSharpSignature (method));
3955 } else if (IsDelegateInvoke) {
3956 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
3957 DelegateType.GetSignatureForError ());
3959 ec.Report.SymbolRelatedToPreviousError (method);
3960 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
3961 method.GetSignatureForError ());
3964 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
3966 string index = (idx + 1).ToString ();
3967 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
3968 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
3969 if ((mod & Parameter.Modifier.ISBYREF) == 0)
3970 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
3971 index, Parameter.GetModifierSignature (a.Modifier));
3973 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
3974 index, Parameter.GetModifierSignature (mod));
3976 string p1 = a.GetSignatureForError ();
3977 string p2 = TypeManager.CSharpName (paramType);
3980 ec.Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
3981 ec.Report.SymbolRelatedToPreviousError (a.Expr.Type);
3982 ec.Report.SymbolRelatedToPreviousError (paramType);
3985 ec.Report.Error (1503, loc,
3986 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
3991 // We have failed to find exact match so we return error info about the closest match
3993 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, Arguments args, bool params_expanded)
3995 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
3996 int arg_count = args == null ? 0 : args.Count;
3998 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
3999 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4000 mg.Error_TypeArgumentsCannotBeUsed (rc.Report, loc, best_candidate, ta_count);
4004 if (lambda_conv_msgs != null) {
4005 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4010 // For candidates which match on parameters count report more details about incorrect arguments
4012 var pm = best_candidate as IParametersMember;
4014 int unexpanded_count = pm.Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4015 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4016 // Reject any inaccessible member
4017 if (!best_candidate.IsAccessible (rc.CurrentType)) {
4018 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4019 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4023 var ms = best_candidate as MethodSpec;
4024 if (ms != null && ms.IsGeneric && ta_count == 0) {
4025 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4028 rc.Report.Error (411, loc,
4029 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4030 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4034 VerifyArguments (rc, ref args, best_candidate, params_expanded);
4040 // We failed to find any method with correct argument count, report best candidate
4042 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4045 if (best_candidate.Kind == MemberKind.Constructor) {
4046 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4047 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4048 } else if (IsDelegateInvoke) {
4049 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4050 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4051 DelegateType.GetSignatureForError (), arg_count.ToString ());
4053 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4054 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4055 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4056 name, arg_count.ToString ());
4060 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, bool chose_params_expanded)
4062 var pm = member as IParametersMember;
4063 var pd = pm.Parameters;
4065 Parameter.Modifier p_mod = 0;
4067 int a_idx = 0, a_pos = 0;
4069 ArrayInitializer params_initializers = null;
4070 bool has_unsafe_arg = pm.MemberType.IsPointer;
4071 int arg_count = args == null ? 0 : args.Count;
4073 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4075 if (p_mod != Parameter.Modifier.PARAMS) {
4076 p_mod = pd.FixedParameters[a_idx].ModFlags;
4077 pt = pd.Types[a_idx];
4078 has_unsafe_arg |= pt.IsPointer;
4080 if (p_mod == Parameter.Modifier.PARAMS) {
4081 if (chose_params_expanded) {
4082 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4083 pt = TypeManager.GetElementType (pt);
4089 // Types have to be identical when ref or out modifer is used
4091 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4092 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4095 if (!TypeManager.IsEqual (a.Expr.Type, pt))
4101 NamedArgument na = a as NamedArgument;
4103 int name_index = pd.GetParameterIndexByName (na.Name);
4104 if (name_index < 0 || name_index >= pd.Count) {
4105 if (IsDelegateInvoke) {
4106 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4107 ec.Report.Error (1746, na.Location,
4108 "The delegate `{0}' does not contain a parameter named `{1}'",
4109 DelegateType.GetSignatureForError (), na.Name);
4111 ec.Report.SymbolRelatedToPreviousError (member);
4112 ec.Report.Error (1739, na.Location,
4113 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4114 TypeManager.CSharpSignature (member), na.Name);
4116 } else if (args[name_index] != a) {
4117 if (IsDelegateInvoke)
4118 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4120 ec.Report.SymbolRelatedToPreviousError (member);
4122 ec.Report.Error (1744, na.Location,
4123 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4128 if (a.Expr.Type == InternalType.Dynamic)
4131 if ((restrictions & Restrictions.Covariant) != 0 && !Delegate.IsTypeCovariant (a.Expr, pt)) {
4132 custom_errors.NoArgumentMatch (ec, member);
4136 Expression conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4141 // Convert params arguments to an array initializer
4143 if (params_initializers != null) {
4144 // we choose to use 'a.Expr' rather than 'conv' so that
4145 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4146 params_initializers.Add (a.Expr);
4147 args.RemoveAt (a_idx--);
4152 // Update the argument with the implicit conversion
4156 if (a_idx != arg_count) {
4157 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4162 // Fill not provided arguments required by params modifier
4164 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4166 args = new Arguments (1);
4168 pt = pd.Types[pd.Count - 1];
4169 pt = TypeManager.GetElementType (pt);
4170 has_unsafe_arg |= pt.IsPointer;
4171 params_initializers = new ArrayInitializer (0, loc);
4175 // Append an array argument with all params arguments
4177 if (params_initializers != null) {
4178 args.Add (new Argument (
4179 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4183 if (has_unsafe_arg && !ec.IsUnsafe) {
4184 Expression.UnsafeError (ec, loc);
4191 public class ConstantExpr : MemberExpr
4195 public ConstantExpr (ConstSpec constant, Location loc)
4197 this.constant = constant;
4201 public override string Name {
4202 get { throw new NotImplementedException (); }
4205 public override bool IsInstance {
4206 get { return !IsStatic; }
4209 public override bool IsStatic {
4210 get { return true; }
4213 protected override TypeSpec DeclaringType {
4214 get { return constant.DeclaringType; }
4217 public override Expression CreateExpressionTree (ResolveContext ec)
4219 throw new NotSupportedException ("ET");
4222 protected override Expression DoResolve (ResolveContext rc)
4224 ResolveInstanceExpression (rc);
4225 DoBestMemberChecks (rc, constant);
4227 var c = constant.GetConstant (rc);
4229 // Creates reference expression to the constant value
4230 return Constant.CreateConstant (rc, constant.MemberType, c.GetValue (), loc);
4233 public override void Emit (EmitContext ec)
4235 throw new NotSupportedException ();
4238 public override string GetSignatureForError ()
4240 return constant.GetSignatureForError ();
4243 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4245 Error_TypeArgumentsCannotBeUsed (ec.Report, "constant", GetSignatureForError (), loc);
4250 /// Fully resolved expression that evaluates to a Field
4252 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
4253 protected FieldSpec spec;
4254 VariableInfo variable_info;
4256 LocalTemporary temp;
4259 protected FieldExpr (Location l)
4264 public FieldExpr (FieldSpec spec, Location loc)
4269 type = spec.MemberType;
4272 public FieldExpr (FieldBase fi, Location l)
4279 public override string Name {
4285 public bool IsHoisted {
4287 IVariableReference hv = InstanceExpression as IVariableReference;
4288 return hv != null && hv.IsHoisted;
4292 public override bool IsInstance {
4294 return !spec.IsStatic;
4298 public override bool IsStatic {
4300 return spec.IsStatic;
4304 public FieldSpec Spec {
4310 protected override TypeSpec DeclaringType {
4312 return spec.DeclaringType;
4316 public VariableInfo VariableInfo {
4318 return variable_info;
4324 public override string GetSignatureForError ()
4326 return TypeManager.GetFullNameSignature (spec);
4329 public bool IsMarshalByRefAccess ()
4331 // Checks possible ldflda of field access expression
4332 return !spec.IsStatic && TypeManager.IsValueType (spec.MemberType) &&
4333 TypeManager.IsSubclassOf (spec.DeclaringType, TypeManager.mbr_type) &&
4334 !(InstanceExpression is This);
4337 public void SetHasAddressTaken ()
4339 IVariableReference vr = InstanceExpression as IVariableReference;
4341 vr.SetHasAddressTaken ();
4344 public override Expression CreateExpressionTree (ResolveContext ec)
4346 Expression instance;
4347 if (InstanceExpression == null) {
4348 instance = new NullLiteral (loc);
4350 instance = InstanceExpression.CreateExpressionTree (ec);
4353 Arguments args = Arguments.CreateForExpressionTree (ec, null,
4355 CreateTypeOfExpression ());
4357 return CreateExpressionFactoryCall (ec, "Field", args);
4360 public Expression CreateTypeOfExpression ()
4362 return new TypeOfField (spec, loc);
4365 protected override Expression DoResolve (ResolveContext ec)
4367 return DoResolve (ec, false, false);
4370 Expression DoResolve (ResolveContext ec, bool lvalue_instance, bool out_access)
4372 if (ResolveInstanceExpression (ec)) {
4373 // Resolve the field's instance expression while flow analysis is turned
4374 // off: when accessing a field "a.b", we must check whether the field
4375 // "a.b" is initialized, not whether the whole struct "a" is initialized.
4377 if (lvalue_instance) {
4378 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4379 Expression right_side =
4380 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
4382 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
4385 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
4386 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
4390 if (InstanceExpression == null)
4393 using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
4394 InstanceExpression.CheckMarshalByRefAccess (ec);
4398 DoBestMemberChecks (ec, spec);
4400 var fb = spec as FixedFieldSpec;
4401 IVariableReference var = InstanceExpression as IVariableReference;
4403 if (lvalue_instance && var != null && var.VariableInfo != null) {
4404 var.VariableInfo.SetFieldAssigned (ec, Name);
4408 IFixedExpression fe = InstanceExpression as IFixedExpression;
4409 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
4410 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
4413 if (InstanceExpression.eclass != ExprClass.Variable) {
4414 ec.Report.SymbolRelatedToPreviousError (spec);
4415 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
4416 TypeManager.GetFullNameSignature (spec));
4417 } else if (var != null && var.IsHoisted) {
4418 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
4421 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
4424 eclass = ExprClass.Variable;
4426 // If the instance expression is a local variable or parameter.
4427 if (var == null || var.VariableInfo == null)
4430 VariableInfo vi = var.VariableInfo;
4431 if (!vi.IsFieldAssigned (ec, Name, loc))
4434 variable_info = vi.GetSubStruct (Name);
4438 static readonly int [] codes = {
4439 191, // instance, write access
4440 192, // instance, out access
4441 198, // static, write access
4442 199, // static, out access
4443 1648, // member of value instance, write access
4444 1649, // member of value instance, out access
4445 1650, // member of value static, write access
4446 1651 // member of value static, out access
4449 static readonly string [] msgs = {
4450 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
4451 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4452 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4453 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
4454 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
4455 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
4456 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
4457 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
4460 // The return value is always null. Returning a value simplifies calling code.
4461 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
4464 if (right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess)
4468 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
4470 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
4475 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4477 bool lvalue_instance = IsInstance && spec.DeclaringType.IsStruct;
4478 bool out_access = right_side == EmptyExpression.OutAccess.Instance || right_side == EmptyExpression.LValueMemberOutAccess;
4480 Expression e = DoResolve (ec, lvalue_instance, out_access);
4485 spec.MemberDefinition.SetIsAssigned ();
4487 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess.Instance) &&
4488 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
4489 ec.Report.Warning (420, 1, loc,
4490 "`{0}': A volatile field references will not be treated as volatile",
4491 spec.GetSignatureForError ());
4494 if (spec.IsReadOnly) {
4495 // InitOnly fields can only be assigned in constructors or initializers
4496 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
4497 return Report_AssignToReadonly (ec, right_side);
4499 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
4501 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
4502 if (!TypeManager.IsEqual (ec.CurrentMemberDefinition.Parent.Definition, spec.DeclaringType.GetDefinition ()))
4503 return Report_AssignToReadonly (ec, right_side);
4504 // static InitOnly fields cannot be assigned-to in an instance constructor
4505 if (IsStatic && !ec.IsStatic)
4506 return Report_AssignToReadonly (ec, right_side);
4507 // instance constructors can't modify InitOnly fields of other instances of the same type
4508 if (!IsStatic && !(InstanceExpression is This))
4509 return Report_AssignToReadonly (ec, right_side);
4513 if (right_side == EmptyExpression.OutAccess.Instance &&
4514 !IsStatic && !(InstanceExpression is This) && TypeManager.mbr_type != null && TypeManager.IsSubclassOf (spec.DeclaringType, TypeManager.mbr_type)) {
4515 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
4516 ec.Report.Warning (197, 1, loc,
4517 "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",
4518 GetSignatureForError ());
4521 eclass = ExprClass.Variable;
4525 public override int GetHashCode ()
4527 return spec.GetHashCode ();
4530 public bool IsFixed {
4533 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
4535 IVariableReference variable = InstanceExpression as IVariableReference;
4536 if (variable != null)
4537 return InstanceExpression.Type.IsStruct && variable.IsFixed;
4539 IFixedExpression fe = InstanceExpression as IFixedExpression;
4540 return fe != null && fe.IsFixed;
4544 public override bool Equals (object obj)
4546 FieldExpr fe = obj as FieldExpr;
4550 if (spec != fe.spec)
4553 if (InstanceExpression == null || fe.InstanceExpression == null)
4556 return InstanceExpression.Equals (fe.InstanceExpression);
4559 public void Emit (EmitContext ec, bool leave_copy)
4561 bool is_volatile = false;
4563 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4566 spec.MemberDefinition.SetIsUsed ();
4570 ec.Emit (OpCodes.Volatile);
4572 ec.Emit (OpCodes.Ldsfld, spec);
4575 EmitInstance (ec, false);
4577 // Optimization for build-in types
4578 if (TypeManager.IsStruct (type) && TypeManager.IsEqual (type, ec.MemberContext.CurrentType) && TypeManager.IsEqual (InstanceExpression.Type, type)) {
4579 ec.EmitLoadFromPtr (type);
4581 var ff = spec as FixedFieldSpec;
4583 ec.Emit (OpCodes.Ldflda, spec);
4584 ec.Emit (OpCodes.Ldflda, ff.Element);
4587 ec.Emit (OpCodes.Volatile);
4589 ec.Emit (OpCodes.Ldfld, spec);
4595 ec.Emit (OpCodes.Dup);
4597 temp = new LocalTemporary (this.Type);
4603 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4605 prepared = prepare_for_load;
4607 EmitInstance (ec, prepared);
4611 ec.Emit (OpCodes.Dup);
4613 temp = new LocalTemporary (this.Type);
4618 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
4619 ec.Emit (OpCodes.Volatile);
4621 spec.MemberDefinition.SetIsAssigned ();
4624 ec.Emit (OpCodes.Stsfld, spec);
4626 ec.Emit (OpCodes.Stfld, spec);
4635 public override void Emit (EmitContext ec)
4640 public override void EmitSideEffect (EmitContext ec)
4642 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
4644 if (is_volatile) // || is_marshal_by_ref ())
4645 base.EmitSideEffect (ec);
4648 public override void Error_VariableIsUsedBeforeItIsDeclared (Report r, string name)
4651 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the field `{1}'",
4652 name, GetSignatureForError ());
4655 public void AddressOf (EmitContext ec, AddressOp mode)
4657 if ((mode & AddressOp.Store) != 0)
4658 spec.MemberDefinition.SetIsAssigned ();
4659 if ((mode & AddressOp.Load) != 0)
4660 spec.MemberDefinition.SetIsUsed ();
4663 // Handle initonly fields specially: make a copy and then
4664 // get the address of the copy.
4667 if (spec.IsReadOnly){
4669 if (ec.HasSet (EmitContext.Options.ConstructorScope)){
4682 local = ec.DeclareLocal (type, false);
4683 ec.Emit (OpCodes.Stloc, local);
4684 ec.Emit (OpCodes.Ldloca, local);
4690 ec.Emit (OpCodes.Ldsflda, spec);
4693 EmitInstance (ec, false);
4694 ec.Emit (OpCodes.Ldflda, spec);
4698 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4700 return MakeExpression (ctx);
4703 public override SLE.Expression MakeExpression (BuilderContext ctx)
4705 return SLE.Expression.Field (InstanceExpression.MakeExpression (ctx), spec.GetMetaInfo ());
4708 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4710 Error_TypeArgumentsCannotBeUsed (ec.Report, "field", GetSignatureForError (), loc);
4716 /// Expression that evaluates to a Property. The Assign class
4717 /// might set the `Value' expression if we are in an assignment.
4719 /// This is not an LValue because we need to re-write the expression, we
4720 /// can not take data from the stack and store it.
4722 class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
4724 public PropertyExpr (PropertySpec spec, Location l)
4727 best_candidate = spec;
4728 type = spec.MemberType;
4733 protected override TypeSpec DeclaringType {
4735 return best_candidate.DeclaringType;
4739 public override string Name {
4741 return best_candidate.Name;
4745 public override bool IsInstance {
4751 public override bool IsStatic {
4753 return best_candidate.IsStatic;
4757 public PropertySpec PropertyInfo {
4759 return best_candidate;
4765 public override Expression CreateExpressionTree (ResolveContext ec)
4768 if (IsSingleDimensionalArrayLength ()) {
4769 args = new Arguments (1);
4770 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4771 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
4774 args = new Arguments (2);
4775 if (InstanceExpression == null)
4776 args.Add (new Argument (new NullLiteral (loc)));
4778 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
4779 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
4780 return CreateExpressionFactoryCall (ec, "Property", args);
4783 public Expression CreateSetterTypeOfExpression ()
4785 return new TypeOfMethod (Setter, loc);
4788 public override string GetSignatureForError ()
4790 return best_candidate.GetSignatureForError ();
4793 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
4795 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
4798 public override SLE.Expression MakeExpression (BuilderContext ctx)
4800 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
4803 void Error_PropertyNotValid (ResolveContext ec)
4805 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4806 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
4807 GetSignatureForError ());
4810 bool IsSingleDimensionalArrayLength ()
4812 if (best_candidate.DeclaringType != TypeManager.array_type || !best_candidate.HasGet || Name != "Length")
4815 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
4816 return ac != null && ac.Rank == 1;
4819 public override void Emit (EmitContext ec, bool leave_copy)
4822 // Special case: length of single dimension array property is turned into ldlen
4824 if (IsSingleDimensionalArrayLength ()) {
4826 EmitInstance (ec, false);
4827 ec.Emit (OpCodes.Ldlen);
4828 ec.Emit (OpCodes.Conv_I4);
4832 Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
4835 ec.Emit (OpCodes.Dup);
4837 temp = new LocalTemporary (this.Type);
4843 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4845 Expression my_source = source;
4847 if (prepare_for_load) {
4852 ec.Emit (OpCodes.Dup);
4854 temp = new LocalTemporary (this.Type);
4858 } else if (leave_copy) {
4860 temp = new LocalTemporary (this.Type);
4865 Arguments args = new Arguments (1);
4866 args.Add (new Argument (my_source));
4868 Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
4876 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
4878 eclass = ExprClass.PropertyAccess;
4880 if (best_candidate.IsNotRealProperty) {
4881 Error_PropertyNotValid (rc);
4884 if (ResolveInstanceExpression (rc)) {
4885 if (right_side != null && best_candidate.DeclaringType.IsStruct)
4886 InstanceExpression.DoResolveLValue (rc, EmptyExpression.LValueMemberAccess);
4889 DoBestMemberChecks (rc, best_candidate);
4893 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4895 Error_TypeArgumentsCannotBeUsed (ec.Report, "property", GetSignatureForError (), loc);
4899 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
4901 // getter and setter can be different for base calls
4902 MethodSpec getter, setter;
4903 protected T best_candidate;
4905 protected LocalTemporary temp;
4906 protected bool prepared;
4908 protected PropertyOrIndexerExpr (Location l)
4915 public MethodSpec Getter {
4924 public MethodSpec Setter {
4935 protected override Expression DoResolve (ResolveContext ec)
4937 if (eclass == ExprClass.Unresolved) {
4938 var expr = OverloadResolve (ec, null);
4942 if (InstanceExpression != null)
4943 InstanceExpression.CheckMarshalByRefAccess (ec);
4946 return expr.Resolve (ec);
4949 if (!ResolveGetter (ec))
4955 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
4957 if (right_side == EmptyExpression.OutAccess.Instance) {
4958 // TODO: best_candidate can be null at this point
4959 if (best_candidate != null && ec.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
4960 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
4961 best_candidate.Name);
4963 right_side.DoResolveLValue (ec, this);
4968 // if the property/indexer returns a value type, and we try to set a field in it
4969 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
4970 Error_CannotModifyIntermediateExpressionValue (ec);
4973 if (eclass == ExprClass.Unresolved) {
4974 var expr = OverloadResolve (ec, right_side);
4979 return expr.ResolveLValue (ec, right_side);
4982 if (!ResolveSetter (ec))
4989 // Implements the IAssignMethod interface for assignments
4991 public abstract void Emit (EmitContext ec, bool leave_copy);
4992 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
4994 public override void Emit (EmitContext ec)
4999 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5001 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5003 bool ResolveGetter (ResolveContext rc)
5005 if (!best_candidate.HasGet) {
5006 if (InstanceExpression != EmptyExpression.Null) {
5007 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5008 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5009 best_candidate.GetSignatureForError ());
5012 } else if (!best_candidate.Get.IsAccessible (rc.CurrentType)) {
5013 if (best_candidate.HasDifferentAccessibility) {
5014 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5015 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5016 TypeManager.CSharpSignature (best_candidate));
5018 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5019 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5023 if (best_candidate.HasDifferentAccessibility) {
5024 CheckProtectedMemberAccess (rc, best_candidate.Get);
5027 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5031 bool ResolveSetter (ResolveContext rc)
5033 if (!best_candidate.HasSet) {
5034 if (rc.CurrentBlock.Toplevel.GetParameterReference (best_candidate.Name, loc) is MemberAccess) {
5035 rc.Report.Error (1947, loc, "A range variable `{0}' cannot be assigned to. Consider using `let' clause to store the value",
5036 best_candidate.Name);
5038 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5039 GetSignatureForError ());
5044 if (!best_candidate.Set.IsAccessible (rc.CurrentType)) {
5045 if (best_candidate.HasDifferentAccessibility) {
5046 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5047 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5048 GetSignatureForError ());
5050 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5051 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5055 if (best_candidate.HasDifferentAccessibility)
5056 CheckProtectedMemberAccess (rc, best_candidate.Set);
5058 setter = CandidateToBaseOverride (rc, best_candidate.Set);
5064 /// Fully resolved expression that evaluates to an Event
5066 public class EventExpr : MemberExpr
5068 readonly EventSpec spec;
5070 public EventExpr (EventSpec spec, Location loc)
5076 public override string Name {
5082 public override bool IsInstance {
5084 return !spec.IsStatic;
5088 public override bool IsStatic {
5090 return spec.IsStatic;
5094 protected override TypeSpec DeclaringType {
5096 return spec.DeclaringType;
5100 public void Error_AssignmentEventOnly (ResolveContext ec)
5102 ec.Report.Error (79, loc, "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
5103 GetSignatureForError ());
5106 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
5109 // If the event is local to this class, we transform ourselves into a FieldExpr
5112 if (spec.DeclaringType == ec.CurrentType ||
5113 TypeManager.IsNestedChildOf(ec.CurrentType, spec.DeclaringType)) {
5115 // TODO: Breaks dynamic binder as currect context fields are imported and not compiled
5116 // EventField mi = spec.MemberDefinition as EventField;
5118 if (spec.BackingField != null) {
5119 spec.MemberDefinition.SetIsUsed ();
5121 if (!ec.IsObsolete) {
5122 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
5124 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
5127 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0 && !ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5128 Error_AssignmentEventOnly (ec);
5130 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
5132 InstanceExpression = null;
5134 return ml.ResolveMemberAccess (ec, left, original);
5138 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope))
5139 Error_AssignmentEventOnly (ec);
5141 return base.ResolveMemberAccess (ec, left, original);
5144 public override Expression CreateExpressionTree (ResolveContext ec)
5146 throw new NotSupportedException ("ET");
5149 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5151 // contexts where an LValue is valid have already devolved to FieldExprs
5152 Error_CannotAssign (ec);
5156 protected override Expression DoResolve (ResolveContext ec)
5158 eclass = ExprClass.EventAccess;
5159 type = spec.MemberType;
5161 if (!spec.IsAccessible (ec.CurrentType)) {
5162 ec.Report.SymbolRelatedToPreviousError (spec);
5163 ErrorIsInaccesible (loc, TypeManager.CSharpSignature (spec), ec.Report);
5166 if (IsBase && spec.IsAbstract) {
5167 Error_CannotCallAbstractBase (ec, GetSignatureForError ());
5170 ResolveInstanceExpression (ec);
5172 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
5173 Error_CannotAssign (ec);
5176 DoBestMemberChecks (ec, spec);
5180 public override void Emit (EmitContext ec)
5182 throw new NotSupportedException ();
5183 //Error_CannotAssign ();
5186 public void Error_CannotAssign (ResolveContext ec)
5188 ec.Report.Error (70, loc,
5189 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
5190 GetSignatureForError (), TypeManager.CSharpName (spec.DeclaringType));
5193 public override string GetSignatureForError ()
5195 return TypeManager.CSharpSignature (spec);
5198 public void EmitAddOrRemove (EmitContext ec, bool is_add, Expression source)
5200 Arguments args = new Arguments (1);
5201 args.Add (new Argument (source));
5202 Invocation.EmitCall (ec, InstanceExpression, is_add ? spec.AccessorAdd : spec.AccessorRemove, args, loc);
5205 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5207 Error_TypeArgumentsCannotBeUsed (ec.Report, "event", GetSignatureForError (), loc);
5211 public class TemporaryVariable : VariableReference
5215 public TemporaryVariable (TypeSpec type, Location loc)
5221 public override Expression CreateExpressionTree (ResolveContext ec)
5223 throw new NotSupportedException ("ET");
5226 protected override Expression DoResolve (ResolveContext ec)
5228 eclass = ExprClass.Variable;
5230 TypeExpr te = new TypeExpression (type, loc);
5231 li = ec.CurrentBlock.AddTemporaryVariable (te, loc);
5232 if (!li.Resolve (ec))
5236 // Don't capture temporary variables except when using
5237 // iterator redirection
5239 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
5240 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
5241 storey.CaptureLocalVariable (ec, li);
5247 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5249 return Resolve (ec);
5252 public override void Emit (EmitContext ec)
5257 public void EmitAssign (EmitContext ec, Expression source)
5259 EmitAssign (ec, source, false, false);
5262 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
5264 return li.HoistedVariant;
5267 public override bool IsFixed {
5268 get { return true; }
5271 public override bool IsRef {
5272 get { return false; }
5275 public override string Name {
5276 get { throw new NotImplementedException (); }
5279 public override void SetHasAddressTaken ()
5281 throw new NotImplementedException ();
5284 protected override ILocalVariable Variable {
5288 public override VariableInfo VariableInfo {
5289 get { throw new NotImplementedException (); }
5294 /// Handles `var' contextual keyword; var becomes a keyword only
5295 /// if no type called var exists in a variable scope
5297 class VarExpr : SimpleName
5299 // Used for error reporting only
5300 int initializers_count;
5302 public VarExpr (Location loc)
5305 initializers_count = 1;
5308 public int VariableInitializersCount {
5310 this.initializers_count = value;
5314 public bool InferType (ResolveContext ec, Expression right_side)
5317 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
5319 type = right_side.Type;
5320 if (type == TypeManager.null_type || type == TypeManager.void_type || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
5321 ec.Report.Error (815, loc,
5322 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
5323 type.GetSignatureForError ());
5327 eclass = ExprClass.Variable;
5331 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
5333 if (RootContext.Version < LanguageVersion.V_3)
5334 base.Error_TypeOrNamespaceNotFound (ec);
5336 ec.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");
5339 public override TypeExpr ResolveAsContextualType (IMemberContext rc, bool silent)
5341 TypeExpr te = base.ResolveAsContextualType (rc, true);
5345 if (RootContext.Version < LanguageVersion.V_3)
5346 rc.Compiler.Report.FeatureIsNotAvailable (loc, "implicitly typed local variable");
5348 if (initializers_count == 1)
5351 if (initializers_count > 1) {
5352 rc.Compiler.Report.Error (819, loc, "An implicitly typed local variable declaration cannot include multiple declarators");
5353 initializers_count = 1;
5357 if (initializers_count == 0) {
5358 initializers_count = 1;
5359 rc.Compiler.Report.Error (818, loc, "An implicitly typed local variable declarator must include an initializer");