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.BreakOnInternalError || 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, bool pointerArray = false)
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);
1092 // Only positive constants are allowed at compile time
1094 Constant c = converted as Constant;
1095 if (c != null && c.IsNegative)
1096 Error_NegativeArrayIndex (ec, source.loc);
1098 // No conversion needed to array index
1099 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1102 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1106 // Derived classes implement this method by cloning the fields that
1107 // could become altered during the Resolve stage
1109 // Only expressions that are created for the parser need to implement
1112 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1114 throw new NotImplementedException (
1116 "CloneTo not implemented for expression {0}", this.GetType ()));
1120 // Clones an expression created by the parser.
1122 // We only support expressions created by the parser so far, not
1123 // expressions that have been resolved (many more classes would need
1124 // to implement CloneTo).
1126 // This infrastructure is here merely for Lambda expressions which
1127 // compile the same code using different type values for the same
1128 // arguments to find the correct overload
1130 public virtual Expression Clone (CloneContext clonectx)
1132 Expression cloned = (Expression) MemberwiseClone ();
1133 CloneTo (clonectx, cloned);
1139 // Implementation of expression to expression tree conversion
1141 public abstract Expression CreateExpressionTree (ResolveContext ec);
1143 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1145 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1148 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1150 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1153 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1155 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1158 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1160 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1164 return new TypeExpression (t, loc);
1168 // Implemented by all expressions which support conversion from
1169 // compiler expression to invokable runtime expression. Used by
1170 // dynamic C# binder.
1172 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1174 throw new NotImplementedException ("MakeExpression for " + GetType ());
1177 public virtual object Accept (StructuralVisitor visitor)
1179 return visitor.Visit (this);
1184 /// This is just a base class for expressions that can
1185 /// appear on statements (invocations, object creation,
1186 /// assignments, post/pre increment and decrement). The idea
1187 /// being that they would support an extra Emition interface that
1188 /// does not leave a result on the stack.
1190 public abstract class ExpressionStatement : Expression
1192 public virtual void MarkReachable (Reachability rc)
1196 public ExpressionStatement ResolveStatement (BlockContext ec)
1198 Expression e = Resolve (ec);
1202 ExpressionStatement es = e as ExpressionStatement;
1203 if (es == null || e is AnonymousMethodBody)
1204 Error_InvalidExpressionStatement (ec);
1207 // This is quite expensive warning, try to limit the damage
1209 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1210 WarningAsyncWithoutWait (ec, e);
1216 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1218 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1219 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1224 // Need to do full resolve because GetAwaiter can be extension method
1225 // available only in this context
1227 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1231 var arguments = new Arguments (0);
1232 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1237 // Use same check rules as for real await
1239 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1240 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1243 bc.Report.Warning (4014, 1, e.Location,
1244 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1248 var inv = e as Invocation;
1249 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1250 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1251 bc.Report.Warning (4014, 1, e.Location,
1252 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1258 /// Requests the expression to be emitted in a `statement'
1259 /// context. This means that no new value is left on the
1260 /// stack after invoking this method (constrasted with
1261 /// Emit that will always leave a value on the stack).
1263 public abstract void EmitStatement (EmitContext ec);
1265 public override void EmitSideEffect (EmitContext ec)
1272 /// This kind of cast is used to encapsulate the child
1273 /// whose type is child.Type into an expression that is
1274 /// reported to return "return_type". This is used to encapsulate
1275 /// expressions which have compatible types, but need to be dealt
1276 /// at higher levels with.
1278 /// For example, a "byte" expression could be encapsulated in one
1279 /// of these as an "unsigned int". The type for the expression
1280 /// would be "unsigned int".
1283 public abstract class TypeCast : Expression
1285 protected readonly Expression child;
1287 protected TypeCast (Expression child, TypeSpec return_type)
1289 eclass = child.eclass;
1290 loc = child.Location;
1295 public Expression Child {
1301 public override bool ContainsEmitWithAwait ()
1303 return child.ContainsEmitWithAwait ();
1306 public override Expression CreateExpressionTree (ResolveContext ec)
1308 Arguments args = new Arguments (2);
1309 args.Add (new Argument (child.CreateExpressionTree (ec)));
1310 args.Add (new Argument (new TypeOf (type, loc)));
1312 if (type.IsPointer || child.Type.IsPointer)
1313 Error_PointerInsideExpressionTree (ec);
1315 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1318 protected override Expression DoResolve (ResolveContext ec)
1320 // This should never be invoked, we are born in fully
1321 // initialized state.
1326 public override void Emit (EmitContext ec)
1331 public override void FlowAnalysis (FlowAnalysisContext fc)
1333 child.FlowAnalysis (fc);
1336 public override SLE.Expression MakeExpression (BuilderContext ctx)
1339 return base.MakeExpression (ctx);
1341 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1342 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1343 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1347 protected override void CloneTo (CloneContext clonectx, Expression t)
1352 public override bool IsNull {
1353 get { return child.IsNull; }
1357 public class EmptyCast : TypeCast {
1358 EmptyCast (Expression child, TypeSpec target_type)
1359 : base (child, target_type)
1363 public static Expression Create (Expression child, TypeSpec type)
1365 Constant c = child as Constant;
1367 var enum_constant = c as EnumConstant;
1368 if (enum_constant != null)
1369 c = enum_constant.Child;
1371 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1375 var res = c.ConvertImplicitly (type);
1381 EmptyCast e = child as EmptyCast;
1383 return new EmptyCast (e.child, type);
1385 return new EmptyCast (child, type);
1388 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1390 child.EmitBranchable (ec, label, on_true);
1393 public override void EmitSideEffect (EmitContext ec)
1395 child.EmitSideEffect (ec);
1400 // Used for predefined type user operator (no obsolete check, etc.)
1402 public class OperatorCast : TypeCast
1404 readonly MethodSpec conversion_operator;
1406 public OperatorCast (Expression expr, TypeSpec target_type)
1407 : this (expr, target_type, target_type, false)
1411 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1412 : this (expr, target_type, target_type, find_explicit)
1416 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1417 : base (expr, returnType)
1419 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1420 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1423 foreach (MethodSpec oper in mi) {
1424 if (oper.ReturnType != returnType)
1427 if (oper.Parameters.Types[0] == expr.Type) {
1428 conversion_operator = oper;
1434 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1435 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1438 public override void Emit (EmitContext ec)
1441 ec.Emit (OpCodes.Call, conversion_operator);
1446 // Constant specialization of EmptyCast.
1447 // We need to special case this since an empty cast of
1448 // a constant is still a constant.
1450 public class EmptyConstantCast : Constant
1452 public readonly Constant child;
1454 public EmptyConstantCast (Constant child, TypeSpec type)
1455 : base (child.Location)
1458 throw new ArgumentNullException ("child");
1461 this.eclass = child.eclass;
1465 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1467 if (child.Type == target_type)
1470 // FIXME: check that 'type' can be converted to 'target_type' first
1471 return child.ConvertExplicitly (in_checked_context, target_type);
1474 public override Expression CreateExpressionTree (ResolveContext ec)
1476 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1477 child.CreateExpressionTree (ec),
1478 new TypeOf (type, loc));
1481 Error_PointerInsideExpressionTree (ec);
1483 return CreateExpressionFactoryCall (ec, "Convert", args);
1486 public override bool IsDefaultValue {
1487 get { return child.IsDefaultValue; }
1490 public override bool IsNegative {
1491 get { return child.IsNegative; }
1494 public override bool IsNull {
1495 get { return child.IsNull; }
1498 public override bool IsOneInteger {
1499 get { return child.IsOneInteger; }
1502 public override bool IsSideEffectFree {
1504 return child.IsSideEffectFree;
1508 public override bool IsZeroInteger {
1509 get { return child.IsZeroInteger; }
1512 public override void Emit (EmitContext ec)
1517 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1519 child.EmitBranchable (ec, label, on_true);
1521 // Only to make verifier happy
1522 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1523 ec.Emit (OpCodes.Unbox_Any, type);
1526 public override void EmitSideEffect (EmitContext ec)
1528 child.EmitSideEffect (ec);
1531 public override object GetValue ()
1533 return child.GetValue ();
1536 public override string GetValueAsLiteral ()
1538 return child.GetValueAsLiteral ();
1541 public override long GetValueAsLong ()
1543 return child.GetValueAsLong ();
1546 public override Constant ConvertImplicitly (TypeSpec target_type)
1548 if (type == target_type)
1551 // FIXME: Do we need to check user conversions?
1552 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1555 return child.ConvertImplicitly (target_type);
1560 /// This class is used to wrap literals which belong inside Enums
1562 public class EnumConstant : Constant
1564 public Constant Child;
1566 public EnumConstant (Constant child, TypeSpec enum_type)
1567 : base (child.Location)
1571 this.eclass = ExprClass.Value;
1572 this.type = enum_type;
1575 protected EnumConstant (Location loc)
1580 public override void Emit (EmitContext ec)
1585 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1587 Child.EncodeAttributeValue (rc, enc, Child.Type);
1590 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1592 Child.EmitBranchable (ec, label, on_true);
1595 public override void EmitSideEffect (EmitContext ec)
1597 Child.EmitSideEffect (ec);
1600 public override string GetSignatureForError()
1602 return Type.GetSignatureForError ();
1605 public override object GetValue ()
1607 return Child.GetValue ();
1611 public override object GetTypedValue ()
1614 // The method can be used in dynamic context only (on closed types)
1616 // System.Enum.ToObject cannot be called on dynamic types
1617 // EnumBuilder has to be used, but we cannot use EnumBuilder
1618 // because it does not properly support generics
1620 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1624 public override string GetValueAsLiteral ()
1626 return Child.GetValueAsLiteral ();
1629 public override long GetValueAsLong ()
1631 return Child.GetValueAsLong ();
1634 public EnumConstant Increment()
1636 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1639 public override bool IsDefaultValue {
1641 return Child.IsDefaultValue;
1645 public override bool IsSideEffectFree {
1647 return Child.IsSideEffectFree;
1651 public override bool IsZeroInteger {
1652 get { return Child.IsZeroInteger; }
1655 public override bool IsNegative {
1657 return Child.IsNegative;
1661 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1663 if (Child.Type == target_type)
1666 return Child.ConvertExplicitly (in_checked_context, target_type);
1669 public override Constant ConvertImplicitly (TypeSpec type)
1671 if (this.type == type) {
1675 if (!Convert.ImplicitStandardConversionExists (this, type)){
1679 return Child.ConvertImplicitly (type);
1684 /// This kind of cast is used to encapsulate Value Types in objects.
1686 /// The effect of it is to box the value type emitted by the previous
1689 public class BoxedCast : TypeCast {
1691 public BoxedCast (Expression expr, TypeSpec target_type)
1692 : base (expr, target_type)
1694 eclass = ExprClass.Value;
1697 protected override Expression DoResolve (ResolveContext ec)
1699 // This should never be invoked, we are born in fully
1700 // initialized state.
1705 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1707 // Only boxing to object type is supported
1708 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1709 base.EncodeAttributeValue (rc, enc, targetType);
1713 enc.Encode (child.Type);
1714 child.EncodeAttributeValue (rc, enc, child.Type);
1717 public override void Emit (EmitContext ec)
1721 ec.Emit (OpCodes.Box, child.Type);
1724 public override void EmitSideEffect (EmitContext ec)
1726 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1727 // so, we need to emit the box+pop instructions in most cases
1728 if (child.Type.IsStruct &&
1729 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1730 child.EmitSideEffect (ec);
1732 base.EmitSideEffect (ec);
1736 public class UnboxCast : TypeCast {
1737 public UnboxCast (Expression expr, TypeSpec return_type)
1738 : base (expr, return_type)
1742 protected override Expression DoResolve (ResolveContext ec)
1744 // This should never be invoked, we are born in fully
1745 // initialized state.
1750 public override void Emit (EmitContext ec)
1754 ec.Emit (OpCodes.Unbox_Any, type);
1759 /// This is used to perform explicit numeric conversions.
1761 /// Explicit numeric conversions might trigger exceptions in a checked
1762 /// context, so they should generate the conv.ovf opcodes instead of
1765 public class ConvCast : TypeCast {
1766 public enum Mode : byte {
1767 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1769 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1770 U2_I1, U2_U1, U2_I2, U2_CH,
1771 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1772 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1773 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1774 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1775 CH_I1, CH_U1, CH_I2,
1776 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1777 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1783 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1784 : base (child, return_type)
1789 protected override Expression DoResolve (ResolveContext ec)
1791 // This should never be invoked, we are born in fully
1792 // initialized state.
1797 public override string ToString ()
1799 return String.Format ("ConvCast ({0}, {1})", mode, child);
1802 public override void Emit (EmitContext ec)
1808 public static void Emit (EmitContext ec, Mode mode)
1810 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1812 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1813 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1814 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1815 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U1_CH: /* nothing */ break;
1821 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1822 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1823 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1824 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1825 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1826 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1828 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1829 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1830 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1831 case Mode.U2_CH: /* nothing */ break;
1833 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1834 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1835 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1836 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1837 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1838 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1839 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1841 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1842 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1843 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1844 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1845 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1846 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1848 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1849 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1850 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1851 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1852 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1853 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1854 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1855 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1856 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1858 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1859 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1860 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1861 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1862 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1863 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1864 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1865 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1866 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1868 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1869 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1870 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1872 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1873 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1874 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1875 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1876 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1877 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1878 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1879 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1880 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1882 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1883 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1884 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1885 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1886 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1887 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1888 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1889 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1890 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1891 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1893 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1897 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1898 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1899 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1900 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1901 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1906 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1907 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1908 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1909 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1910 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1911 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1913 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1914 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1915 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1916 case Mode.U2_CH: /* nothing */ break;
1918 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1919 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1920 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1921 case Mode.I4_U4: /* nothing */ break;
1922 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1923 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1924 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1926 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1927 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1928 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1929 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1930 case Mode.U4_I4: /* nothing */ break;
1931 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1933 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1934 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1935 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1936 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1937 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1938 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1939 case Mode.I8_U8: /* nothing */ break;
1940 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1941 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1943 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1944 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1945 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1946 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1947 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1948 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1949 case Mode.U8_I8: /* nothing */ break;
1950 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1951 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1953 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1954 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1955 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1957 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1958 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1959 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1960 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1961 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1962 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1963 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1964 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1965 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1967 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1968 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1969 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1970 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1971 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1972 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1973 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1974 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1975 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1976 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1978 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1984 class OpcodeCast : TypeCast
1988 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1989 : base (child, return_type)
1994 protected override Expression DoResolve (ResolveContext ec)
1996 // This should never be invoked, we are born in fully
1997 // initialized state.
2002 public override void Emit (EmitContext ec)
2008 public TypeSpec UnderlyingType {
2009 get { return child.Type; }
2014 // Opcode casts expression with 2 opcodes but only
2015 // single expression tree node
2017 class OpcodeCastDuplex : OpcodeCast
2019 readonly OpCode second;
2021 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2022 : base (child, returnType, first)
2024 this.second = second;
2027 public override void Emit (EmitContext ec)
2035 /// This kind of cast is used to encapsulate a child and cast it
2036 /// to the class requested
2038 public sealed class ClassCast : TypeCast {
2039 readonly bool forced;
2041 public ClassCast (Expression child, TypeSpec return_type)
2042 : base (child, return_type)
2046 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2047 : base (child, return_type)
2049 this.forced = forced;
2052 public override void Emit (EmitContext ec)
2056 bool gen = TypeManager.IsGenericParameter (child.Type);
2058 ec.Emit (OpCodes.Box, child.Type);
2060 if (type.IsGenericParameter) {
2061 ec.Emit (OpCodes.Unbox_Any, type);
2068 ec.Emit (OpCodes.Castclass, type);
2073 // Created during resolving pahse when an expression is wrapped or constantified
2074 // and original expression can be used later (e.g. for expression trees)
2076 public class ReducedExpression : Expression
2078 public sealed class ReducedConstantExpression : EmptyConstantCast
2080 readonly Expression orig_expr;
2082 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2083 : base (expr, expr.Type)
2085 this.orig_expr = orig_expr;
2088 public Expression OriginalExpression {
2094 public override Constant ConvertImplicitly (TypeSpec target_type)
2096 Constant c = base.ConvertImplicitly (target_type);
2098 c = new ReducedConstantExpression (c, orig_expr);
2103 public override Expression CreateExpressionTree (ResolveContext ec)
2105 return orig_expr.CreateExpressionTree (ec);
2108 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2110 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2112 c = new ReducedConstantExpression (c, orig_expr);
2116 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2119 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2121 if (orig_expr is Conditional)
2122 child.EncodeAttributeValue (rc, enc, targetType);
2124 base.EncodeAttributeValue (rc, enc, targetType);
2128 sealed class ReducedExpressionStatement : ExpressionStatement
2130 readonly Expression orig_expr;
2131 readonly ExpressionStatement stm;
2133 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2135 this.orig_expr = orig;
2137 this.eclass = stm.eclass;
2138 this.type = stm.Type;
2140 this.loc = orig.Location;
2143 public override bool ContainsEmitWithAwait ()
2145 return stm.ContainsEmitWithAwait ();
2148 public override Expression CreateExpressionTree (ResolveContext ec)
2150 return orig_expr.CreateExpressionTree (ec);
2153 protected override Expression DoResolve (ResolveContext ec)
2158 public override void Emit (EmitContext ec)
2163 public override void EmitStatement (EmitContext ec)
2165 stm.EmitStatement (ec);
2168 public override void FlowAnalysis (FlowAnalysisContext fc)
2170 stm.FlowAnalysis (fc);
2174 readonly Expression expr, orig_expr;
2176 private ReducedExpression (Expression expr, Expression orig_expr)
2179 this.eclass = expr.eclass;
2180 this.type = expr.Type;
2181 this.orig_expr = orig_expr;
2182 this.loc = orig_expr.Location;
2187 public override bool IsSideEffectFree {
2189 return expr.IsSideEffectFree;
2193 public Expression OriginalExpression {
2201 public override bool ContainsEmitWithAwait ()
2203 return expr.ContainsEmitWithAwait ();
2207 // Creates fully resolved expression switcher
2209 public static Constant Create (Constant expr, Expression original_expr)
2211 if (expr.eclass == ExprClass.Unresolved)
2212 throw new ArgumentException ("Unresolved expression");
2214 return new ReducedConstantExpression (expr, original_expr);
2217 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2219 return new ReducedExpressionStatement (s, orig);
2222 public static Expression Create (Expression expr, Expression original_expr)
2224 return Create (expr, original_expr, true);
2228 // Creates unresolved reduce expression. The original expression has to be
2229 // already resolved. Created expression is constant based based on `expr'
2230 // value unless canBeConstant is used
2232 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2234 if (canBeConstant) {
2235 Constant c = expr as Constant;
2237 return Create (c, original_expr);
2240 ExpressionStatement s = expr as ExpressionStatement;
2242 return Create (s, original_expr);
2244 if (expr.eclass == ExprClass.Unresolved)
2245 throw new ArgumentException ("Unresolved expression");
2247 return new ReducedExpression (expr, original_expr);
2250 public override Expression CreateExpressionTree (ResolveContext ec)
2252 return orig_expr.CreateExpressionTree (ec);
2255 protected override Expression DoResolve (ResolveContext ec)
2260 public override void Emit (EmitContext ec)
2265 public override Expression EmitToField (EmitContext ec)
2267 return expr.EmitToField(ec);
2270 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2272 expr.EmitBranchable (ec, target, on_true);
2275 public override void FlowAnalysis (FlowAnalysisContext fc)
2277 expr.FlowAnalysis (fc);
2280 public override SLE.Expression MakeExpression (BuilderContext ctx)
2282 return orig_expr.MakeExpression (ctx);
2287 // Standard composite pattern
2289 public abstract class CompositeExpression : Expression
2291 protected Expression expr;
2293 protected CompositeExpression (Expression expr)
2296 this.loc = expr.Location;
2299 public override bool ContainsEmitWithAwait ()
2301 return expr.ContainsEmitWithAwait ();
2304 public override Expression CreateExpressionTree (ResolveContext rc)
2306 return expr.CreateExpressionTree (rc);
2309 public Expression Child {
2310 get { return expr; }
2313 protected override Expression DoResolve (ResolveContext rc)
2315 expr = expr.Resolve (rc);
2320 eclass = expr.eclass;
2324 public override void Emit (EmitContext ec)
2329 public override bool IsNull {
2330 get { return expr.IsNull; }
2335 // Base of expressions used only to narrow resolve flow
2337 public abstract class ShimExpression : Expression
2339 protected Expression expr;
2341 protected ShimExpression (Expression expr)
2346 public Expression Expr {
2352 protected override void CloneTo (CloneContext clonectx, Expression t)
2357 ShimExpression target = (ShimExpression) t;
2358 target.expr = expr.Clone (clonectx);
2361 public override bool ContainsEmitWithAwait ()
2363 return expr.ContainsEmitWithAwait ();
2366 public override Expression CreateExpressionTree (ResolveContext ec)
2368 throw new NotSupportedException ("ET");
2371 public override void Emit (EmitContext ec)
2373 throw new InternalErrorException ("Missing Resolve call");
2377 public class UnreachableExpression : Expression
2379 public UnreachableExpression (Expression expr)
2381 this.loc = expr.Location;
2384 public override Expression CreateExpressionTree (ResolveContext ec)
2387 throw new NotImplementedException ();
2390 protected override Expression DoResolve (ResolveContext rc)
2392 throw new NotSupportedException ();
2395 public override void FlowAnalysis (FlowAnalysisContext fc)
2397 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2400 public override void Emit (EmitContext ec)
2404 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2410 // Unresolved type name expressions
2412 public abstract class ATypeNameExpression : FullNamedExpression
2415 protected TypeArguments targs;
2417 protected ATypeNameExpression (string name, Location l)
2423 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2430 protected ATypeNameExpression (string name, int arity, Location l)
2431 : this (name, new UnboundTypeArguments (arity), l)
2437 protected int Arity {
2439 return targs == null ? 0 : targs.Count;
2443 public bool HasTypeArguments {
2445 return targs != null && !targs.IsEmpty;
2449 public string Name {
2458 public TypeArguments TypeArguments {
2466 public override bool Equals (object obj)
2468 ATypeNameExpression atne = obj as ATypeNameExpression;
2469 return atne != null && atne.Name == Name &&
2470 (targs == null || targs.Equals (atne.targs));
2473 public override int GetHashCode ()
2475 return Name.GetHashCode ();
2478 // TODO: Move it to MemberCore
2479 public static string GetMemberType (MemberCore mc)
2485 if (mc is FieldBase)
2487 if (mc is MethodCore)
2489 if (mc is EnumMember)
2497 public override string GetSignatureForError ()
2499 if (targs != null) {
2500 return Name + "<" + targs.GetSignatureForError () + ">";
2506 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2510 /// SimpleName expressions are formed of a single word and only happen at the beginning
2511 /// of a dotted-name.
2513 public class SimpleName : ATypeNameExpression
2515 public SimpleName (string name, Location l)
2520 public SimpleName (string name, TypeArguments args, Location l)
2521 : base (name, args, l)
2525 public SimpleName (string name, int arity, Location l)
2526 : base (name, arity, l)
2530 public SimpleName GetMethodGroup ()
2532 return new SimpleName (Name, targs, loc);
2535 protected override Expression DoResolve (ResolveContext rc)
2537 return SimpleNameResolve (rc, null);
2540 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2542 return SimpleNameResolve (ec, right_side);
2545 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2547 if (ctx.CurrentType != null) {
2548 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2549 if (member != null) {
2550 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2555 var report = ctx.Module.Compiler.Report;
2557 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2558 if (retval != null) {
2559 report.SymbolRelatedToPreviousError (retval.Type);
2560 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2564 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2565 if (retval != null) {
2566 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2570 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2571 if (ns_candidates != null) {
2572 if (ctx is UsingAliasNamespace.AliasContext) {
2573 report.Error (246, loc,
2574 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2575 ns_candidates[0], Name);
2577 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2578 report.Error (246, loc,
2579 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2583 report.Error (246, loc,
2584 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2589 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2591 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2594 if (fne.Type != null && Arity > 0) {
2595 if (HasTypeArguments) {
2596 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2597 if (ct.ResolveAsType (mc) == null)
2603 return new GenericOpenTypeExpr (fne.Type, loc);
2607 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2609 if (!(fne is Namespace))
2613 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2614 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2615 mc.Module.Compiler.Report.Error (1980, Location,
2616 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2617 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2620 fne = new DynamicTypeExpr (loc);
2621 fne.ResolveAsType (mc);
2627 Error_TypeOrNamespaceNotFound (mc);
2631 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2633 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2636 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2638 int lookup_arity = Arity;
2639 bool errorMode = false;
2641 Block current_block = rc.CurrentBlock;
2642 INamedBlockVariable variable = null;
2643 bool variable_found = false;
2647 // Stage 1: binding to local variables or parameters
2649 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2651 if (current_block != null && lookup_arity == 0) {
2652 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2653 if (!variable.IsDeclared) {
2654 // We found local name in accessible block but it's not
2655 // initialized yet, maybe the user wanted to bind to something else
2657 variable_found = true;
2659 e = variable.CreateReferenceExpression (rc, loc);
2662 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2671 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2673 TypeSpec member_type = rc.CurrentType;
2674 for (; member_type != null; member_type = member_type.DeclaringType) {
2675 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2679 var me = e as MemberExpr;
2681 // The name matches a type, defer to ResolveAsTypeStep
2689 if (variable != null) {
2690 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2691 rc.Report.Error (844, loc,
2692 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2693 Name, me.GetSignatureForError ());
2697 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2698 // Leave it to overload resolution to report correct error
2700 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2701 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2704 // LAMESPEC: again, ignores InvocableOnly
2705 if (variable != null) {
2706 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2707 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2711 // MemberLookup does not check accessors availability, this is actually needed for properties only
2713 var pe = me as PropertyExpr;
2716 // Break as there is no other overload available anyway
2717 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2718 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2721 pe.Getter = pe.PropertyInfo.Get;
2723 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2726 pe.Setter = pe.PropertyInfo.Set;
2731 // TODO: It's used by EventExpr -> FieldExpr transformation only
2732 // TODO: Should go to MemberAccess
2733 me = me.ResolveMemberAccess (rc, null, null);
2737 me.SetTypeArguments (rc, targs);
2744 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2746 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2747 if (IsPossibleTypeOrNamespace (rc)) {
2748 if (variable != null) {
2749 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2750 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2753 return ResolveAsTypeOrNamespace (rc);
2758 if (variable_found) {
2759 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2762 var tparams = rc.CurrentTypeParameters;
2763 if (tparams != null) {
2764 if (tparams.Find (Name) != null) {
2765 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2770 var ct = rc.CurrentType;
2772 if (ct.MemberDefinition.TypeParametersCount > 0) {
2773 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2774 if (ctp.Name == Name) {
2775 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2781 ct = ct.DeclaringType;
2782 } while (ct != null);
2785 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2786 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2788 rc.Report.SymbolRelatedToPreviousError (e.Type);
2789 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2793 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2795 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2796 return ErrorExpression.Instance;
2800 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2802 if (e.Type.Arity != Arity) {
2803 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2807 if (e is TypeExpr) {
2808 // TypeExpression does not have correct location
2809 if (e is TypeExpression)
2810 e = new TypeExpression (e.Type, loc);
2816 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2819 return ErrorExpression.Instance;
2822 if (rc.Module.Evaluator != null) {
2823 var fi = rc.Module.Evaluator.LookupField (Name);
2825 return new FieldExpr (fi.Item1, loc);
2833 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2835 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2840 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2841 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2845 if (right_side != null) {
2846 e = e.ResolveLValue (ec, right_side);
2854 public override object Accept (StructuralVisitor visitor)
2856 return visitor.Visit (this);
2861 /// Represents a namespace or a type. The name of the class was inspired by
2862 /// section 10.8.1 (Fully Qualified Names).
2864 public abstract class FullNamedExpression : Expression
2866 protected override void CloneTo (CloneContext clonectx, Expression target)
2868 // Do nothing, most unresolved type expressions cannot be
2869 // resolved to different type
2872 public override bool ContainsEmitWithAwait ()
2877 public override Expression CreateExpressionTree (ResolveContext ec)
2879 throw new NotSupportedException ("ET");
2882 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2885 // This is used to resolve the expression as a type, a null
2886 // value will be returned if the expression is not a type
2889 public override TypeSpec ResolveAsType (IMemberContext mc)
2891 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2896 TypeExpr te = fne as TypeExpr;
2898 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2906 var dep = type.GetMissingDependencies ();
2908 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2911 if (type.Kind == MemberKind.Void) {
2912 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2916 // Obsolete checks cannot be done when resolving base context as they
2917 // require type dependencies to be set but we are in process of resolving them
2919 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2920 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2921 if (obsolete_attr != null && !mc.IsObsolete) {
2922 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2930 public override void Emit (EmitContext ec)
2932 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2933 GetSignatureForError ());
2938 /// Expression that evaluates to a type
2940 public abstract class TypeExpr : FullNamedExpression
2942 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2948 protected sealed override Expression DoResolve (ResolveContext ec)
2954 public override bool Equals (object obj)
2956 TypeExpr tobj = obj as TypeExpr;
2960 return Type == tobj.Type;
2963 public override int GetHashCode ()
2965 return Type.GetHashCode ();
2970 /// Fully resolved Expression that already evaluated to a type
2972 public class TypeExpression : TypeExpr
2974 public TypeExpression (TypeSpec t, Location l)
2977 eclass = ExprClass.Type;
2981 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2988 /// This class denotes an expression which evaluates to a member
2989 /// of a struct or a class.
2991 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2994 // An instance expression associated with this member, if it's a
2995 // non-static member
2997 public Expression InstanceExpression;
3000 /// The name of this member.
3002 public abstract string Name {
3007 // When base.member is used
3009 public bool IsBase {
3010 get { return InstanceExpression is BaseThis; }
3014 /// Whether this is an instance member.
3016 public abstract bool IsInstance {
3021 /// Whether this is a static member.
3023 public abstract bool IsStatic {
3027 public abstract string KindName {
3031 protected abstract TypeSpec DeclaringType {
3035 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3037 return InstanceExpression.Type;
3042 // Converts best base candidate for virtual method starting from QueriedBaseType
3044 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3047 // Only when base.member is used and method is virtual
3053 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3054 // means for base.member access we have to find the closest match after we found best candidate
3056 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3058 // The method could already be what we are looking for
3060 TypeSpec[] targs = null;
3061 if (method.DeclaringType != InstanceExpression.Type) {
3063 // Candidate can have inflated MVAR parameters and we need to find
3064 // base match for original definition not inflated parameter types
3066 var parameters = method.Parameters;
3067 if (method.Arity > 0) {
3068 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3069 var inflated = method.DeclaringType as InflatedTypeSpec;
3070 if (inflated != null) {
3071 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3075 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3076 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3077 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3078 if (base_override.IsGeneric)
3079 targs = method.TypeArguments;
3081 method = base_override;
3086 // When base access is used inside anonymous method/iterator/etc we need to
3087 // get back to the context of original type. We do it by emiting proxy
3088 // method in original class and rewriting base call to this compiler
3089 // generated method call which does the actual base invocation. This may
3090 // introduce redundant storey but with `this' only but it's tricky to avoid
3091 // at this stage as we don't know what expressions follow base
3093 if (rc.CurrentAnonymousMethod != null) {
3094 if (targs == null && method.IsGeneric) {
3095 targs = method.TypeArguments;
3096 method = method.GetGenericMethodDefinition ();
3099 if (method.Parameters.HasArglist)
3100 throw new NotImplementedException ("__arglist base call proxy");
3102 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3104 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3105 // get/set member expressions second call would fail to proxy because left expression
3106 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3107 // FIXME: The async check is another hack but will probably fail with mutators
3108 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3109 InstanceExpression = new This (loc).Resolve (rc);
3113 method = method.MakeGenericMethod (rc, targs);
3117 // Only base will allow this invocation to happen.
3119 if (method.IsAbstract) {
3120 rc.Report.SymbolRelatedToPreviousError (method);
3121 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3127 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3129 if (InstanceExpression == null)
3132 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3133 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3134 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3139 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3141 if (InstanceExpression == null)
3144 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3147 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3149 var ct = rc.CurrentType;
3150 if (ct == qualifier)
3153 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3156 qualifier = qualifier.GetDefinition ();
3157 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3164 public override bool ContainsEmitWithAwait ()
3166 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3169 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3172 type = type.GetDefinition ();
3174 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3177 type = type.DeclaringType;
3178 } while (type != null);
3183 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3185 if (InstanceExpression != null) {
3186 InstanceExpression = InstanceExpression.Resolve (rc);
3187 CheckProtectedMemberAccess (rc, member);
3190 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3191 UnsafeError (rc, loc);
3194 var dep = member.GetMissingDependencies ();
3196 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3199 if (!rc.IsObsolete) {
3200 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3202 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3205 if (!(member is FieldSpec))
3206 member.MemberDefinition.SetIsUsed ();
3209 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3211 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3214 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3216 rc.Report.SymbolRelatedToPreviousError (member);
3217 rc.Report.Error (1540, loc,
3218 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3219 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3222 public override void FlowAnalysis (FlowAnalysisContext fc)
3224 if (InstanceExpression != null)
3225 InstanceExpression.FlowAnalysis (fc);
3228 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3230 if (!ResolveInstanceExpressionCore (rc, rhs))
3234 // Check intermediate value modification which won't have any effect
3236 if (rhs != null && InstanceExpression.Type.IsStruct) {
3237 var fexpr = InstanceExpression as FieldExpr;
3238 if (fexpr != null) {
3239 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3242 if (fexpr.IsStatic) {
3243 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3244 fexpr.GetSignatureForError ());
3246 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3247 fexpr.GetSignatureForError ());
3253 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3254 if (rc.CurrentInitializerVariable != null) {
3255 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3256 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3258 rc.Report.Error (1612, loc,
3259 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3260 InstanceExpression.GetSignatureForError ());
3266 var lvr = InstanceExpression as LocalVariableReference;
3269 if (!lvr.local_info.IsReadonly)
3272 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3273 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3280 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3283 if (InstanceExpression != null) {
3284 if (InstanceExpression is TypeExpr) {
3285 var t = InstanceExpression.Type;
3287 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3288 if (oa != null && !rc.IsObsolete) {
3289 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3292 t = t.DeclaringType;
3293 } while (t != null);
3295 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3296 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3297 rc.Report.Error (176, loc,
3298 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3299 GetSignatureForError ());
3303 InstanceExpression = null;
3309 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3310 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3311 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3312 rc.Report.Error (236, loc,
3313 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3314 GetSignatureForError ());
3316 rc.Report.Error (120, loc,
3317 "An object reference is required to access non-static member `{0}'",
3318 GetSignatureForError ());
3320 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3324 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3325 rc.Report.Error (38, loc,
3326 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3327 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3330 InstanceExpression = new This (loc).Resolve (rc);
3334 var me = InstanceExpression as MemberExpr;
3336 me.ResolveInstanceExpressionCore (rc, rhs);
3338 var fe = me as FieldExpr;
3339 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3340 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3341 rc.Report.Warning (1690, 1, loc,
3342 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3343 me.GetSignatureForError ());
3350 // Additional checks for l-value member access
3353 if (InstanceExpression is UnboxCast) {
3354 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3361 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3363 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3364 ec.Report.Warning (1720, 1, left.Location,
3365 "Expression will always cause a `{0}'", "System.NullReferenceException");
3368 InstanceExpression = left;
3372 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3374 TypeSpec instance_type = InstanceExpression.Type;
3375 if (TypeSpec.IsValueType (instance_type)) {
3376 if (InstanceExpression is IMemoryLocation) {
3377 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3379 // Cannot release the temporary variable when its address
3380 // is required to be on stack for any parent
3381 LocalTemporary t = new LocalTemporary (instance_type);
3382 InstanceExpression.Emit (ec);
3384 t.AddressOf (ec, AddressOp.Store);
3387 InstanceExpression.Emit (ec);
3389 // Only to make verifier happy
3390 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3391 ec.Emit (OpCodes.Box, instance_type);
3394 if (prepare_for_load)
3395 ec.Emit (OpCodes.Dup);
3398 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3401 public class ExtensionMethodCandidates
3403 readonly NamespaceContainer container;
3404 readonly IList<MethodSpec> methods;
3406 readonly IMemberContext context;
3408 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3410 this.context = context;
3411 this.methods = methods;
3412 this.container = nsContainer;
3413 this.index = lookupIndex;
3416 public NamespaceContainer Container {
3422 public IMemberContext Context {
3428 public int LookupIndex {
3434 public IList<MethodSpec> Methods {
3442 // Represents a group of extension method candidates for whole namespace
3444 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3446 ExtensionMethodCandidates candidates;
3447 public Expression ExtensionExpression;
3449 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3450 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3452 this.candidates = candidates;
3453 this.ExtensionExpression = extensionExpr;
3456 public override bool IsStatic {
3457 get { return true; }
3461 // For extension methodgroup we are not looking for base members but parent
3462 // namespace extension methods
3464 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3466 // TODO: candidates are null only when doing error reporting, that's
3467 // incorrect. We have to discover same extension methods in error mode
3468 if (candidates == null)
3471 int arity = type_arguments == null ? 0 : type_arguments.Count;
3473 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3474 if (candidates == null)
3477 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3480 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3482 // We are already here
3486 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3488 if (arguments == null)
3489 arguments = new Arguments (1);
3491 ExtensionExpression = ExtensionExpression.Resolve (ec);
3492 if (ExtensionExpression == null)
3495 var cand = candidates;
3496 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3497 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3499 // Restore candidates in case we are running in probing mode
3502 // Store resolved argument and restore original arguments
3504 // Clean-up modified arguments for error reporting
3505 arguments.RemoveAt (0);
3509 var me = ExtensionExpression as MemberExpr;
3511 me.ResolveInstanceExpression (ec, null);
3512 var fe = me as FieldExpr;
3514 fe.Spec.MemberDefinition.SetIsUsed ();
3517 InstanceExpression = null;
3521 #region IErrorHandler Members
3523 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3528 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3530 rc.Report.SymbolRelatedToPreviousError (best);
3531 rc.Report.Error (1928, loc,
3532 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3533 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3536 rc.Report.Error (1929, loc,
3537 "Extension method instance type `{0}' cannot be converted to `{1}'",
3538 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3544 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3549 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3558 /// MethodGroupExpr represents a group of method candidates which
3559 /// can be resolved to the best method overload
3561 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3563 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3565 protected IList<MemberSpec> Methods;
3566 MethodSpec best_candidate;
3567 TypeSpec best_candidate_return;
3568 protected TypeArguments type_arguments;
3570 SimpleName simple_name;
3571 protected TypeSpec queried_type;
3573 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3577 this.type = InternalType.MethodGroup;
3579 eclass = ExprClass.MethodGroup;
3580 queried_type = type;
3583 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3584 : this (new MemberSpec[] { m }, type, loc)
3590 public MethodSpec BestCandidate {
3592 return best_candidate;
3596 public TypeSpec BestCandidateReturnType {
3598 return best_candidate_return;
3602 public IList<MemberSpec> Candidates {
3608 protected override TypeSpec DeclaringType {
3610 return queried_type;
3614 public bool IsConditionallyExcluded {
3616 return Methods == Excluded;
3620 public override bool IsInstance {
3622 if (best_candidate != null)
3623 return !best_candidate.IsStatic;
3629 public override bool IsSideEffectFree {
3631 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3635 public override bool IsStatic {
3637 if (best_candidate != null)
3638 return best_candidate.IsStatic;
3644 public override string KindName {
3645 get { return "method"; }
3648 public override string Name {
3650 if (best_candidate != null)
3651 return best_candidate.Name;
3654 return Methods.First ().Name;
3661 // When best candidate is already know this factory can be used
3662 // to avoid expensive overload resolution to be called
3664 // NOTE: InstanceExpression has to be set manually
3666 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3668 return new MethodGroupExpr (best, queriedType, loc) {
3669 best_candidate = best,
3670 best_candidate_return = best.ReturnType
3674 public override string GetSignatureForError ()
3676 if (best_candidate != null)
3677 return best_candidate.GetSignatureForError ();
3679 return Methods.First ().GetSignatureForError ();
3682 public override Expression CreateExpressionTree (ResolveContext ec)
3684 if (best_candidate == null) {
3685 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3689 if (IsConditionallyExcluded)
3690 ec.Report.Error (765, loc,
3691 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3693 return new TypeOfMethod (best_candidate, loc);
3696 protected override Expression DoResolve (ResolveContext ec)
3698 this.eclass = ExprClass.MethodGroup;
3700 if (InstanceExpression != null) {
3701 InstanceExpression = InstanceExpression.Resolve (ec);
3702 if (InstanceExpression == null)
3709 public override void Emit (EmitContext ec)
3711 throw new NotSupportedException ();
3714 public void EmitCall (EmitContext ec, Arguments arguments)
3716 var call = new CallEmitter ();
3717 call.InstanceExpression = InstanceExpression;
3718 call.Emit (ec, best_candidate, arguments, loc);
3721 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3723 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3724 Name, target.GetSignatureForError ());
3727 public static bool IsExtensionMethodArgument (Expression expr)
3730 // LAMESPEC: No details about which expressions are not allowed
3732 return !(expr is TypeExpr) && !(expr is BaseThis);
3736 /// Find the Applicable Function Members (7.4.2.1)
3738 /// me: Method Group expression with the members to select.
3739 /// it might contain constructors or methods (or anything
3740 /// that maps to a method).
3742 /// Arguments: ArrayList containing resolved Argument objects.
3744 /// loc: The location if we want an error to be reported, or a Null
3745 /// location for "probing" purposes.
3747 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3748 /// that is the best match of me on Arguments.
3751 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3753 // TODO: causes issues with probing mode, remove explicit Kind check
3754 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3757 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3758 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3759 r.BaseMembersProvider = this;
3760 r.InstanceQualifier = this;
3763 if (cerrors != null)
3764 r.CustomErrors = cerrors;
3766 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3767 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3768 if (best_candidate == null)
3769 return r.BestCandidateIsDynamic ? this : null;
3771 // Overload resolver had to create a new method group, all checks bellow have already been executed
3772 if (r.BestCandidateNewMethodGroup != null)
3773 return r.BestCandidateNewMethodGroup;
3775 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3776 if (InstanceExpression != null) {
3777 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3778 InstanceExpression = null;
3780 if (best_candidate.IsStatic && simple_name != null) {
3781 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3784 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3788 ResolveInstanceExpression (ec, null);
3791 var base_override = CandidateToBaseOverride (ec, best_candidate);
3792 if (base_override == best_candidate) {
3793 best_candidate_return = r.BestCandidateReturnType;
3795 best_candidate = base_override;
3796 best_candidate_return = best_candidate.ReturnType;
3799 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3800 ConstraintChecker cc = new ConstraintChecker (ec);
3801 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3805 // Additional check for possible imported base override method which
3806 // could not be done during IsOverrideMethodBaseTypeAccessible
3808 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3809 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3810 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3811 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3814 // Speed up the check by not doing it on disallowed targets
3815 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
3821 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3823 var fe = left as FieldExpr;
3826 // Using method-group on struct fields makes the struct assigned. I am not sure
3827 // why but that's what .net does
3829 fe.Spec.MemberDefinition.SetIsAssigned ();
3832 simple_name = original;
3833 return base.ResolveMemberAccess (ec, left, original);
3836 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3838 type_arguments = ta;
3841 #region IBaseMembersProvider Members
3843 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3845 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3848 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3850 if (queried_type == member.DeclaringType)
3853 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3854 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3858 // Extension methods lookup after ordinary methods candidates failed to apply
3860 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3862 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3865 if (!IsExtensionMethodArgument (InstanceExpression))
3868 int arity = type_arguments == null ? 0 : type_arguments.Count;
3869 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3870 if (methods == null)
3873 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3874 emg.SetTypeArguments (rc, type_arguments);
3881 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3883 public ConstructorInstanceQualifier (TypeSpec type)
3886 InstanceType = type;
3889 public TypeSpec InstanceType { get; private set; }
3891 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3893 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3897 public struct OverloadResolver
3900 public enum Restrictions
3904 ProbingOnly = 1 << 1,
3905 CovariantDelegate = 1 << 2,
3906 NoBaseMembers = 1 << 3,
3907 BaseMembersIncluded = 1 << 4
3910 public interface IBaseMembersProvider
3912 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3913 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3914 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3917 public interface IErrorHandler
3919 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3920 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3921 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3922 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3925 public interface IInstanceQualifier
3927 TypeSpec InstanceType { get; }
3928 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3931 sealed class NoBaseMembers : IBaseMembersProvider
3933 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3935 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3940 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3945 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3951 struct AmbiguousCandidate
3953 public readonly MemberSpec Member;
3954 public readonly bool Expanded;
3955 public readonly AParametersCollection Parameters;
3957 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3960 Parameters = parameters;
3961 Expanded = expanded;
3966 IList<MemberSpec> members;
3967 TypeArguments type_arguments;
3968 IBaseMembersProvider base_provider;
3969 IErrorHandler custom_errors;
3970 IInstanceQualifier instance_qualifier;
3971 Restrictions restrictions;
3972 MethodGroupExpr best_candidate_extension_group;
3973 TypeSpec best_candidate_return_type;
3975 SessionReportPrinter lambda_conv_msgs;
3977 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3978 : this (members, null, restrictions, loc)
3982 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3985 if (members == null || members.Count == 0)
3986 throw new ArgumentException ("empty members set");
3988 this.members = members;
3990 type_arguments = targs;
3991 this.restrictions = restrictions;
3992 if (IsDelegateInvoke)
3993 this.restrictions |= Restrictions.NoBaseMembers;
3995 base_provider = NoBaseMembers.Instance;
4000 public IBaseMembersProvider BaseMembersProvider {
4002 return base_provider;
4005 base_provider = value;
4009 public bool BestCandidateIsDynamic { get; set; }
4012 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4014 public MethodGroupExpr BestCandidateNewMethodGroup {
4016 return best_candidate_extension_group;
4021 // Return type can be different between best candidate and closest override
4023 public TypeSpec BestCandidateReturnType {
4025 return best_candidate_return_type;
4029 public IErrorHandler CustomErrors {
4031 return custom_errors;
4034 custom_errors = value;
4038 TypeSpec DelegateType {
4040 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4041 throw new InternalErrorException ("Not running in delegate mode", loc);
4043 return members [0].DeclaringType;
4047 public IInstanceQualifier InstanceQualifier {
4049 return instance_qualifier;
4052 instance_qualifier = value;
4056 bool IsProbingOnly {
4058 return (restrictions & Restrictions.ProbingOnly) != 0;
4062 bool IsDelegateInvoke {
4064 return (restrictions & Restrictions.DelegateInvoke) != 0;
4071 // 7.4.3.3 Better conversion from expression
4072 // Returns : 1 if a->p is better,
4073 // 2 if a->q is better,
4074 // 0 if neither is better
4076 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4078 TypeSpec argument_type = a.Type;
4081 // If argument is an anonymous function
4083 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4085 // p and q are delegate types or expression tree types
4087 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4088 if (q.MemberDefinition != p.MemberDefinition) {
4093 // Uwrap delegate from Expression<T>
4095 q = TypeManager.GetTypeArguments (q)[0];
4096 p = TypeManager.GetTypeArguments (p)[0];
4099 var p_m = Delegate.GetInvokeMethod (p);
4100 var q_m = Delegate.GetInvokeMethod (q);
4103 // With identical parameter lists
4105 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4114 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4116 if (p.Kind == MemberKind.Void) {
4117 return q.Kind != MemberKind.Void ? 2 : 0;
4121 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4123 if (q.Kind == MemberKind.Void) {
4124 return p.Kind != MemberKind.Void ? 1: 0;
4127 var am = (AnonymousMethodExpression) a.Expr;
4130 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4131 // better conversion is performed between underlying types Y1 and Y2
4133 if (p.IsGenericTask || q.IsGenericTask) {
4134 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4135 q = q.TypeArguments[0];
4136 p = p.TypeArguments[0];
4138 } else if (q != p) {
4140 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4142 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4143 var am_rt = am.InferReturnType (ec, null, orig_q);
4144 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4146 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4147 var am_rt = am.InferReturnType (ec, null, orig_p);
4148 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4154 // The parameters are identicial and return type is not void, use better type conversion
4155 // on return type to determine better one
4158 if (argument_type == p)
4161 if (argument_type == q)
4165 return BetterTypeConversion (ec, p, q);
4169 // 7.4.3.4 Better conversion from type
4171 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4173 if (p == null || q == null)
4174 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4176 switch (p.BuiltinType) {
4177 case BuiltinTypeSpec.Type.Int:
4178 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4181 case BuiltinTypeSpec.Type.Long:
4182 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4185 case BuiltinTypeSpec.Type.SByte:
4186 switch (q.BuiltinType) {
4187 case BuiltinTypeSpec.Type.Byte:
4188 case BuiltinTypeSpec.Type.UShort:
4189 case BuiltinTypeSpec.Type.UInt:
4190 case BuiltinTypeSpec.Type.ULong:
4194 case BuiltinTypeSpec.Type.Short:
4195 switch (q.BuiltinType) {
4196 case BuiltinTypeSpec.Type.UShort:
4197 case BuiltinTypeSpec.Type.UInt:
4198 case BuiltinTypeSpec.Type.ULong:
4202 case BuiltinTypeSpec.Type.Dynamic:
4203 // Dynamic is never better
4207 switch (q.BuiltinType) {
4208 case BuiltinTypeSpec.Type.Int:
4209 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4212 case BuiltinTypeSpec.Type.Long:
4213 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4216 case BuiltinTypeSpec.Type.SByte:
4217 switch (p.BuiltinType) {
4218 case BuiltinTypeSpec.Type.Byte:
4219 case BuiltinTypeSpec.Type.UShort:
4220 case BuiltinTypeSpec.Type.UInt:
4221 case BuiltinTypeSpec.Type.ULong:
4225 case BuiltinTypeSpec.Type.Short:
4226 switch (p.BuiltinType) {
4227 case BuiltinTypeSpec.Type.UShort:
4228 case BuiltinTypeSpec.Type.UInt:
4229 case BuiltinTypeSpec.Type.ULong:
4233 case BuiltinTypeSpec.Type.Dynamic:
4234 // Dynamic is never better
4238 // FIXME: handle lifted operators
4240 // TODO: this is expensive
4241 Expression p_tmp = new EmptyExpression (p);
4242 Expression q_tmp = new EmptyExpression (q);
4244 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4245 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4247 if (p_to_q && !q_to_p)
4250 if (q_to_p && !p_to_q)
4257 /// Determines "Better function" between candidate
4258 /// and the current best match
4261 /// Returns a boolean indicating :
4262 /// false if candidate ain't better
4263 /// true if candidate is better than the current best match
4265 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4266 MemberSpec best, AParametersCollection bparam, bool best_params)
4268 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4269 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4271 bool better_at_least_one = false;
4273 int args_count = args == null ? 0 : args.Count;
4277 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4280 // Default arguments are ignored for better decision
4281 if (a.IsDefaultArgument)
4285 // When comparing named argument the parameter type index has to be looked up
4286 // in original parameter set (override version for virtual members)
4288 NamedArgument na = a as NamedArgument;
4290 int idx = cparam.GetParameterIndexByName (na.Name);
4291 ct = candidate_pd.Types[idx];
4292 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4293 ct = TypeManager.GetElementType (ct);
4295 idx = bparam.GetParameterIndexByName (na.Name);
4296 bt = best_pd.Types[idx];
4297 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4298 bt = TypeManager.GetElementType (bt);
4300 ct = candidate_pd.Types[c_idx];
4301 bt = best_pd.Types[b_idx];
4303 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4304 ct = TypeManager.GetElementType (ct);
4308 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4309 bt = TypeManager.GetElementType (bt);
4314 if (TypeSpecComparer.IsEqual (ct, bt))
4318 int result = BetterExpressionConversion (ec, a, ct, bt);
4320 // for each argument, the conversion to 'ct' should be no worse than
4321 // the conversion to 'bt'.
4325 // for at least one argument, the conversion to 'ct' should be better than
4326 // the conversion to 'bt'.
4328 better_at_least_one = true;
4331 if (better_at_least_one)
4335 // This handles the case
4337 // Add (float f1, float f2, float f3);
4338 // Add (params decimal [] foo);
4340 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4341 // first candidate would've chosen as better.
4343 if (!same && !a.IsDefaultArgument)
4347 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4351 // This handles the following cases:
4353 // Foo (int i) is better than Foo (int i, long l = 0)
4354 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4355 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4357 // Prefer non-optional version
4359 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4361 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4362 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4365 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4368 return candidate_pd.Count >= best_pd.Count;
4372 // One is a non-generic method and second is a generic method, then non-generic is better
4374 if (best.IsGeneric != candidate.IsGeneric)
4375 return best.IsGeneric;
4378 // This handles the following cases:
4380 // Trim () is better than Trim (params char[] chars)
4381 // Concat (string s1, string s2, string s3) is better than
4382 // Concat (string s1, params string [] srest)
4383 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4385 // Prefer non-expanded version
4387 if (candidate_params != best_params)
4390 int candidate_param_count = candidate_pd.Count;
4391 int best_param_count = best_pd.Count;
4393 if (candidate_param_count != best_param_count)
4394 // can only happen if (candidate_params && best_params)
4395 return candidate_param_count > best_param_count && best_pd.HasParams;
4398 // Both methods have the same number of parameters, and the parameters have equal types
4399 // Pick the "more specific" signature using rules over original (non-inflated) types
4401 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4402 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4404 bool specific_at_least_once = false;
4405 for (j = 0; j < args_count; ++j) {
4406 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4408 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4409 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4411 ct = candidate_def_pd.Types[j];
4412 bt = best_def_pd.Types[j];
4417 TypeSpec specific = MoreSpecific (ct, bt);
4421 specific_at_least_once = true;
4424 if (specific_at_least_once)
4430 static bool CheckInflatedArguments (MethodSpec ms)
4432 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4435 // Setup constraint checker for probing only
4436 ConstraintChecker cc = new ConstraintChecker (null);
4438 var mp = ms.Parameters.Types;
4439 for (int i = 0; i < mp.Length; ++i) {
4440 var type = mp[i] as InflatedTypeSpec;
4444 var targs = type.TypeArguments;
4445 if (targs.Length == 0)
4448 // TODO: Checking inflated MVAR arguments should be enough
4449 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4456 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4458 rc.Report.Error (1729, loc,
4459 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4460 type.GetSignatureForError (), argCount.ToString ());
4464 // Determines if the candidate method is applicable to the given set of arguments
4465 // There could be two different set of parameters for same candidate where one
4466 // is the closest override for default values and named arguments checks and second
4467 // one being the virtual base for the parameter types and modifiers.
4469 // A return value rates candidate method compatibility,
4470 // 0 = the best, int.MaxValue = the worst
4473 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)
4475 // Parameters of most-derived type used mainly for named and optional parameters
4476 var pd = pm.Parameters;
4478 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4479 // params modifier instead of most-derived type
4480 var cpd = ((IParametersMember) candidate).Parameters;
4481 int param_count = pd.Count;
4482 int optional_count = 0;
4484 Arguments orig_args = arguments;
4486 if (arg_count != param_count) {
4488 // No arguments expansion when doing exact match for delegates
4490 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4491 for (int i = 0; i < pd.Count; ++i) {
4492 if (pd.FixedParameters[i].HasDefaultValue) {
4493 optional_count = pd.Count - i;
4499 if (optional_count != 0) {
4500 // Readjust expected number when params used
4501 if (cpd.HasParams) {
4503 if (arg_count < param_count)
4505 } else if (arg_count > param_count) {
4506 int args_gap = System.Math.Abs (arg_count - param_count);
4507 return int.MaxValue - 10000 + args_gap;
4508 } else if (arg_count < param_count - optional_count) {
4509 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4510 return int.MaxValue - 10000 + args_gap;
4512 } else if (arg_count != param_count) {
4513 int args_gap = System.Math.Abs (arg_count - param_count);
4515 return int.MaxValue - 10000 + args_gap;
4516 if (arg_count < param_count - 1)
4517 return int.MaxValue - 10000 + args_gap;
4520 // Resize to fit optional arguments
4521 if (optional_count != 0) {
4522 if (arguments == null) {
4523 arguments = new Arguments (optional_count);
4525 // Have to create a new container, so the next run can do same
4526 var resized = new Arguments (param_count);
4527 resized.AddRange (arguments);
4528 arguments = resized;
4531 for (int i = arg_count; i < param_count; ++i)
4532 arguments.Add (null);
4536 if (arg_count > 0) {
4538 // Shuffle named arguments to the right positions if there are any
4540 if (arguments[arg_count - 1] is NamedArgument) {
4541 arg_count = arguments.Count;
4543 for (int i = 0; i < arg_count; ++i) {
4544 bool arg_moved = false;
4546 NamedArgument na = arguments[i] as NamedArgument;
4550 int index = pd.GetParameterIndexByName (na.Name);
4552 // Named parameter not found
4556 // already reordered
4561 if (index >= param_count) {
4562 // When using parameters which should not be available to the user
4563 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4566 arguments.Add (null);
4570 temp = arguments[index];
4572 // The slot has been taken by positional argument
4573 if (temp != null && !(temp is NamedArgument))
4578 arguments = arguments.MarkOrderedArgument (na);
4582 if (arguments == orig_args) {
4583 arguments = new Arguments (orig_args.Count);
4584 arguments.AddRange (orig_args);
4587 arguments[index] = arguments[i];
4588 arguments[i] = temp;
4595 arg_count = arguments.Count;
4597 } else if (arguments != null) {
4598 arg_count = arguments.Count;
4602 // Don't do any expensive checks when the candidate cannot succeed
4604 if (arg_count != param_count && !cpd.HasParams)
4605 return (param_count - arg_count) * 2 + 1;
4607 var dep = candidate.GetMissingDependencies ();
4609 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4614 // 1. Handle generic method using type arguments when specified or type inference
4617 var ms = candidate as MethodSpec;
4618 if (ms != null && ms.IsGeneric) {
4619 if (type_arguments != null) {
4620 var g_args_count = ms.Arity;
4621 if (g_args_count != type_arguments.Count)
4622 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4624 if (type_arguments.Arguments != null)
4625 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4628 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4629 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4630 // candidate was found use the set to report more details about what was wrong with lambda body.
4631 // The general idea is to distinguish between code errors and errors caused by
4632 // trial-and-error type inference
4634 if (lambda_conv_msgs == null) {
4635 for (int i = 0; i < arg_count; i++) {
4636 Argument a = arguments[i];
4640 var am = a.Expr as AnonymousMethodExpression;
4642 if (lambda_conv_msgs == null)
4643 lambda_conv_msgs = new SessionReportPrinter ();
4645 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4650 var ti = new TypeInference (arguments);
4651 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4654 return ti.InferenceScore - 20000;
4657 // Clear any error messages when the result was success
4659 if (lambda_conv_msgs != null)
4660 lambda_conv_msgs.ClearSession ();
4662 if (i_args.Length != 0) {
4663 ms = ms.MakeGenericMethod (ec, i_args);
4668 // Type arguments constraints have to match for the method to be applicable
4670 if (!CheckInflatedArguments (ms)) {
4672 return int.MaxValue - 25000;
4676 // We have a generic return type and at same time the method is override which
4677 // means we have to also inflate override return type in case the candidate is
4678 // best candidate and override return type is different to base return type.
4680 // virtual Foo<T, object> with override Foo<T, dynamic>
4682 if (candidate != pm) {
4683 MethodSpec override_ms = (MethodSpec) pm;
4684 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4685 returnType = inflator.Inflate (returnType);
4687 returnType = ms.ReturnType;
4694 if (type_arguments != null)
4695 return int.MaxValue - 15000;
4701 // 2. Each argument has to be implicitly convertible to method parameter
4703 Parameter.Modifier p_mod = 0;
4706 for (int i = 0; i < arg_count; i++) {
4707 Argument a = arguments[i];
4709 var fp = pd.FixedParameters[i];
4710 if (!fp.HasDefaultValue) {
4711 arguments = orig_args;
4712 return arg_count * 2 + 2;
4716 // Get the default value expression, we can use the same expression
4717 // if the type matches
4719 Expression e = fp.DefaultValue;
4721 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4723 // Restore for possible error reporting
4724 for (int ii = i; ii < arg_count; ++ii)
4725 arguments.RemoveAt (i);
4727 return (arg_count - i) * 2 + 1;
4731 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4733 // LAMESPEC: Attributes can be mixed together with build-in priority
4735 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4736 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4737 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4738 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4739 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4740 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4744 arguments[i] = new Argument (e, Argument.AType.Default);
4748 if (p_mod != Parameter.Modifier.PARAMS) {
4749 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4751 } else if (!params_expanded_form) {
4752 params_expanded_form = true;
4753 pt = ((ElementTypeSpec) pt).Element;
4759 if (!params_expanded_form) {
4760 if (a.ArgType == Argument.AType.ExtensionType) {
4762 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4764 // LAMESPEC: or implicit type parameter conversion
4767 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4768 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4769 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4774 score = IsArgumentCompatible (ec, a, p_mod, pt);
4777 dynamicArgument = true;
4782 // It can be applicable in expanded form (when not doing exact match like for delegates)
4784 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4785 if (!params_expanded_form) {
4786 pt = ((ElementTypeSpec) pt).Element;
4790 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4793 params_expanded_form = true;
4794 dynamicArgument = true;
4795 } else if (score == 0 || arg_count > pd.Count) {
4796 params_expanded_form = true;
4801 if (params_expanded_form)
4803 return (arg_count - i) * 2 + score;
4808 // When params parameter has no argument it will be provided later if the method is the best candidate
4810 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4811 params_expanded_form = true;
4814 // Restore original arguments for dynamic binder to keep the intention of original source code
4816 if (dynamicArgument)
4817 arguments = orig_args;
4822 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4824 if (e is Constant && e.Type == ptype)
4828 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4830 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4831 e = new MemberAccess (new MemberAccess (new MemberAccess (
4832 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4833 } else if (e is Constant) {
4835 // Handles int to int? conversions, DefaultParameterValue check
4837 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4841 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4844 return e.Resolve (ec);
4848 // Tests argument compatibility with the parameter
4849 // The possible return values are
4851 // 1 - modifier mismatch
4852 // 2 - type mismatch
4853 // -1 - dynamic binding required
4855 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4858 // Types have to be identical when ref or out modifer
4859 // is used and argument is not of dynamic type
4861 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4862 if (argument.Type != parameter) {
4864 // Do full equality check after quick path
4866 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4868 // Using dynamic for ref/out parameter can still succeed at runtime
4870 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4877 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4879 // Using dynamic for ref/out parameter can still succeed at runtime
4881 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4888 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4892 // Use implicit conversion in all modes to return same candidates when the expression
4893 // is used as argument or delegate conversion
4895 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4896 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4903 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4905 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4907 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4910 var ac_p = p as ArrayContainer;
4912 var ac_q = q as ArrayContainer;
4916 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4917 if (specific == ac_p.Element)
4919 if (specific == ac_q.Element)
4921 } else if (p.IsGeneric && q.IsGeneric) {
4922 var pargs = TypeManager.GetTypeArguments (p);
4923 var qargs = TypeManager.GetTypeArguments (q);
4925 bool p_specific_at_least_once = false;
4926 bool q_specific_at_least_once = false;
4928 for (int i = 0; i < pargs.Length; i++) {
4929 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4930 if (specific == pargs[i])
4931 p_specific_at_least_once = true;
4932 if (specific == qargs[i])
4933 q_specific_at_least_once = true;
4936 if (p_specific_at_least_once && !q_specific_at_least_once)
4938 if (!p_specific_at_least_once && q_specific_at_least_once)
4946 // Find the best method from candidate list
4948 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4950 List<AmbiguousCandidate> ambiguous_candidates = null;
4952 MemberSpec best_candidate;
4953 Arguments best_candidate_args = null;
4954 bool best_candidate_params = false;
4955 bool best_candidate_dynamic = false;
4956 int best_candidate_rate;
4957 IParametersMember best_parameter_member = null;
4959 int args_count = args != null ? args.Count : 0;
4961 Arguments candidate_args = args;
4962 bool error_mode = false;
4963 MemberSpec invocable_member = null;
4966 best_candidate = null;
4967 best_candidate_rate = int.MaxValue;
4969 var type_members = members;
4971 for (int i = 0; i < type_members.Count; ++i) {
4972 var member = type_members[i];
4975 // Methods in a base class are not candidates if any method in a derived
4976 // class is applicable
4978 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4982 if (!member.IsAccessible (rc))
4985 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4988 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4989 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4994 IParametersMember pm = member as IParametersMember;
4997 // Will use it later to report ambiguity between best method and invocable member
4999 if (Invocation.IsMemberInvocable (member))
5000 invocable_member = member;
5006 // Overload resolution is looking for base member but using parameter names
5007 // and default values from the closest member. That means to do expensive lookup
5008 // for the closest override for virtual or abstract members
5010 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5011 var override_params = base_provider.GetOverrideMemberParameters (member);
5012 if (override_params != null)
5013 pm = override_params;
5017 // Check if the member candidate is applicable
5019 bool params_expanded_form = false;
5020 bool dynamic_argument = false;
5021 TypeSpec rt = pm.MemberType;
5022 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5024 if (lambda_conv_msgs != null)
5025 lambda_conv_msgs.EndSession ();
5028 // How does it score compare to others
5030 if (candidate_rate < best_candidate_rate) {
5032 // Fatal error (missing dependency), cannot continue
5033 if (candidate_rate < 0)
5036 best_candidate_rate = candidate_rate;
5037 best_candidate = member;
5038 best_candidate_args = candidate_args;
5039 best_candidate_params = params_expanded_form;
5040 best_candidate_dynamic = dynamic_argument;
5041 best_parameter_member = pm;
5042 best_candidate_return_type = rt;
5043 } else if (candidate_rate == 0) {
5045 // The member look is done per type for most operations but sometimes
5046 // it's not possible like for binary operators overload because they
5047 // are unioned between 2 sides
5049 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5050 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5055 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5057 // We pack all interface members into top level type which makes the overload resolution
5058 // more complicated for interfaces. We compensate it by removing methods with same
5059 // signature when building the cache hence this path should not really be hit often
5062 // interface IA { void Foo (int arg); }
5063 // interface IB : IA { void Foo (params int[] args); }
5065 // IB::Foo is the best overload when calling IB.Foo (1)
5068 if (ambiguous_candidates != null) {
5069 foreach (var amb_cand in ambiguous_candidates) {
5070 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5079 ambiguous_candidates = null;
5082 // Is the new candidate better
5083 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5087 best_candidate = member;
5088 best_candidate_args = candidate_args;
5089 best_candidate_params = params_expanded_form;
5090 best_candidate_dynamic = dynamic_argument;
5091 best_parameter_member = pm;
5092 best_candidate_return_type = rt;
5094 // It's not better but any other found later could be but we are not sure yet
5095 if (ambiguous_candidates == null)
5096 ambiguous_candidates = new List<AmbiguousCandidate> ();
5098 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5102 // Restore expanded arguments
5103 candidate_args = args;
5105 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5108 // We've found exact match
5110 if (best_candidate_rate == 0)
5114 // Try extension methods lookup when no ordinary method match was found and provider enables it
5117 var emg = base_provider.LookupExtensionMethod (rc);
5119 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5121 best_candidate_extension_group = emg;
5122 return (T) (MemberSpec) emg.BestCandidate;
5127 // Don't run expensive error reporting mode for probing
5134 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5137 lambda_conv_msgs = null;
5142 // No best member match found, report an error
5144 if (best_candidate_rate != 0 || error_mode) {
5145 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5149 if (best_candidate_dynamic) {
5150 if (args[0].ArgType == Argument.AType.ExtensionType) {
5151 rc.Report.Error (1973, loc,
5152 "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",
5153 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5157 // Check type constraints only when explicit type arguments are used
5159 if (best_candidate.IsGeneric && type_arguments != null) {
5160 MethodSpec bc = best_candidate as MethodSpec;
5161 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5162 ConstraintChecker cc = new ConstraintChecker (rc);
5163 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5167 BestCandidateIsDynamic = true;
5172 // These flags indicates we are running delegate probing conversion. No need to
5173 // do more expensive checks
5175 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5176 return (T) best_candidate;
5178 if (ambiguous_candidates != null) {
5180 // Now check that there are no ambiguities i.e the selected method
5181 // should be better than all the others
5183 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5184 var candidate = ambiguous_candidates [ix];
5186 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5187 var ambiguous = candidate.Member;
5188 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5189 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5190 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5191 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5192 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5195 return (T) best_candidate;
5200 if (invocable_member != null && !IsProbingOnly) {
5201 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5202 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5203 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5204 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5208 // And now check if the arguments are all
5209 // compatible, perform conversions if
5210 // necessary etc. and return if everything is
5213 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5216 if (best_candidate == null)
5220 // Don't run possibly expensive checks in probing mode
5222 if (!IsProbingOnly && !rc.IsInProbingMode) {
5224 // Check ObsoleteAttribute on the best method
5226 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5227 if (oa != null && !rc.IsObsolete)
5228 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5230 best_candidate.MemberDefinition.SetIsUsed ();
5233 args = best_candidate_args;
5234 return (T) best_candidate;
5237 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5239 return ResolveMember<MethodSpec> (rc, ref args);
5242 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5243 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5245 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5248 if (a.Type == InternalType.ErrorType)
5251 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5252 ec.Report.SymbolRelatedToPreviousError (method);
5253 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5254 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5255 TypeManager.CSharpSignature (method));
5258 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5259 TypeManager.CSharpSignature (method));
5260 } else if (IsDelegateInvoke) {
5261 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5262 DelegateType.GetSignatureForError ());
5264 ec.Report.SymbolRelatedToPreviousError (method);
5265 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5266 method.GetSignatureForError ());
5269 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5271 string index = (idx + 1).ToString ();
5272 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5273 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5274 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5275 index, Parameter.GetModifierSignature (a.Modifier));
5277 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5278 index, Parameter.GetModifierSignature (mod));
5280 string p1 = a.GetSignatureForError ();
5281 string p2 = paramType.GetSignatureForError ();
5284 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5285 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5288 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5289 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5290 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5293 ec.Report.Error (1503, a.Expr.Location,
5294 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5299 // We have failed to find exact match so we return error info about the closest match
5301 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5303 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5304 int arg_count = args == null ? 0 : args.Count;
5306 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5307 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5308 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5312 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5317 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5318 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5319 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5323 // For candidates which match on parameters count report more details about incorrect arguments
5326 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5327 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5328 // Reject any inaccessible member
5329 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5330 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5331 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5335 var ms = best_candidate as MethodSpec;
5336 if (ms != null && ms.IsGeneric) {
5337 bool constr_ok = true;
5338 if (ms.TypeArguments != null)
5339 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5341 if (ta_count == 0 && ms.TypeArguments == null) {
5342 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5346 rc.Report.Error (411, loc,
5347 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5348 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5355 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5361 // We failed to find any method with correct argument count, report best candidate
5363 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5366 if (best_candidate.Kind == MemberKind.Constructor) {
5367 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5368 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5369 } else if (IsDelegateInvoke) {
5370 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5371 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5372 DelegateType.GetSignatureForError (), arg_count.ToString ());
5374 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5375 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5376 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5377 name, arg_count.ToString ());
5381 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5383 var pd = pm.Parameters;
5384 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5386 Parameter.Modifier p_mod = 0;
5388 int a_idx = 0, a_pos = 0;
5390 ArrayInitializer params_initializers = null;
5391 bool has_unsafe_arg = pm.MemberType.IsPointer;
5392 int arg_count = args == null ? 0 : args.Count;
5394 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5399 if (p_mod != Parameter.Modifier.PARAMS) {
5400 p_mod = pd.FixedParameters[a_idx].ModFlags;
5402 has_unsafe_arg |= pt.IsPointer;
5404 if (p_mod == Parameter.Modifier.PARAMS) {
5405 if (chose_params_expanded) {
5406 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5407 pt = TypeManager.GetElementType (pt);
5413 // Types have to be identical when ref or out modifer is used
5415 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5416 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5419 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5425 NamedArgument na = a as NamedArgument;
5427 int name_index = pd.GetParameterIndexByName (na.Name);
5428 if (name_index < 0 || name_index >= pd.Count) {
5429 if (IsDelegateInvoke) {
5430 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5431 ec.Report.Error (1746, na.Location,
5432 "The delegate `{0}' does not contain a parameter named `{1}'",
5433 DelegateType.GetSignatureForError (), na.Name);
5435 ec.Report.SymbolRelatedToPreviousError (member);
5436 ec.Report.Error (1739, na.Location,
5437 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5438 TypeManager.CSharpSignature (member), na.Name);
5440 } else if (args[name_index] != a && args[name_index] != null) {
5441 if (IsDelegateInvoke)
5442 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5444 ec.Report.SymbolRelatedToPreviousError (member);
5446 ec.Report.Error (1744, na.Location,
5447 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5452 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5455 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5456 custom_errors.NoArgumentMatch (ec, member);
5461 if (a.ArgType == Argument.AType.ExtensionType) {
5462 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5465 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5467 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5470 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5477 // Convert params arguments to an array initializer
5479 if (params_initializers != null) {
5480 // we choose to use 'a.Expr' rather than 'conv' so that
5481 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5482 params_initializers.Add (a.Expr);
5483 args.RemoveAt (a_idx--);
5489 // Update the argument with the implicit conversion
5493 if (a_idx != arg_count) {
5494 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5499 // Fill not provided arguments required by params modifier
5501 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5503 args = new Arguments (1);
5505 pt = ptypes[pd.Count - 1];
5506 pt = TypeManager.GetElementType (pt);
5507 has_unsafe_arg |= pt.IsPointer;
5508 params_initializers = new ArrayInitializer (0, loc);
5512 // Append an array argument with all params arguments
5514 if (params_initializers != null) {
5515 args.Add (new Argument (
5516 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5520 if (has_unsafe_arg && !ec.IsUnsafe) {
5521 Expression.UnsafeError (ec, loc);
5525 // We could infer inaccesible type arguments
5527 if (type_arguments == null && member.IsGeneric) {
5528 var ms = (MethodSpec) member;
5529 foreach (var ta in ms.TypeArguments) {
5530 if (!ta.IsAccessible (ec)) {
5531 ec.Report.SymbolRelatedToPreviousError (ta);
5532 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5542 public class ConstantExpr : MemberExpr
5544 readonly ConstSpec constant;
5546 public ConstantExpr (ConstSpec constant, Location loc)
5548 this.constant = constant;
5552 public override string Name {
5553 get { throw new NotImplementedException (); }
5556 public override string KindName {
5557 get { return "constant"; }
5560 public override bool IsInstance {
5561 get { return !IsStatic; }
5564 public override bool IsStatic {
5565 get { return true; }
5568 protected override TypeSpec DeclaringType {
5569 get { return constant.DeclaringType; }
5572 public override Expression CreateExpressionTree (ResolveContext ec)
5574 throw new NotSupportedException ("ET");
5577 protected override Expression DoResolve (ResolveContext rc)
5579 ResolveInstanceExpression (rc, null);
5580 DoBestMemberChecks (rc, constant);
5582 var c = constant.GetConstant (rc);
5584 // Creates reference expression to the constant value
5585 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5588 public override void Emit (EmitContext ec)
5590 throw new NotSupportedException ();
5593 public override string GetSignatureForError ()
5595 return constant.GetSignatureForError ();
5598 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5600 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5605 // Fully resolved expression that references a Field
5607 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5609 protected FieldSpec spec;
5610 VariableInfo variable_info;
5612 LocalTemporary temp;
5615 protected FieldExpr (Location l)
5620 public FieldExpr (FieldSpec spec, Location loc)
5625 type = spec.MemberType;
5628 public FieldExpr (FieldBase fi, Location l)
5635 public override string Name {
5641 public bool IsHoisted {
5643 IVariableReference hv = InstanceExpression as IVariableReference;
5644 return hv != null && hv.IsHoisted;
5648 public override bool IsInstance {
5650 return !spec.IsStatic;
5654 public override bool IsStatic {
5656 return spec.IsStatic;
5660 public override string KindName {
5661 get { return "field"; }
5664 public FieldSpec Spec {
5670 protected override TypeSpec DeclaringType {
5672 return spec.DeclaringType;
5676 public VariableInfo VariableInfo {
5678 return variable_info;
5684 public override string GetSignatureForError ()
5686 return spec.GetSignatureForError ();
5689 public bool IsMarshalByRefAccess (ResolveContext rc)
5691 // Checks possible ldflda of field access expression
5692 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5693 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5694 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5697 public void SetHasAddressTaken ()
5699 IVariableReference vr = InstanceExpression as IVariableReference;
5701 vr.SetHasAddressTaken ();
5705 public override Expression CreateExpressionTree (ResolveContext ec)
5707 return CreateExpressionTree (ec, true);
5710 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5713 Expression instance;
5715 if (InstanceExpression == null) {
5716 instance = new NullLiteral (loc);
5717 } else if (convertInstance) {
5718 instance = InstanceExpression.CreateExpressionTree (ec);
5720 args = new Arguments (1);
5721 args.Add (new Argument (InstanceExpression));
5722 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5725 args = Arguments.CreateForExpressionTree (ec, null,
5727 CreateTypeOfExpression ());
5729 return CreateExpressionFactoryCall (ec, "Field", args);
5732 public Expression CreateTypeOfExpression ()
5734 return new TypeOfField (spec, loc);
5737 protected override Expression DoResolve (ResolveContext ec)
5739 spec.MemberDefinition.SetIsUsed ();
5741 return DoResolve (ec, null);
5744 Expression DoResolve (ResolveContext ec, Expression rhs)
5746 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5749 if (ResolveInstanceExpression (ec, rhs)) {
5750 // Resolve the field's instance expression while flow analysis is turned
5751 // off: when accessing a field "a.b", we must check whether the field
5752 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5754 if (lvalue_instance) {
5755 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5757 Expression right_side =
5758 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5760 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5762 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5765 if (InstanceExpression == null)
5769 DoBestMemberChecks (ec, spec);
5772 var fb = spec as FixedFieldSpec;
5773 IVariableReference var = InstanceExpression as IVariableReference;
5776 IFixedExpression fe = InstanceExpression as IFixedExpression;
5777 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5778 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5781 if (InstanceExpression.eclass != ExprClass.Variable) {
5782 ec.Report.SymbolRelatedToPreviousError (spec);
5783 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5784 TypeManager.GetFullNameSignature (spec));
5785 } else if (var != null && var.IsHoisted) {
5786 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5789 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5793 // Set flow-analysis variable info for struct member access. It will be check later
5794 // for precise error reporting
5796 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5797 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5800 eclass = ExprClass.Variable;
5804 public void SetFieldAssigned (FlowAnalysisContext fc)
5809 bool lvalue_instance = spec.DeclaringType.IsStruct;
5810 if (lvalue_instance) {
5811 var var = InstanceExpression as IVariableReference;
5812 if (var != null && var.VariableInfo != null) {
5813 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5817 var fe = InstanceExpression as FieldExpr;
5819 Expression instance;
5822 instance = fe.InstanceExpression;
5823 var fe_instance = instance as FieldExpr;
5824 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5825 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5826 var var = InstanceExpression as IVariableReference;
5827 if (var != null && var.VariableInfo == null) {
5828 var var_inst = instance as IVariableReference;
5829 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5830 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5834 if (fe_instance != null) {
5843 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
5844 instance.FlowAnalysis (fc);
5846 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
5847 InstanceExpression.FlowAnalysis (fc);
5851 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5853 // The return value is always null. Returning a value simplifies calling code.
5855 if (right_side == EmptyExpression.OutAccess) {
5857 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5858 GetSignatureForError ());
5860 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5861 GetSignatureForError ());
5867 if (right_side == EmptyExpression.LValueMemberAccess) {
5868 // Already reported as CS1648/CS1650
5872 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5874 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5875 GetSignatureForError ());
5877 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5878 GetSignatureForError ());
5884 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5885 GetSignatureForError ());
5887 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5888 GetSignatureForError ());
5894 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5896 if (spec is FixedFieldSpec) {
5897 // It could be much better error message but we want to be error compatible
5898 Error_ValueAssignment (ec, right_side);
5901 Expression e = DoResolve (ec, right_side);
5906 spec.MemberDefinition.SetIsAssigned ();
5908 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5909 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5910 ec.Report.Warning (420, 1, loc,
5911 "`{0}': A volatile field references will not be treated as volatile",
5912 spec.GetSignatureForError ());
5915 if (spec.IsReadOnly) {
5916 // InitOnly fields can only be assigned in constructors or initializers
5917 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5918 return Error_AssignToReadonly (ec, right_side);
5920 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5922 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5923 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5924 return Error_AssignToReadonly (ec, right_side);
5925 // static InitOnly fields cannot be assigned-to in an instance constructor
5926 if (IsStatic && !ec.IsStatic)
5927 return Error_AssignToReadonly (ec, right_side);
5928 // instance constructors can't modify InitOnly fields of other instances of the same type
5929 if (!IsStatic && !(InstanceExpression is This))
5930 return Error_AssignToReadonly (ec, right_side);
5934 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5935 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5936 ec.Report.Warning (197, 1, loc,
5937 "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",
5938 GetSignatureForError ());
5941 eclass = ExprClass.Variable;
5945 public override void FlowAnalysis (FlowAnalysisContext fc)
5947 var var = InstanceExpression as IVariableReference;
5949 var vi = var.VariableInfo;
5950 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
5951 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
5955 if (TypeSpec.IsValueType (InstanceExpression.Type))
5959 base.FlowAnalysis (fc);
5962 public override int GetHashCode ()
5964 return spec.GetHashCode ();
5967 public bool IsFixed {
5970 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5972 IVariableReference variable = InstanceExpression as IVariableReference;
5973 if (variable != null)
5974 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5976 IFixedExpression fe = InstanceExpression as IFixedExpression;
5977 return fe != null && fe.IsFixed;
5981 public override bool Equals (object obj)
5983 FieldExpr fe = obj as FieldExpr;
5987 if (spec != fe.spec)
5990 if (InstanceExpression == null || fe.InstanceExpression == null)
5993 return InstanceExpression.Equals (fe.InstanceExpression);
5996 public void Emit (EmitContext ec, bool leave_copy)
5998 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6002 ec.Emit (OpCodes.Volatile);
6004 ec.Emit (OpCodes.Ldsfld, spec);
6007 EmitInstance (ec, false);
6009 // Optimization for build-in types
6010 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6011 ec.EmitLoadFromPtr (type);
6013 var ff = spec as FixedFieldSpec;
6015 ec.Emit (OpCodes.Ldflda, spec);
6016 ec.Emit (OpCodes.Ldflda, ff.Element);
6019 ec.Emit (OpCodes.Volatile);
6021 ec.Emit (OpCodes.Ldfld, spec);
6027 ec.Emit (OpCodes.Dup);
6029 temp = new LocalTemporary (this.Type);
6035 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6037 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6038 if (isCompound && !(source is DynamicExpressionStatement)) {
6039 if (has_await_source) {
6041 InstanceExpression = InstanceExpression.EmitToField (ec);
6048 if (has_await_source)
6049 source = source.EmitToField (ec);
6051 EmitInstance (ec, prepared);
6057 ec.Emit (OpCodes.Dup);
6059 temp = new LocalTemporary (this.Type);
6064 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6065 ec.Emit (OpCodes.Volatile);
6067 spec.MemberDefinition.SetIsAssigned ();
6070 ec.Emit (OpCodes.Stsfld, spec);
6072 ec.Emit (OpCodes.Stfld, spec);
6082 // Emits store to field with prepared values on stack
6084 public void EmitAssignFromStack (EmitContext ec)
6087 ec.Emit (OpCodes.Stsfld, spec);
6089 ec.Emit (OpCodes.Stfld, spec);
6093 public override void Emit (EmitContext ec)
6098 public override void EmitSideEffect (EmitContext ec)
6100 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6102 if (is_volatile) // || is_marshal_by_ref ())
6103 base.EmitSideEffect (ec);
6106 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6108 if ((mode & AddressOp.Store) != 0)
6109 spec.MemberDefinition.SetIsAssigned ();
6110 if ((mode & AddressOp.Load) != 0)
6111 spec.MemberDefinition.SetIsUsed ();
6114 // Handle initonly fields specially: make a copy and then
6115 // get the address of the copy.
6118 if (spec.IsReadOnly){
6120 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6132 var temp = ec.GetTemporaryLocal (type);
6133 ec.Emit (OpCodes.Stloc, temp);
6134 ec.Emit (OpCodes.Ldloca, temp);
6135 ec.FreeTemporaryLocal (temp, type);
6141 ec.Emit (OpCodes.Ldsflda, spec);
6144 EmitInstance (ec, false);
6145 ec.Emit (OpCodes.Ldflda, spec);
6149 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6151 return MakeExpression (ctx);
6154 public override SLE.Expression MakeExpression (BuilderContext ctx)
6157 return base.MakeExpression (ctx);
6159 return SLE.Expression.Field (
6160 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6161 spec.GetMetaInfo ());
6165 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6167 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6173 // Expression that evaluates to a Property.
6175 // This is not an LValue because we need to re-write the expression. We
6176 // can not take data from the stack and store it.
6178 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6180 Arguments arguments;
6182 public PropertyExpr (PropertySpec spec, Location l)
6185 best_candidate = spec;
6186 type = spec.MemberType;
6191 protected override Arguments Arguments {
6200 protected override TypeSpec DeclaringType {
6202 return best_candidate.DeclaringType;
6206 public override string Name {
6208 return best_candidate.Name;
6212 public override bool IsInstance {
6218 public override bool IsStatic {
6220 return best_candidate.IsStatic;
6224 public override string KindName {
6225 get { return "property"; }
6228 public PropertySpec PropertyInfo {
6230 return best_candidate;
6236 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6238 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6241 var args_count = arguments == null ? 0 : arguments.Count;
6242 if (args_count != body.Parameters.Count && args_count == 0)
6245 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6246 mg.InstanceExpression = InstanceExpression;
6251 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6253 return new PropertyExpr (spec, loc) {
6259 public override Expression CreateExpressionTree (ResolveContext ec)
6262 if (IsSingleDimensionalArrayLength ()) {
6263 args = new Arguments (1);
6264 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6265 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6268 args = new Arguments (2);
6269 if (InstanceExpression == null)
6270 args.Add (new Argument (new NullLiteral (loc)));
6272 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6273 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6274 return CreateExpressionFactoryCall (ec, "Property", args);
6277 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6279 DoResolveLValue (rc, null);
6280 return new TypeOfMethod (Setter, loc);
6283 public override string GetSignatureForError ()
6285 return best_candidate.GetSignatureForError ();
6288 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6291 return base.MakeExpression (ctx);
6293 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6297 public override SLE.Expression MakeExpression (BuilderContext ctx)
6300 return base.MakeExpression (ctx);
6302 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6306 void Error_PropertyNotValid (ResolveContext ec)
6308 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6309 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6310 GetSignatureForError ());
6313 bool IsSingleDimensionalArrayLength ()
6315 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6318 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6319 return ac != null && ac.Rank == 1;
6322 public override void Emit (EmitContext ec, bool leave_copy)
6325 // Special case: length of single dimension array property is turned into ldlen
6327 if (IsSingleDimensionalArrayLength ()) {
6328 EmitInstance (ec, false);
6329 ec.Emit (OpCodes.Ldlen);
6330 ec.Emit (OpCodes.Conv_I4);
6334 base.Emit (ec, leave_copy);
6337 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6340 LocalTemporary await_source_arg = null;
6342 if (isCompound && !(source is DynamicExpressionStatement)) {
6343 emitting_compound_assignment = true;
6346 if (has_await_arguments) {
6347 await_source_arg = new LocalTemporary (Type);
6348 await_source_arg.Store (ec);
6350 args = new Arguments (1);
6351 args.Add (new Argument (await_source_arg));
6354 temp = await_source_arg;
6357 has_await_arguments = false;
6362 ec.Emit (OpCodes.Dup);
6363 temp = new LocalTemporary (this.Type);
6368 args = arguments ?? new Arguments (1);
6372 temp = new LocalTemporary (this.Type);
6374 args.Add (new Argument (temp));
6376 args.Add (new Argument (source));
6380 emitting_compound_assignment = false;
6382 var call = new CallEmitter ();
6383 call.InstanceExpression = InstanceExpression;
6385 call.InstanceExpressionOnStack = true;
6387 call.Emit (ec, Setter, args, loc);
6394 if (await_source_arg != null) {
6395 await_source_arg.Release (ec);
6399 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6401 eclass = ExprClass.PropertyAccess;
6403 if (best_candidate.IsNotCSharpCompatible) {
6404 Error_PropertyNotValid (rc);
6407 ResolveInstanceExpression (rc, right_side);
6409 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6410 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6411 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6413 type = p.MemberType;
6417 DoBestMemberChecks (rc, best_candidate);
6419 // Handling of com-imported properties with any number of default property parameters
6420 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6421 var p = best_candidate.Get.Parameters;
6422 arguments = new Arguments (p.Count);
6423 for (int i = 0; i < p.Count; ++i) {
6424 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6426 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6427 var p = best_candidate.Set.Parameters;
6428 arguments = new Arguments (p.Count - 1);
6429 for (int i = 0; i < p.Count - 1; ++i) {
6430 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6437 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6439 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6443 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6445 // getter and setter can be different for base calls
6446 MethodSpec getter, setter;
6447 protected T best_candidate;
6449 protected LocalTemporary temp;
6450 protected bool emitting_compound_assignment;
6451 protected bool has_await_arguments;
6453 protected PropertyOrIndexerExpr (Location l)
6460 protected abstract Arguments Arguments { get; set; }
6462 public MethodSpec Getter {
6471 public MethodSpec Setter {
6482 protected override Expression DoResolve (ResolveContext ec)
6484 if (eclass == ExprClass.Unresolved) {
6485 var expr = OverloadResolve (ec, null);
6490 return expr.Resolve (ec);
6493 if (!ResolveGetter (ec))
6499 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6501 if (right_side == EmptyExpression.OutAccess) {
6502 // TODO: best_candidate can be null at this point
6503 INamedBlockVariable variable = null;
6504 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6505 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6506 best_candidate.Name);
6508 right_side.DoResolveLValue (ec, this);
6513 if (eclass == ExprClass.Unresolved) {
6514 var expr = OverloadResolve (ec, right_side);
6519 return expr.ResolveLValue (ec, right_side);
6521 ResolveInstanceExpression (ec, right_side);
6524 if (!ResolveSetter (ec))
6531 // Implements the IAssignMethod interface for assignments
6533 public virtual void Emit (EmitContext ec, bool leave_copy)
6535 var call = new CallEmitter ();
6536 call.InstanceExpression = InstanceExpression;
6537 if (has_await_arguments)
6538 call.HasAwaitArguments = true;
6540 call.DuplicateArguments = emitting_compound_assignment;
6542 call.Emit (ec, Getter, Arguments, loc);
6544 if (call.HasAwaitArguments) {
6545 InstanceExpression = call.InstanceExpression;
6546 Arguments = call.EmittedArguments;
6547 has_await_arguments = true;
6551 ec.Emit (OpCodes.Dup);
6552 temp = new LocalTemporary (Type);
6557 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6559 public override void Emit (EmitContext ec)
6564 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6566 has_await_arguments = true;
6571 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6573 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6575 bool ResolveGetter (ResolveContext rc)
6577 if (!best_candidate.HasGet) {
6578 if (InstanceExpression != EmptyExpression.Null) {
6579 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6580 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6581 best_candidate.GetSignatureForError ());
6584 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6585 if (best_candidate.HasDifferentAccessibility) {
6586 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6587 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6588 TypeManager.CSharpSignature (best_candidate));
6590 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6591 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6595 if (best_candidate.HasDifferentAccessibility) {
6596 CheckProtectedMemberAccess (rc, best_candidate.Get);
6599 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6603 bool ResolveSetter (ResolveContext rc)
6605 if (!best_candidate.HasSet) {
6606 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6607 GetSignatureForError ());
6611 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6612 if (best_candidate.HasDifferentAccessibility) {
6613 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6614 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6615 GetSignatureForError ());
6617 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6618 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6622 if (best_candidate.HasDifferentAccessibility)
6623 CheckProtectedMemberAccess (rc, best_candidate.Set);
6625 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6631 /// Fully resolved expression that evaluates to an Event
6633 public class EventExpr : MemberExpr, IAssignMethod
6635 readonly EventSpec spec;
6638 public EventExpr (EventSpec spec, Location loc)
6646 protected override TypeSpec DeclaringType {
6648 return spec.DeclaringType;
6652 public override string Name {
6658 public override bool IsInstance {
6660 return !spec.IsStatic;
6664 public override bool IsStatic {
6666 return spec.IsStatic;
6670 public override string KindName {
6671 get { return "event"; }
6674 public MethodSpec Operator {
6682 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6685 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6687 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6688 if (spec.BackingField != null &&
6689 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6691 spec.MemberDefinition.SetIsUsed ();
6693 if (!ec.IsObsolete) {
6694 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6696 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6699 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6700 Error_AssignmentEventOnly (ec);
6702 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6704 InstanceExpression = null;
6706 return ml.ResolveMemberAccess (ec, left, original);
6710 return base.ResolveMemberAccess (ec, left, original);
6713 public override Expression CreateExpressionTree (ResolveContext ec)
6715 throw new NotSupportedException ("ET");
6718 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6720 if (right_side == EmptyExpression.EventAddition) {
6721 op = spec.AccessorAdd;
6722 } else if (right_side == EmptyExpression.EventSubtraction) {
6723 op = spec.AccessorRemove;
6727 Error_AssignmentEventOnly (ec);
6731 op = CandidateToBaseOverride (ec, op);
6735 protected override Expression DoResolve (ResolveContext ec)
6737 eclass = ExprClass.EventAccess;
6738 type = spec.MemberType;
6740 ResolveInstanceExpression (ec, null);
6742 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6743 Error_AssignmentEventOnly (ec);
6746 DoBestMemberChecks (ec, spec);
6750 public override void Emit (EmitContext ec)
6752 throw new NotSupportedException ();
6753 //Error_CannotAssign ();
6756 #region IAssignMethod Members
6758 public void Emit (EmitContext ec, bool leave_copy)
6760 throw new NotImplementedException ();
6763 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6765 if (leave_copy || !isCompound)
6766 throw new NotImplementedException ("EventExpr::EmitAssign");
6768 Arguments args = new Arguments (1);
6769 args.Add (new Argument (source));
6771 var call = new CallEmitter ();
6772 call.InstanceExpression = InstanceExpression;
6773 call.Emit (ec, op, args, loc);
6778 void Error_AssignmentEventOnly (ResolveContext ec)
6780 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6781 ec.Report.Error (79, loc,
6782 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6783 GetSignatureForError ());
6785 ec.Report.Error (70, loc,
6786 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6787 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6791 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6793 name = name.Substring (0, name.LastIndexOf ('.'));
6794 base.Error_CannotCallAbstractBase (rc, name);
6797 public override string GetSignatureForError ()
6799 return TypeManager.CSharpSignature (spec);
6802 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6804 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6808 public class TemporaryVariableReference : VariableReference
6810 public class Declarator : Statement
6812 TemporaryVariableReference variable;
6814 public Declarator (TemporaryVariableReference variable)
6816 this.variable = variable;
6820 protected override void DoEmit (EmitContext ec)
6822 variable.li.CreateBuilder (ec);
6825 public override void Emit (EmitContext ec)
6827 // Don't create sequence point
6831 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6836 protected override void CloneTo (CloneContext clonectx, Statement target)
6844 public TemporaryVariableReference (LocalVariable li, Location loc)
6847 this.type = li.Type;
6851 public override bool IsLockedByStatement {
6859 public LocalVariable LocalInfo {
6865 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6867 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6868 return new TemporaryVariableReference (li, loc);
6871 protected override Expression DoResolve (ResolveContext ec)
6873 eclass = ExprClass.Variable;
6876 // Don't capture temporary variables except when using
6877 // state machine redirection and block yields
6879 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6880 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6881 ec.IsVariableCapturingRequired) {
6882 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6883 storey.CaptureLocalVariable (ec, li);
6889 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6891 return Resolve (ec);
6894 public override void Emit (EmitContext ec)
6896 li.CreateBuilder (ec);
6901 public void EmitAssign (EmitContext ec, Expression source)
6903 li.CreateBuilder (ec);
6905 EmitAssign (ec, source, false, false);
6908 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6910 return li.HoistedVariant;
6913 public override bool IsFixed {
6914 get { return true; }
6917 public override bool IsRef {
6918 get { return false; }
6921 public override string Name {
6922 get { throw new NotImplementedException (); }
6925 public override void SetHasAddressTaken ()
6927 throw new NotImplementedException ();
6930 protected override ILocalVariable Variable {
6934 public override VariableInfo VariableInfo {
6935 get { return null; }
6940 /// Handles `var' contextual keyword; var becomes a keyword only
6941 /// if no type called var exists in a variable scope
6943 class VarExpr : SimpleName
6945 public VarExpr (Location loc)
6950 public bool InferType (ResolveContext ec, Expression right_side)
6953 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6955 type = right_side.Type;
6956 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6957 ec.Report.Error (815, loc,
6958 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6959 type.GetSignatureForError ());
6963 eclass = ExprClass.Variable;
6967 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6969 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6970 base.Error_TypeOrNamespaceNotFound (ec);
6972 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");