2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@seznam.cz)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
122 /// Base class for expressions
124 public abstract class Expression {
125 public ExprClass eclass;
126 protected TypeSpec type;
127 protected Location loc;
129 public TypeSpec Type {
131 set { type = value; }
134 public virtual bool IsSideEffectFree {
140 public Location Location {
144 public virtual bool IsNull {
151 // Returns true when the expression during Emit phase breaks stack
152 // by using await expression
154 public virtual bool ContainsEmitWithAwait ()
160 /// Performs semantic analysis on the Expression
164 /// The Resolve method is invoked to perform the semantic analysis
167 /// The return value is an expression (it can be the
168 /// same expression in some cases) or a new
169 /// expression that better represents this node.
171 /// For example, optimizations of Unary (LiteralInt)
172 /// would return a new LiteralInt with a negated
175 /// If there is an error during semantic analysis,
176 /// then an error should be reported (using Report)
177 /// and a null value should be returned.
179 /// There are two side effects expected from calling
180 /// Resolve(): the the field variable "eclass" should
181 /// be set to any value of the enumeration
182 /// `ExprClass' and the type variable should be set
183 /// to a valid type (this is the type of the
186 protected abstract Expression DoResolve (ResolveContext rc);
188 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
194 // This is used if the expression should be resolved as a type or namespace name.
195 // the default implementation fails.
197 public virtual TypeSpec ResolveAsType (IMemberContext mc)
199 ResolveContext ec = new ResolveContext (mc);
200 Expression e = Resolve (ec);
202 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
207 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
209 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
212 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
214 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
217 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
219 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
220 name, TypeManager.CSharpName (type));
223 public static void Error_InvalidExpressionStatement (Report Report, Location loc)
225 Report.Error (201, loc, "Only assignment, call, increment, decrement, and new object " +
226 "expressions can be used as a statement");
229 public void Error_InvalidExpressionStatement (BlockContext ec)
231 Error_InvalidExpressionStatement (ec.Report, loc);
234 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
236 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
239 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
241 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
244 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
246 // The error was already reported as CS1660
247 if (type == InternalType.AnonymousMethod)
250 string from_type = type.GetSignatureForError ();
251 string to_type = target.GetSignatureForError ();
252 if (from_type == to_type) {
253 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
254 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
258 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
263 ec.Report.DisableReporting ();
264 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
265 ec.Report.EnableReporting ();
268 ec.Report.Error (266, loc,
269 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
272 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
277 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
279 // Better message for possible generic expressions
280 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
281 var report = context.Module.Compiler.Report;
282 report.SymbolRelatedToPreviousError (member);
283 if (member is TypeSpec)
284 member = ((TypeSpec) member).GetDefinition ();
286 member = ((MethodSpec) member).GetGenericMethodDefinition ();
288 string name = member.Kind == MemberKind.Method ? "method" : "type";
289 if (member.IsGeneric) {
290 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
291 name, member.GetSignatureForError (), member.Arity.ToString ());
293 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
294 name, member.GetSignatureForError ());
297 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
301 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
303 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
307 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
309 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
312 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
314 ec.Report.SymbolRelatedToPreviousError (type);
315 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
316 TypeManager.CSharpName (type), name);
319 public void Error_ValueAssignment (ResolveContext rc, Expression rhs)
321 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
322 rc.Report.SymbolRelatedToPreviousError (type);
323 if (rc.CurrentInitializerVariable != null) {
324 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
325 type.GetSignatureForError (), GetSignatureForError ());
327 rc.Report.Error (1612, loc, "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
328 GetSignatureForError ());
331 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
335 protected void Error_VoidPointerOperation (ResolveContext rc)
337 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
340 public ResolveFlags ExprClassToResolveFlags {
344 case ExprClass.Namespace:
345 return ResolveFlags.Type;
347 case ExprClass.MethodGroup:
348 return ResolveFlags.MethodGroup;
350 case ExprClass.TypeParameter:
351 return ResolveFlags.TypeParameter;
353 case ExprClass.Value:
354 case ExprClass.Variable:
355 case ExprClass.PropertyAccess:
356 case ExprClass.EventAccess:
357 case ExprClass.IndexerAccess:
358 return ResolveFlags.VariableOrValue;
361 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
366 public virtual string GetSignatureForError ()
368 return type.GetDefinition ().GetSignatureForError ();
372 /// Resolves an expression and performs semantic analysis on it.
376 /// Currently Resolve wraps DoResolve to perform sanity
377 /// checking and assertion checking on what we expect from Resolve.
379 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
381 if (eclass != ExprClass.Unresolved)
391 if ((flags & e.ExprClassToResolveFlags) == 0) {
392 e.Error_UnexpectedKind (ec, flags, loc);
397 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
400 } catch (Exception ex) {
401 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled)
404 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
405 return ErrorExpression.Instance; // TODO: Add location
410 /// Resolves an expression and performs semantic analysis on it.
412 public Expression Resolve (ResolveContext rc)
414 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
418 /// Resolves an expression for LValue assignment
422 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
423 /// checking and assertion checking on what we expect from Resolve
425 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
427 int errors = ec.Report.Errors;
428 bool out_access = right_side == EmptyExpression.OutAccess;
430 Expression e = DoResolveLValue (ec, right_side);
432 if (e != null && out_access && !(e is IMemoryLocation)) {
433 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
434 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
436 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
437 // e.GetType () + " " + e.GetSignatureForError ());
442 if (errors == ec.Report.Errors) {
444 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
446 Error_ValueAssignment (ec, right_side);
451 if (e.eclass == ExprClass.Unresolved)
452 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
454 if ((e.type == null) && !(e is GenericTypeExpr))
455 throw new Exception ("Expression " + e + " did not set its type after Resolve");
460 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
462 rc.Module.Compiler.Report.Error (182, loc,
463 "An attribute argument must be a constant expression, typeof expression or array creation expression");
467 /// Emits the code for the expression
471 /// The Emit method is invoked to generate the code
472 /// for the expression.
474 public abstract void Emit (EmitContext ec);
477 // Emit code to branch to @target if this expression is equivalent to @on_true.
478 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
479 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
480 // including the use of conditional branches. Note also that a branch MUST be emitted
481 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
484 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
487 // Emit this expression for its side effects, not for its value.
488 // The default implementation is to emit the value, and then throw it away.
489 // Subclasses can provide more efficient implementations, but those MUST be equivalent
490 public virtual void EmitSideEffect (EmitContext ec)
493 ec.Emit (OpCodes.Pop);
497 // Emits the expression into temporary field variable. The method
498 // should be used for await expressions only
500 public virtual Expression EmitToField (EmitContext ec)
503 // This is the await prepare Emit method. When emitting code like
504 // a + b we emit code like
510 // For await a + await b we have to interfere the flow to keep the
511 // stack clean because await yields from the expression. The emit
514 // a = a.EmitToField () // a is changed to temporary field access
515 // b = b.EmitToField ()
521 // The idea is to emit expression and leave the stack empty with
522 // result value still available.
524 // Expressions should override this default implementation when
525 // optimized version can be provided (e.g. FieldExpr)
528 // We can optimize for side-effect free expressions, they can be
529 // emitted out of order
531 if (IsSideEffectFree)
534 bool needs_temporary = ContainsEmitWithAwait ();
535 if (!needs_temporary)
538 // Emit original code
539 EmitToFieldSource (ec);
542 // Store the result to temporary field when we
543 // cannot load `this' directly
545 var field = ec.GetTemporaryField (type);
546 if (needs_temporary) {
548 // Create temporary local (we cannot load `this' before Emit)
550 var temp = ec.GetTemporaryLocal (type);
551 ec.Emit (OpCodes.Stloc, temp);
554 ec.Emit (OpCodes.Ldloc, temp);
555 field.EmitAssignFromStack (ec);
557 ec.FreeTemporaryLocal (temp, type);
559 field.EmitAssignFromStack (ec);
565 protected virtual void EmitToFieldSource (EmitContext ec)
568 // Default implementation calls Emit method
573 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
575 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
576 bool contains_await = false;
578 for (int i = 1; i < expressions.Count; ++i) {
579 if (expressions[i].ContainsEmitWithAwait ()) {
580 contains_await = true;
585 if (contains_await) {
586 for (int i = 0; i < expressions.Count; ++i) {
587 expressions[i] = expressions[i].EmitToField (ec);
592 for (int i = 0; i < expressions.Count; ++i) {
593 expressions[i].Emit (ec);
598 /// Protected constructor. Only derivate types should
599 /// be able to be created
602 protected Expression ()
607 /// Returns a fully formed expression after a MemberLookup
610 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
612 if (spec is EventSpec)
613 return new EventExpr ((EventSpec) spec, loc);
614 if (spec is ConstSpec)
615 return new ConstantExpr ((ConstSpec) spec, loc);
616 if (spec is FieldSpec)
617 return new FieldExpr ((FieldSpec) spec, loc);
618 if (spec is PropertySpec)
619 return new PropertyExpr ((PropertySpec) spec, loc);
620 if (spec is TypeSpec)
621 return new TypeExpression (((TypeSpec) spec), loc);
626 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
628 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
630 rc.Report.SymbolRelatedToPreviousError (type);
632 // Report meaningful error for struct as they always have default ctor in C# context
633 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
635 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
636 type.GetSignatureForError ());
642 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
643 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
644 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
647 return r.ResolveMember<MethodSpec> (rc, ref args);
651 public enum MemberLookupRestrictions
660 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
661 // `qualifier_type' or null to lookup members in the current class.
663 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
665 var members = MemberCache.FindMembers (queried_type, name, false);
669 MemberSpec non_method = null;
670 MemberSpec ambig_non_method = null;
672 for (int i = 0; i < members.Count; ++i) {
673 var member = members[i];
675 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
676 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
679 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0)
682 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
686 if (!member.IsAccessible (rc))
690 // With runtime binder we can have a situation where queried type is inaccessible
691 // because it came via dynamic object, the check about inconsisted accessibility
692 // had no effect as the type was unknown during compilation
695 // private class N { }
697 // public dynamic Foo ()
703 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
707 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
708 if (member is MethodSpec)
709 return new MethodGroupExpr (members, queried_type, loc);
711 if (!Invocation.IsMemberInvocable (member))
715 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
717 } else if (!errorMode && !member.IsNotCSharpCompatible) {
718 ambig_non_method = member;
722 if (non_method != null) {
723 if (ambig_non_method != null && rc != null) {
724 var report = rc.Module.Compiler.Report;
725 report.SymbolRelatedToPreviousError (non_method);
726 report.SymbolRelatedToPreviousError (ambig_non_method);
727 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
728 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
731 if (non_method is MethodSpec)
732 return new MethodGroupExpr (members, queried_type, loc);
734 return ExprClassFromMemberInfo (non_method, loc);
737 if (members[0].DeclaringType.BaseType == null)
740 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
742 } while (members != null);
747 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
749 throw new NotImplementedException ();
752 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
754 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
755 oper, t.GetSignatureForError ());
758 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
760 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
764 /// Returns an expression that can be used to invoke operator true
765 /// on the expression if it exists.
767 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
769 return GetOperatorTrueOrFalse (ec, e, true, loc);
773 /// Returns an expression that can be used to invoke operator false
774 /// on the expression if it exists.
776 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
778 return GetOperatorTrueOrFalse (ec, e, false, loc);
781 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
783 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
784 var methods = MemberCache.GetUserOperator (e.type, op, false);
788 Arguments arguments = new Arguments (1);
789 arguments.Add (new Argument (e));
791 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
792 var oper = res.ResolveOperator (ec, ref arguments);
797 return new UserOperatorCall (oper, arguments, null, loc);
800 public virtual string ExprClassName
804 case ExprClass.Unresolved:
806 case ExprClass.Value:
808 case ExprClass.Variable:
810 case ExprClass.Namespace:
814 case ExprClass.MethodGroup:
815 return "method group";
816 case ExprClass.PropertyAccess:
817 return "property access";
818 case ExprClass.EventAccess:
819 return "event access";
820 case ExprClass.IndexerAccess:
821 return "indexer access";
822 case ExprClass.Nothing:
824 case ExprClass.TypeParameter:
825 return "type parameter";
827 throw new Exception ("Should not happen");
832 /// Reports that we were expecting `expr' to be of class `expected'
834 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, Location loc)
836 Error_UnexpectedKind (r, mc, expected, ExprClassName, loc);
839 public void Error_UnexpectedKind (Report r, MemberCore mc, string expected, string was, Location loc)
843 name = mc.GetSignatureForError ();
845 name = GetSignatureForError ();
847 r.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected",
848 name, was, expected);
851 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
853 string [] valid = new string [4];
856 if ((flags & ResolveFlags.VariableOrValue) != 0) {
857 valid [count++] = "variable";
858 valid [count++] = "value";
861 if ((flags & ResolveFlags.Type) != 0)
862 valid [count++] = "type";
864 if ((flags & ResolveFlags.MethodGroup) != 0)
865 valid [count++] = "method group";
868 valid [count++] = "unknown";
870 StringBuilder sb = new StringBuilder (valid [0]);
871 for (int i = 1; i < count - 1; i++) {
873 sb.Append (valid [i]);
876 sb.Append ("' or `");
877 sb.Append (valid [count - 1]);
880 ec.Report.Error (119, loc,
881 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
884 public static void UnsafeError (ResolveContext ec, Location loc)
886 UnsafeError (ec.Report, loc);
889 public static void UnsafeError (Report Report, Location loc)
891 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
895 // Converts `source' to an int, uint, long or ulong.
897 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
899 var btypes = ec.BuiltinTypes;
901 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
902 Arguments args = new Arguments (1);
903 args.Add (new Argument (source));
904 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
907 Expression converted;
909 using (ec.Set (ResolveContext.Options.CheckedScope)) {
910 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
911 if (converted == null)
912 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
913 if (converted == null)
914 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
915 if (converted == null)
916 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
918 if (converted == null) {
919 source.Error_ValueCannotBeConverted (ec, source.loc, btypes.Int, false);
925 // Only positive constants are allowed at compile time
927 Constant c = converted as Constant;
928 if (c != null && c.IsNegative)
929 Error_NegativeArrayIndex (ec, source.loc);
931 // No conversion needed to array index
932 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
935 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
939 // Derived classes implement this method by cloning the fields that
940 // could become altered during the Resolve stage
942 // Only expressions that are created for the parser need to implement
945 protected virtual void CloneTo (CloneContext clonectx, Expression target)
947 throw new NotImplementedException (
949 "CloneTo not implemented for expression {0}", this.GetType ()));
953 // Clones an expression created by the parser.
955 // We only support expressions created by the parser so far, not
956 // expressions that have been resolved (many more classes would need
957 // to implement CloneTo).
959 // This infrastructure is here merely for Lambda expressions which
960 // compile the same code using different type values for the same
961 // arguments to find the correct overload
963 public virtual Expression Clone (CloneContext clonectx)
965 Expression cloned = (Expression) MemberwiseClone ();
966 CloneTo (clonectx, cloned);
972 // Implementation of expression to expression tree conversion
974 public abstract Expression CreateExpressionTree (ResolveContext ec);
976 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
978 return CreateExpressionFactoryCall (ec, name, null, args, loc);
981 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
983 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
986 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
988 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
991 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
993 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
997 return new TypeExpression (t, loc);
1001 // Implemented by all expressions which support conversion from
1002 // compiler expression to invokable runtime expression. Used by
1003 // dynamic C# binder.
1005 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1007 throw new NotImplementedException ("MakeExpression for " + GetType ());
1012 /// This is just a base class for expressions that can
1013 /// appear on statements (invocations, object creation,
1014 /// assignments, post/pre increment and decrement). The idea
1015 /// being that they would support an extra Emition interface that
1016 /// does not leave a result on the stack.
1018 public abstract class ExpressionStatement : Expression {
1020 public ExpressionStatement ResolveStatement (BlockContext ec)
1022 Expression e = Resolve (ec);
1026 ExpressionStatement es = e as ExpressionStatement;
1028 Error_InvalidExpressionStatement (ec);
1034 /// Requests the expression to be emitted in a `statement'
1035 /// context. This means that no new value is left on the
1036 /// stack after invoking this method (constrasted with
1037 /// Emit that will always leave a value on the stack).
1039 public abstract void EmitStatement (EmitContext ec);
1041 public override void EmitSideEffect (EmitContext ec)
1048 /// This kind of cast is used to encapsulate the child
1049 /// whose type is child.Type into an expression that is
1050 /// reported to return "return_type". This is used to encapsulate
1051 /// expressions which have compatible types, but need to be dealt
1052 /// at higher levels with.
1054 /// For example, a "byte" expression could be encapsulated in one
1055 /// of these as an "unsigned int". The type for the expression
1056 /// would be "unsigned int".
1059 public abstract class TypeCast : Expression
1061 protected readonly Expression child;
1063 protected TypeCast (Expression child, TypeSpec return_type)
1065 eclass = child.eclass;
1066 loc = child.Location;
1071 public Expression Child {
1077 public override bool ContainsEmitWithAwait ()
1079 return child.ContainsEmitWithAwait ();
1082 public override Expression CreateExpressionTree (ResolveContext ec)
1084 Arguments args = new Arguments (2);
1085 args.Add (new Argument (child.CreateExpressionTree (ec)));
1086 args.Add (new Argument (new TypeOf (type, loc)));
1088 if (type.IsPointer || child.Type.IsPointer)
1089 Error_PointerInsideExpressionTree (ec);
1091 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1094 protected override Expression DoResolve (ResolveContext ec)
1096 // This should never be invoked, we are born in fully
1097 // initialized state.
1102 public override void Emit (EmitContext ec)
1107 public override SLE.Expression MakeExpression (BuilderContext ctx)
1110 return base.MakeExpression (ctx);
1112 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1113 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1114 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1118 protected override void CloneTo (CloneContext clonectx, Expression t)
1123 public override bool IsNull {
1124 get { return child.IsNull; }
1128 public class EmptyCast : TypeCast {
1129 EmptyCast (Expression child, TypeSpec target_type)
1130 : base (child, target_type)
1134 public static Expression Create (Expression child, TypeSpec type)
1136 Constant c = child as Constant;
1138 return new EmptyConstantCast (c, type);
1140 EmptyCast e = child as EmptyCast;
1142 return new EmptyCast (e.child, type);
1144 return new EmptyCast (child, type);
1147 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1149 child.EmitBranchable (ec, label, on_true);
1152 public override void EmitSideEffect (EmitContext ec)
1154 child.EmitSideEffect (ec);
1159 // Used for predefined type user operator (no obsolete check, etc.)
1161 public class OperatorCast : TypeCast
1163 readonly MethodSpec conversion_operator;
1165 public OperatorCast (Expression expr, TypeSpec target_type)
1166 : this (expr, target_type, target_type, false)
1170 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1171 : this (expr, target_type, target_type, find_explicit)
1175 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1176 : base (expr, returnType)
1178 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1179 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1182 foreach (MethodSpec oper in mi) {
1183 if (oper.ReturnType != returnType)
1186 if (oper.Parameters.Types[0] == expr.Type) {
1187 conversion_operator = oper;
1193 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1194 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1197 public override void Emit (EmitContext ec)
1200 ec.Emit (OpCodes.Call, conversion_operator);
1205 // Constant specialization of EmptyCast.
1206 // We need to special case this since an empty cast of
1207 // a constant is still a constant.
1209 public class EmptyConstantCast : Constant
1211 public readonly Constant child;
1213 public EmptyConstantCast (Constant child, TypeSpec type)
1214 : base (child.Location)
1217 throw new ArgumentNullException ("child");
1220 this.eclass = child.eclass;
1224 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1226 if (child.Type == target_type)
1229 // FIXME: check that 'type' can be converted to 'target_type' first
1230 return child.ConvertExplicitly (in_checked_context, target_type);
1233 public override Expression CreateExpressionTree (ResolveContext ec)
1235 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1236 child.CreateExpressionTree (ec),
1237 new TypeOf (type, loc));
1240 Error_PointerInsideExpressionTree (ec);
1242 return CreateExpressionFactoryCall (ec, "Convert", args);
1245 public override bool IsDefaultValue {
1246 get { return child.IsDefaultValue; }
1249 public override bool IsNegative {
1250 get { return child.IsNegative; }
1253 public override bool IsNull {
1254 get { return child.IsNull; }
1257 public override bool IsOneInteger {
1258 get { return child.IsOneInteger; }
1261 public override bool IsSideEffectFree {
1263 return child.IsSideEffectFree;
1267 public override bool IsZeroInteger {
1268 get { return child.IsZeroInteger; }
1271 public override void Emit (EmitContext ec)
1276 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1278 child.EmitBranchable (ec, label, on_true);
1280 // Only to make verifier happy
1281 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1282 ec.Emit (OpCodes.Unbox_Any, type);
1285 public override void EmitSideEffect (EmitContext ec)
1287 child.EmitSideEffect (ec);
1290 public override object GetValue ()
1292 return child.GetValue ();
1295 public override string GetValueAsLiteral ()
1297 return child.GetValueAsLiteral ();
1300 public override long GetValueAsLong ()
1302 return child.GetValueAsLong ();
1305 public override Constant ConvertImplicitly (TypeSpec target_type)
1307 if (type == target_type)
1310 // FIXME: Do we need to check user conversions?
1311 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1314 return child.ConvertImplicitly (target_type);
1319 /// This class is used to wrap literals which belong inside Enums
1321 public class EnumConstant : Constant
1323 public Constant Child;
1325 public EnumConstant (Constant child, TypeSpec enum_type)
1326 : base (child.Location)
1330 this.eclass = ExprClass.Value;
1331 this.type = enum_type;
1334 protected EnumConstant (Location loc)
1339 public override void Emit (EmitContext ec)
1344 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1346 Child.EncodeAttributeValue (rc, enc, Child.Type);
1349 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1351 Child.EmitBranchable (ec, label, on_true);
1354 public override void EmitSideEffect (EmitContext ec)
1356 Child.EmitSideEffect (ec);
1359 public override string GetSignatureForError()
1361 return TypeManager.CSharpName (Type);
1364 public override object GetValue ()
1366 return Child.GetValue ();
1370 public override object GetTypedValue ()
1373 // The method can be used in dynamic context only (on closed types)
1375 // System.Enum.ToObject cannot be called on dynamic types
1376 // EnumBuilder has to be used, but we cannot use EnumBuilder
1377 // because it does not properly support generics
1379 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1383 public override string GetValueAsLiteral ()
1385 return Child.GetValueAsLiteral ();
1388 public override long GetValueAsLong ()
1390 return Child.GetValueAsLong ();
1393 public EnumConstant Increment()
1395 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1398 public override bool IsDefaultValue {
1400 return Child.IsDefaultValue;
1404 public override bool IsSideEffectFree {
1406 return Child.IsSideEffectFree;
1410 public override bool IsZeroInteger {
1411 get { return Child.IsZeroInteger; }
1414 public override bool IsNegative {
1416 return Child.IsNegative;
1420 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1422 if (Child.Type == target_type)
1425 return Child.ConvertExplicitly (in_checked_context, target_type);
1428 public override Constant ConvertImplicitly (TypeSpec type)
1430 if (this.type == type) {
1434 if (!Convert.ImplicitStandardConversionExists (this, type)){
1438 return Child.ConvertImplicitly (type);
1443 /// This kind of cast is used to encapsulate Value Types in objects.
1445 /// The effect of it is to box the value type emitted by the previous
1448 public class BoxedCast : TypeCast {
1450 public BoxedCast (Expression expr, TypeSpec target_type)
1451 : base (expr, target_type)
1453 eclass = ExprClass.Value;
1456 protected override Expression DoResolve (ResolveContext ec)
1458 // This should never be invoked, we are born in fully
1459 // initialized state.
1464 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1466 // Only boxing to object type is supported
1467 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1468 base.EncodeAttributeValue (rc, enc, targetType);
1472 enc.Encode (child.Type);
1473 child.EncodeAttributeValue (rc, enc, child.Type);
1476 public override void Emit (EmitContext ec)
1480 ec.Emit (OpCodes.Box, child.Type);
1483 public override void EmitSideEffect (EmitContext ec)
1485 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1486 // so, we need to emit the box+pop instructions in most cases
1487 if (child.Type.IsStruct &&
1488 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1489 child.EmitSideEffect (ec);
1491 base.EmitSideEffect (ec);
1495 public class UnboxCast : TypeCast {
1496 public UnboxCast (Expression expr, TypeSpec return_type)
1497 : base (expr, return_type)
1501 protected override Expression DoResolve (ResolveContext ec)
1503 // This should never be invoked, we are born in fully
1504 // initialized state.
1509 public override void Emit (EmitContext ec)
1513 ec.Emit (OpCodes.Unbox_Any, type);
1518 /// This is used to perform explicit numeric conversions.
1520 /// Explicit numeric conversions might trigger exceptions in a checked
1521 /// context, so they should generate the conv.ovf opcodes instead of
1524 public class ConvCast : TypeCast {
1525 public enum Mode : byte {
1526 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1528 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1529 U2_I1, U2_U1, U2_I2, U2_CH,
1530 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1531 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1532 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1533 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1534 CH_I1, CH_U1, CH_I2,
1535 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1536 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1542 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1543 : base (child, return_type)
1548 protected override Expression DoResolve (ResolveContext ec)
1550 // This should never be invoked, we are born in fully
1551 // initialized state.
1556 public override string ToString ()
1558 return String.Format ("ConvCast ({0}, {1})", mode, child);
1561 public override void Emit (EmitContext ec)
1565 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1567 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1568 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1569 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1570 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1571 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1573 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1574 case Mode.U1_CH: /* nothing */ break;
1576 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1577 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1578 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1579 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1580 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1581 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1583 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1584 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1585 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1586 case Mode.U2_CH: /* nothing */ break;
1588 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1589 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1590 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1591 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1592 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1593 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1594 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1596 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1597 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1598 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1599 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1600 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1601 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1603 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1604 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1605 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1606 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1607 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1608 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1609 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1610 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1611 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1613 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1614 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1615 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1616 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1617 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1618 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1619 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1620 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1621 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1623 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1624 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1625 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1627 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1628 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1629 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1630 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1631 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1632 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1633 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1634 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1635 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1637 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1638 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1639 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1640 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1641 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1642 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1643 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1644 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1645 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1646 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1648 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1652 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1653 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1654 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1655 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1656 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1658 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1659 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1661 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1662 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1663 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1664 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1665 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1666 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1668 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1669 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1670 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1671 case Mode.U2_CH: /* nothing */ break;
1673 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1674 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1675 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1676 case Mode.I4_U4: /* nothing */ break;
1677 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1678 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1679 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1681 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1682 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1683 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1684 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1685 case Mode.U4_I4: /* nothing */ break;
1686 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1688 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1689 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1690 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1691 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1692 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1693 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1694 case Mode.I8_U8: /* nothing */ break;
1695 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1696 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1698 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1699 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1700 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1701 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1702 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1703 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1704 case Mode.U8_I8: /* nothing */ break;
1705 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1706 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1708 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1709 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1710 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1712 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1713 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1714 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1715 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1716 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1717 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1718 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1719 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1720 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1722 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1723 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1724 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1725 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1726 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1727 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1728 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1729 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1730 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1731 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1733 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1739 class OpcodeCast : TypeCast
1743 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1744 : base (child, return_type)
1749 protected override Expression DoResolve (ResolveContext ec)
1751 // This should never be invoked, we are born in fully
1752 // initialized state.
1757 public override void Emit (EmitContext ec)
1763 public TypeSpec UnderlyingType {
1764 get { return child.Type; }
1769 // Opcode casts expression with 2 opcodes but only
1770 // single expression tree node
1772 class OpcodeCastDuplex : OpcodeCast
1774 readonly OpCode second;
1776 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1777 : base (child, returnType, first)
1779 this.second = second;
1782 public override void Emit (EmitContext ec)
1790 /// This kind of cast is used to encapsulate a child and cast it
1791 /// to the class requested
1793 public sealed class ClassCast : TypeCast {
1794 readonly bool forced;
1796 public ClassCast (Expression child, TypeSpec return_type)
1797 : base (child, return_type)
1801 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1802 : base (child, return_type)
1804 this.forced = forced;
1807 public override void Emit (EmitContext ec)
1811 bool gen = TypeManager.IsGenericParameter (child.Type);
1813 ec.Emit (OpCodes.Box, child.Type);
1815 if (type.IsGenericParameter) {
1816 ec.Emit (OpCodes.Unbox_Any, type);
1823 ec.Emit (OpCodes.Castclass, type);
1828 // Created during resolving pahse when an expression is wrapped or constantified
1829 // and original expression can be used later (e.g. for expression trees)
1831 public class ReducedExpression : Expression
1833 sealed class ReducedConstantExpression : EmptyConstantCast
1835 readonly Expression orig_expr;
1837 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1838 : base (expr, expr.Type)
1840 this.orig_expr = orig_expr;
1843 public override Constant ConvertImplicitly (TypeSpec target_type)
1845 Constant c = base.ConvertImplicitly (target_type);
1847 c = new ReducedConstantExpression (c, orig_expr);
1852 public override Expression CreateExpressionTree (ResolveContext ec)
1854 return orig_expr.CreateExpressionTree (ec);
1857 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1859 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1861 c = new ReducedConstantExpression (c, orig_expr);
1865 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1868 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1870 if (orig_expr is Conditional)
1871 child.EncodeAttributeValue (rc, enc, targetType);
1873 base.EncodeAttributeValue (rc, enc, targetType);
1877 sealed class ReducedExpressionStatement : ExpressionStatement
1879 readonly Expression orig_expr;
1880 readonly ExpressionStatement stm;
1882 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1884 this.orig_expr = orig;
1886 this.eclass = stm.eclass;
1887 this.type = stm.Type;
1889 this.loc = orig.Location;
1892 public override bool ContainsEmitWithAwait ()
1894 return stm.ContainsEmitWithAwait ();
1897 public override Expression CreateExpressionTree (ResolveContext ec)
1899 return orig_expr.CreateExpressionTree (ec);
1902 protected override Expression DoResolve (ResolveContext ec)
1907 public override void Emit (EmitContext ec)
1912 public override void EmitStatement (EmitContext ec)
1914 stm.EmitStatement (ec);
1918 readonly Expression expr, orig_expr;
1920 private ReducedExpression (Expression expr, Expression orig_expr)
1923 this.eclass = expr.eclass;
1924 this.type = expr.Type;
1925 this.orig_expr = orig_expr;
1926 this.loc = orig_expr.Location;
1931 public Expression OriginalExpression {
1939 public override bool ContainsEmitWithAwait ()
1941 return expr.ContainsEmitWithAwait ();
1945 // Creates fully resolved expression switcher
1947 public static Constant Create (Constant expr, Expression original_expr)
1949 if (expr.eclass == ExprClass.Unresolved)
1950 throw new ArgumentException ("Unresolved expression");
1952 return new ReducedConstantExpression (expr, original_expr);
1955 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
1957 return new ReducedExpressionStatement (s, orig);
1960 public static Expression Create (Expression expr, Expression original_expr)
1962 return Create (expr, original_expr, true);
1966 // Creates unresolved reduce expression. The original expression has to be
1967 // already resolved. Created expression is constant based based on `expr'
1968 // value unless canBeConstant is used
1970 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
1972 if (canBeConstant) {
1973 Constant c = expr as Constant;
1975 return Create (c, original_expr);
1978 ExpressionStatement s = expr as ExpressionStatement;
1980 return Create (s, original_expr);
1982 if (expr.eclass == ExprClass.Unresolved)
1983 throw new ArgumentException ("Unresolved expression");
1985 return new ReducedExpression (expr, original_expr);
1988 public override Expression CreateExpressionTree (ResolveContext ec)
1990 return orig_expr.CreateExpressionTree (ec);
1993 protected override Expression DoResolve (ResolveContext ec)
1998 public override void Emit (EmitContext ec)
2003 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2005 expr.EmitBranchable (ec, target, on_true);
2008 public override SLE.Expression MakeExpression (BuilderContext ctx)
2010 return orig_expr.MakeExpression (ctx);
2015 // Standard composite pattern
2017 public abstract class CompositeExpression : Expression
2019 protected Expression expr;
2021 protected CompositeExpression (Expression expr)
2024 this.loc = expr.Location;
2027 public override bool ContainsEmitWithAwait ()
2029 return expr.ContainsEmitWithAwait ();
2032 public override Expression CreateExpressionTree (ResolveContext rc)
2034 return expr.CreateExpressionTree (rc);
2037 public Expression Child {
2038 get { return expr; }
2041 protected override Expression DoResolve (ResolveContext rc)
2043 expr = expr.Resolve (rc);
2046 eclass = expr.eclass;
2052 public override void Emit (EmitContext ec)
2057 public override bool IsNull {
2058 get { return expr.IsNull; }
2063 // Base of expressions used only to narrow resolve flow
2065 public abstract class ShimExpression : Expression
2067 protected Expression expr;
2069 protected ShimExpression (Expression expr)
2074 public Expression Expr {
2080 protected override void CloneTo (CloneContext clonectx, Expression t)
2085 ShimExpression target = (ShimExpression) t;
2086 target.expr = expr.Clone (clonectx);
2089 public override bool ContainsEmitWithAwait ()
2091 return expr.ContainsEmitWithAwait ();
2094 public override Expression CreateExpressionTree (ResolveContext ec)
2096 throw new NotSupportedException ("ET");
2099 public override void Emit (EmitContext ec)
2101 throw new InternalErrorException ("Missing Resolve call");
2107 // Unresolved type name expressions
2109 public abstract class ATypeNameExpression : FullNamedExpression
2112 protected TypeArguments targs;
2114 protected ATypeNameExpression (string name, Location l)
2120 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2127 protected ATypeNameExpression (string name, int arity, Location l)
2128 : this (name, new UnboundTypeArguments (arity), l)
2134 protected int Arity {
2136 return targs == null ? 0 : targs.Count;
2140 public bool HasTypeArguments {
2142 return targs != null && !targs.IsEmpty;
2146 public string Name {
2155 public TypeArguments TypeArguments {
2163 public override bool Equals (object obj)
2165 ATypeNameExpression atne = obj as ATypeNameExpression;
2166 return atne != null && atne.Name == Name &&
2167 (targs == null || targs.Equals (atne.targs));
2170 public override int GetHashCode ()
2172 return Name.GetHashCode ();
2175 // TODO: Move it to MemberCore
2176 public static string GetMemberType (MemberCore mc)
2182 if (mc is FieldBase)
2184 if (mc is MethodCore)
2186 if (mc is EnumMember)
2194 public override string GetSignatureForError ()
2196 if (targs != null) {
2197 return Name + "<" + targs.GetSignatureForError () + ">";
2203 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2207 /// SimpleName expressions are formed of a single word and only happen at the beginning
2208 /// of a dotted-name.
2210 public class SimpleName : ATypeNameExpression
2212 public SimpleName (string name, Location l)
2217 public SimpleName (string name, TypeArguments args, Location l)
2218 : base (name, args, l)
2222 public SimpleName (string name, int arity, Location l)
2223 : base (name, arity, l)
2227 public SimpleName GetMethodGroup ()
2229 return new SimpleName (Name, targs, loc);
2232 protected override Expression DoResolve (ResolveContext rc)
2234 var e = SimpleNameResolve (rc, null, false);
2236 var fe = e as FieldExpr;
2238 fe.VerifyAssignedStructField (rc, null);
2244 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2246 return SimpleNameResolve (ec, right_side, false);
2249 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2251 if (ctx.CurrentType != null) {
2252 if (ctx.CurrentMemberDefinition != null) {
2253 MemberCore mc = ctx.CurrentMemberDefinition.Parent.GetDefinition (Name);
2255 Error_UnexpectedKind (ctx.Module.Compiler.Report, mc, "type", GetMemberType (mc), loc);
2261 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2262 if (retval != null) {
2263 ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
2264 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2268 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2269 if (retval != null) {
2270 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2274 NamespaceContainer.Error_NamespaceNotFound (loc, Name, ctx.Module.Compiler.Report);
2277 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2279 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2282 if (fne.Type != null && Arity > 0) {
2283 if (HasTypeArguments) {
2284 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2285 if (ct.ResolveAsType (ec) == null)
2291 return new GenericOpenTypeExpr (fne.Type, loc);
2295 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2297 if (!(fne is Namespace))
2301 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2302 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2303 ec.Module.Compiler.Report.Error (1980, Location,
2304 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2305 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2308 fne = new DynamicTypeExpr (loc);
2309 fne.ResolveAsType (ec);
2315 Error_TypeOrNamespaceNotFound (ec);
2319 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2321 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2324 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2326 int lookup_arity = Arity;
2327 bool errorMode = false;
2329 Block current_block = rc.CurrentBlock;
2330 INamedBlockVariable variable = null;
2331 bool variable_found = false;
2335 // Stage 1: binding to local variables or parameters
2337 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2339 if (current_block != null && lookup_arity == 0) {
2340 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2341 if (!variable.IsDeclared) {
2342 // We found local name in accessible block but it's not
2343 // initialized yet, maybe the user wanted to bind to something else
2345 variable_found = true;
2347 e = variable.CreateReferenceExpression (rc, loc);
2350 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2359 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2361 TypeSpec member_type = rc.CurrentType;
2362 for (; member_type != null; member_type = member_type.DeclaringType) {
2363 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2367 var me = e as MemberExpr;
2369 // The name matches a type, defer to ResolveAsTypeStep
2377 if (variable != null) {
2378 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2379 rc.Report.Error (844, loc,
2380 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2381 Name, me.GetSignatureForError ());
2385 } else if (me is MethodGroupExpr) {
2386 // Leave it to overload resolution to report correct error
2388 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2389 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2392 // LAMESPEC: again, ignores InvocableOnly
2393 if (variable != null) {
2394 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2395 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2399 // MemberLookup does not check accessors availability, this is actually needed for properties only
2401 var pe = me as PropertyExpr;
2404 // Break as there is no other overload available anyway
2405 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2406 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2409 pe.Getter = pe.PropertyInfo.Get;
2411 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2414 pe.Setter = pe.PropertyInfo.Set;
2419 // TODO: It's used by EventExpr -> FieldExpr transformation only
2420 // TODO: Should go to MemberAccess
2421 me = me.ResolveMemberAccess (rc, null, null);
2425 me.SetTypeArguments (rc, targs);
2432 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2434 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2435 if (IsPossibleTypeOrNamespace (rc)) {
2436 if (variable != null) {
2437 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2438 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2441 return ResolveAsTypeOrNamespace (rc);
2446 if (variable_found) {
2447 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2450 TypeParameter[] tparams = rc.CurrentTypeParameters;
2451 if (tparams != null) {
2452 foreach (var ctp in tparams) {
2453 if (ctp.Name == Name) {
2454 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2460 var ct = rc.CurrentType;
2462 if (ct.MemberDefinition.TypeParametersCount > 0) {
2463 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2464 if (ctp.Name == Name) {
2465 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2471 ct = ct.DeclaringType;
2472 } while (ct != null);
2475 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2476 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2478 rc.Report.SymbolRelatedToPreviousError (e.Type);
2479 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2484 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2486 if (!(e is TypeExpr) || (restrictions & MemberLookupRestrictions.InvocableOnly) == 0 || !e.Type.IsDelegate) {
2487 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2492 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2495 return ErrorExpression.Instance;
2498 if (rc.Module.Evaluator != null) {
2499 var fi = rc.Module.Evaluator.LookupField (Name);
2501 return new FieldExpr (fi.Item1, loc);
2509 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2511 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2516 if (right_side != null) {
2517 if (e is TypeExpr) {
2518 e.Error_UnexpectedKind (ec, ResolveFlags.VariableOrValue, loc);
2522 e = e.ResolveLValue (ec, right_side);
2527 //if (ec.CurrentBlock == null || ec.CurrentBlock.CheckInvariantMeaningInBlock (Name, e, Location))
2533 /// Represents a namespace or a type. The name of the class was inspired by
2534 /// section 10.8.1 (Fully Qualified Names).
2536 public abstract class FullNamedExpression : Expression
2538 protected override void CloneTo (CloneContext clonectx, Expression target)
2540 // Do nothing, most unresolved type expressions cannot be
2541 // resolved to different type
2544 public override bool ContainsEmitWithAwait ()
2549 public override Expression CreateExpressionTree (ResolveContext ec)
2551 throw new NotSupportedException ("ET");
2554 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2557 // This is used to resolve the expression as a type, a null
2558 // value will be returned if the expression is not a type
2561 public override TypeSpec ResolveAsType (IMemberContext mc)
2563 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2568 TypeExpr te = fne as TypeExpr;
2570 fne.Error_UnexpectedKind (mc.Module.Compiler.Report, null, "type", loc);
2578 var dep = type.GetMissingDependencies ();
2580 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2584 // Obsolete checks cannot be done when resolving base context as they
2585 // require type dependencies to be set but we are in process of resolving them
2587 if (!(mc is TypeContainer.BaseContext)) {
2588 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2589 if (obsolete_attr != null && !mc.IsObsolete) {
2590 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2598 public override void Emit (EmitContext ec)
2600 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2601 GetSignatureForError ());
2606 /// Expression that evaluates to a type
2608 public abstract class TypeExpr : FullNamedExpression
2610 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2616 protected sealed override Expression DoResolve (ResolveContext ec)
2622 public override bool Equals (object obj)
2624 TypeExpr tobj = obj as TypeExpr;
2628 return Type == tobj.Type;
2631 public override int GetHashCode ()
2633 return Type.GetHashCode ();
2638 /// Fully resolved Expression that already evaluated to a type
2640 public class TypeExpression : TypeExpr
2642 public TypeExpression (TypeSpec t, Location l)
2645 eclass = ExprClass.Type;
2649 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2656 /// This class denotes an expression which evaluates to a member
2657 /// of a struct or a class.
2659 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2662 // An instance expression associated with this member, if it's a
2663 // non-static member
2665 public Expression InstanceExpression;
2668 /// The name of this member.
2670 public abstract string Name {
2675 // When base.member is used
2677 public bool IsBase {
2678 get { return InstanceExpression is BaseThis; }
2682 /// Whether this is an instance member.
2684 public abstract bool IsInstance {
2689 /// Whether this is a static member.
2691 public abstract bool IsStatic {
2695 protected abstract TypeSpec DeclaringType {
2699 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2701 return InstanceExpression.Type;
2706 // Converts best base candidate for virtual method starting from QueriedBaseType
2708 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2711 // Only when base.member is used and method is virtual
2717 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2718 // means for base.member access we have to find the closest match after we found best candidate
2720 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2722 // The method could already be what we are looking for
2724 TypeSpec[] targs = null;
2725 if (method.DeclaringType != InstanceExpression.Type) {
2726 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly) as MethodSpec;
2727 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2728 if (base_override.IsGeneric)
2729 targs = method.TypeArguments;
2731 method = base_override;
2735 // TODO: For now we do it for any hoisted call even if it's needed for
2736 // hoisted stories only but that requires a new expression wrapper
2737 if (rc.CurrentAnonymousMethod != null) {
2738 if (targs == null && method.IsGeneric) {
2739 targs = method.TypeArguments;
2740 method = method.GetGenericMethodDefinition ();
2743 if (method.Parameters.HasArglist)
2744 throw new NotImplementedException ("__arglist base call proxy");
2746 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2748 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2749 // get/set member expressions second call would fail to proxy because left expression
2750 // would be of 'this' and not 'base'
2751 if (rc.CurrentType.IsStruct)
2752 InstanceExpression = new This (loc).Resolve (rc);
2756 method = method.MakeGenericMethod (rc, targs);
2760 // Only base will allow this invocation to happen.
2762 if (method.IsAbstract) {
2763 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2769 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2771 if (InstanceExpression == null)
2774 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2775 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2776 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2781 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2783 if (InstanceExpression == null)
2786 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2789 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2791 var ct = rc.CurrentType;
2792 if (ct == qualifier)
2795 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2798 qualifier = qualifier.GetDefinition ();
2799 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2806 public override bool ContainsEmitWithAwait ()
2808 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2811 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2814 type = type.GetDefinition ();
2816 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2819 type = type.DeclaringType;
2820 } while (type != null);
2825 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2827 if (InstanceExpression != null) {
2828 InstanceExpression = InstanceExpression.Resolve (rc);
2829 CheckProtectedMemberAccess (rc, member);
2832 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2833 UnsafeError (rc, loc);
2836 var dep = member.GetMissingDependencies ();
2838 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2841 if (!rc.IsObsolete) {
2842 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2844 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
2847 if (!(member is FieldSpec))
2848 member.MemberDefinition.SetIsUsed ();
2851 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
2853 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
2856 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
2858 rc.Report.SymbolRelatedToPreviousError (member);
2859 rc.Report.Error (1540, loc,
2860 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
2861 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2865 // Implements identicial simple name and type-name
2867 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
2870 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
2873 // 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
2874 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
2876 if (left is MemberExpr || left is VariableReference) {
2877 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
2878 if (identical_type != null && identical_type.Type == left.Type)
2879 return identical_type;
2885 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
2888 if (InstanceExpression != null) {
2889 if (InstanceExpression is TypeExpr) {
2890 var t = InstanceExpression.Type;
2892 ObsoleteAttribute oa = t.GetAttributeObsolete ();
2893 if (oa != null && !rc.IsObsolete) {
2894 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
2897 t = t.DeclaringType;
2898 } while (t != null);
2900 var runtime_expr = InstanceExpression as RuntimeValueExpression;
2901 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
2902 rc.Report.Error (176, loc,
2903 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
2904 GetSignatureForError ());
2908 InstanceExpression = null;
2914 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
2915 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
2916 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
2917 rc.Report.Error (236, loc,
2918 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
2919 GetSignatureForError ());
2921 rc.Report.Error (120, loc,
2922 "An object reference is required to access non-static member `{0}'",
2923 GetSignatureForError ());
2925 InstanceExpression = new CompilerGeneratedThis (type, loc).Resolve (rc);
2929 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
2930 rc.Report.Error (38, loc,
2931 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
2932 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
2935 InstanceExpression = new This (loc);
2936 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2937 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
2938 InstanceExpression = InstanceExpression.Resolve (rc);
2941 InstanceExpression = InstanceExpression.Resolve (rc);
2947 var me = InstanceExpression as MemberExpr;
2949 me.ResolveInstanceExpression (rc, rhs);
2951 var fe = me as FieldExpr;
2952 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
2953 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
2954 rc.Report.Warning (1690, 1, loc,
2955 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
2956 me.GetSignatureForError ());
2963 // Run member-access postponed check once we know that
2964 // the expression is not field expression which is the only
2965 // expression which can use uninitialized this
2967 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
2968 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
2972 // Additional checks for l-value member access
2975 if (InstanceExpression is UnboxCast) {
2976 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
2983 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
2985 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
2986 ec.Report.Warning (1720, 1, left.Location,
2987 "Expression will always cause a `{0}'", "System.NullReferenceException");
2990 InstanceExpression = left;
2994 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
2996 TypeSpec instance_type = InstanceExpression.Type;
2997 if (TypeSpec.IsValueType (instance_type)) {
2998 if (InstanceExpression is IMemoryLocation) {
2999 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3001 // Cannot release the temporary variable when its address
3002 // is required to be on stack for any parent
3003 LocalTemporary t = new LocalTemporary (instance_type);
3004 InstanceExpression.Emit (ec);
3006 t.AddressOf (ec, AddressOp.Store);
3009 InstanceExpression.Emit (ec);
3011 // Only to make verifier happy
3012 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3013 ec.Emit (OpCodes.Box, instance_type);
3016 if (prepare_for_load)
3017 ec.Emit (OpCodes.Dup);
3020 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3023 public class ExtensionMethodCandidates
3025 NamespaceContainer container;
3027 IList<MethodSpec> methods;
3029 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
3030 : this (methods, nsContainer, null)
3034 public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
3036 this.methods = methods;
3037 this.container = nsContainer;
3041 public NamespaceContainer Container {
3047 public bool HasUninspectedMembers { get; set; }
3049 public Namespace Namespace {
3055 public IList<MethodSpec> Methods {
3063 // Represents a group of extension method candidates for whole namespace
3065 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3067 ExtensionMethodCandidates candidates;
3068 public readonly Expression ExtensionExpression;
3070 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3071 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3073 this.candidates = candidates;
3074 this.ExtensionExpression = extensionExpr;
3077 public override bool IsStatic {
3078 get { return true; }
3082 // For extension methodgroup we are not looking for base members but parent
3083 // namespace extension methods
3085 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3087 // TODO: candidates are null only when doing error reporting, that's
3088 // incorrect. We have to discover same extension methods in error mode
3089 if (candidates == null)
3092 int arity = type_arguments == null ? 0 : type_arguments.Count;
3095 // Here we try to resume the search for extension method at the point
3096 // where the last bunch of candidates was found. It's more tricky than
3097 // it seems as we have to check both namespace containers and namespace
3098 // in correct order.
3104 // namespace B.C.D {
3105 // <our first search found candidates in A.B.C.D
3109 // In the example above namespace A.B.C.D, A.B.C and A.B have to be
3110 // checked before we hit A.N1 using
3112 if (candidates.Namespace == null) {
3114 var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
3115 if (methods != null) {
3116 candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
3117 return methods.Cast<MemberSpec> ().ToList ();
3121 var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
3122 if (ns_container == null)
3125 candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
3126 if (candidates == null)
3129 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3132 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3134 // We are already here
3138 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3140 if (arguments == null)
3141 arguments = new Arguments (1);
3143 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3144 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3146 // Store resolved argument and restore original arguments
3148 // Clean-up modified arguments for error reporting
3149 arguments.RemoveAt (0);
3153 var me = ExtensionExpression as MemberExpr;
3155 me.ResolveInstanceExpression (ec, null);
3157 InstanceExpression = null;
3161 #region IErrorHandler Members
3163 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3168 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3170 rc.Report.SymbolRelatedToPreviousError (best);
3171 rc.Report.Error (1928, loc,
3172 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3173 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3176 rc.Report.Error (1929, loc,
3177 "Extension method instance type `{0}' cannot be converted to `{1}'",
3178 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3184 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3189 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3198 /// MethodGroupExpr represents a group of method candidates which
3199 /// can be resolved to the best method overload
3201 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3203 protected IList<MemberSpec> Methods;
3204 MethodSpec best_candidate;
3205 TypeSpec best_candidate_return;
3206 protected TypeArguments type_arguments;
3208 SimpleName simple_name;
3209 protected TypeSpec queried_type;
3211 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3215 this.type = InternalType.MethodGroup;
3217 eclass = ExprClass.MethodGroup;
3218 queried_type = type;
3221 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3222 : this (new MemberSpec[] { m }, type, loc)
3228 public MethodSpec BestCandidate {
3230 return best_candidate;
3234 public TypeSpec BestCandidateReturnType {
3236 return best_candidate_return;
3240 public IList<MemberSpec> Candidates {
3246 protected override TypeSpec DeclaringType {
3248 return queried_type;
3252 public override bool IsInstance {
3254 if (best_candidate != null)
3255 return !best_candidate.IsStatic;
3261 public override bool IsStatic {
3263 if (best_candidate != null)
3264 return best_candidate.IsStatic;
3270 public override string Name {
3272 if (best_candidate != null)
3273 return best_candidate.Name;
3276 return Methods.First ().Name;
3283 // When best candidate is already know this factory can be used
3284 // to avoid expensive overload resolution to be called
3286 // NOTE: InstanceExpression has to be set manually
3288 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3290 return new MethodGroupExpr (best, queriedType, loc) {
3291 best_candidate = best,
3292 best_candidate_return = best.ReturnType
3296 public override string GetSignatureForError ()
3298 if (best_candidate != null)
3299 return best_candidate.GetSignatureForError ();
3301 return Methods.First ().GetSignatureForError ();
3304 public override Expression CreateExpressionTree (ResolveContext ec)
3306 if (best_candidate == null) {
3307 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3311 if (best_candidate.IsConditionallyExcluded (ec.Module.Compiler, loc))
3312 ec.Report.Error (765, loc,
3313 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3315 return new TypeOfMethod (best_candidate, loc);
3318 protected override Expression DoResolve (ResolveContext ec)
3320 this.eclass = ExprClass.MethodGroup;
3322 if (InstanceExpression != null) {
3323 InstanceExpression = InstanceExpression.Resolve (ec);
3324 if (InstanceExpression == null)
3331 public override void Emit (EmitContext ec)
3333 throw new NotSupportedException ();
3336 public void EmitCall (EmitContext ec, Arguments arguments)
3338 var call = new CallEmitter ();
3339 call.InstanceExpression = InstanceExpression;
3340 call.Emit (ec, best_candidate, arguments, loc);
3343 public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
3345 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3346 Name, TypeManager.CSharpName (target));
3349 public static bool IsExtensionMethodArgument (Expression expr)
3352 // LAMESPEC: No details about which expressions are not allowed
3354 return !(expr is TypeExpr) && !(expr is BaseThis);
3358 /// Find the Applicable Function Members (7.4.2.1)
3360 /// me: Method Group expression with the members to select.
3361 /// it might contain constructors or methods (or anything
3362 /// that maps to a method).
3364 /// Arguments: ArrayList containing resolved Argument objects.
3366 /// loc: The location if we want an error to be reported, or a Null
3367 /// location for "probing" purposes.
3369 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3370 /// that is the best match of me on Arguments.
3373 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3375 // TODO: causes issues with probing mode, remove explicit Kind check
3376 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3379 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3380 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3381 r.BaseMembersProvider = this;
3382 r.InstanceQualifier = this;
3385 if (cerrors != null)
3386 r.CustomErrors = cerrors;
3388 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3389 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3390 if (best_candidate == null)
3391 return r.BestCandidateIsDynamic ? this : null;
3393 // Overload resolver had to create a new method group, all checks bellow have already been executed
3394 if (r.BestCandidateNewMethodGroup != null)
3395 return r.BestCandidateNewMethodGroup;
3397 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3398 if (InstanceExpression != null) {
3399 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3400 InstanceExpression = null;
3402 if (best_candidate.IsStatic && simple_name != null) {
3403 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3406 InstanceExpression.Resolve (ec);
3410 ResolveInstanceExpression (ec, null);
3413 var base_override = CandidateToBaseOverride (ec, best_candidate);
3414 if (base_override == best_candidate) {
3415 best_candidate_return = r.BestCandidateReturnType;
3417 best_candidate = base_override;
3418 best_candidate_return = best_candidate.ReturnType;
3424 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3426 simple_name = original;
3427 return base.ResolveMemberAccess (ec, left, original);
3430 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3432 type_arguments = ta;
3435 #region IBaseMembersProvider Members
3437 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3439 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3442 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3444 if (queried_type == member.DeclaringType)
3447 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3448 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3452 // Extension methods lookup after ordinary methods candidates failed to apply
3454 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3456 if (InstanceExpression == null)
3459 InstanceExpression = InstanceExpression.Resolve (rc);
3460 if (!IsExtensionMethodArgument (InstanceExpression))
3463 int arity = type_arguments == null ? 0 : type_arguments.Count;
3464 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3465 if (methods == null)
3468 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3469 emg.SetTypeArguments (rc, type_arguments);
3476 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3478 public ConstructorInstanceQualifier (TypeSpec type)
3481 InstanceType = type;
3484 public TypeSpec InstanceType { get; private set; }
3486 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3488 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3492 public struct OverloadResolver
3495 public enum Restrictions
3499 ProbingOnly = 1 << 1,
3500 CovariantDelegate = 1 << 2,
3501 NoBaseMembers = 1 << 3,
3502 BaseMembersIncluded = 1 << 4
3505 public interface IBaseMembersProvider
3507 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3508 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3509 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3512 public interface IErrorHandler
3514 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3515 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3516 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3517 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3520 public interface IInstanceQualifier
3522 TypeSpec InstanceType { get; }
3523 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3526 sealed class NoBaseMembers : IBaseMembersProvider
3528 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3530 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3535 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3540 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3546 struct AmbiguousCandidate
3548 public readonly MemberSpec Member;
3549 public readonly bool Expanded;
3550 public readonly AParametersCollection Parameters;
3552 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3555 Parameters = parameters;
3556 Expanded = expanded;
3561 IList<MemberSpec> members;
3562 TypeArguments type_arguments;
3563 IBaseMembersProvider base_provider;
3564 IErrorHandler custom_errors;
3565 IInstanceQualifier instance_qualifier;
3566 Restrictions restrictions;
3567 MethodGroupExpr best_candidate_extension_group;
3568 TypeSpec best_candidate_return_type;
3570 SessionReportPrinter lambda_conv_msgs;
3571 ReportPrinter prev_recorder;
3573 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3574 : this (members, null, restrictions, loc)
3578 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3581 if (members == null || members.Count == 0)
3582 throw new ArgumentException ("empty members set");
3584 this.members = members;
3586 type_arguments = targs;
3587 this.restrictions = restrictions;
3588 if (IsDelegateInvoke)
3589 this.restrictions |= Restrictions.NoBaseMembers;
3591 base_provider = NoBaseMembers.Instance;
3596 public IBaseMembersProvider BaseMembersProvider {
3598 return base_provider;
3601 base_provider = value;
3605 public bool BestCandidateIsDynamic { get; set; }
3608 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3610 public MethodGroupExpr BestCandidateNewMethodGroup {
3612 return best_candidate_extension_group;
3617 // Return type can be different between best candidate and closest override
3619 public TypeSpec BestCandidateReturnType {
3621 return best_candidate_return_type;
3625 public IErrorHandler CustomErrors {
3627 return custom_errors;
3630 custom_errors = value;
3634 TypeSpec DelegateType {
3636 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3637 throw new InternalErrorException ("Not running in delegate mode", loc);
3639 return members [0].DeclaringType;
3643 public IInstanceQualifier InstanceQualifier {
3645 return instance_qualifier;
3648 instance_qualifier = value;
3652 bool IsProbingOnly {
3654 return (restrictions & Restrictions.ProbingOnly) != 0;
3658 bool IsDelegateInvoke {
3660 return (restrictions & Restrictions.DelegateInvoke) != 0;
3667 // 7.4.3.3 Better conversion from expression
3668 // Returns : 1 if a->p is better,
3669 // 2 if a->q is better,
3670 // 0 if neither is better
3672 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3674 TypeSpec argument_type = a.Type;
3677 // If argument is an anonymous function
3679 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3681 // p and q are delegate types or expression tree types
3683 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3684 if (q.MemberDefinition != p.MemberDefinition) {
3689 // Uwrap delegate from Expression<T>
3691 q = TypeManager.GetTypeArguments (q)[0];
3692 p = TypeManager.GetTypeArguments (p)[0];
3695 var p_m = Delegate.GetInvokeMethod (p);
3696 var q_m = Delegate.GetInvokeMethod (q);
3699 // With identical parameter lists
3701 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3708 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3710 if (p.Kind == MemberKind.Void) {
3711 return q.Kind != MemberKind.Void ? 2 : 0;
3715 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3717 if (q.Kind == MemberKind.Void) {
3718 return p.Kind != MemberKind.Void ? 1: 0;
3722 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3723 // better conversion is performed between underlying types Y1 and Y2
3725 if (p.IsGenericTask || q.IsGenericTask) {
3726 var async_am = a.Expr as AnonymousMethodExpression;
3727 if (async_am != null && async_am.Block.IsAsync) {
3729 if (p.IsGenericTask != q.IsGenericTask) {
3733 q = q.TypeArguments[0];
3734 p = p.TypeArguments[0];
3739 // The parameters are identicial and return type is not void, use better type conversion
3740 // on return type to determine better one
3743 if (argument_type == p)
3746 if (argument_type == q)
3750 return BetterTypeConversion (ec, p, q);
3754 // 7.4.3.4 Better conversion from type
3756 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3758 if (p == null || q == null)
3759 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3761 switch (p.BuiltinType) {
3762 case BuiltinTypeSpec.Type.Int:
3763 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3766 case BuiltinTypeSpec.Type.Long:
3767 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3770 case BuiltinTypeSpec.Type.SByte:
3771 switch (q.BuiltinType) {
3772 case BuiltinTypeSpec.Type.Byte:
3773 case BuiltinTypeSpec.Type.UShort:
3774 case BuiltinTypeSpec.Type.UInt:
3775 case BuiltinTypeSpec.Type.ULong:
3779 case BuiltinTypeSpec.Type.Short:
3780 switch (q.BuiltinType) {
3781 case BuiltinTypeSpec.Type.UShort:
3782 case BuiltinTypeSpec.Type.UInt:
3783 case BuiltinTypeSpec.Type.ULong:
3787 case BuiltinTypeSpec.Type.Dynamic:
3788 // Dynamic is never better
3792 switch (q.BuiltinType) {
3793 case BuiltinTypeSpec.Type.Int:
3794 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3797 case BuiltinTypeSpec.Type.Long:
3798 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3801 case BuiltinTypeSpec.Type.SByte:
3802 switch (p.BuiltinType) {
3803 case BuiltinTypeSpec.Type.Byte:
3804 case BuiltinTypeSpec.Type.UShort:
3805 case BuiltinTypeSpec.Type.UInt:
3806 case BuiltinTypeSpec.Type.ULong:
3810 case BuiltinTypeSpec.Type.Short:
3811 switch (p.BuiltinType) {
3812 case BuiltinTypeSpec.Type.UShort:
3813 case BuiltinTypeSpec.Type.UInt:
3814 case BuiltinTypeSpec.Type.ULong:
3818 case BuiltinTypeSpec.Type.Dynamic:
3819 // Dynamic is never better
3823 // FIXME: handle lifted operators
3825 // TODO: this is expensive
3826 Expression p_tmp = new EmptyExpression (p);
3827 Expression q_tmp = new EmptyExpression (q);
3829 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3830 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3832 if (p_to_q && !q_to_p)
3835 if (q_to_p && !p_to_q)
3842 /// Determines "Better function" between candidate
3843 /// and the current best match
3846 /// Returns a boolean indicating :
3847 /// false if candidate ain't better
3848 /// true if candidate is better than the current best match
3850 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
3851 MemberSpec best, AParametersCollection bparam, bool best_params)
3853 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
3854 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
3856 bool better_at_least_one = false;
3858 int args_count = args == null ? 0 : args.Count;
3862 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
3865 // Default arguments are ignored for better decision
3866 if (a.IsDefaultArgument)
3870 // When comparing named argument the parameter type index has to be looked up
3871 // in original parameter set (override version for virtual members)
3873 NamedArgument na = a as NamedArgument;
3875 int idx = cparam.GetParameterIndexByName (na.Name);
3876 ct = candidate_pd.Types[idx];
3877 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3878 ct = TypeManager.GetElementType (ct);
3880 idx = bparam.GetParameterIndexByName (na.Name);
3881 bt = best_pd.Types[idx];
3882 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
3883 bt = TypeManager.GetElementType (bt);
3885 ct = candidate_pd.Types[c_idx];
3886 bt = best_pd.Types[b_idx];
3888 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
3889 ct = TypeManager.GetElementType (ct);
3893 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
3894 bt = TypeManager.GetElementType (bt);
3899 if (TypeSpecComparer.IsEqual (ct, bt))
3903 int result = BetterExpressionConversion (ec, a, ct, bt);
3905 // for each argument, the conversion to 'ct' should be no worse than
3906 // the conversion to 'bt'.
3910 // for at least one argument, the conversion to 'ct' should be better than
3911 // the conversion to 'bt'.
3913 better_at_least_one = true;
3916 if (better_at_least_one)
3920 // This handles the case
3922 // Add (float f1, float f2, float f3);
3923 // Add (params decimal [] foo);
3925 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
3926 // first candidate would've chosen as better.
3928 if (!same && !a.IsDefaultArgument)
3932 // The two methods have equal non-optional parameter types, apply tie-breaking rules
3936 // This handles the following cases:
3938 // Foo (int i) is better than Foo (int i, long l = 0)
3939 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
3941 // Prefer non-optional version
3943 // LAMESPEC: Specification claims this should be done at last but the opposite is true
3945 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
3946 if (candidate_pd.Count >= best_pd.Count)
3949 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
3956 // One is a non-generic method and second is a generic method, then non-generic is better
3958 if (best.IsGeneric != candidate.IsGeneric)
3959 return best.IsGeneric;
3962 // This handles the following cases:
3964 // Trim () is better than Trim (params char[] chars)
3965 // Concat (string s1, string s2, string s3) is better than
3966 // Concat (string s1, params string [] srest)
3967 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
3969 // Prefer non-expanded version
3971 if (candidate_params != best_params)
3974 int candidate_param_count = candidate_pd.Count;
3975 int best_param_count = best_pd.Count;
3977 if (candidate_param_count != best_param_count)
3978 // can only happen if (candidate_params && best_params)
3979 return candidate_param_count > best_param_count && best_pd.HasParams;
3982 // Both methods have the same number of parameters, and the parameters have equal types
3983 // Pick the "more specific" signature using rules over original (non-inflated) types
3985 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
3986 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
3988 bool specific_at_least_once = false;
3989 for (j = 0; j < args_count; ++j) {
3990 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
3992 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
3993 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
3995 ct = candidate_def_pd.Types[j];
3996 bt = best_def_pd.Types[j];
4001 TypeSpec specific = MoreSpecific (ct, bt);
4005 specific_at_least_once = true;
4008 if (specific_at_least_once)
4014 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4016 rc.Report.Error (1729, loc,
4017 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4018 type.GetSignatureForError (), argCount.ToString ());
4022 // Determines if the candidate method is applicable to the given set of arguments
4023 // There could be two different set of parameters for same candidate where one
4024 // is the closest override for default values and named arguments checks and second
4025 // one being the virtual base for the parameter types and modifiers.
4027 // A return value rates candidate method compatibility,
4028 // 0 = the best, int.MaxValue = the worst
4030 int IsApplicable (ResolveContext ec, ref Arguments arguments, int arg_count, ref MemberSpec candidate, IParametersMember pm, ref bool params_expanded_form, ref bool dynamicArgument, ref TypeSpec returnType)
4032 // Parameters of most-derived type used mainly for named and optional parameters
4033 var pd = pm.Parameters;
4035 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4036 // params modifier instead of most-derived type
4037 var cpd = ((IParametersMember) candidate).Parameters;
4038 int param_count = pd.Count;
4039 int optional_count = 0;
4041 Arguments orig_args = arguments;
4043 if (arg_count != param_count) {
4044 for (int i = 0; i < pd.Count; ++i) {
4045 if (pd.FixedParameters[i].HasDefaultValue) {
4046 optional_count = pd.Count - i;
4051 if (optional_count != 0) {
4052 // Readjust expected number when params used
4053 if (cpd.HasParams) {
4055 if (arg_count < param_count)
4057 } else if (arg_count > param_count) {
4058 int args_gap = System.Math.Abs (arg_count - param_count);
4059 return int.MaxValue - 10000 + args_gap;
4061 } else if (arg_count != param_count) {
4062 int args_gap = System.Math.Abs (arg_count - param_count);
4064 return int.MaxValue - 10000 + args_gap;
4065 if (arg_count < param_count - 1)
4066 return int.MaxValue - 10000 + args_gap;
4069 // Resize to fit optional arguments
4070 if (optional_count != 0) {
4071 if (arguments == null) {
4072 arguments = new Arguments (optional_count);
4074 // Have to create a new container, so the next run can do same
4075 var resized = new Arguments (param_count);
4076 resized.AddRange (arguments);
4077 arguments = resized;
4080 for (int i = arg_count; i < param_count; ++i)
4081 arguments.Add (null);
4085 if (arg_count > 0) {
4087 // Shuffle named arguments to the right positions if there are any
4089 if (arguments[arg_count - 1] is NamedArgument) {
4090 arg_count = arguments.Count;
4092 for (int i = 0; i < arg_count; ++i) {
4093 bool arg_moved = false;
4095 NamedArgument na = arguments[i] as NamedArgument;
4099 int index = pd.GetParameterIndexByName (na.Name);
4101 // Named parameter not found
4105 // already reordered
4110 if (index >= param_count) {
4111 // When using parameters which should not be available to the user
4112 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4115 arguments.Add (null);
4119 temp = arguments[index];
4121 // The slot has been taken by positional argument
4122 if (temp != null && !(temp is NamedArgument))
4127 arguments = arguments.MarkOrderedArgument (na);
4131 arguments[index] = arguments[i];
4132 arguments[i] = temp;
4139 arg_count = arguments.Count;
4141 } else if (arguments != null) {
4142 arg_count = arguments.Count;
4146 // 1. Handle generic method using type arguments when specified or type inference
4149 var ms = candidate as MethodSpec;
4150 if (ms != null && ms.IsGeneric) {
4151 // Setup constraint checker for probing only
4152 ConstraintChecker cc = new ConstraintChecker (null);
4154 if (type_arguments != null) {
4155 var g_args_count = ms.Arity;
4156 if (g_args_count != type_arguments.Count)
4157 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4159 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4161 // TODO: It should not be here (we don't know yet whether any argument is lambda) but
4162 // for now it simplifies things. I should probably add a callback to ResolveContext
4163 if (lambda_conv_msgs == null) {
4164 lambda_conv_msgs = new SessionReportPrinter ();
4165 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4168 var ti = new TypeInference (arguments);
4169 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4170 lambda_conv_msgs.EndSession ();
4173 return ti.InferenceScore - 20000;
4175 if (i_args.Length != 0) {
4176 ms = ms.MakeGenericMethod (ec, i_args);
4179 cc.IgnoreInferredDynamic = true;
4183 // Type arguments constraints have to match for the method to be applicable
4185 if (!cc.CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc)) {
4187 return int.MaxValue - 25000;
4191 // We have a generic return type and at same time the method is override which
4192 // means we have to also inflate override return type in case the candidate is
4193 // best candidate and override return type is different to base return type.
4195 // virtual Foo<T, object> with override Foo<T, dynamic>
4197 if (candidate != pm) {
4198 MethodSpec override_ms = (MethodSpec) pm;
4199 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4200 returnType = inflator.Inflate (returnType);
4202 returnType = ms.ReturnType;
4206 ptypes = ms.Parameters.Types;
4208 if (type_arguments != null)
4209 return int.MaxValue - 15000;
4215 // 2. Each argument has to be implicitly convertible to method parameter
4217 Parameter.Modifier p_mod = 0;
4220 for (int i = 0; i < arg_count; i++) {
4221 Argument a = arguments[i];
4223 if (!pd.FixedParameters[i].HasDefaultValue) {
4224 arguments = orig_args;
4225 return arg_count * 2 + 2;
4229 // Get the default value expression, we can use the same expression
4230 // if the type matches
4232 Expression e = pd.FixedParameters[i].DefaultValue;
4233 if (!(e is Constant) || e.Type.IsGenericOrParentIsGeneric || e.Type.IsGenericParameter) {
4235 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4237 if (e == EmptyExpression.MissingValue && ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Object || ptypes[i].BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4238 e = new MemberAccess (new MemberAccess (new MemberAccess (
4239 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4241 e = new DefaultValueExpression (new TypeExpression (ptypes [i], loc), loc);
4247 arguments[i] = new Argument (e, Argument.AType.Default);
4251 if (p_mod != Parameter.Modifier.PARAMS) {
4252 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4254 } else if (!params_expanded_form) {
4255 params_expanded_form = true;
4256 pt = ((ElementTypeSpec) pt).Element;
4262 if (!params_expanded_form) {
4263 if (a.ArgType == Argument.AType.ExtensionType) {
4265 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4267 // LAMESPEC: or implicit type parameter conversion
4270 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4271 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4272 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4277 score = IsArgumentCompatible (ec, a, p_mod & ~Parameter.Modifier.PARAMS, pt);
4280 dynamicArgument = true;
4285 // It can be applicable in expanded form (when not doing exact match like for delegates)
4287 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4288 if (!params_expanded_form)
4289 pt = ((ElementTypeSpec) pt).Element;
4292 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4295 params_expanded_form = true;
4296 } else if (score < 0) {
4297 params_expanded_form = true;
4298 dynamicArgument = true;
4303 if (params_expanded_form)
4305 return (arg_count - i) * 2 + score;
4310 // When params parameter has no argument it will be provided later if the method is the best candidate
4312 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4313 params_expanded_form = true;
4316 // Restore original arguments for dynamic binder to keep the intention of original source code
4318 if (dynamicArgument)
4319 arguments = orig_args;
4325 // Tests argument compatibility with the parameter
4326 // The possible return values are
4328 // 1 - modifier mismatch
4329 // 2 - type mismatch
4330 // -1 - dynamic binding required
4332 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4335 // Types have to be identical when ref or out modifer
4336 // is used and argument is not of dynamic type
4338 if ((argument.Modifier | param_mod) != 0) {
4339 if (argument.Type != parameter) {
4341 // Do full equality check after quick path
4343 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4345 // Using dynamic for ref/out parameter can still succeed at runtime
4347 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4354 if (argument.Modifier != param_mod) {
4356 // Using dynamic for ref/out parameter can still succeed at runtime
4358 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && argument.Modifier == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4365 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4369 // Deploy custom error reporting for lambda methods. When probing lambda methods
4370 // keep all errors reported in separate set and once we are done and no best
4371 // candidate was found, this set is used to report more details about what was wrong
4374 if (argument.Expr.Type == InternalType.AnonymousMethod) {
4375 if (lambda_conv_msgs == null) {
4376 lambda_conv_msgs = new SessionReportPrinter ();
4377 prev_recorder = ec.Report.SetPrinter (lambda_conv_msgs);
4382 // Use implicit conversion in all modes to return same candidates when the expression
4383 // is used as argument or delegate conversion
4385 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4386 if (lambda_conv_msgs != null) {
4387 lambda_conv_msgs.EndSession ();
4397 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4399 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4401 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4404 var ac_p = p as ArrayContainer;
4406 var ac_q = ((ArrayContainer) q);
4407 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4408 if (specific == ac_p.Element)
4410 if (specific == ac_q.Element)
4412 } else if (TypeManager.IsGenericType (p)) {
4413 var pargs = TypeManager.GetTypeArguments (p);
4414 var qargs = TypeManager.GetTypeArguments (q);
4416 bool p_specific_at_least_once = false;
4417 bool q_specific_at_least_once = false;
4419 for (int i = 0; i < pargs.Length; i++) {
4420 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4421 if (specific == pargs[i])
4422 p_specific_at_least_once = true;
4423 if (specific == qargs[i])
4424 q_specific_at_least_once = true;
4427 if (p_specific_at_least_once && !q_specific_at_least_once)
4429 if (!p_specific_at_least_once && q_specific_at_least_once)
4437 // Find the best method from candidate list
4439 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4441 List<AmbiguousCandidate> ambiguous_candidates = null;
4443 MemberSpec best_candidate;
4444 Arguments best_candidate_args = null;
4445 bool best_candidate_params = false;
4446 bool best_candidate_dynamic = false;
4447 int best_candidate_rate;
4448 IParametersMember best_parameter_member = null;
4450 int args_count = args != null ? args.Count : 0;
4452 Arguments candidate_args = args;
4453 bool error_mode = false;
4454 MemberSpec invocable_member = null;
4456 // Be careful, cannot return until error reporter is restored
4458 best_candidate = null;
4459 best_candidate_rate = int.MaxValue;
4461 var type_members = members;
4465 for (int i = 0; i < type_members.Count; ++i) {
4466 var member = type_members[i];
4469 // Methods in a base class are not candidates if any method in a derived
4470 // class is applicable
4472 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4476 if (!member.IsAccessible (rc))
4479 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4482 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4483 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4488 IParametersMember pm = member as IParametersMember;
4491 // Will use it later to report ambiguity between best method and invocable member
4493 if (Invocation.IsMemberInvocable (member))
4494 invocable_member = member;
4500 // Overload resolution is looking for base member but using parameter names
4501 // and default values from the closest member. That means to do expensive lookup
4502 // for the closest override for virtual or abstract members
4504 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4505 var override_params = base_provider.GetOverrideMemberParameters (member);
4506 if (override_params != null)
4507 pm = override_params;
4511 // Check if the member candidate is applicable
4513 bool params_expanded_form = false;
4514 bool dynamic_argument = false;
4515 TypeSpec rt = pm.MemberType;
4516 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4519 // How does it score compare to others
4521 if (candidate_rate < best_candidate_rate) {
4522 best_candidate_rate = candidate_rate;
4523 best_candidate = member;
4524 best_candidate_args = candidate_args;
4525 best_candidate_params = params_expanded_form;
4526 best_candidate_dynamic = dynamic_argument;
4527 best_parameter_member = pm;
4528 best_candidate_return_type = rt;
4529 } else if (candidate_rate == 0) {
4531 // The member look is done per type for most operations but sometimes
4532 // it's not possible like for binary operators overload because they
4533 // are unioned between 2 sides
4535 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4536 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4541 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4543 // We pack all interface members into top level type which makes the overload resolution
4544 // more complicated for interfaces. We compensate it by removing methods with same
4545 // signature when building the cache hence this path should not really be hit often
4548 // interface IA { void Foo (int arg); }
4549 // interface IB : IA { void Foo (params int[] args); }
4551 // IB::Foo is the best overload when calling IB.Foo (1)
4554 if (ambiguous_candidates != null) {
4555 foreach (var amb_cand in ambiguous_candidates) {
4556 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4565 ambiguous_candidates = null;
4568 // Is the new candidate better
4569 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4573 best_candidate = member;
4574 best_candidate_args = candidate_args;
4575 best_candidate_params = params_expanded_form;
4576 best_candidate_dynamic = dynamic_argument;
4577 best_parameter_member = pm;
4578 best_candidate_return_type = rt;
4580 // It's not better but any other found later could be but we are not sure yet
4581 if (ambiguous_candidates == null)
4582 ambiguous_candidates = new List<AmbiguousCandidate> ();
4584 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4588 // Restore expanded arguments
4589 if (candidate_args != args)
4590 candidate_args = args;
4592 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4594 if (prev_recorder != null)
4595 rc.Report.SetPrinter (prev_recorder);
4599 // We've found exact match
4601 if (best_candidate_rate == 0)
4605 // Try extension methods lookup when no ordinary method match was found and provider enables it
4608 var emg = base_provider.LookupExtensionMethod (rc);
4610 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4612 best_candidate_extension_group = emg;
4613 return (T) (MemberSpec) emg.BestCandidate;
4618 // Don't run expensive error reporting mode for probing
4625 lambda_conv_msgs = null;
4630 // No best member match found, report an error
4632 if (best_candidate_rate != 0 || error_mode) {
4633 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4637 if (best_candidate_dynamic) {
4638 if (args[0].ArgType == Argument.AType.ExtensionType) {
4639 rc.Report.Error (1973, loc,
4640 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' cannot be dynamically dispatched. Consider calling the method without the extension method syntax",
4641 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4644 BestCandidateIsDynamic = true;
4649 // These flags indicates we are running delegate probing conversion. No need to
4650 // do more expensive checks
4652 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4653 return (T) best_candidate;
4655 if (ambiguous_candidates != null) {
4657 // Now check that there are no ambiguities i.e the selected method
4658 // should be better than all the others
4660 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4661 var candidate = ambiguous_candidates [ix];
4663 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4664 var ambiguous = candidate.Member;
4665 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4666 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4667 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4668 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4669 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4672 return (T) best_candidate;
4677 if (invocable_member != null) {
4678 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4679 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4680 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4681 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4685 // And now check if the arguments are all
4686 // compatible, perform conversions if
4687 // necessary etc. and return if everything is
4690 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4693 if (best_candidate == null)
4697 // Check ObsoleteAttribute on the best method
4699 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4700 if (oa != null && !rc.IsObsolete)
4701 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4703 var dep = best_candidate.GetMissingDependencies ();
4705 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
4708 best_candidate.MemberDefinition.SetIsUsed ();
4710 args = best_candidate_args;
4711 return (T) best_candidate;
4714 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4716 return ResolveMember<MethodSpec> (rc, ref args);
4719 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4720 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4722 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4725 if (a is CollectionElementInitializer.ElementInitializerArgument) {
4726 ec.Report.SymbolRelatedToPreviousError (method);
4727 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.ISBYREF) != 0) {
4728 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have 'ref', or `out' modifier",
4729 TypeManager.CSharpSignature (method));
4732 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
4733 TypeManager.CSharpSignature (method));
4734 } else if (IsDelegateInvoke) {
4735 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4736 DelegateType.GetSignatureForError ());
4738 ec.Report.SymbolRelatedToPreviousError (method);
4739 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4740 method.GetSignatureForError ());
4743 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
4745 string index = (idx + 1).ToString ();
4746 if (((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) ^
4747 (a.Modifier & (Parameter.Modifier.REF | Parameter.Modifier.OUT))) != 0) {
4748 if ((mod & Parameter.Modifier.ISBYREF) == 0)
4749 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
4750 index, Parameter.GetModifierSignature (a.Modifier));
4752 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
4753 index, Parameter.GetModifierSignature (mod));
4754 } else if (a.Expr != ErrorExpression.Instance) {
4755 string p1 = a.GetSignatureForError ();
4756 string p2 = TypeManager.CSharpName (paramType);
4759 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
4760 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
4763 ec.Report.Error (1503, loc,
4764 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
4769 // We have failed to find exact match so we return error info about the closest match
4771 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
4773 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
4774 int arg_count = args == null ? 0 : args.Count;
4776 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
4777 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
4778 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
4782 if (lambda_conv_msgs != null) {
4783 if (lambda_conv_msgs.Merge (rc.Report.Printer))
4788 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4789 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
4790 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
4794 // For candidates which match on parameters count report more details about incorrect arguments
4797 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
4798 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
4799 // Reject any inaccessible member
4800 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
4801 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4802 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
4806 var ms = best_candidate as MethodSpec;
4807 if (ms != null && ms.IsGeneric) {
4808 bool constr_ok = true;
4809 if (ms.TypeArguments != null)
4810 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
4812 if (ta_count == 0) {
4813 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
4817 rc.Report.Error (411, loc,
4818 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
4819 ms.GetGenericMethodDefinition ().GetSignatureForError ());
4826 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
4832 // We failed to find any method with correct argument count, report best candidate
4834 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
4837 if (best_candidate.Kind == MemberKind.Constructor) {
4838 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4839 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
4840 } else if (IsDelegateInvoke) {
4841 rc.Report.SymbolRelatedToPreviousError (DelegateType);
4842 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
4843 DelegateType.GetSignatureForError (), arg_count.ToString ());
4845 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
4846 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4847 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4848 name, arg_count.ToString ());
4852 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
4854 var pd = pm.Parameters;
4855 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
4857 Parameter.Modifier p_mod = 0;
4859 int a_idx = 0, a_pos = 0;
4861 ArrayInitializer params_initializers = null;
4862 bool has_unsafe_arg = pm.MemberType.IsPointer;
4863 int arg_count = args == null ? 0 : args.Count;
4865 for (; a_idx < arg_count; a_idx++, ++a_pos) {
4867 if (p_mod != Parameter.Modifier.PARAMS) {
4868 p_mod = pd.FixedParameters[a_idx].ModFlags;
4870 has_unsafe_arg |= pt.IsPointer;
4872 if (p_mod == Parameter.Modifier.PARAMS) {
4873 if (chose_params_expanded) {
4874 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
4875 pt = TypeManager.GetElementType (pt);
4881 // Types have to be identical when ref or out modifer is used
4883 if (a.Modifier != 0 || (p_mod & ~Parameter.Modifier.PARAMS) != 0) {
4884 if ((p_mod & ~Parameter.Modifier.PARAMS) != a.Modifier)
4887 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
4893 NamedArgument na = a as NamedArgument;
4895 int name_index = pd.GetParameterIndexByName (na.Name);
4896 if (name_index < 0 || name_index >= pd.Count) {
4897 if (IsDelegateInvoke) {
4898 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4899 ec.Report.Error (1746, na.Location,
4900 "The delegate `{0}' does not contain a parameter named `{1}'",
4901 DelegateType.GetSignatureForError (), na.Name);
4903 ec.Report.SymbolRelatedToPreviousError (member);
4904 ec.Report.Error (1739, na.Location,
4905 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
4906 TypeManager.CSharpSignature (member), na.Name);
4908 } else if (args[name_index] != a) {
4909 if (IsDelegateInvoke)
4910 ec.Report.SymbolRelatedToPreviousError (DelegateType);
4912 ec.Report.SymbolRelatedToPreviousError (member);
4914 ec.Report.Error (1744, na.Location,
4915 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
4920 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4923 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
4924 custom_errors.NoArgumentMatch (ec, member);
4928 Expression conv = null;
4929 if (a.ArgType == Argument.AType.ExtensionType) {
4930 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
4933 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
4935 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
4938 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
4945 // Convert params arguments to an array initializer
4947 if (params_initializers != null) {
4948 // we choose to use 'a.Expr' rather than 'conv' so that
4949 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
4950 params_initializers.Add (a.Expr);
4951 args.RemoveAt (a_idx--);
4956 // Update the argument with the implicit conversion
4960 if (a_idx != arg_count) {
4961 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
4966 // Fill not provided arguments required by params modifier
4968 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
4970 args = new Arguments (1);
4972 pt = ptypes[pd.Count - 1];
4973 pt = TypeManager.GetElementType (pt);
4974 has_unsafe_arg |= pt.IsPointer;
4975 params_initializers = new ArrayInitializer (0, loc);
4979 // Append an array argument with all params arguments
4981 if (params_initializers != null) {
4982 args.Add (new Argument (
4983 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
4987 if (has_unsafe_arg && !ec.IsUnsafe) {
4988 Expression.UnsafeError (ec, loc);
4992 // We could infer inaccesible type arguments
4994 if (type_arguments == null && member.IsGeneric) {
4995 var ms = (MethodSpec) member;
4996 foreach (var ta in ms.TypeArguments) {
4997 if (!ta.IsAccessible (ec)) {
4998 ec.Report.SymbolRelatedToPreviousError (ta);
4999 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5009 public class ConstantExpr : MemberExpr
5011 readonly ConstSpec constant;
5013 public ConstantExpr (ConstSpec constant, Location loc)
5015 this.constant = constant;
5019 public override string Name {
5020 get { throw new NotImplementedException (); }
5023 public override bool IsInstance {
5024 get { return !IsStatic; }
5027 public override bool IsStatic {
5028 get { return true; }
5031 protected override TypeSpec DeclaringType {
5032 get { return constant.DeclaringType; }
5035 public override Expression CreateExpressionTree (ResolveContext ec)
5037 throw new NotSupportedException ("ET");
5040 protected override Expression DoResolve (ResolveContext rc)
5042 ResolveInstanceExpression (rc, null);
5043 DoBestMemberChecks (rc, constant);
5045 var c = constant.GetConstant (rc);
5047 // Creates reference expression to the constant value
5048 return Constant.CreateConstant (constant.MemberType, c.GetValue (), loc);
5051 public override void Emit (EmitContext ec)
5053 throw new NotSupportedException ();
5056 public override string GetSignatureForError ()
5058 return constant.GetSignatureForError ();
5061 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5063 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5068 // Fully resolved expression that references a Field
5070 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5072 protected FieldSpec spec;
5073 VariableInfo variable_info;
5075 LocalTemporary temp;
5078 protected FieldExpr (Location l)
5083 public FieldExpr (FieldSpec spec, Location loc)
5088 type = spec.MemberType;
5091 public FieldExpr (FieldBase fi, Location l)
5098 public override string Name {
5104 public bool IsHoisted {
5106 IVariableReference hv = InstanceExpression as IVariableReference;
5107 return hv != null && hv.IsHoisted;
5111 public override bool IsInstance {
5113 return !spec.IsStatic;
5117 public override bool IsStatic {
5119 return spec.IsStatic;
5123 public FieldSpec Spec {
5129 protected override TypeSpec DeclaringType {
5131 return spec.DeclaringType;
5135 public VariableInfo VariableInfo {
5137 return variable_info;
5143 public override string GetSignatureForError ()
5145 return spec.GetSignatureForError ();
5148 public bool IsMarshalByRefAccess (ResolveContext rc)
5150 // Checks possible ldflda of field access expression
5151 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5152 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5153 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5156 public void SetHasAddressTaken ()
5158 IVariableReference vr = InstanceExpression as IVariableReference;
5160 vr.SetHasAddressTaken ();
5164 public override Expression CreateExpressionTree (ResolveContext ec)
5166 Expression instance;
5167 if (InstanceExpression == null) {
5168 instance = new NullLiteral (loc);
5170 instance = InstanceExpression.CreateExpressionTree (ec);
5173 Arguments args = Arguments.CreateForExpressionTree (ec, null,
5175 CreateTypeOfExpression ());
5177 return CreateExpressionFactoryCall (ec, "Field", args);
5180 public Expression CreateTypeOfExpression ()
5182 return new TypeOfField (spec, loc);
5185 protected override Expression DoResolve (ResolveContext ec)
5187 return DoResolve (ec, null);
5190 Expression DoResolve (ResolveContext ec, Expression rhs)
5192 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5195 if (ResolveInstanceExpression (ec, rhs)) {
5196 // Resolve the field's instance expression while flow analysis is turned
5197 // off: when accessing a field "a.b", we must check whether the field
5198 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5200 if (lvalue_instance) {
5201 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5202 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5204 Expression right_side =
5205 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5207 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5210 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5211 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5215 if (InstanceExpression == null)
5219 DoBestMemberChecks (ec, spec);
5222 var fb = spec as FixedFieldSpec;
5223 IVariableReference var = InstanceExpression as IVariableReference;
5225 if (lvalue_instance && var != null && var.VariableInfo != null) {
5226 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5230 IFixedExpression fe = InstanceExpression as IFixedExpression;
5231 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5232 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5235 if (InstanceExpression.eclass != ExprClass.Variable) {
5236 ec.Report.SymbolRelatedToPreviousError (spec);
5237 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5238 TypeManager.GetFullNameSignature (spec));
5239 } else if (var != null && var.IsHoisted) {
5240 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5243 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5247 // Set flow-analysis variable info for struct member access. It will be check later
5248 // for precise error reporting
5250 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5251 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5252 if (rhs != null && variable_info != null)
5253 variable_info.SetStructFieldAssigned (ec, Name);
5256 eclass = ExprClass.Variable;
5260 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5265 var var = fe.InstanceExpression as IVariableReference;
5267 var vi = var.VariableInfo;
5269 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5271 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5273 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5280 fe = fe.InstanceExpression as FieldExpr;
5282 } while (fe != null);
5285 static readonly int [] codes = {
5286 191, // instance, write access
5287 192, // instance, out access
5288 198, // static, write access
5289 199, // static, out access
5290 1648, // member of value instance, write access
5291 1649, // member of value instance, out access
5292 1650, // member of value static, write access
5293 1651 // member of value static, out access
5296 static readonly string [] msgs = {
5297 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5298 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5299 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5300 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5301 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5302 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5303 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5304 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5307 // The return value is always null. Returning a value simplifies calling code.
5308 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5311 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5315 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5317 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5322 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5324 Expression e = DoResolve (ec, right_side);
5329 spec.MemberDefinition.SetIsAssigned ();
5331 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5332 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5333 ec.Report.Warning (420, 1, loc,
5334 "`{0}': A volatile field references will not be treated as volatile",
5335 spec.GetSignatureForError ());
5338 if (spec.IsReadOnly) {
5339 // InitOnly fields can only be assigned in constructors or initializers
5340 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5341 return Report_AssignToReadonly (ec, right_side);
5343 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5345 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5346 if (ec.CurrentMemberDefinition.Parent.Definition != spec.DeclaringType.GetDefinition ())
5347 return Report_AssignToReadonly (ec, right_side);
5348 // static InitOnly fields cannot be assigned-to in an instance constructor
5349 if (IsStatic && !ec.IsStatic)
5350 return Report_AssignToReadonly (ec, right_side);
5351 // instance constructors can't modify InitOnly fields of other instances of the same type
5352 if (!IsStatic && !(InstanceExpression is This))
5353 return Report_AssignToReadonly (ec, right_side);
5357 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5358 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5359 ec.Report.Warning (197, 1, loc,
5360 "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",
5361 GetSignatureForError ());
5364 eclass = ExprClass.Variable;
5368 public override int GetHashCode ()
5370 return spec.GetHashCode ();
5373 public bool IsFixed {
5376 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5378 IVariableReference variable = InstanceExpression as IVariableReference;
5379 if (variable != null)
5380 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5382 IFixedExpression fe = InstanceExpression as IFixedExpression;
5383 return fe != null && fe.IsFixed;
5387 public override bool Equals (object obj)
5389 FieldExpr fe = obj as FieldExpr;
5393 if (spec != fe.spec)
5396 if (InstanceExpression == null || fe.InstanceExpression == null)
5399 return InstanceExpression.Equals (fe.InstanceExpression);
5402 public void Emit (EmitContext ec, bool leave_copy)
5404 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5406 spec.MemberDefinition.SetIsUsed ();
5410 ec.Emit (OpCodes.Volatile);
5412 ec.Emit (OpCodes.Ldsfld, spec);
5415 EmitInstance (ec, false);
5417 // Optimization for build-in types
5418 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5419 ec.EmitLoadFromPtr (type);
5421 var ff = spec as FixedFieldSpec;
5423 ec.Emit (OpCodes.Ldflda, spec);
5424 ec.Emit (OpCodes.Ldflda, ff.Element);
5427 ec.Emit (OpCodes.Volatile);
5429 ec.Emit (OpCodes.Ldfld, spec);
5435 ec.Emit (OpCodes.Dup);
5437 temp = new LocalTemporary (this.Type);
5443 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5445 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5446 if (isCompound && !(source is DynamicExpressionStatement)) {
5447 if (has_await_source) {
5449 InstanceExpression = InstanceExpression.EmitToField (ec);
5456 if (has_await_source)
5457 source = source.EmitToField (ec);
5459 EmitInstance (ec, prepared);
5465 ec.Emit (OpCodes.Dup);
5467 temp = new LocalTemporary (this.Type);
5472 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5473 ec.Emit (OpCodes.Volatile);
5475 spec.MemberDefinition.SetIsAssigned ();
5478 ec.Emit (OpCodes.Stsfld, spec);
5480 ec.Emit (OpCodes.Stfld, spec);
5490 // Emits store to field with prepared values on stack
5492 public void EmitAssignFromStack (EmitContext ec)
5495 ec.Emit (OpCodes.Stsfld, spec);
5497 ec.Emit (OpCodes.Stfld, spec);
5501 public override void Emit (EmitContext ec)
5506 public override void EmitSideEffect (EmitContext ec)
5508 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5510 if (is_volatile) // || is_marshal_by_ref ())
5511 base.EmitSideEffect (ec);
5514 public void AddressOf (EmitContext ec, AddressOp mode)
5516 if ((mode & AddressOp.Store) != 0)
5517 spec.MemberDefinition.SetIsAssigned ();
5518 if ((mode & AddressOp.Load) != 0)
5519 spec.MemberDefinition.SetIsUsed ();
5522 // Handle initonly fields specially: make a copy and then
5523 // get the address of the copy.
5526 if (spec.IsReadOnly){
5528 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5540 var temp = ec.GetTemporaryLocal (type);
5541 ec.Emit (OpCodes.Stloc, temp);
5542 ec.Emit (OpCodes.Ldloca, temp);
5543 ec.FreeTemporaryLocal (temp, type);
5549 ec.Emit (OpCodes.Ldsflda, spec);
5552 EmitInstance (ec, false);
5553 ec.Emit (OpCodes.Ldflda, spec);
5557 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5559 return MakeExpression (ctx);
5562 public override SLE.Expression MakeExpression (BuilderContext ctx)
5565 return base.MakeExpression (ctx);
5567 return SLE.Expression.Field (
5568 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5569 spec.GetMetaInfo ());
5573 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5575 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5581 // Expression that evaluates to a Property.
5583 // This is not an LValue because we need to re-write the expression. We
5584 // can not take data from the stack and store it.
5586 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5588 public PropertyExpr (PropertySpec spec, Location l)
5591 best_candidate = spec;
5592 type = spec.MemberType;
5597 protected override Arguments Arguments {
5605 protected override TypeSpec DeclaringType {
5607 return best_candidate.DeclaringType;
5611 public override string Name {
5613 return best_candidate.Name;
5617 public override bool IsInstance {
5623 public override bool IsStatic {
5625 return best_candidate.IsStatic;
5629 public PropertySpec PropertyInfo {
5631 return best_candidate;
5637 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5639 return new PropertyExpr (spec, loc) {
5645 public override Expression CreateExpressionTree (ResolveContext ec)
5648 if (IsSingleDimensionalArrayLength ()) {
5649 args = new Arguments (1);
5650 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5651 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5654 args = new Arguments (2);
5655 if (InstanceExpression == null)
5656 args.Add (new Argument (new NullLiteral (loc)));
5658 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5659 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5660 return CreateExpressionFactoryCall (ec, "Property", args);
5663 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5665 DoResolveLValue (rc, null);
5666 return new TypeOfMethod (Setter, loc);
5669 public override string GetSignatureForError ()
5671 return best_candidate.GetSignatureForError ();
5674 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5677 return base.MakeExpression (ctx);
5679 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5683 public override SLE.Expression MakeExpression (BuilderContext ctx)
5686 return base.MakeExpression (ctx);
5688 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
5692 void Error_PropertyNotValid (ResolveContext ec)
5694 ec.Report.SymbolRelatedToPreviousError (best_candidate);
5695 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
5696 GetSignatureForError ());
5699 bool IsSingleDimensionalArrayLength ()
5701 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
5704 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
5705 return ac != null && ac.Rank == 1;
5708 public override void Emit (EmitContext ec, bool leave_copy)
5711 // Special case: length of single dimension array property is turned into ldlen
5713 if (IsSingleDimensionalArrayLength ()) {
5714 EmitInstance (ec, false);
5715 ec.Emit (OpCodes.Ldlen);
5716 ec.Emit (OpCodes.Conv_I4);
5720 base.Emit (ec, leave_copy);
5723 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5726 LocalTemporary await_source_arg = null;
5728 if (isCompound && !(source is DynamicExpressionStatement)) {
5729 emitting_compound_assignment = true;
5732 if (has_await_arguments) {
5733 await_source_arg = new LocalTemporary (Type);
5734 await_source_arg.Store (ec);
5736 args = new Arguments (1);
5737 args.Add (new Argument (await_source_arg));
5740 temp = await_source_arg;
5743 has_await_arguments = false;
5748 ec.Emit (OpCodes.Dup);
5749 temp = new LocalTemporary (this.Type);
5754 args = new Arguments (1);
5758 temp = new LocalTemporary (this.Type);
5760 args.Add (new Argument (temp));
5762 args.Add (new Argument (source));
5766 emitting_compound_assignment = false;
5768 var call = new CallEmitter ();
5769 call.InstanceExpression = InstanceExpression;
5771 call.InstanceExpressionOnStack = true;
5773 call.Emit (ec, Setter, args, loc);
5780 if (await_source_arg != null) {
5781 await_source_arg.Release (ec);
5785 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
5787 eclass = ExprClass.PropertyAccess;
5789 if (best_candidate.IsNotCSharpCompatible) {
5790 Error_PropertyNotValid (rc);
5793 ResolveInstanceExpression (rc, right_side);
5795 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
5796 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
5797 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
5799 type = p.MemberType;
5803 DoBestMemberChecks (rc, best_candidate);
5807 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5809 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
5813 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
5815 // getter and setter can be different for base calls
5816 MethodSpec getter, setter;
5817 protected T best_candidate;
5819 protected LocalTemporary temp;
5820 protected bool emitting_compound_assignment;
5821 protected bool has_await_arguments;
5823 protected PropertyOrIndexerExpr (Location l)
5830 protected abstract Arguments Arguments { get; set; }
5832 public MethodSpec Getter {
5841 public MethodSpec Setter {
5852 protected override Expression DoResolve (ResolveContext ec)
5854 if (eclass == ExprClass.Unresolved) {
5855 var expr = OverloadResolve (ec, null);
5860 return expr.Resolve (ec);
5863 if (!ResolveGetter (ec))
5869 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5871 if (right_side == EmptyExpression.OutAccess) {
5872 // TODO: best_candidate can be null at this point
5873 INamedBlockVariable variable = null;
5874 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
5875 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
5876 best_candidate.Name);
5878 right_side.DoResolveLValue (ec, this);
5883 // if the property/indexer returns a value type, and we try to set a field in it
5884 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
5885 Error_ValueAssignment (ec, right_side);
5888 if (eclass == ExprClass.Unresolved) {
5889 var expr = OverloadResolve (ec, right_side);
5894 return expr.ResolveLValue (ec, right_side);
5897 if (!ResolveSetter (ec))
5904 // Implements the IAssignMethod interface for assignments
5906 public virtual void Emit (EmitContext ec, bool leave_copy)
5908 var call = new CallEmitter ();
5909 call.InstanceExpression = InstanceExpression;
5910 if (has_await_arguments)
5911 call.HasAwaitArguments = true;
5913 call.DuplicateArguments = emitting_compound_assignment;
5915 call.Emit (ec, Getter, Arguments, loc);
5917 if (call.HasAwaitArguments) {
5918 InstanceExpression = call.InstanceExpression;
5919 Arguments = call.EmittedArguments;
5920 has_await_arguments = true;
5924 ec.Emit (OpCodes.Dup);
5925 temp = new LocalTemporary (Type);
5930 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
5932 public override void Emit (EmitContext ec)
5937 protected override void EmitToFieldSource (EmitContext ec)
5939 has_await_arguments = true;
5943 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
5945 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
5947 bool ResolveGetter (ResolveContext rc)
5949 if (!best_candidate.HasGet) {
5950 if (InstanceExpression != EmptyExpression.Null) {
5951 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5952 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
5953 best_candidate.GetSignatureForError ());
5956 } else if (!best_candidate.Get.IsAccessible (rc)) {
5957 if (best_candidate.HasDifferentAccessibility) {
5958 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5959 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
5960 TypeManager.CSharpSignature (best_candidate));
5962 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
5963 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
5967 if (best_candidate.HasDifferentAccessibility) {
5968 CheckProtectedMemberAccess (rc, best_candidate.Get);
5971 getter = CandidateToBaseOverride (rc, best_candidate.Get);
5975 bool ResolveSetter (ResolveContext rc)
5977 if (!best_candidate.HasSet) {
5978 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
5979 GetSignatureForError ());
5983 if (!best_candidate.Set.IsAccessible (rc)) {
5984 if (best_candidate.HasDifferentAccessibility) {
5985 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5986 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
5987 GetSignatureForError ());
5989 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
5990 ErrorIsInaccesible (rc, best_candidate.Set.GetSignatureForError (), loc);
5994 if (best_candidate.HasDifferentAccessibility)
5995 CheckProtectedMemberAccess (rc, best_candidate.Set);
5997 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6003 /// Fully resolved expression that evaluates to an Event
6005 public class EventExpr : MemberExpr, IAssignMethod
6007 readonly EventSpec spec;
6010 public EventExpr (EventSpec spec, Location loc)
6018 protected override TypeSpec DeclaringType {
6020 return spec.DeclaringType;
6024 public override string Name {
6030 public override bool IsInstance {
6032 return !spec.IsStatic;
6036 public override bool IsStatic {
6038 return spec.IsStatic;
6042 public MethodSpec Operator {
6050 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6053 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6055 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6056 if (spec.BackingField != null &&
6057 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6059 spec.MemberDefinition.SetIsUsed ();
6061 if (!ec.IsObsolete) {
6062 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6064 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6067 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6068 Error_AssignmentEventOnly (ec);
6070 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6072 InstanceExpression = null;
6074 return ml.ResolveMemberAccess (ec, left, original);
6078 return base.ResolveMemberAccess (ec, left, original);
6081 public override Expression CreateExpressionTree (ResolveContext ec)
6083 throw new NotSupportedException ("ET");
6086 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6088 if (right_side == EmptyExpression.EventAddition) {
6089 op = spec.AccessorAdd;
6090 } else if (right_side == EmptyExpression.EventSubtraction) {
6091 op = spec.AccessorRemove;
6095 Error_AssignmentEventOnly (ec);
6099 op = CandidateToBaseOverride (ec, op);
6103 protected override Expression DoResolve (ResolveContext ec)
6105 eclass = ExprClass.EventAccess;
6106 type = spec.MemberType;
6108 ResolveInstanceExpression (ec, null);
6110 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6111 Error_AssignmentEventOnly (ec);
6114 DoBestMemberChecks (ec, spec);
6118 public override void Emit (EmitContext ec)
6120 throw new NotSupportedException ();
6121 //Error_CannotAssign ();
6124 #region IAssignMethod Members
6126 public void Emit (EmitContext ec, bool leave_copy)
6128 throw new NotImplementedException ();
6131 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6133 if (leave_copy || !isCompound)
6134 throw new NotImplementedException ("EventExpr::EmitAssign");
6136 Arguments args = new Arguments (1);
6137 args.Add (new Argument (source));
6139 var call = new CallEmitter ();
6140 call.InstanceExpression = InstanceExpression;
6141 call.Emit (ec, op, args, loc);
6146 void Error_AssignmentEventOnly (ResolveContext ec)
6148 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6149 ec.Report.Error (79, loc,
6150 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6151 GetSignatureForError ());
6153 ec.Report.Error (70, loc,
6154 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6155 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6159 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6161 name = name.Substring (0, name.LastIndexOf ('.'));
6162 base.Error_CannotCallAbstractBase (rc, name);
6165 public override string GetSignatureForError ()
6167 return TypeManager.CSharpSignature (spec);
6170 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6172 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6176 public class TemporaryVariableReference : VariableReference
6178 public class Declarator : Statement
6180 TemporaryVariableReference variable;
6182 public Declarator (TemporaryVariableReference variable)
6184 this.variable = variable;
6188 protected override void DoEmit (EmitContext ec)
6190 variable.li.CreateBuilder (ec);
6193 protected override void CloneTo (CloneContext clonectx, Statement target)
6201 public TemporaryVariableReference (LocalVariable li, Location loc)
6204 this.type = li.Type;
6208 public override bool IsLockedByStatement {
6216 public LocalVariable LocalInfo {
6222 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6224 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6225 return new TemporaryVariableReference (li, loc);
6228 protected override Expression DoResolve (ResolveContext ec)
6230 eclass = ExprClass.Variable;
6233 // Don't capture temporary variables except when using
6234 // state machine redirection
6236 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
6237 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6238 storey.CaptureLocalVariable (ec, li);
6244 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6246 return Resolve (ec);
6249 public override void Emit (EmitContext ec)
6251 li.CreateBuilder (ec);
6256 public void EmitAssign (EmitContext ec, Expression source)
6258 li.CreateBuilder (ec);
6260 EmitAssign (ec, source, false, false);
6263 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6265 return li.HoistedVariant;
6268 public override bool IsFixed {
6269 get { return true; }
6272 public override bool IsRef {
6273 get { return false; }
6276 public override string Name {
6277 get { throw new NotImplementedException (); }
6280 public override void SetHasAddressTaken ()
6282 throw new NotImplementedException ();
6285 protected override ILocalVariable Variable {
6289 public override VariableInfo VariableInfo {
6290 get { return null; }
6293 public override void VerifyAssigned (ResolveContext rc)
6299 /// Handles `var' contextual keyword; var becomes a keyword only
6300 /// if no type called var exists in a variable scope
6302 class VarExpr : SimpleName
6304 public VarExpr (Location loc)
6309 public bool InferType (ResolveContext ec, Expression right_side)
6312 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6314 type = right_side.Type;
6315 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6316 ec.Report.Error (815, loc,
6317 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6318 type.GetSignatureForError ());
6322 eclass = ExprClass.Variable;
6326 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6328 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6329 base.Error_TypeOrNamespaceNotFound (ec);
6331 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");