2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 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; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // 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
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
434 /// Resolves an expression and performs semantic analysis on it.
438 /// Currently Resolve wraps DoResolve to perform sanity
439 /// checking and assertion checking on what we expect from Resolve.
441 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
443 if (eclass != ExprClass.Unresolved) {
444 if ((flags & ExprClassToResolveFlags) == 0) {
445 Error_UnexpectedKind (ec, flags, loc);
459 if ((flags & e.ExprClassToResolveFlags) == 0) {
460 e.Error_UnexpectedKind (ec, flags, loc);
465 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
468 } catch (Exception ex) {
469 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
470 ec.Report.Printer is NullReportPrinter)
473 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
474 return ErrorExpression.Instance; // TODO: Add location
479 /// Resolves an expression and performs semantic analysis on it.
481 public Expression Resolve (ResolveContext rc)
483 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
487 /// Resolves an expression for LValue assignment
491 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
492 /// checking and assertion checking on what we expect from Resolve
494 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
496 int errors = ec.Report.Errors;
497 bool out_access = right_side == EmptyExpression.OutAccess;
499 Expression e = DoResolveLValue (ec, right_side);
501 if (e != null && out_access && !(e is IMemoryLocation)) {
502 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
503 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
505 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
506 // e.GetType () + " " + e.GetSignatureForError ());
511 if (errors == ec.Report.Errors) {
512 Error_ValueAssignment (ec, right_side);
517 if (e.eclass == ExprClass.Unresolved)
518 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
520 if ((e.type == null) && !(e is GenericTypeExpr))
521 throw new Exception ("Expression " + e + " did not set its type after Resolve");
526 public Constant ResolveLabelConstant (ResolveContext rc)
528 var expr = Resolve (rc);
532 Constant c = expr as Constant;
534 if (expr.type != InternalType.ErrorType)
535 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
543 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
545 rc.Module.Compiler.Report.Error (182, loc,
546 "An attribute argument must be a constant expression, typeof expression or array creation expression");
550 /// Emits the code for the expression
554 /// The Emit method is invoked to generate the code
555 /// for the expression.
557 public abstract void Emit (EmitContext ec);
560 // Emit code to branch to @target if this expression is equivalent to @on_true.
561 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
562 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
563 // including the use of conditional branches. Note also that a branch MUST be emitted
564 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
567 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
570 // Emit this expression for its side effects, not for its value.
571 // The default implementation is to emit the value, and then throw it away.
572 // Subclasses can provide more efficient implementations, but those MUST be equivalent
573 public virtual void EmitSideEffect (EmitContext ec)
576 ec.Emit (OpCodes.Pop);
580 // Emits the expression into temporary field variable. The method
581 // should be used for await expressions only
583 public virtual Expression EmitToField (EmitContext ec)
586 // This is the await prepare Emit method. When emitting code like
587 // a + b we emit code like
593 // For await a + await b we have to interfere the flow to keep the
594 // stack clean because await yields from the expression. The emit
597 // a = a.EmitToField () // a is changed to temporary field access
598 // b = b.EmitToField ()
604 // The idea is to emit expression and leave the stack empty with
605 // result value still available.
607 // Expressions should override this default implementation when
608 // optimized version can be provided (e.g. FieldExpr)
611 // We can optimize for side-effect free expressions, they can be
612 // emitted out of order
614 if (IsSideEffectFree)
617 bool needs_temporary = ContainsEmitWithAwait ();
618 if (!needs_temporary)
621 // Emit original code
622 var field = EmitToFieldSource (ec);
625 // Store the result to temporary field when we
626 // cannot load `this' directly
628 field = ec.GetTemporaryField (type);
629 if (needs_temporary) {
631 // Create temporary local (we cannot load `this' before Emit)
633 var temp = ec.GetTemporaryLocal (type);
634 ec.Emit (OpCodes.Stloc, temp);
637 ec.Emit (OpCodes.Ldloc, temp);
638 field.EmitAssignFromStack (ec);
640 ec.FreeTemporaryLocal (temp, type);
642 field.EmitAssignFromStack (ec);
649 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
652 // Default implementation calls Emit method
658 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
660 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
661 bool contains_await = false;
663 for (int i = 1; i < expressions.Count; ++i) {
664 if (expressions[i].ContainsEmitWithAwait ()) {
665 contains_await = true;
670 if (contains_await) {
671 for (int i = 0; i < expressions.Count; ++i) {
672 expressions[i] = expressions[i].EmitToField (ec);
677 for (int i = 0; i < expressions.Count; ++i) {
678 expressions[i].Emit (ec);
683 /// Protected constructor. Only derivate types should
684 /// be able to be created
687 protected Expression ()
692 /// Returns a fully formed expression after a MemberLookup
695 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
697 if (spec is EventSpec)
698 return new EventExpr ((EventSpec) spec, loc);
699 if (spec is ConstSpec)
700 return new ConstantExpr ((ConstSpec) spec, loc);
701 if (spec is FieldSpec)
702 return new FieldExpr ((FieldSpec) spec, loc);
703 if (spec is PropertySpec)
704 return new PropertyExpr ((PropertySpec) spec, loc);
705 if (spec is TypeSpec)
706 return new TypeExpression (((TypeSpec) spec), loc);
711 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
713 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
716 case MemberKind.Struct:
717 rc.Report.SymbolRelatedToPreviousError (type);
718 // Report meaningful error for struct as they always have default ctor in C# context
719 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
721 case MemberKind.MissingType:
722 case MemberKind.InternalCompilerType:
725 rc.Report.SymbolRelatedToPreviousError (type);
726 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
727 type.GetSignatureForError ());
734 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
735 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
736 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
739 return r.ResolveMember<MethodSpec> (rc, ref args);
743 public enum MemberLookupRestrictions
752 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
753 // `qualifier_type' or null to lookup members in the current class.
755 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
757 var members = MemberCache.FindMembers (queried_type, name, false);
761 MemberSpec non_method = null;
762 MemberSpec ambig_non_method = null;
764 for (int i = 0; i < members.Count; ++i) {
765 var member = members[i];
767 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
768 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
771 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
774 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
778 if (!member.IsAccessible (rc))
782 // With runtime binder we can have a situation where queried type is inaccessible
783 // because it came via dynamic object, the check about inconsisted accessibility
784 // had no effect as the type was unknown during compilation
787 // private class N { }
789 // public dynamic Foo ()
795 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
799 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
800 if (member is MethodSpec) {
802 // Interface members that are hidden by class members are removed from the set. This
803 // step only has an effect if T is a type parameter and T has both an effective base
804 // class other than object and a non-empty effective interface set
806 var tps = queried_type as TypeParameterSpec;
807 if (tps != null && tps.HasTypeConstraint)
808 members = RemoveHiddenTypeParameterMethods (members);
810 return new MethodGroupExpr (members, queried_type, loc);
813 if (!Invocation.IsMemberInvocable (member))
817 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
819 } else if (!errorMode && !member.IsNotCSharpCompatible) {
821 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
822 // T has both an effective base class other than object and a non-empty effective interface set.
824 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
826 var tps = queried_type as TypeParameterSpec;
827 if (tps != null && tps.HasTypeConstraint) {
828 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
831 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
837 ambig_non_method = member;
841 if (non_method != null) {
842 if (ambig_non_method != null && rc != null) {
843 var report = rc.Module.Compiler.Report;
844 report.SymbolRelatedToPreviousError (non_method);
845 report.SymbolRelatedToPreviousError (ambig_non_method);
846 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
847 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
850 if (non_method is MethodSpec)
851 return new MethodGroupExpr (members, queried_type, loc);
853 return ExprClassFromMemberInfo (non_method, loc);
856 if (members[0].DeclaringType.BaseType == null)
859 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
861 } while (members != null);
866 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
868 if (members.Count < 2)
872 // If M is a method, then all non-method members declared in an interface declaration
873 // are removed from the set, and all methods with the same signature as M declared in
874 // an interface declaration are removed from the set
878 for (int i = 0; i < members.Count; ++i) {
879 var method = members[i] as MethodSpec;
880 if (method == null) {
883 members = new List<MemberSpec> (members);
886 members.RemoveAt (i--);
890 if (!method.DeclaringType.IsInterface)
893 for (int ii = 0; ii < members.Count; ++ii) {
894 var candidate = members[ii] as MethodSpec;
895 if (candidate == null || !candidate.DeclaringType.IsClass)
898 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
903 members = new List<MemberSpec> (members);
906 members.RemoveAt (i--);
914 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
916 throw new NotImplementedException ();
919 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
921 if (t == InternalType.ErrorType)
924 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
925 oper, t.GetSignatureForError ());
928 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
930 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
933 public virtual void FlowAnalysis (FlowAnalysisContext fc)
938 /// Returns an expression that can be used to invoke operator true
939 /// on the expression if it exists.
941 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
943 return GetOperatorTrueOrFalse (ec, e, true, loc);
947 /// Returns an expression that can be used to invoke operator false
948 /// on the expression if it exists.
950 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
952 return GetOperatorTrueOrFalse (ec, e, false, loc);
955 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
957 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
958 var methods = MemberCache.GetUserOperator (e.type, op, false);
962 Arguments arguments = new Arguments (1);
963 arguments.Add (new Argument (e));
965 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
966 var oper = res.ResolveOperator (ec, ref arguments);
971 return new UserOperatorCall (oper, arguments, null, loc);
974 public virtual string ExprClassName
978 case ExprClass.Unresolved:
980 case ExprClass.Value:
982 case ExprClass.Variable:
984 case ExprClass.Namespace:
988 case ExprClass.MethodGroup:
989 return "method group";
990 case ExprClass.PropertyAccess:
991 return "property access";
992 case ExprClass.EventAccess:
993 return "event access";
994 case ExprClass.IndexerAccess:
995 return "indexer access";
996 case ExprClass.Nothing:
998 case ExprClass.TypeParameter:
999 return "type parameter";
1001 throw new Exception ("Should not happen");
1006 /// Reports that we were expecting `expr' to be of class `expected'
1008 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1010 var name = memberExpr.GetSignatureForError ();
1012 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1015 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1017 string [] valid = new string [4];
1020 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1021 valid [count++] = "variable";
1022 valid [count++] = "value";
1025 if ((flags & ResolveFlags.Type) != 0)
1026 valid [count++] = "type";
1028 if ((flags & ResolveFlags.MethodGroup) != 0)
1029 valid [count++] = "method group";
1032 valid [count++] = "unknown";
1034 StringBuilder sb = new StringBuilder (valid [0]);
1035 for (int i = 1; i < count - 1; i++) {
1037 sb.Append (valid [i]);
1040 sb.Append ("' or `");
1041 sb.Append (valid [count - 1]);
1044 ec.Report.Error (119, loc,
1045 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1048 public static void UnsafeError (ResolveContext ec, Location loc)
1050 UnsafeError (ec.Report, loc);
1053 public static void UnsafeError (Report Report, Location loc)
1055 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1059 // Converts `source' to an int, uint, long or ulong.
1061 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1063 var btypes = ec.BuiltinTypes;
1065 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1066 Arguments args = new Arguments (1);
1067 args.Add (new Argument (source));
1068 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1071 Expression converted;
1073 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1074 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1075 if (converted == null)
1076 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1077 if (converted == null)
1078 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1079 if (converted == null)
1080 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1082 if (converted == null) {
1083 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1089 // Only positive constants are allowed at compile time
1091 Constant c = converted as Constant;
1092 if (c != null && c.IsNegative)
1093 Error_NegativeArrayIndex (ec, source.loc);
1095 // No conversion needed to array index
1096 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1099 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1103 // Derived classes implement this method by cloning the fields that
1104 // could become altered during the Resolve stage
1106 // Only expressions that are created for the parser need to implement
1109 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1111 throw new NotImplementedException (
1113 "CloneTo not implemented for expression {0}", this.GetType ()));
1117 // Clones an expression created by the parser.
1119 // We only support expressions created by the parser so far, not
1120 // expressions that have been resolved (many more classes would need
1121 // to implement CloneTo).
1123 // This infrastructure is here merely for Lambda expressions which
1124 // compile the same code using different type values for the same
1125 // arguments to find the correct overload
1127 public virtual Expression Clone (CloneContext clonectx)
1129 Expression cloned = (Expression) MemberwiseClone ();
1130 CloneTo (clonectx, cloned);
1136 // Implementation of expression to expression tree conversion
1138 public abstract Expression CreateExpressionTree (ResolveContext ec);
1140 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1142 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1145 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1147 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1150 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1152 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1155 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1157 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1161 return new TypeExpression (t, loc);
1165 // Implemented by all expressions which support conversion from
1166 // compiler expression to invokable runtime expression. Used by
1167 // dynamic C# binder.
1169 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1171 throw new NotImplementedException ("MakeExpression for " + GetType ());
1174 public virtual object Accept (StructuralVisitor visitor)
1176 return visitor.Visit (this);
1181 /// This is just a base class for expressions that can
1182 /// appear on statements (invocations, object creation,
1183 /// assignments, post/pre increment and decrement). The idea
1184 /// being that they would support an extra Emition interface that
1185 /// does not leave a result on the stack.
1187 public abstract class ExpressionStatement : Expression
1189 public virtual void MarkReachable (Reachability rc)
1193 public ExpressionStatement ResolveStatement (BlockContext ec)
1195 Expression e = Resolve (ec);
1199 ExpressionStatement es = e as ExpressionStatement;
1200 if (es == null || e is AnonymousMethodBody)
1201 Error_InvalidExpressionStatement (ec);
1204 // This is quite expensive warning, try to limit the damage
1206 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1207 WarningAsyncWithoutWait (ec, e);
1213 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1215 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1216 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1221 // Need to do full resolve because GetAwaiter can be extension method
1222 // available only in this context
1224 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1228 var arguments = new Arguments (0);
1229 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1234 // Use same check rules as for real await
1236 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1237 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1240 bc.Report.Warning (4014, 1, e.Location,
1241 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1245 var inv = e as Invocation;
1246 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1247 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1248 bc.Report.Warning (4014, 1, e.Location,
1249 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1255 /// Requests the expression to be emitted in a `statement'
1256 /// context. This means that no new value is left on the
1257 /// stack after invoking this method (constrasted with
1258 /// Emit that will always leave a value on the stack).
1260 public abstract void EmitStatement (EmitContext ec);
1262 public override void EmitSideEffect (EmitContext ec)
1269 /// This kind of cast is used to encapsulate the child
1270 /// whose type is child.Type into an expression that is
1271 /// reported to return "return_type". This is used to encapsulate
1272 /// expressions which have compatible types, but need to be dealt
1273 /// at higher levels with.
1275 /// For example, a "byte" expression could be encapsulated in one
1276 /// of these as an "unsigned int". The type for the expression
1277 /// would be "unsigned int".
1280 public abstract class TypeCast : Expression
1282 protected readonly Expression child;
1284 protected TypeCast (Expression child, TypeSpec return_type)
1286 eclass = child.eclass;
1287 loc = child.Location;
1292 public Expression Child {
1298 public override bool ContainsEmitWithAwait ()
1300 return child.ContainsEmitWithAwait ();
1303 public override Expression CreateExpressionTree (ResolveContext ec)
1305 Arguments args = new Arguments (2);
1306 args.Add (new Argument (child.CreateExpressionTree (ec)));
1307 args.Add (new Argument (new TypeOf (type, loc)));
1309 if (type.IsPointer || child.Type.IsPointer)
1310 Error_PointerInsideExpressionTree (ec);
1312 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1315 protected override Expression DoResolve (ResolveContext ec)
1317 // This should never be invoked, we are born in fully
1318 // initialized state.
1323 public override void Emit (EmitContext ec)
1328 public override void FlowAnalysis (FlowAnalysisContext fc)
1330 child.FlowAnalysis (fc);
1333 public override SLE.Expression MakeExpression (BuilderContext ctx)
1336 return base.MakeExpression (ctx);
1338 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1339 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1340 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1344 protected override void CloneTo (CloneContext clonectx, Expression t)
1349 public override bool IsNull {
1350 get { return child.IsNull; }
1354 public class EmptyCast : TypeCast {
1355 EmptyCast (Expression child, TypeSpec target_type)
1356 : base (child, target_type)
1360 public static Expression Create (Expression child, TypeSpec type)
1362 Constant c = child as Constant;
1364 var enum_constant = c as EnumConstant;
1365 if (enum_constant != null)
1366 c = enum_constant.Child;
1368 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1372 var res = c.ConvertImplicitly (type);
1378 EmptyCast e = child as EmptyCast;
1380 return new EmptyCast (e.child, type);
1382 return new EmptyCast (child, type);
1385 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1387 child.EmitBranchable (ec, label, on_true);
1390 public override void EmitSideEffect (EmitContext ec)
1392 child.EmitSideEffect (ec);
1397 // Used for predefined type user operator (no obsolete check, etc.)
1399 public class OperatorCast : TypeCast
1401 readonly MethodSpec conversion_operator;
1403 public OperatorCast (Expression expr, TypeSpec target_type)
1404 : this (expr, target_type, target_type, false)
1408 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1409 : this (expr, target_type, target_type, find_explicit)
1413 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1414 : base (expr, returnType)
1416 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1417 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1420 foreach (MethodSpec oper in mi) {
1421 if (oper.ReturnType != returnType)
1424 if (oper.Parameters.Types[0] == expr.Type) {
1425 conversion_operator = oper;
1431 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1432 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1435 public override void Emit (EmitContext ec)
1438 ec.Emit (OpCodes.Call, conversion_operator);
1443 // Constant specialization of EmptyCast.
1444 // We need to special case this since an empty cast of
1445 // a constant is still a constant.
1447 public class EmptyConstantCast : Constant
1449 public readonly Constant child;
1451 public EmptyConstantCast (Constant child, TypeSpec type)
1452 : base (child.Location)
1455 throw new ArgumentNullException ("child");
1458 this.eclass = child.eclass;
1462 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1464 if (child.Type == target_type)
1467 // FIXME: check that 'type' can be converted to 'target_type' first
1468 return child.ConvertExplicitly (in_checked_context, target_type);
1471 public override Expression CreateExpressionTree (ResolveContext ec)
1473 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1474 child.CreateExpressionTree (ec),
1475 new TypeOf (type, loc));
1478 Error_PointerInsideExpressionTree (ec);
1480 return CreateExpressionFactoryCall (ec, "Convert", args);
1483 public override bool IsDefaultValue {
1484 get { return child.IsDefaultValue; }
1487 public override bool IsNegative {
1488 get { return child.IsNegative; }
1491 public override bool IsNull {
1492 get { return child.IsNull; }
1495 public override bool IsOneInteger {
1496 get { return child.IsOneInteger; }
1499 public override bool IsSideEffectFree {
1501 return child.IsSideEffectFree;
1505 public override bool IsZeroInteger {
1506 get { return child.IsZeroInteger; }
1509 public override void Emit (EmitContext ec)
1514 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1516 child.EmitBranchable (ec, label, on_true);
1518 // Only to make verifier happy
1519 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1520 ec.Emit (OpCodes.Unbox_Any, type);
1523 public override void EmitSideEffect (EmitContext ec)
1525 child.EmitSideEffect (ec);
1528 public override object GetValue ()
1530 return child.GetValue ();
1533 public override string GetValueAsLiteral ()
1535 return child.GetValueAsLiteral ();
1538 public override long GetValueAsLong ()
1540 return child.GetValueAsLong ();
1543 public override Constant ConvertImplicitly (TypeSpec target_type)
1545 if (type == target_type)
1548 // FIXME: Do we need to check user conversions?
1549 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1552 return child.ConvertImplicitly (target_type);
1557 /// This class is used to wrap literals which belong inside Enums
1559 public class EnumConstant : Constant
1561 public Constant Child;
1563 public EnumConstant (Constant child, TypeSpec enum_type)
1564 : base (child.Location)
1568 this.eclass = ExprClass.Value;
1569 this.type = enum_type;
1572 protected EnumConstant (Location loc)
1577 public override void Emit (EmitContext ec)
1582 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1584 Child.EncodeAttributeValue (rc, enc, Child.Type);
1587 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1589 Child.EmitBranchable (ec, label, on_true);
1592 public override void EmitSideEffect (EmitContext ec)
1594 Child.EmitSideEffect (ec);
1597 public override string GetSignatureForError()
1599 return Type.GetSignatureForError ();
1602 public override object GetValue ()
1604 return Child.GetValue ();
1608 public override object GetTypedValue ()
1611 // The method can be used in dynamic context only (on closed types)
1613 // System.Enum.ToObject cannot be called on dynamic types
1614 // EnumBuilder has to be used, but we cannot use EnumBuilder
1615 // because it does not properly support generics
1617 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1621 public override string GetValueAsLiteral ()
1623 return Child.GetValueAsLiteral ();
1626 public override long GetValueAsLong ()
1628 return Child.GetValueAsLong ();
1631 public EnumConstant Increment()
1633 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1636 public override bool IsDefaultValue {
1638 return Child.IsDefaultValue;
1642 public override bool IsSideEffectFree {
1644 return Child.IsSideEffectFree;
1648 public override bool IsZeroInteger {
1649 get { return Child.IsZeroInteger; }
1652 public override bool IsNegative {
1654 return Child.IsNegative;
1658 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1660 if (Child.Type == target_type)
1663 return Child.ConvertExplicitly (in_checked_context, target_type);
1666 public override Constant ConvertImplicitly (TypeSpec type)
1668 if (this.type == type) {
1672 if (!Convert.ImplicitStandardConversionExists (this, type)){
1676 return Child.ConvertImplicitly (type);
1681 /// This kind of cast is used to encapsulate Value Types in objects.
1683 /// The effect of it is to box the value type emitted by the previous
1686 public class BoxedCast : TypeCast {
1688 public BoxedCast (Expression expr, TypeSpec target_type)
1689 : base (expr, target_type)
1691 eclass = ExprClass.Value;
1694 protected override Expression DoResolve (ResolveContext ec)
1696 // This should never be invoked, we are born in fully
1697 // initialized state.
1702 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1704 // Only boxing to object type is supported
1705 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1706 base.EncodeAttributeValue (rc, enc, targetType);
1710 enc.Encode (child.Type);
1711 child.EncodeAttributeValue (rc, enc, child.Type);
1714 public override void Emit (EmitContext ec)
1718 ec.Emit (OpCodes.Box, child.Type);
1721 public override void EmitSideEffect (EmitContext ec)
1723 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1724 // so, we need to emit the box+pop instructions in most cases
1725 if (child.Type.IsStruct &&
1726 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1727 child.EmitSideEffect (ec);
1729 base.EmitSideEffect (ec);
1733 public class UnboxCast : TypeCast {
1734 public UnboxCast (Expression expr, TypeSpec return_type)
1735 : base (expr, return_type)
1739 protected override Expression DoResolve (ResolveContext ec)
1741 // This should never be invoked, we are born in fully
1742 // initialized state.
1747 public override void Emit (EmitContext ec)
1751 ec.Emit (OpCodes.Unbox_Any, type);
1756 /// This is used to perform explicit numeric conversions.
1758 /// Explicit numeric conversions might trigger exceptions in a checked
1759 /// context, so they should generate the conv.ovf opcodes instead of
1762 public class ConvCast : TypeCast {
1763 public enum Mode : byte {
1764 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1766 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1767 U2_I1, U2_U1, U2_I2, U2_CH,
1768 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1769 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1770 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1771 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1772 CH_I1, CH_U1, CH_I2,
1773 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1774 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1780 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1781 : base (child, return_type)
1786 protected override Expression DoResolve (ResolveContext ec)
1788 // This should never be invoked, we are born in fully
1789 // initialized state.
1794 public override string ToString ()
1796 return String.Format ("ConvCast ({0}, {1})", mode, child);
1799 public override void Emit (EmitContext ec)
1805 public static void Emit (EmitContext ec, Mode mode)
1807 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1809 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1810 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1811 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1812 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1813 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1815 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1816 case Mode.U1_CH: /* nothing */ break;
1818 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1819 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1820 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1821 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1822 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1823 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1825 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1826 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1827 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1828 case Mode.U2_CH: /* nothing */ break;
1830 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1831 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1832 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1833 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1834 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1835 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1836 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1838 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1839 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1840 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1841 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1842 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1843 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1845 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1846 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1847 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1848 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1849 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1850 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1851 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1852 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1853 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1855 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1856 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1857 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1858 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1859 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1860 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1861 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1862 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1863 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1865 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1866 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1867 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1869 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1870 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1871 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1872 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1873 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1874 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1875 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1876 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1877 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1879 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1880 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1881 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1882 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1883 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1884 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1885 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1886 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1887 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1888 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1890 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1894 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1895 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1896 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1897 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1898 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1900 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1901 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1905 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1906 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1907 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1908 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1910 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1911 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1912 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1913 case Mode.U2_CH: /* nothing */ break;
1915 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1916 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1917 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1918 case Mode.I4_U4: /* nothing */ break;
1919 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1920 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1921 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1924 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1925 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1926 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1927 case Mode.U4_I4: /* nothing */ break;
1928 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1930 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1931 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1932 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1933 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1934 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1935 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1936 case Mode.I8_U8: /* nothing */ break;
1937 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1938 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1940 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1941 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1942 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1943 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1944 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1945 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1946 case Mode.U8_I8: /* nothing */ break;
1947 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1948 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1950 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1951 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1952 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1954 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1955 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1956 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1957 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1958 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1959 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1960 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1961 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1962 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1964 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1965 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1966 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1967 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1968 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1969 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1970 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1971 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1972 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1973 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1975 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1981 class OpcodeCast : TypeCast
1985 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1986 : base (child, return_type)
1991 protected override Expression DoResolve (ResolveContext ec)
1993 // This should never be invoked, we are born in fully
1994 // initialized state.
1999 public override void Emit (EmitContext ec)
2005 public TypeSpec UnderlyingType {
2006 get { return child.Type; }
2011 // Opcode casts expression with 2 opcodes but only
2012 // single expression tree node
2014 class OpcodeCastDuplex : OpcodeCast
2016 readonly OpCode second;
2018 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2019 : base (child, returnType, first)
2021 this.second = second;
2024 public override void Emit (EmitContext ec)
2032 /// This kind of cast is used to encapsulate a child and cast it
2033 /// to the class requested
2035 public sealed class ClassCast : TypeCast {
2036 readonly bool forced;
2038 public ClassCast (Expression child, TypeSpec return_type)
2039 : base (child, return_type)
2043 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2044 : base (child, return_type)
2046 this.forced = forced;
2049 public override void Emit (EmitContext ec)
2053 bool gen = TypeManager.IsGenericParameter (child.Type);
2055 ec.Emit (OpCodes.Box, child.Type);
2057 if (type.IsGenericParameter) {
2058 ec.Emit (OpCodes.Unbox_Any, type);
2065 ec.Emit (OpCodes.Castclass, type);
2070 // Created during resolving pahse when an expression is wrapped or constantified
2071 // and original expression can be used later (e.g. for expression trees)
2073 public class ReducedExpression : Expression
2075 public sealed class ReducedConstantExpression : EmptyConstantCast
2077 readonly Expression orig_expr;
2079 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2080 : base (expr, expr.Type)
2082 this.orig_expr = orig_expr;
2085 public Expression OriginalExpression {
2091 public override Constant ConvertImplicitly (TypeSpec target_type)
2093 Constant c = base.ConvertImplicitly (target_type);
2095 c = new ReducedConstantExpression (c, orig_expr);
2100 public override Expression CreateExpressionTree (ResolveContext ec)
2102 return orig_expr.CreateExpressionTree (ec);
2105 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2107 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2109 c = new ReducedConstantExpression (c, orig_expr);
2113 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2116 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2118 if (orig_expr is Conditional)
2119 child.EncodeAttributeValue (rc, enc, targetType);
2121 base.EncodeAttributeValue (rc, enc, targetType);
2125 sealed class ReducedExpressionStatement : ExpressionStatement
2127 readonly Expression orig_expr;
2128 readonly ExpressionStatement stm;
2130 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2132 this.orig_expr = orig;
2134 this.eclass = stm.eclass;
2135 this.type = stm.Type;
2137 this.loc = orig.Location;
2140 public override bool ContainsEmitWithAwait ()
2142 return stm.ContainsEmitWithAwait ();
2145 public override Expression CreateExpressionTree (ResolveContext ec)
2147 return orig_expr.CreateExpressionTree (ec);
2150 protected override Expression DoResolve (ResolveContext ec)
2155 public override void Emit (EmitContext ec)
2160 public override void EmitStatement (EmitContext ec)
2162 stm.EmitStatement (ec);
2165 public override void FlowAnalysis (FlowAnalysisContext fc)
2167 stm.FlowAnalysis (fc);
2171 readonly Expression expr, orig_expr;
2173 private ReducedExpression (Expression expr, Expression orig_expr)
2176 this.eclass = expr.eclass;
2177 this.type = expr.Type;
2178 this.orig_expr = orig_expr;
2179 this.loc = orig_expr.Location;
2184 public override bool IsSideEffectFree {
2186 return expr.IsSideEffectFree;
2190 public Expression OriginalExpression {
2198 public override bool ContainsEmitWithAwait ()
2200 return expr.ContainsEmitWithAwait ();
2204 // Creates fully resolved expression switcher
2206 public static Constant Create (Constant expr, Expression original_expr)
2208 if (expr.eclass == ExprClass.Unresolved)
2209 throw new ArgumentException ("Unresolved expression");
2211 return new ReducedConstantExpression (expr, original_expr);
2214 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2216 return new ReducedExpressionStatement (s, orig);
2219 public static Expression Create (Expression expr, Expression original_expr)
2221 return Create (expr, original_expr, true);
2225 // Creates unresolved reduce expression. The original expression has to be
2226 // already resolved. Created expression is constant based based on `expr'
2227 // value unless canBeConstant is used
2229 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2231 if (canBeConstant) {
2232 Constant c = expr as Constant;
2234 return Create (c, original_expr);
2237 ExpressionStatement s = expr as ExpressionStatement;
2239 return Create (s, original_expr);
2241 if (expr.eclass == ExprClass.Unresolved)
2242 throw new ArgumentException ("Unresolved expression");
2244 return new ReducedExpression (expr, original_expr);
2247 public override Expression CreateExpressionTree (ResolveContext ec)
2249 return orig_expr.CreateExpressionTree (ec);
2252 protected override Expression DoResolve (ResolveContext ec)
2257 public override void Emit (EmitContext ec)
2262 public override Expression EmitToField (EmitContext ec)
2264 return expr.EmitToField(ec);
2267 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2269 expr.EmitBranchable (ec, target, on_true);
2272 public override void FlowAnalysis (FlowAnalysisContext fc)
2274 expr.FlowAnalysis (fc);
2277 public override SLE.Expression MakeExpression (BuilderContext ctx)
2279 return orig_expr.MakeExpression (ctx);
2284 // Standard composite pattern
2286 public abstract class CompositeExpression : Expression
2288 protected Expression expr;
2290 protected CompositeExpression (Expression expr)
2293 this.loc = expr.Location;
2296 public override bool ContainsEmitWithAwait ()
2298 return expr.ContainsEmitWithAwait ();
2301 public override Expression CreateExpressionTree (ResolveContext rc)
2303 return expr.CreateExpressionTree (rc);
2306 public Expression Child {
2307 get { return expr; }
2310 protected override Expression DoResolve (ResolveContext rc)
2312 expr = expr.Resolve (rc);
2315 eclass = expr.eclass;
2321 public override void Emit (EmitContext ec)
2326 public override bool IsNull {
2327 get { return expr.IsNull; }
2332 // Base of expressions used only to narrow resolve flow
2334 public abstract class ShimExpression : Expression
2336 protected Expression expr;
2338 protected ShimExpression (Expression expr)
2343 public Expression Expr {
2349 protected override void CloneTo (CloneContext clonectx, Expression t)
2354 ShimExpression target = (ShimExpression) t;
2355 target.expr = expr.Clone (clonectx);
2358 public override bool ContainsEmitWithAwait ()
2360 return expr.ContainsEmitWithAwait ();
2363 public override Expression CreateExpressionTree (ResolveContext ec)
2365 throw new NotSupportedException ("ET");
2368 public override void Emit (EmitContext ec)
2370 throw new InternalErrorException ("Missing Resolve call");
2374 public class UnreachableExpression : Expression
2376 public UnreachableExpression (Expression expr)
2378 this.loc = expr.Location;
2381 public override Expression CreateExpressionTree (ResolveContext ec)
2384 throw new NotImplementedException ();
2387 protected override Expression DoResolve (ResolveContext rc)
2389 throw new NotSupportedException ();
2392 public override void FlowAnalysis (FlowAnalysisContext fc)
2394 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2397 public override void Emit (EmitContext ec)
2401 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2407 // Unresolved type name expressions
2409 public abstract class ATypeNameExpression : FullNamedExpression
2412 protected TypeArguments targs;
2414 protected ATypeNameExpression (string name, Location l)
2420 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2427 protected ATypeNameExpression (string name, int arity, Location l)
2428 : this (name, new UnboundTypeArguments (arity), l)
2434 protected int Arity {
2436 return targs == null ? 0 : targs.Count;
2440 public bool HasTypeArguments {
2442 return targs != null && !targs.IsEmpty;
2446 public string Name {
2455 public TypeArguments TypeArguments {
2463 public override bool Equals (object obj)
2465 ATypeNameExpression atne = obj as ATypeNameExpression;
2466 return atne != null && atne.Name == Name &&
2467 (targs == null || targs.Equals (atne.targs));
2470 public override int GetHashCode ()
2472 return Name.GetHashCode ();
2475 // TODO: Move it to MemberCore
2476 public static string GetMemberType (MemberCore mc)
2482 if (mc is FieldBase)
2484 if (mc is MethodCore)
2486 if (mc is EnumMember)
2494 public override string GetSignatureForError ()
2496 if (targs != null) {
2497 return Name + "<" + targs.GetSignatureForError () + ">";
2503 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2507 /// SimpleName expressions are formed of a single word and only happen at the beginning
2508 /// of a dotted-name.
2510 public class SimpleName : ATypeNameExpression
2512 public SimpleName (string name, Location l)
2517 public SimpleName (string name, TypeArguments args, Location l)
2518 : base (name, args, l)
2522 public SimpleName (string name, int arity, Location l)
2523 : base (name, arity, l)
2527 public SimpleName GetMethodGroup ()
2529 return new SimpleName (Name, targs, loc);
2532 protected override Expression DoResolve (ResolveContext rc)
2534 return SimpleNameResolve (rc, null);
2537 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2539 return SimpleNameResolve (ec, right_side);
2542 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2544 if (ctx.CurrentType != null) {
2545 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2546 if (member != null) {
2547 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2552 var report = ctx.Module.Compiler.Report;
2554 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2555 if (retval != null) {
2556 report.SymbolRelatedToPreviousError (retval.Type);
2557 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2561 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2562 if (retval != null) {
2563 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2567 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2568 if (ns_candidates != null) {
2569 if (ctx is UsingAliasNamespace.AliasContext) {
2570 report.Error (246, loc,
2571 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2572 ns_candidates[0], Name);
2574 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2575 report.Error (246, loc,
2576 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2580 report.Error (246, loc,
2581 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2586 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2588 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2591 if (fne.Type != null && Arity > 0) {
2592 if (HasTypeArguments) {
2593 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2594 if (ct.ResolveAsType (mc) == null)
2600 return new GenericOpenTypeExpr (fne.Type, loc);
2604 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2606 if (!(fne is Namespace))
2610 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2611 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2612 mc.Module.Compiler.Report.Error (1980, Location,
2613 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2614 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2617 fne = new DynamicTypeExpr (loc);
2618 fne.ResolveAsType (mc);
2624 Error_TypeOrNamespaceNotFound (mc);
2628 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2630 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2633 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2635 int lookup_arity = Arity;
2636 bool errorMode = false;
2638 Block current_block = rc.CurrentBlock;
2639 INamedBlockVariable variable = null;
2640 bool variable_found = false;
2644 // Stage 1: binding to local variables or parameters
2646 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2648 if (current_block != null && lookup_arity == 0) {
2649 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2650 if (!variable.IsDeclared) {
2651 // We found local name in accessible block but it's not
2652 // initialized yet, maybe the user wanted to bind to something else
2654 variable_found = true;
2656 e = variable.CreateReferenceExpression (rc, loc);
2659 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2668 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2670 TypeSpec member_type = rc.CurrentType;
2671 for (; member_type != null; member_type = member_type.DeclaringType) {
2672 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2676 var me = e as MemberExpr;
2678 // The name matches a type, defer to ResolveAsTypeStep
2686 if (variable != null) {
2687 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2688 rc.Report.Error (844, loc,
2689 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2690 Name, me.GetSignatureForError ());
2694 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2695 // Leave it to overload resolution to report correct error
2697 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2698 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2701 // LAMESPEC: again, ignores InvocableOnly
2702 if (variable != null) {
2703 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2704 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2708 // MemberLookup does not check accessors availability, this is actually needed for properties only
2710 var pe = me as PropertyExpr;
2713 // Break as there is no other overload available anyway
2714 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2715 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2718 pe.Getter = pe.PropertyInfo.Get;
2720 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2723 pe.Setter = pe.PropertyInfo.Set;
2728 // TODO: It's used by EventExpr -> FieldExpr transformation only
2729 // TODO: Should go to MemberAccess
2730 me = me.ResolveMemberAccess (rc, null, null);
2734 me.SetTypeArguments (rc, targs);
2741 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2743 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2744 if (IsPossibleTypeOrNamespace (rc)) {
2745 if (variable != null) {
2746 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2747 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2750 return ResolveAsTypeOrNamespace (rc);
2755 if (variable_found) {
2756 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2759 var tparams = rc.CurrentTypeParameters;
2760 if (tparams != null) {
2761 if (tparams.Find (Name) != null) {
2762 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2767 var ct = rc.CurrentType;
2769 if (ct.MemberDefinition.TypeParametersCount > 0) {
2770 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2771 if (ctp.Name == Name) {
2772 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2778 ct = ct.DeclaringType;
2779 } while (ct != null);
2782 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2783 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2785 rc.Report.SymbolRelatedToPreviousError (e.Type);
2786 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2790 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2792 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2793 return ErrorExpression.Instance;
2797 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2799 if (e.Type.Arity != Arity) {
2800 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2804 if (e is TypeExpr) {
2805 // TypeExpression does not have correct location
2806 if (e is TypeExpression)
2807 e = new TypeExpression (e.Type, loc);
2813 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2816 return ErrorExpression.Instance;
2819 if (rc.Module.Evaluator != null) {
2820 var fi = rc.Module.Evaluator.LookupField (Name);
2822 return new FieldExpr (fi.Item1, loc);
2830 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2832 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2837 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2838 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2842 if (right_side != null) {
2843 e = e.ResolveLValue (ec, right_side);
2851 public override object Accept (StructuralVisitor visitor)
2853 return visitor.Visit (this);
2858 /// Represents a namespace or a type. The name of the class was inspired by
2859 /// section 10.8.1 (Fully Qualified Names).
2861 public abstract class FullNamedExpression : Expression
2863 protected override void CloneTo (CloneContext clonectx, Expression target)
2865 // Do nothing, most unresolved type expressions cannot be
2866 // resolved to different type
2869 public override bool ContainsEmitWithAwait ()
2874 public override Expression CreateExpressionTree (ResolveContext ec)
2876 throw new NotSupportedException ("ET");
2879 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2882 // This is used to resolve the expression as a type, a null
2883 // value will be returned if the expression is not a type
2886 public override TypeSpec ResolveAsType (IMemberContext mc)
2888 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2893 TypeExpr te = fne as TypeExpr;
2895 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2903 var dep = type.GetMissingDependencies ();
2905 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2908 if (type.Kind == MemberKind.Void) {
2909 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2913 // Obsolete checks cannot be done when resolving base context as they
2914 // require type dependencies to be set but we are in process of resolving them
2916 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2917 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2918 if (obsolete_attr != null && !mc.IsObsolete) {
2919 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2927 public override void Emit (EmitContext ec)
2929 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2930 GetSignatureForError ());
2935 /// Expression that evaluates to a type
2937 public abstract class TypeExpr : FullNamedExpression
2939 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2945 protected sealed override Expression DoResolve (ResolveContext ec)
2951 public override bool Equals (object obj)
2953 TypeExpr tobj = obj as TypeExpr;
2957 return Type == tobj.Type;
2960 public override int GetHashCode ()
2962 return Type.GetHashCode ();
2967 /// Fully resolved Expression that already evaluated to a type
2969 public class TypeExpression : TypeExpr
2971 public TypeExpression (TypeSpec t, Location l)
2974 eclass = ExprClass.Type;
2978 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2985 /// This class denotes an expression which evaluates to a member
2986 /// of a struct or a class.
2988 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2991 // An instance expression associated with this member, if it's a
2992 // non-static member
2994 public Expression InstanceExpression;
2997 /// The name of this member.
2999 public abstract string Name {
3004 // When base.member is used
3006 public bool IsBase {
3007 get { return InstanceExpression is BaseThis; }
3011 /// Whether this is an instance member.
3013 public abstract bool IsInstance {
3018 /// Whether this is a static member.
3020 public abstract bool IsStatic {
3024 public abstract string KindName {
3028 protected abstract TypeSpec DeclaringType {
3032 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3034 return InstanceExpression.Type;
3039 // Converts best base candidate for virtual method starting from QueriedBaseType
3041 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3044 // Only when base.member is used and method is virtual
3050 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3051 // means for base.member access we have to find the closest match after we found best candidate
3053 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3055 // The method could already be what we are looking for
3057 TypeSpec[] targs = null;
3058 if (method.DeclaringType != InstanceExpression.Type) {
3060 // Candidate can have inflated MVAR parameters and we need to find
3061 // base match for original definition not inflated parameter types
3063 var parameters = method.Parameters;
3064 if (method.Arity > 0) {
3065 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3066 var inflated = method.DeclaringType as InflatedTypeSpec;
3067 if (inflated != null) {
3068 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3072 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3073 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3074 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3075 if (base_override.IsGeneric)
3076 targs = method.TypeArguments;
3078 method = base_override;
3083 // When base access is used inside anonymous method/iterator/etc we need to
3084 // get back to the context of original type. We do it by emiting proxy
3085 // method in original class and rewriting base call to this compiler
3086 // generated method call which does the actual base invocation. This may
3087 // introduce redundant storey but with `this' only but it's tricky to avoid
3088 // at this stage as we don't know what expressions follow base
3090 if (rc.CurrentAnonymousMethod != null) {
3091 if (targs == null && method.IsGeneric) {
3092 targs = method.TypeArguments;
3093 method = method.GetGenericMethodDefinition ();
3096 if (method.Parameters.HasArglist)
3097 throw new NotImplementedException ("__arglist base call proxy");
3099 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3101 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3102 // get/set member expressions second call would fail to proxy because left expression
3103 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3104 // FIXME: The async check is another hack but will probably fail with mutators
3105 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3106 InstanceExpression = new This (loc).Resolve (rc);
3110 method = method.MakeGenericMethod (rc, targs);
3114 // Only base will allow this invocation to happen.
3116 if (method.IsAbstract) {
3117 rc.Report.SymbolRelatedToPreviousError (method);
3118 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3124 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3126 if (InstanceExpression == null)
3129 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3130 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3131 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3136 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3138 if (InstanceExpression == null)
3141 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3144 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3146 var ct = rc.CurrentType;
3147 if (ct == qualifier)
3150 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3153 qualifier = qualifier.GetDefinition ();
3154 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3161 public override bool ContainsEmitWithAwait ()
3163 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3166 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3169 type = type.GetDefinition ();
3171 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3174 type = type.DeclaringType;
3175 } while (type != null);
3180 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3182 if (InstanceExpression != null) {
3183 InstanceExpression = InstanceExpression.Resolve (rc);
3184 CheckProtectedMemberAccess (rc, member);
3187 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3188 UnsafeError (rc, loc);
3191 var dep = member.GetMissingDependencies ();
3193 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3196 if (!rc.IsObsolete) {
3197 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3199 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3202 if (!(member is FieldSpec))
3203 member.MemberDefinition.SetIsUsed ();
3206 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3208 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3211 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3213 rc.Report.SymbolRelatedToPreviousError (member);
3214 rc.Report.Error (1540, loc,
3215 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3216 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3219 public override void FlowAnalysis (FlowAnalysisContext fc)
3221 if (InstanceExpression != null)
3222 InstanceExpression.FlowAnalysis (fc);
3225 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3227 if (!ResolveInstanceExpressionCore (rc, rhs))
3231 // Check intermediate value modification which won't have any effect
3233 if (rhs != null && InstanceExpression.Type.IsStruct) {
3234 var fexpr = InstanceExpression as FieldExpr;
3235 if (fexpr != null) {
3236 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3239 if (fexpr.IsStatic) {
3240 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3241 fexpr.GetSignatureForError ());
3243 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3244 fexpr.GetSignatureForError ());
3250 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3251 if (rc.CurrentInitializerVariable != null) {
3252 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3253 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3255 rc.Report.Error (1612, loc,
3256 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3257 InstanceExpression.GetSignatureForError ());
3263 var lvr = InstanceExpression as LocalVariableReference;
3266 if (!lvr.local_info.IsReadonly)
3269 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3270 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3277 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3280 if (InstanceExpression != null) {
3281 if (InstanceExpression is TypeExpr) {
3282 var t = InstanceExpression.Type;
3284 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3285 if (oa != null && !rc.IsObsolete) {
3286 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3289 t = t.DeclaringType;
3290 } while (t != null);
3292 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3293 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3294 rc.Report.Error (176, loc,
3295 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3296 GetSignatureForError ());
3300 InstanceExpression = null;
3306 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3307 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3308 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3309 rc.Report.Error (236, loc,
3310 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3311 GetSignatureForError ());
3313 rc.Report.Error (120, loc,
3314 "An object reference is required to access non-static member `{0}'",
3315 GetSignatureForError ());
3317 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3321 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3322 rc.Report.Error (38, loc,
3323 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3324 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3327 InstanceExpression = new This (loc).Resolve (rc);
3331 var me = InstanceExpression as MemberExpr;
3333 me.ResolveInstanceExpressionCore (rc, rhs);
3335 var fe = me as FieldExpr;
3336 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3337 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3338 rc.Report.Warning (1690, 1, loc,
3339 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3340 me.GetSignatureForError ());
3347 // Additional checks for l-value member access
3350 if (InstanceExpression is UnboxCast) {
3351 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3358 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3360 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3361 ec.Report.Warning (1720, 1, left.Location,
3362 "Expression will always cause a `{0}'", "System.NullReferenceException");
3365 InstanceExpression = left;
3369 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3371 TypeSpec instance_type = InstanceExpression.Type;
3372 if (TypeSpec.IsValueType (instance_type)) {
3373 if (InstanceExpression is IMemoryLocation) {
3374 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3376 // Cannot release the temporary variable when its address
3377 // is required to be on stack for any parent
3378 LocalTemporary t = new LocalTemporary (instance_type);
3379 InstanceExpression.Emit (ec);
3381 t.AddressOf (ec, AddressOp.Store);
3384 InstanceExpression.Emit (ec);
3386 // Only to make verifier happy
3387 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3388 ec.Emit (OpCodes.Box, instance_type);
3391 if (prepare_for_load)
3392 ec.Emit (OpCodes.Dup);
3395 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3398 public class ExtensionMethodCandidates
3400 readonly NamespaceContainer container;
3401 readonly IList<MethodSpec> methods;
3403 readonly IMemberContext context;
3405 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3407 this.context = context;
3408 this.methods = methods;
3409 this.container = nsContainer;
3410 this.index = lookupIndex;
3413 public NamespaceContainer Container {
3419 public IMemberContext Context {
3425 public int LookupIndex {
3431 public IList<MethodSpec> Methods {
3439 // Represents a group of extension method candidates for whole namespace
3441 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3443 ExtensionMethodCandidates candidates;
3444 public Expression ExtensionExpression;
3446 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3447 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3449 this.candidates = candidates;
3450 this.ExtensionExpression = extensionExpr;
3453 public override bool IsStatic {
3454 get { return true; }
3458 // For extension methodgroup we are not looking for base members but parent
3459 // namespace extension methods
3461 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3463 // TODO: candidates are null only when doing error reporting, that's
3464 // incorrect. We have to discover same extension methods in error mode
3465 if (candidates == null)
3468 int arity = type_arguments == null ? 0 : type_arguments.Count;
3470 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3471 if (candidates == null)
3474 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3477 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3479 // We are already here
3483 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3485 if (arguments == null)
3486 arguments = new Arguments (1);
3488 ExtensionExpression = ExtensionExpression.Resolve (ec);
3489 if (ExtensionExpression == null)
3492 var cand = candidates;
3493 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3494 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3496 // Restore candidates in case we are running in probing mode
3499 // Store resolved argument and restore original arguments
3501 // Clean-up modified arguments for error reporting
3502 arguments.RemoveAt (0);
3506 var me = ExtensionExpression as MemberExpr;
3508 me.ResolveInstanceExpression (ec, null);
3509 var fe = me as FieldExpr;
3511 fe.Spec.MemberDefinition.SetIsUsed ();
3514 InstanceExpression = null;
3518 #region IErrorHandler Members
3520 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3525 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3527 rc.Report.SymbolRelatedToPreviousError (best);
3528 rc.Report.Error (1928, loc,
3529 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3530 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3533 rc.Report.Error (1929, loc,
3534 "Extension method instance type `{0}' cannot be converted to `{1}'",
3535 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3541 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3546 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3555 /// MethodGroupExpr represents a group of method candidates which
3556 /// can be resolved to the best method overload
3558 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3560 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3562 protected IList<MemberSpec> Methods;
3563 MethodSpec best_candidate;
3564 TypeSpec best_candidate_return;
3565 protected TypeArguments type_arguments;
3567 SimpleName simple_name;
3568 protected TypeSpec queried_type;
3570 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3574 this.type = InternalType.MethodGroup;
3576 eclass = ExprClass.MethodGroup;
3577 queried_type = type;
3580 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3581 : this (new MemberSpec[] { m }, type, loc)
3587 public MethodSpec BestCandidate {
3589 return best_candidate;
3593 public TypeSpec BestCandidateReturnType {
3595 return best_candidate_return;
3599 public IList<MemberSpec> Candidates {
3605 protected override TypeSpec DeclaringType {
3607 return queried_type;
3611 public bool IsConditionallyExcluded {
3613 return Methods == Excluded;
3617 public override bool IsInstance {
3619 if (best_candidate != null)
3620 return !best_candidate.IsStatic;
3626 public override bool IsSideEffectFree {
3628 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3632 public override bool IsStatic {
3634 if (best_candidate != null)
3635 return best_candidate.IsStatic;
3641 public override string KindName {
3642 get { return "method"; }
3645 public override string Name {
3647 if (best_candidate != null)
3648 return best_candidate.Name;
3651 return Methods.First ().Name;
3658 // When best candidate is already know this factory can be used
3659 // to avoid expensive overload resolution to be called
3661 // NOTE: InstanceExpression has to be set manually
3663 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3665 return new MethodGroupExpr (best, queriedType, loc) {
3666 best_candidate = best,
3667 best_candidate_return = best.ReturnType
3671 public override string GetSignatureForError ()
3673 if (best_candidate != null)
3674 return best_candidate.GetSignatureForError ();
3676 return Methods.First ().GetSignatureForError ();
3679 public override Expression CreateExpressionTree (ResolveContext ec)
3681 if (best_candidate == null) {
3682 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3686 if (IsConditionallyExcluded)
3687 ec.Report.Error (765, loc,
3688 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3690 return new TypeOfMethod (best_candidate, loc);
3693 protected override Expression DoResolve (ResolveContext ec)
3695 this.eclass = ExprClass.MethodGroup;
3697 if (InstanceExpression != null) {
3698 InstanceExpression = InstanceExpression.Resolve (ec);
3699 if (InstanceExpression == null)
3706 public override void Emit (EmitContext ec)
3708 throw new NotSupportedException ();
3711 public void EmitCall (EmitContext ec, Arguments arguments)
3713 var call = new CallEmitter ();
3714 call.InstanceExpression = InstanceExpression;
3715 call.Emit (ec, best_candidate, arguments, loc);
3718 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3720 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3721 Name, target.GetSignatureForError ());
3724 public static bool IsExtensionMethodArgument (Expression expr)
3727 // LAMESPEC: No details about which expressions are not allowed
3729 return !(expr is TypeExpr) && !(expr is BaseThis);
3733 /// Find the Applicable Function Members (7.4.2.1)
3735 /// me: Method Group expression with the members to select.
3736 /// it might contain constructors or methods (or anything
3737 /// that maps to a method).
3739 /// Arguments: ArrayList containing resolved Argument objects.
3741 /// loc: The location if we want an error to be reported, or a Null
3742 /// location for "probing" purposes.
3744 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3745 /// that is the best match of me on Arguments.
3748 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3750 // TODO: causes issues with probing mode, remove explicit Kind check
3751 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3754 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3755 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3756 r.BaseMembersProvider = this;
3757 r.InstanceQualifier = this;
3760 if (cerrors != null)
3761 r.CustomErrors = cerrors;
3763 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3764 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3765 if (best_candidate == null)
3766 return r.BestCandidateIsDynamic ? this : null;
3768 // Overload resolver had to create a new method group, all checks bellow have already been executed
3769 if (r.BestCandidateNewMethodGroup != null)
3770 return r.BestCandidateNewMethodGroup;
3772 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3773 if (InstanceExpression != null) {
3774 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3775 InstanceExpression = null;
3777 if (best_candidate.IsStatic && simple_name != null) {
3778 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3781 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3785 ResolveInstanceExpression (ec, null);
3788 var base_override = CandidateToBaseOverride (ec, best_candidate);
3789 if (base_override == best_candidate) {
3790 best_candidate_return = r.BestCandidateReturnType;
3792 best_candidate = base_override;
3793 best_candidate_return = best_candidate.ReturnType;
3796 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3797 ConstraintChecker cc = new ConstraintChecker (ec);
3798 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3802 // Additional check for possible imported base override method which
3803 // could not be done during IsOverrideMethodBaseTypeAccessible
3805 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3806 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3807 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3808 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3811 // Speed up the check by not doing it on disallowed targets
3812 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3818 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3820 var fe = left as FieldExpr;
3823 // Using method-group on struct fields makes the struct assigned. I am not sure
3824 // why but that's what .net does
3826 fe.Spec.MemberDefinition.SetIsAssigned ();
3829 simple_name = original;
3830 return base.ResolveMemberAccess (ec, left, original);
3833 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3835 type_arguments = ta;
3838 #region IBaseMembersProvider Members
3840 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3842 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3845 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3847 if (queried_type == member.DeclaringType)
3850 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3851 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3855 // Extension methods lookup after ordinary methods candidates failed to apply
3857 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3859 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3862 if (!IsExtensionMethodArgument (InstanceExpression))
3865 int arity = type_arguments == null ? 0 : type_arguments.Count;
3866 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3867 if (methods == null)
3870 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3871 emg.SetTypeArguments (rc, type_arguments);
3878 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3880 public ConstructorInstanceQualifier (TypeSpec type)
3883 InstanceType = type;
3886 public TypeSpec InstanceType { get; private set; }
3888 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3890 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3894 public struct OverloadResolver
3897 public enum Restrictions
3901 ProbingOnly = 1 << 1,
3902 CovariantDelegate = 1 << 2,
3903 NoBaseMembers = 1 << 3,
3904 BaseMembersIncluded = 1 << 4
3907 public interface IBaseMembersProvider
3909 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3910 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3911 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3914 public interface IErrorHandler
3916 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3917 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3918 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3919 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3922 public interface IInstanceQualifier
3924 TypeSpec InstanceType { get; }
3925 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3928 sealed class NoBaseMembers : IBaseMembersProvider
3930 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3932 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3937 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3942 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3948 struct AmbiguousCandidate
3950 public readonly MemberSpec Member;
3951 public readonly bool Expanded;
3952 public readonly AParametersCollection Parameters;
3954 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3957 Parameters = parameters;
3958 Expanded = expanded;
3963 IList<MemberSpec> members;
3964 TypeArguments type_arguments;
3965 IBaseMembersProvider base_provider;
3966 IErrorHandler custom_errors;
3967 IInstanceQualifier instance_qualifier;
3968 Restrictions restrictions;
3969 MethodGroupExpr best_candidate_extension_group;
3970 TypeSpec best_candidate_return_type;
3972 SessionReportPrinter lambda_conv_msgs;
3974 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3975 : this (members, null, restrictions, loc)
3979 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3982 if (members == null || members.Count == 0)
3983 throw new ArgumentException ("empty members set");
3985 this.members = members;
3987 type_arguments = targs;
3988 this.restrictions = restrictions;
3989 if (IsDelegateInvoke)
3990 this.restrictions |= Restrictions.NoBaseMembers;
3992 base_provider = NoBaseMembers.Instance;
3997 public IBaseMembersProvider BaseMembersProvider {
3999 return base_provider;
4002 base_provider = value;
4006 public bool BestCandidateIsDynamic { get; set; }
4009 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4011 public MethodGroupExpr BestCandidateNewMethodGroup {
4013 return best_candidate_extension_group;
4018 // Return type can be different between best candidate and closest override
4020 public TypeSpec BestCandidateReturnType {
4022 return best_candidate_return_type;
4026 public IErrorHandler CustomErrors {
4028 return custom_errors;
4031 custom_errors = value;
4035 TypeSpec DelegateType {
4037 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4038 throw new InternalErrorException ("Not running in delegate mode", loc);
4040 return members [0].DeclaringType;
4044 public IInstanceQualifier InstanceQualifier {
4046 return instance_qualifier;
4049 instance_qualifier = value;
4053 bool IsProbingOnly {
4055 return (restrictions & Restrictions.ProbingOnly) != 0;
4059 bool IsDelegateInvoke {
4061 return (restrictions & Restrictions.DelegateInvoke) != 0;
4068 // 7.4.3.3 Better conversion from expression
4069 // Returns : 1 if a->p is better,
4070 // 2 if a->q is better,
4071 // 0 if neither is better
4073 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4075 TypeSpec argument_type = a.Type;
4078 // If argument is an anonymous function
4080 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4082 // p and q are delegate types or expression tree types
4084 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4085 if (q.MemberDefinition != p.MemberDefinition) {
4090 // Uwrap delegate from Expression<T>
4092 q = TypeManager.GetTypeArguments (q)[0];
4093 p = TypeManager.GetTypeArguments (p)[0];
4096 var p_m = Delegate.GetInvokeMethod (p);
4097 var q_m = Delegate.GetInvokeMethod (q);
4100 // With identical parameter lists
4102 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4111 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4113 if (p.Kind == MemberKind.Void) {
4114 return q.Kind != MemberKind.Void ? 2 : 0;
4118 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4120 if (q.Kind == MemberKind.Void) {
4121 return p.Kind != MemberKind.Void ? 1: 0;
4124 var am = (AnonymousMethodExpression) a.Expr;
4127 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4128 // better conversion is performed between underlying types Y1 and Y2
4130 if (p.IsGenericTask || q.IsGenericTask) {
4131 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4132 q = q.TypeArguments[0];
4133 p = p.TypeArguments[0];
4135 } else if (q != p) {
4137 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4139 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4140 var am_rt = am.InferReturnType (ec, null, orig_q);
4141 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4143 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4144 var am_rt = am.InferReturnType (ec, null, orig_p);
4145 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4151 // The parameters are identicial and return type is not void, use better type conversion
4152 // on return type to determine better one
4155 if (argument_type == p)
4158 if (argument_type == q)
4162 return BetterTypeConversion (ec, p, q);
4166 // 7.4.3.4 Better conversion from type
4168 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4170 if (p == null || q == null)
4171 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4173 switch (p.BuiltinType) {
4174 case BuiltinTypeSpec.Type.Int:
4175 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4178 case BuiltinTypeSpec.Type.Long:
4179 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4182 case BuiltinTypeSpec.Type.SByte:
4183 switch (q.BuiltinType) {
4184 case BuiltinTypeSpec.Type.Byte:
4185 case BuiltinTypeSpec.Type.UShort:
4186 case BuiltinTypeSpec.Type.UInt:
4187 case BuiltinTypeSpec.Type.ULong:
4191 case BuiltinTypeSpec.Type.Short:
4192 switch (q.BuiltinType) {
4193 case BuiltinTypeSpec.Type.UShort:
4194 case BuiltinTypeSpec.Type.UInt:
4195 case BuiltinTypeSpec.Type.ULong:
4199 case BuiltinTypeSpec.Type.Dynamic:
4200 // Dynamic is never better
4204 switch (q.BuiltinType) {
4205 case BuiltinTypeSpec.Type.Int:
4206 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4209 case BuiltinTypeSpec.Type.Long:
4210 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4213 case BuiltinTypeSpec.Type.SByte:
4214 switch (p.BuiltinType) {
4215 case BuiltinTypeSpec.Type.Byte:
4216 case BuiltinTypeSpec.Type.UShort:
4217 case BuiltinTypeSpec.Type.UInt:
4218 case BuiltinTypeSpec.Type.ULong:
4222 case BuiltinTypeSpec.Type.Short:
4223 switch (p.BuiltinType) {
4224 case BuiltinTypeSpec.Type.UShort:
4225 case BuiltinTypeSpec.Type.UInt:
4226 case BuiltinTypeSpec.Type.ULong:
4230 case BuiltinTypeSpec.Type.Dynamic:
4231 // Dynamic is never better
4235 // FIXME: handle lifted operators
4237 // TODO: this is expensive
4238 Expression p_tmp = new EmptyExpression (p);
4239 Expression q_tmp = new EmptyExpression (q);
4241 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4242 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4244 if (p_to_q && !q_to_p)
4247 if (q_to_p && !p_to_q)
4254 /// Determines "Better function" between candidate
4255 /// and the current best match
4258 /// Returns a boolean indicating :
4259 /// false if candidate ain't better
4260 /// true if candidate is better than the current best match
4262 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4263 MemberSpec best, AParametersCollection bparam, bool best_params)
4265 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4266 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4268 bool better_at_least_one = false;
4270 int args_count = args == null ? 0 : args.Count;
4274 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4277 // Default arguments are ignored for better decision
4278 if (a.IsDefaultArgument)
4282 // When comparing named argument the parameter type index has to be looked up
4283 // in original parameter set (override version for virtual members)
4285 NamedArgument na = a as NamedArgument;
4287 int idx = cparam.GetParameterIndexByName (na.Name);
4288 ct = candidate_pd.Types[idx];
4289 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4290 ct = TypeManager.GetElementType (ct);
4292 idx = bparam.GetParameterIndexByName (na.Name);
4293 bt = best_pd.Types[idx];
4294 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4295 bt = TypeManager.GetElementType (bt);
4297 ct = candidate_pd.Types[c_idx];
4298 bt = best_pd.Types[b_idx];
4300 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4301 ct = TypeManager.GetElementType (ct);
4305 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4306 bt = TypeManager.GetElementType (bt);
4311 if (TypeSpecComparer.IsEqual (ct, bt))
4315 int result = BetterExpressionConversion (ec, a, ct, bt);
4317 // for each argument, the conversion to 'ct' should be no worse than
4318 // the conversion to 'bt'.
4322 // for at least one argument, the conversion to 'ct' should be better than
4323 // the conversion to 'bt'.
4325 better_at_least_one = true;
4328 if (better_at_least_one)
4332 // This handles the case
4334 // Add (float f1, float f2, float f3);
4335 // Add (params decimal [] foo);
4337 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4338 // first candidate would've chosen as better.
4340 if (!same && !a.IsDefaultArgument)
4344 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4348 // This handles the following cases:
4350 // Foo (int i) is better than Foo (int i, long l = 0)
4351 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4352 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4354 // Prefer non-optional version
4356 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4358 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4359 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4362 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4365 return candidate_pd.Count >= best_pd.Count;
4369 // One is a non-generic method and second is a generic method, then non-generic is better
4371 if (best.IsGeneric != candidate.IsGeneric)
4372 return best.IsGeneric;
4375 // This handles the following cases:
4377 // Trim () is better than Trim (params char[] chars)
4378 // Concat (string s1, string s2, string s3) is better than
4379 // Concat (string s1, params string [] srest)
4380 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4382 // Prefer non-expanded version
4384 if (candidate_params != best_params)
4387 int candidate_param_count = candidate_pd.Count;
4388 int best_param_count = best_pd.Count;
4390 if (candidate_param_count != best_param_count)
4391 // can only happen if (candidate_params && best_params)
4392 return candidate_param_count > best_param_count && best_pd.HasParams;
4395 // Both methods have the same number of parameters, and the parameters have equal types
4396 // Pick the "more specific" signature using rules over original (non-inflated) types
4398 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4399 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4401 bool specific_at_least_once = false;
4402 for (j = 0; j < args_count; ++j) {
4403 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4405 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4406 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4408 ct = candidate_def_pd.Types[j];
4409 bt = best_def_pd.Types[j];
4414 TypeSpec specific = MoreSpecific (ct, bt);
4418 specific_at_least_once = true;
4421 if (specific_at_least_once)
4427 static bool CheckInflatedArguments (MethodSpec ms)
4429 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4432 // Setup constraint checker for probing only
4433 ConstraintChecker cc = new ConstraintChecker (null);
4435 var mp = ms.Parameters.Types;
4436 for (int i = 0; i < mp.Length; ++i) {
4437 var type = mp[i] as InflatedTypeSpec;
4441 var targs = type.TypeArguments;
4442 if (targs.Length == 0)
4445 // TODO: Checking inflated MVAR arguments should be enough
4446 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4453 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4455 rc.Report.Error (1729, loc,
4456 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4457 type.GetSignatureForError (), argCount.ToString ());
4461 // Determines if the candidate method is applicable to the given set of arguments
4462 // There could be two different set of parameters for same candidate where one
4463 // is the closest override for default values and named arguments checks and second
4464 // one being the virtual base for the parameter types and modifiers.
4466 // A return value rates candidate method compatibility,
4467 // 0 = the best, int.MaxValue = the worst
4470 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)
4472 // Parameters of most-derived type used mainly for named and optional parameters
4473 var pd = pm.Parameters;
4475 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4476 // params modifier instead of most-derived type
4477 var cpd = ((IParametersMember) candidate).Parameters;
4478 int param_count = pd.Count;
4479 int optional_count = 0;
4481 Arguments orig_args = arguments;
4483 if (arg_count != param_count) {
4485 // No arguments expansion when doing exact match for delegates
4487 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4488 for (int i = 0; i < pd.Count; ++i) {
4489 if (pd.FixedParameters[i].HasDefaultValue) {
4490 optional_count = pd.Count - i;
4496 if (optional_count != 0) {
4497 // Readjust expected number when params used
4498 if (cpd.HasParams) {
4500 if (arg_count < param_count)
4502 } else if (arg_count > param_count) {
4503 int args_gap = System.Math.Abs (arg_count - param_count);
4504 return int.MaxValue - 10000 + args_gap;
4505 } else if (arg_count < param_count - optional_count) {
4506 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4507 return int.MaxValue - 10000 + args_gap;
4509 } else if (arg_count != param_count) {
4510 int args_gap = System.Math.Abs (arg_count - param_count);
4512 return int.MaxValue - 10000 + args_gap;
4513 if (arg_count < param_count - 1)
4514 return int.MaxValue - 10000 + args_gap;
4517 // Resize to fit optional arguments
4518 if (optional_count != 0) {
4519 if (arguments == null) {
4520 arguments = new Arguments (optional_count);
4522 // Have to create a new container, so the next run can do same
4523 var resized = new Arguments (param_count);
4524 resized.AddRange (arguments);
4525 arguments = resized;
4528 for (int i = arg_count; i < param_count; ++i)
4529 arguments.Add (null);
4533 if (arg_count > 0) {
4535 // Shuffle named arguments to the right positions if there are any
4537 if (arguments[arg_count - 1] is NamedArgument) {
4538 arg_count = arguments.Count;
4540 for (int i = 0; i < arg_count; ++i) {
4541 bool arg_moved = false;
4543 NamedArgument na = arguments[i] as NamedArgument;
4547 int index = pd.GetParameterIndexByName (na.Name);
4549 // Named parameter not found
4553 // already reordered
4558 if (index >= param_count) {
4559 // When using parameters which should not be available to the user
4560 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4563 arguments.Add (null);
4567 temp = arguments[index];
4569 // The slot has been taken by positional argument
4570 if (temp != null && !(temp is NamedArgument))
4575 arguments = arguments.MarkOrderedArgument (na);
4579 if (arguments == orig_args) {
4580 arguments = new Arguments (orig_args.Count);
4581 arguments.AddRange (orig_args);
4584 arguments[index] = arguments[i];
4585 arguments[i] = temp;
4592 arg_count = arguments.Count;
4594 } else if (arguments != null) {
4595 arg_count = arguments.Count;
4599 // Don't do any expensive checks when the candidate cannot succeed
4601 if (arg_count != param_count && !cpd.HasParams)
4602 return (param_count - arg_count) * 2 + 1;
4604 var dep = candidate.GetMissingDependencies ();
4606 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4611 // 1. Handle generic method using type arguments when specified or type inference
4614 var ms = candidate as MethodSpec;
4615 if (ms != null && ms.IsGeneric) {
4616 if (type_arguments != null) {
4617 var g_args_count = ms.Arity;
4618 if (g_args_count != type_arguments.Count)
4619 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4621 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4624 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4625 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4626 // candidate was found use the set to report more details about what was wrong with lambda body.
4627 // The general idea is to distinguish between code errors and errors caused by
4628 // trial-and-error type inference
4630 if (lambda_conv_msgs == null) {
4631 for (int i = 0; i < arg_count; i++) {
4632 Argument a = arguments[i];
4636 var am = a.Expr as AnonymousMethodExpression;
4638 if (lambda_conv_msgs == null)
4639 lambda_conv_msgs = new SessionReportPrinter ();
4641 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4646 var ti = new TypeInference (arguments);
4647 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4650 return ti.InferenceScore - 20000;
4653 // Clear any error messages when the result was success
4655 if (lambda_conv_msgs != null)
4656 lambda_conv_msgs.ClearSession ();
4658 if (i_args.Length != 0) {
4659 ms = ms.MakeGenericMethod (ec, i_args);
4664 // Type arguments constraints have to match for the method to be applicable
4666 if (!CheckInflatedArguments (ms)) {
4668 return int.MaxValue - 25000;
4672 // We have a generic return type and at same time the method is override which
4673 // means we have to also inflate override return type in case the candidate is
4674 // best candidate and override return type is different to base return type.
4676 // virtual Foo<T, object> with override Foo<T, dynamic>
4678 if (candidate != pm) {
4679 MethodSpec override_ms = (MethodSpec) pm;
4680 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4681 returnType = inflator.Inflate (returnType);
4683 returnType = ms.ReturnType;
4690 if (type_arguments != null)
4691 return int.MaxValue - 15000;
4697 // 2. Each argument has to be implicitly convertible to method parameter
4699 Parameter.Modifier p_mod = 0;
4702 for (int i = 0; i < arg_count; i++) {
4703 Argument a = arguments[i];
4705 var fp = pd.FixedParameters[i];
4706 if (!fp.HasDefaultValue) {
4707 arguments = orig_args;
4708 return arg_count * 2 + 2;
4712 // Get the default value expression, we can use the same expression
4713 // if the type matches
4715 Expression e = fp.DefaultValue;
4717 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4719 // Restore for possible error reporting
4720 for (int ii = i; ii < arg_count; ++ii)
4721 arguments.RemoveAt (i);
4723 return (arg_count - i) * 2 + 1;
4727 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4729 // LAMESPEC: Attributes can be mixed together with build-in priority
4731 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4732 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4733 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4734 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4735 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4736 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4740 arguments[i] = new Argument (e, Argument.AType.Default);
4744 if (p_mod != Parameter.Modifier.PARAMS) {
4745 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4747 } else if (!params_expanded_form) {
4748 params_expanded_form = true;
4749 pt = ((ElementTypeSpec) pt).Element;
4755 if (!params_expanded_form) {
4756 if (a.ArgType == Argument.AType.ExtensionType) {
4758 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4760 // LAMESPEC: or implicit type parameter conversion
4763 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4764 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4765 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4770 score = IsArgumentCompatible (ec, a, p_mod, pt);
4773 dynamicArgument = true;
4778 // It can be applicable in expanded form (when not doing exact match like for delegates)
4780 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4781 if (!params_expanded_form) {
4782 pt = ((ElementTypeSpec) pt).Element;
4786 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4789 params_expanded_form = true;
4790 dynamicArgument = true;
4791 } else if (score == 0 || arg_count > pd.Count) {
4792 params_expanded_form = true;
4797 if (params_expanded_form)
4799 return (arg_count - i) * 2 + score;
4804 // When params parameter has no argument it will be provided later if the method is the best candidate
4806 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4807 params_expanded_form = true;
4810 // Restore original arguments for dynamic binder to keep the intention of original source code
4812 if (dynamicArgument)
4813 arguments = orig_args;
4818 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4820 if (e is Constant && e.Type == ptype)
4824 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4826 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4827 e = new MemberAccess (new MemberAccess (new MemberAccess (
4828 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4829 } else if (e is Constant) {
4831 // Handles int to int? conversions, DefaultParameterValue check
4833 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4837 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4840 return e.Resolve (ec);
4844 // Tests argument compatibility with the parameter
4845 // The possible return values are
4847 // 1 - modifier mismatch
4848 // 2 - type mismatch
4849 // -1 - dynamic binding required
4851 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4854 // Types have to be identical when ref or out modifer
4855 // is used and argument is not of dynamic type
4857 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4858 if (argument.Type != parameter) {
4860 // Do full equality check after quick path
4862 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4864 // Using dynamic for ref/out parameter can still succeed at runtime
4866 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4873 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4875 // Using dynamic for ref/out parameter can still succeed at runtime
4877 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4884 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4888 // Use implicit conversion in all modes to return same candidates when the expression
4889 // is used as argument or delegate conversion
4891 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4892 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4899 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4901 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4903 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4906 var ac_p = p as ArrayContainer;
4908 var ac_q = q as ArrayContainer;
4912 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4913 if (specific == ac_p.Element)
4915 if (specific == ac_q.Element)
4917 } else if (p.IsGeneric && q.IsGeneric) {
4918 var pargs = TypeManager.GetTypeArguments (p);
4919 var qargs = TypeManager.GetTypeArguments (q);
4921 bool p_specific_at_least_once = false;
4922 bool q_specific_at_least_once = false;
4924 for (int i = 0; i < pargs.Length; i++) {
4925 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4926 if (specific == pargs[i])
4927 p_specific_at_least_once = true;
4928 if (specific == qargs[i])
4929 q_specific_at_least_once = true;
4932 if (p_specific_at_least_once && !q_specific_at_least_once)
4934 if (!p_specific_at_least_once && q_specific_at_least_once)
4942 // Find the best method from candidate list
4944 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4946 List<AmbiguousCandidate> ambiguous_candidates = null;
4948 MemberSpec best_candidate;
4949 Arguments best_candidate_args = null;
4950 bool best_candidate_params = false;
4951 bool best_candidate_dynamic = false;
4952 int best_candidate_rate;
4953 IParametersMember best_parameter_member = null;
4955 int args_count = args != null ? args.Count : 0;
4957 Arguments candidate_args = args;
4958 bool error_mode = false;
4959 MemberSpec invocable_member = null;
4962 best_candidate = null;
4963 best_candidate_rate = int.MaxValue;
4965 var type_members = members;
4967 for (int i = 0; i < type_members.Count; ++i) {
4968 var member = type_members[i];
4971 // Methods in a base class are not candidates if any method in a derived
4972 // class is applicable
4974 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4978 if (!member.IsAccessible (rc))
4981 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4984 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4985 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4990 IParametersMember pm = member as IParametersMember;
4993 // Will use it later to report ambiguity between best method and invocable member
4995 if (Invocation.IsMemberInvocable (member))
4996 invocable_member = member;
5002 // Overload resolution is looking for base member but using parameter names
5003 // and default values from the closest member. That means to do expensive lookup
5004 // for the closest override for virtual or abstract members
5006 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5007 var override_params = base_provider.GetOverrideMemberParameters (member);
5008 if (override_params != null)
5009 pm = override_params;
5013 // Check if the member candidate is applicable
5015 bool params_expanded_form = false;
5016 bool dynamic_argument = false;
5017 TypeSpec rt = pm.MemberType;
5018 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5020 if (lambda_conv_msgs != null)
5021 lambda_conv_msgs.EndSession ();
5024 // How does it score compare to others
5026 if (candidate_rate < best_candidate_rate) {
5028 // Fatal error (missing dependency), cannot continue
5029 if (candidate_rate < 0)
5032 best_candidate_rate = candidate_rate;
5033 best_candidate = member;
5034 best_candidate_args = candidate_args;
5035 best_candidate_params = params_expanded_form;
5036 best_candidate_dynamic = dynamic_argument;
5037 best_parameter_member = pm;
5038 best_candidate_return_type = rt;
5039 } else if (candidate_rate == 0) {
5041 // The member look is done per type for most operations but sometimes
5042 // it's not possible like for binary operators overload because they
5043 // are unioned between 2 sides
5045 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5046 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5051 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5053 // We pack all interface members into top level type which makes the overload resolution
5054 // more complicated for interfaces. We compensate it by removing methods with same
5055 // signature when building the cache hence this path should not really be hit often
5058 // interface IA { void Foo (int arg); }
5059 // interface IB : IA { void Foo (params int[] args); }
5061 // IB::Foo is the best overload when calling IB.Foo (1)
5064 if (ambiguous_candidates != null) {
5065 foreach (var amb_cand in ambiguous_candidates) {
5066 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5075 ambiguous_candidates = null;
5078 // Is the new candidate better
5079 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5083 best_candidate = member;
5084 best_candidate_args = candidate_args;
5085 best_candidate_params = params_expanded_form;
5086 best_candidate_dynamic = dynamic_argument;
5087 best_parameter_member = pm;
5088 best_candidate_return_type = rt;
5090 // It's not better but any other found later could be but we are not sure yet
5091 if (ambiguous_candidates == null)
5092 ambiguous_candidates = new List<AmbiguousCandidate> ();
5094 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5098 // Restore expanded arguments
5099 candidate_args = args;
5101 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5104 // We've found exact match
5106 if (best_candidate_rate == 0)
5110 // Try extension methods lookup when no ordinary method match was found and provider enables it
5113 var emg = base_provider.LookupExtensionMethod (rc);
5115 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5117 best_candidate_extension_group = emg;
5118 return (T) (MemberSpec) emg.BestCandidate;
5123 // Don't run expensive error reporting mode for probing
5130 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5133 lambda_conv_msgs = null;
5138 // No best member match found, report an error
5140 if (best_candidate_rate != 0 || error_mode) {
5141 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5145 if (best_candidate_dynamic) {
5146 if (args[0].ArgType == Argument.AType.ExtensionType) {
5147 rc.Report.Error (1973, loc,
5148 "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",
5149 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5153 // Check type constraints only when explicit type arguments are used
5155 if (best_candidate.IsGeneric && type_arguments != null) {
5156 MethodSpec bc = best_candidate as MethodSpec;
5157 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5158 ConstraintChecker cc = new ConstraintChecker (rc);
5159 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5163 BestCandidateIsDynamic = true;
5168 // These flags indicates we are running delegate probing conversion. No need to
5169 // do more expensive checks
5171 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5172 return (T) best_candidate;
5174 if (ambiguous_candidates != null) {
5176 // Now check that there are no ambiguities i.e the selected method
5177 // should be better than all the others
5179 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5180 var candidate = ambiguous_candidates [ix];
5182 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5183 var ambiguous = candidate.Member;
5184 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5185 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5186 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5187 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5188 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5191 return (T) best_candidate;
5196 if (invocable_member != null && !IsProbingOnly) {
5197 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5198 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5199 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5200 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5204 // And now check if the arguments are all
5205 // compatible, perform conversions if
5206 // necessary etc. and return if everything is
5209 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5212 if (best_candidate == null)
5216 // Don't run possibly expensive checks in probing mode
5218 if (!IsProbingOnly && !rc.IsInProbingMode) {
5220 // Check ObsoleteAttribute on the best method
5222 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5223 if (oa != null && !rc.IsObsolete)
5224 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5226 best_candidate.MemberDefinition.SetIsUsed ();
5229 args = best_candidate_args;
5230 return (T) best_candidate;
5233 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5235 return ResolveMember<MethodSpec> (rc, ref args);
5238 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5239 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5241 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5244 if (a.Type == InternalType.ErrorType)
5247 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5248 ec.Report.SymbolRelatedToPreviousError (method);
5249 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5250 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5251 TypeManager.CSharpSignature (method));
5254 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5255 TypeManager.CSharpSignature (method));
5256 } else if (IsDelegateInvoke) {
5257 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5258 DelegateType.GetSignatureForError ());
5260 ec.Report.SymbolRelatedToPreviousError (method);
5261 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5262 method.GetSignatureForError ());
5265 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5267 string index = (idx + 1).ToString ();
5268 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5269 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5270 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5271 index, Parameter.GetModifierSignature (a.Modifier));
5273 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5274 index, Parameter.GetModifierSignature (mod));
5276 string p1 = a.GetSignatureForError ();
5277 string p2 = paramType.GetSignatureForError ();
5280 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5281 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5284 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5285 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5286 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5289 ec.Report.Error (1503, a.Expr.Location,
5290 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5295 // We have failed to find exact match so we return error info about the closest match
5297 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5299 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5300 int arg_count = args == null ? 0 : args.Count;
5302 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5303 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5304 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5308 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5313 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5314 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5315 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5319 // For candidates which match on parameters count report more details about incorrect arguments
5322 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5323 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5324 // Reject any inaccessible member
5325 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5326 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5327 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5331 var ms = best_candidate as MethodSpec;
5332 if (ms != null && ms.IsGeneric) {
5333 bool constr_ok = true;
5334 if (ms.TypeArguments != null)
5335 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5337 if (ta_count == 0 && ms.TypeArguments == null) {
5338 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5342 rc.Report.Error (411, loc,
5343 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5344 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5351 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5357 // We failed to find any method with correct argument count, report best candidate
5359 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5362 if (best_candidate.Kind == MemberKind.Constructor) {
5363 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5364 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5365 } else if (IsDelegateInvoke) {
5366 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5367 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5368 DelegateType.GetSignatureForError (), arg_count.ToString ());
5370 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5371 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5372 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5373 name, arg_count.ToString ());
5377 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5379 var pd = pm.Parameters;
5380 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5382 Parameter.Modifier p_mod = 0;
5384 int a_idx = 0, a_pos = 0;
5386 ArrayInitializer params_initializers = null;
5387 bool has_unsafe_arg = pm.MemberType.IsPointer;
5388 int arg_count = args == null ? 0 : args.Count;
5390 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5395 if (p_mod != Parameter.Modifier.PARAMS) {
5396 p_mod = pd.FixedParameters[a_idx].ModFlags;
5398 has_unsafe_arg |= pt.IsPointer;
5400 if (p_mod == Parameter.Modifier.PARAMS) {
5401 if (chose_params_expanded) {
5402 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5403 pt = TypeManager.GetElementType (pt);
5409 // Types have to be identical when ref or out modifer is used
5411 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5412 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5415 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5421 NamedArgument na = a as NamedArgument;
5423 int name_index = pd.GetParameterIndexByName (na.Name);
5424 if (name_index < 0 || name_index >= pd.Count) {
5425 if (IsDelegateInvoke) {
5426 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5427 ec.Report.Error (1746, na.Location,
5428 "The delegate `{0}' does not contain a parameter named `{1}'",
5429 DelegateType.GetSignatureForError (), na.Name);
5431 ec.Report.SymbolRelatedToPreviousError (member);
5432 ec.Report.Error (1739, na.Location,
5433 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5434 TypeManager.CSharpSignature (member), na.Name);
5436 } else if (args[name_index] != a && args[name_index] != null) {
5437 if (IsDelegateInvoke)
5438 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5440 ec.Report.SymbolRelatedToPreviousError (member);
5442 ec.Report.Error (1744, na.Location,
5443 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5448 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5451 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5452 custom_errors.NoArgumentMatch (ec, member);
5457 if (a.ArgType == Argument.AType.ExtensionType) {
5458 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5461 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5463 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5466 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5473 // Convert params arguments to an array initializer
5475 if (params_initializers != null) {
5476 // we choose to use 'a.Expr' rather than 'conv' so that
5477 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5478 params_initializers.Add (a.Expr);
5479 args.RemoveAt (a_idx--);
5485 // Update the argument with the implicit conversion
5489 if (a_idx != arg_count) {
5490 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5495 // Fill not provided arguments required by params modifier
5497 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5499 args = new Arguments (1);
5501 pt = ptypes[pd.Count - 1];
5502 pt = TypeManager.GetElementType (pt);
5503 has_unsafe_arg |= pt.IsPointer;
5504 params_initializers = new ArrayInitializer (0, loc);
5508 // Append an array argument with all params arguments
5510 if (params_initializers != null) {
5511 args.Add (new Argument (
5512 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5516 if (has_unsafe_arg && !ec.IsUnsafe) {
5517 Expression.UnsafeError (ec, loc);
5521 // We could infer inaccesible type arguments
5523 if (type_arguments == null && member.IsGeneric) {
5524 var ms = (MethodSpec) member;
5525 foreach (var ta in ms.TypeArguments) {
5526 if (!ta.IsAccessible (ec)) {
5527 ec.Report.SymbolRelatedToPreviousError (ta);
5528 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5538 public class ConstantExpr : MemberExpr
5540 readonly ConstSpec constant;
5542 public ConstantExpr (ConstSpec constant, Location loc)
5544 this.constant = constant;
5548 public override string Name {
5549 get { throw new NotImplementedException (); }
5552 public override string KindName {
5553 get { return "constant"; }
5556 public override bool IsInstance {
5557 get { return !IsStatic; }
5560 public override bool IsStatic {
5561 get { return true; }
5564 protected override TypeSpec DeclaringType {
5565 get { return constant.DeclaringType; }
5568 public override Expression CreateExpressionTree (ResolveContext ec)
5570 throw new NotSupportedException ("ET");
5573 protected override Expression DoResolve (ResolveContext rc)
5575 ResolveInstanceExpression (rc, null);
5576 DoBestMemberChecks (rc, constant);
5578 var c = constant.GetConstant (rc);
5580 // Creates reference expression to the constant value
5581 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5584 public override void Emit (EmitContext ec)
5586 throw new NotSupportedException ();
5589 public override string GetSignatureForError ()
5591 return constant.GetSignatureForError ();
5594 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5596 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5601 // Fully resolved expression that references a Field
5603 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5605 protected FieldSpec spec;
5606 VariableInfo variable_info;
5608 LocalTemporary temp;
5611 protected FieldExpr (Location l)
5616 public FieldExpr (FieldSpec spec, Location loc)
5621 type = spec.MemberType;
5624 public FieldExpr (FieldBase fi, Location l)
5631 public override string Name {
5637 public bool IsHoisted {
5639 IVariableReference hv = InstanceExpression as IVariableReference;
5640 return hv != null && hv.IsHoisted;
5644 public override bool IsInstance {
5646 return !spec.IsStatic;
5650 public override bool IsStatic {
5652 return spec.IsStatic;
5656 public override string KindName {
5657 get { return "field"; }
5660 public FieldSpec Spec {
5666 protected override TypeSpec DeclaringType {
5668 return spec.DeclaringType;
5672 public VariableInfo VariableInfo {
5674 return variable_info;
5680 public override string GetSignatureForError ()
5682 return spec.GetSignatureForError ();
5685 public bool IsMarshalByRefAccess (ResolveContext rc)
5687 // Checks possible ldflda of field access expression
5688 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5689 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5690 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5693 public void SetHasAddressTaken ()
5695 IVariableReference vr = InstanceExpression as IVariableReference;
5697 vr.SetHasAddressTaken ();
5701 public override Expression CreateExpressionTree (ResolveContext ec)
5703 return CreateExpressionTree (ec, true);
5706 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5709 Expression instance;
5711 if (InstanceExpression == null) {
5712 instance = new NullLiteral (loc);
5713 } else if (convertInstance) {
5714 instance = InstanceExpression.CreateExpressionTree (ec);
5716 args = new Arguments (1);
5717 args.Add (new Argument (InstanceExpression));
5718 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5721 args = Arguments.CreateForExpressionTree (ec, null,
5723 CreateTypeOfExpression ());
5725 return CreateExpressionFactoryCall (ec, "Field", args);
5728 public Expression CreateTypeOfExpression ()
5730 return new TypeOfField (spec, loc);
5733 protected override Expression DoResolve (ResolveContext ec)
5735 spec.MemberDefinition.SetIsUsed ();
5737 return DoResolve (ec, null);
5740 Expression DoResolve (ResolveContext ec, Expression rhs)
5742 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5745 if (ResolveInstanceExpression (ec, rhs)) {
5746 // Resolve the field's instance expression while flow analysis is turned
5747 // off: when accessing a field "a.b", we must check whether the field
5748 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5750 if (lvalue_instance) {
5751 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5753 Expression right_side =
5754 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5756 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5758 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5761 if (InstanceExpression == null)
5765 DoBestMemberChecks (ec, spec);
5768 var fb = spec as FixedFieldSpec;
5769 IVariableReference var = InstanceExpression as IVariableReference;
5772 IFixedExpression fe = InstanceExpression as IFixedExpression;
5773 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5774 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5777 if (InstanceExpression.eclass != ExprClass.Variable) {
5778 ec.Report.SymbolRelatedToPreviousError (spec);
5779 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5780 TypeManager.GetFullNameSignature (spec));
5781 } else if (var != null && var.IsHoisted) {
5782 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5785 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5789 // Set flow-analysis variable info for struct member access. It will be check later
5790 // for precise error reporting
5792 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5793 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5796 eclass = ExprClass.Variable;
5800 public void SetFieldAssigned (FlowAnalysisContext fc)
5805 bool lvalue_instance = spec.DeclaringType.IsStruct;
5806 if (lvalue_instance) {
5807 var var = InstanceExpression as IVariableReference;
5808 if (var != null && var.VariableInfo != null) {
5809 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5813 var fe = InstanceExpression as FieldExpr;
5814 if (fe != null || lvalue_instance) {
5819 while (fe.InstanceExpression is FieldExpr) {
5820 fe = (FieldExpr) fe.InstanceExpression;
5821 if (!fe.Spec.DeclaringType.IsStruct)
5824 if (fe.VariableInfo != null && fc.IsStructFieldDefinitelyAssigned (fe.VariableInfo, fe.Name)) {
5825 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5829 fe.InstanceExpression.FlowAnalysis (fc);
5832 InstanceExpression.FlowAnalysis (fc);
5837 public void VerifyAssignedStructField (FlowAnalysisContext fc)
5842 var var = fe.InstanceExpression as IVariableReference;
5844 var vi = var.VariableInfo;
5846 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, fe.Name) && !fe.type.IsStruct) {
5847 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5851 fe = fe.InstanceExpression as FieldExpr;
5853 } while (fe != null);
5856 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5858 // The return value is always null. Returning a value simplifies calling code.
5860 if (right_side == EmptyExpression.OutAccess) {
5862 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5863 GetSignatureForError ());
5865 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5866 GetSignatureForError ());
5872 if (right_side == EmptyExpression.LValueMemberAccess) {
5873 // Already reported as CS1648/CS1650
5877 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5879 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5880 GetSignatureForError ());
5882 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5883 GetSignatureForError ());
5889 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5890 GetSignatureForError ());
5892 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5893 GetSignatureForError ());
5899 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5901 if (spec is FixedFieldSpec) {
5902 // It could be much better error message but we want to be error compatible
5903 Error_ValueAssignment (ec, right_side);
5906 Expression e = DoResolve (ec, right_side);
5911 spec.MemberDefinition.SetIsAssigned ();
5913 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5914 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5915 ec.Report.Warning (420, 1, loc,
5916 "`{0}': A volatile field references will not be treated as volatile",
5917 spec.GetSignatureForError ());
5920 if (spec.IsReadOnly) {
5921 // InitOnly fields can only be assigned in constructors or initializers
5922 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5923 return Error_AssignToReadonly (ec, right_side);
5925 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5927 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5928 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5929 return Error_AssignToReadonly (ec, right_side);
5930 // static InitOnly fields cannot be assigned-to in an instance constructor
5931 if (IsStatic && !ec.IsStatic)
5932 return Error_AssignToReadonly (ec, right_side);
5933 // instance constructors can't modify InitOnly fields of other instances of the same type
5934 if (!IsStatic && !(InstanceExpression is This))
5935 return Error_AssignToReadonly (ec, right_side);
5939 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5940 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5941 ec.Report.Warning (197, 1, loc,
5942 "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",
5943 GetSignatureForError ());
5946 eclass = ExprClass.Variable;
5950 public override void FlowAnalysis (FlowAnalysisContext fc)
5952 var var = InstanceExpression as IVariableReference;
5954 var vi = var.VariableInfo;
5955 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
5956 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
5960 if (TypeSpec.IsValueType (InstanceExpression.Type))
5964 base.FlowAnalysis (fc);
5967 public override int GetHashCode ()
5969 return spec.GetHashCode ();
5972 public bool IsFixed {
5975 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5977 IVariableReference variable = InstanceExpression as IVariableReference;
5978 if (variable != null)
5979 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5981 IFixedExpression fe = InstanceExpression as IFixedExpression;
5982 return fe != null && fe.IsFixed;
5986 public override bool Equals (object obj)
5988 FieldExpr fe = obj as FieldExpr;
5992 if (spec != fe.spec)
5995 if (InstanceExpression == null || fe.InstanceExpression == null)
5998 return InstanceExpression.Equals (fe.InstanceExpression);
6001 public void Emit (EmitContext ec, bool leave_copy)
6003 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6007 ec.Emit (OpCodes.Volatile);
6009 ec.Emit (OpCodes.Ldsfld, spec);
6012 EmitInstance (ec, false);
6014 // Optimization for build-in types
6015 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6016 ec.EmitLoadFromPtr (type);
6018 var ff = spec as FixedFieldSpec;
6020 ec.Emit (OpCodes.Ldflda, spec);
6021 ec.Emit (OpCodes.Ldflda, ff.Element);
6024 ec.Emit (OpCodes.Volatile);
6026 ec.Emit (OpCodes.Ldfld, spec);
6032 ec.Emit (OpCodes.Dup);
6034 temp = new LocalTemporary (this.Type);
6040 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6042 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6043 if (isCompound && !(source is DynamicExpressionStatement)) {
6044 if (has_await_source) {
6046 InstanceExpression = InstanceExpression.EmitToField (ec);
6053 if (has_await_source)
6054 source = source.EmitToField (ec);
6056 EmitInstance (ec, prepared);
6062 ec.Emit (OpCodes.Dup);
6064 temp = new LocalTemporary (this.Type);
6069 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6070 ec.Emit (OpCodes.Volatile);
6072 spec.MemberDefinition.SetIsAssigned ();
6075 ec.Emit (OpCodes.Stsfld, spec);
6077 ec.Emit (OpCodes.Stfld, spec);
6087 // Emits store to field with prepared values on stack
6089 public void EmitAssignFromStack (EmitContext ec)
6092 ec.Emit (OpCodes.Stsfld, spec);
6094 ec.Emit (OpCodes.Stfld, spec);
6098 public override void Emit (EmitContext ec)
6103 public override void EmitSideEffect (EmitContext ec)
6105 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6107 if (is_volatile) // || is_marshal_by_ref ())
6108 base.EmitSideEffect (ec);
6111 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6113 if ((mode & AddressOp.Store) != 0)
6114 spec.MemberDefinition.SetIsAssigned ();
6115 if ((mode & AddressOp.Load) != 0)
6116 spec.MemberDefinition.SetIsUsed ();
6119 // Handle initonly fields specially: make a copy and then
6120 // get the address of the copy.
6123 if (spec.IsReadOnly){
6125 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6137 var temp = ec.GetTemporaryLocal (type);
6138 ec.Emit (OpCodes.Stloc, temp);
6139 ec.Emit (OpCodes.Ldloca, temp);
6140 ec.FreeTemporaryLocal (temp, type);
6146 ec.Emit (OpCodes.Ldsflda, spec);
6149 EmitInstance (ec, false);
6150 ec.Emit (OpCodes.Ldflda, spec);
6154 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6156 return MakeExpression (ctx);
6159 public override SLE.Expression MakeExpression (BuilderContext ctx)
6162 return base.MakeExpression (ctx);
6164 return SLE.Expression.Field (
6165 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6166 spec.GetMetaInfo ());
6170 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6172 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6178 // Expression that evaluates to a Property.
6180 // This is not an LValue because we need to re-write the expression. We
6181 // can not take data from the stack and store it.
6183 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6185 Arguments arguments;
6187 public PropertyExpr (PropertySpec spec, Location l)
6190 best_candidate = spec;
6191 type = spec.MemberType;
6196 protected override Arguments Arguments {
6205 protected override TypeSpec DeclaringType {
6207 return best_candidate.DeclaringType;
6211 public override string Name {
6213 return best_candidate.Name;
6217 public override bool IsInstance {
6223 public override bool IsStatic {
6225 return best_candidate.IsStatic;
6229 public override string KindName {
6230 get { return "property"; }
6233 public PropertySpec PropertyInfo {
6235 return best_candidate;
6241 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6243 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6246 var args_count = arguments == null ? 0 : arguments.Count;
6247 if (args_count != body.Parameters.Count && args_count == 0)
6250 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6251 mg.InstanceExpression = InstanceExpression;
6256 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6258 return new PropertyExpr (spec, loc) {
6264 public override Expression CreateExpressionTree (ResolveContext ec)
6267 if (IsSingleDimensionalArrayLength ()) {
6268 args = new Arguments (1);
6269 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6270 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6273 args = new Arguments (2);
6274 if (InstanceExpression == null)
6275 args.Add (new Argument (new NullLiteral (loc)));
6277 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6278 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6279 return CreateExpressionFactoryCall (ec, "Property", args);
6282 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6284 DoResolveLValue (rc, null);
6285 return new TypeOfMethod (Setter, loc);
6288 public override string GetSignatureForError ()
6290 return best_candidate.GetSignatureForError ();
6293 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6296 return base.MakeExpression (ctx);
6298 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6302 public override SLE.Expression MakeExpression (BuilderContext ctx)
6305 return base.MakeExpression (ctx);
6307 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6311 void Error_PropertyNotValid (ResolveContext ec)
6313 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6314 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6315 GetSignatureForError ());
6318 bool IsSingleDimensionalArrayLength ()
6320 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6323 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6324 return ac != null && ac.Rank == 1;
6327 public override void Emit (EmitContext ec, bool leave_copy)
6330 // Special case: length of single dimension array property is turned into ldlen
6332 if (IsSingleDimensionalArrayLength ()) {
6333 EmitInstance (ec, false);
6334 ec.Emit (OpCodes.Ldlen);
6335 ec.Emit (OpCodes.Conv_I4);
6339 base.Emit (ec, leave_copy);
6342 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6345 LocalTemporary await_source_arg = null;
6347 if (isCompound && !(source is DynamicExpressionStatement)) {
6348 emitting_compound_assignment = true;
6351 if (has_await_arguments) {
6352 await_source_arg = new LocalTemporary (Type);
6353 await_source_arg.Store (ec);
6355 args = new Arguments (1);
6356 args.Add (new Argument (await_source_arg));
6359 temp = await_source_arg;
6362 has_await_arguments = false;
6367 ec.Emit (OpCodes.Dup);
6368 temp = new LocalTemporary (this.Type);
6373 args = arguments ?? new Arguments (1);
6377 temp = new LocalTemporary (this.Type);
6379 args.Add (new Argument (temp));
6381 args.Add (new Argument (source));
6385 emitting_compound_assignment = false;
6387 var call = new CallEmitter ();
6388 call.InstanceExpression = InstanceExpression;
6390 call.InstanceExpressionOnStack = true;
6392 call.Emit (ec, Setter, args, loc);
6399 if (await_source_arg != null) {
6400 await_source_arg.Release (ec);
6404 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6406 eclass = ExprClass.PropertyAccess;
6408 if (best_candidate.IsNotCSharpCompatible) {
6409 Error_PropertyNotValid (rc);
6412 ResolveInstanceExpression (rc, right_side);
6414 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6415 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6416 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6418 type = p.MemberType;
6422 DoBestMemberChecks (rc, best_candidate);
6424 // Handling of com-imported properties with any number of default property parameters
6425 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6426 var p = best_candidate.Get.Parameters;
6427 arguments = new Arguments (p.Count);
6428 for (int i = 0; i < p.Count; ++i) {
6429 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6431 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6432 var p = best_candidate.Set.Parameters;
6433 arguments = new Arguments (p.Count - 1);
6434 for (int i = 0; i < p.Count - 1; ++i) {
6435 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6442 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6444 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6448 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6450 // getter and setter can be different for base calls
6451 MethodSpec getter, setter;
6452 protected T best_candidate;
6454 protected LocalTemporary temp;
6455 protected bool emitting_compound_assignment;
6456 protected bool has_await_arguments;
6458 protected PropertyOrIndexerExpr (Location l)
6465 protected abstract Arguments Arguments { get; set; }
6467 public MethodSpec Getter {
6476 public MethodSpec Setter {
6487 protected override Expression DoResolve (ResolveContext ec)
6489 if (eclass == ExprClass.Unresolved) {
6490 var expr = OverloadResolve (ec, null);
6495 return expr.Resolve (ec);
6498 if (!ResolveGetter (ec))
6504 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6506 if (right_side == EmptyExpression.OutAccess) {
6507 // TODO: best_candidate can be null at this point
6508 INamedBlockVariable variable = null;
6509 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6510 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6511 best_candidate.Name);
6513 right_side.DoResolveLValue (ec, this);
6518 if (eclass == ExprClass.Unresolved) {
6519 var expr = OverloadResolve (ec, right_side);
6524 return expr.ResolveLValue (ec, right_side);
6527 if (!ResolveSetter (ec))
6534 // Implements the IAssignMethod interface for assignments
6536 public virtual void Emit (EmitContext ec, bool leave_copy)
6538 var call = new CallEmitter ();
6539 call.InstanceExpression = InstanceExpression;
6540 if (has_await_arguments)
6541 call.HasAwaitArguments = true;
6543 call.DuplicateArguments = emitting_compound_assignment;
6545 call.Emit (ec, Getter, Arguments, loc);
6547 if (call.HasAwaitArguments) {
6548 InstanceExpression = call.InstanceExpression;
6549 Arguments = call.EmittedArguments;
6550 has_await_arguments = true;
6554 ec.Emit (OpCodes.Dup);
6555 temp = new LocalTemporary (Type);
6560 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6562 public override void Emit (EmitContext ec)
6567 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6569 has_await_arguments = true;
6574 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6576 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6578 bool ResolveGetter (ResolveContext rc)
6580 if (!best_candidate.HasGet) {
6581 if (InstanceExpression != EmptyExpression.Null) {
6582 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6583 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6584 best_candidate.GetSignatureForError ());
6587 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6588 if (best_candidate.HasDifferentAccessibility) {
6589 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6590 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6591 TypeManager.CSharpSignature (best_candidate));
6593 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6594 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6598 if (best_candidate.HasDifferentAccessibility) {
6599 CheckProtectedMemberAccess (rc, best_candidate.Get);
6602 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6606 bool ResolveSetter (ResolveContext rc)
6608 if (!best_candidate.HasSet) {
6609 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6610 GetSignatureForError ());
6614 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6615 if (best_candidate.HasDifferentAccessibility) {
6616 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6617 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6618 GetSignatureForError ());
6620 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6621 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6625 if (best_candidate.HasDifferentAccessibility)
6626 CheckProtectedMemberAccess (rc, best_candidate.Set);
6628 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6634 /// Fully resolved expression that evaluates to an Event
6636 public class EventExpr : MemberExpr, IAssignMethod
6638 readonly EventSpec spec;
6641 public EventExpr (EventSpec spec, Location loc)
6649 protected override TypeSpec DeclaringType {
6651 return spec.DeclaringType;
6655 public override string Name {
6661 public override bool IsInstance {
6663 return !spec.IsStatic;
6667 public override bool IsStatic {
6669 return spec.IsStatic;
6673 public override string KindName {
6674 get { return "event"; }
6677 public MethodSpec Operator {
6685 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6688 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6690 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6691 if (spec.BackingField != null &&
6692 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6694 spec.MemberDefinition.SetIsUsed ();
6696 if (!ec.IsObsolete) {
6697 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6699 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6702 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6703 Error_AssignmentEventOnly (ec);
6705 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6707 InstanceExpression = null;
6709 return ml.ResolveMemberAccess (ec, left, original);
6713 return base.ResolveMemberAccess (ec, left, original);
6716 public override Expression CreateExpressionTree (ResolveContext ec)
6718 throw new NotSupportedException ("ET");
6721 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6723 if (right_side == EmptyExpression.EventAddition) {
6724 op = spec.AccessorAdd;
6725 } else if (right_side == EmptyExpression.EventSubtraction) {
6726 op = spec.AccessorRemove;
6730 Error_AssignmentEventOnly (ec);
6734 op = CandidateToBaseOverride (ec, op);
6738 protected override Expression DoResolve (ResolveContext ec)
6740 eclass = ExprClass.EventAccess;
6741 type = spec.MemberType;
6743 ResolveInstanceExpression (ec, null);
6745 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6746 Error_AssignmentEventOnly (ec);
6749 DoBestMemberChecks (ec, spec);
6753 public override void Emit (EmitContext ec)
6755 throw new NotSupportedException ();
6756 //Error_CannotAssign ();
6759 #region IAssignMethod Members
6761 public void Emit (EmitContext ec, bool leave_copy)
6763 throw new NotImplementedException ();
6766 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6768 if (leave_copy || !isCompound)
6769 throw new NotImplementedException ("EventExpr::EmitAssign");
6771 Arguments args = new Arguments (1);
6772 args.Add (new Argument (source));
6774 var call = new CallEmitter ();
6775 call.InstanceExpression = InstanceExpression;
6776 call.Emit (ec, op, args, loc);
6781 void Error_AssignmentEventOnly (ResolveContext ec)
6783 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6784 ec.Report.Error (79, loc,
6785 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6786 GetSignatureForError ());
6788 ec.Report.Error (70, loc,
6789 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6790 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6794 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6796 name = name.Substring (0, name.LastIndexOf ('.'));
6797 base.Error_CannotCallAbstractBase (rc, name);
6800 public override string GetSignatureForError ()
6802 return TypeManager.CSharpSignature (spec);
6805 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6807 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6811 public class TemporaryVariableReference : VariableReference
6813 public class Declarator : Statement
6815 TemporaryVariableReference variable;
6817 public Declarator (TemporaryVariableReference variable)
6819 this.variable = variable;
6823 protected override void DoEmit (EmitContext ec)
6825 variable.li.CreateBuilder (ec);
6828 public override void Emit (EmitContext ec)
6830 // Don't create sequence point
6834 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6839 protected override void CloneTo (CloneContext clonectx, Statement target)
6847 public TemporaryVariableReference (LocalVariable li, Location loc)
6850 this.type = li.Type;
6854 public override bool IsLockedByStatement {
6862 public LocalVariable LocalInfo {
6868 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6870 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6871 return new TemporaryVariableReference (li, loc);
6874 protected override Expression DoResolve (ResolveContext ec)
6876 eclass = ExprClass.Variable;
6879 // Don't capture temporary variables except when using
6880 // state machine redirection and block yields
6882 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6883 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6884 ec.IsVariableCapturingRequired) {
6885 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6886 storey.CaptureLocalVariable (ec, li);
6892 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6894 return Resolve (ec);
6897 public override void Emit (EmitContext ec)
6899 li.CreateBuilder (ec);
6904 public void EmitAssign (EmitContext ec, Expression source)
6906 li.CreateBuilder (ec);
6908 EmitAssign (ec, source, false, false);
6911 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6913 return li.HoistedVariant;
6916 public override bool IsFixed {
6917 get { return true; }
6920 public override bool IsRef {
6921 get { return false; }
6924 public override string Name {
6925 get { throw new NotImplementedException (); }
6928 public override void SetHasAddressTaken ()
6930 throw new NotImplementedException ();
6933 protected override ILocalVariable Variable {
6937 public override VariableInfo VariableInfo {
6938 get { return null; }
6943 /// Handles `var' contextual keyword; var becomes a keyword only
6944 /// if no type called var exists in a variable scope
6946 class VarExpr : SimpleName
6948 public VarExpr (Location loc)
6953 public bool InferType (ResolveContext ec, Expression right_side)
6956 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6958 type = right_side.Type;
6959 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6960 ec.Report.Error (815, loc,
6961 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6962 type.GetSignatureForError ());
6966 eclass = ExprClass.Variable;
6970 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6972 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6973 base.Error_TypeOrNamespaceNotFound (ec);
6975 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");