2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public static void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
434 /// Resolves an expression and performs semantic analysis on it.
438 /// Currently Resolve wraps DoResolve to perform sanity
439 /// checking and assertion checking on what we expect from Resolve.
441 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
443 if (eclass != ExprClass.Unresolved) {
444 if ((flags & ExprClassToResolveFlags) == 0) {
445 Error_UnexpectedKind (ec, flags, loc);
459 if ((flags & e.ExprClassToResolveFlags) == 0) {
460 e.Error_UnexpectedKind (ec, flags, loc);
465 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
468 } catch (Exception ex) {
469 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
470 ec.Report.Printer is NullReportPrinter)
473 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
474 return ErrorExpression.Instance; // TODO: Add location
479 /// Resolves an expression and performs semantic analysis on it.
481 public Expression Resolve (ResolveContext rc)
483 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
487 /// Resolves an expression for LValue assignment
491 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
492 /// checking and assertion checking on what we expect from Resolve
494 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
496 int errors = ec.Report.Errors;
497 bool out_access = right_side == EmptyExpression.OutAccess;
499 Expression e = DoResolveLValue (ec, right_side);
501 if (e != null && out_access && !(e is IMemoryLocation)) {
502 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
503 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
505 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
506 // e.GetType () + " " + e.GetSignatureForError ());
511 if (errors == ec.Report.Errors) {
512 Error_ValueAssignment (ec, right_side);
517 if (e.eclass == ExprClass.Unresolved)
518 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
520 if ((e.type == null) && !(e is GenericTypeExpr))
521 throw new Exception ("Expression " + e + " did not set its type after Resolve");
526 public Constant ResolveLabelConstant (ResolveContext rc)
528 var expr = Resolve (rc);
532 Constant c = expr as Constant;
534 if (expr.type != InternalType.ErrorType)
535 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
543 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
545 rc.Module.Compiler.Report.Error (182, loc,
546 "An attribute argument must be a constant expression, typeof expression or array creation expression");
550 /// Emits the code for the expression
554 /// The Emit method is invoked to generate the code
555 /// for the expression.
557 public abstract void Emit (EmitContext ec);
560 // Emit code to branch to @target if this expression is equivalent to @on_true.
561 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
562 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
563 // including the use of conditional branches. Note also that a branch MUST be emitted
564 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
567 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
570 // Emit this expression for its side effects, not for its value.
571 // The default implementation is to emit the value, and then throw it away.
572 // Subclasses can provide more efficient implementations, but those MUST be equivalent
573 public virtual void EmitSideEffect (EmitContext ec)
576 ec.Emit (OpCodes.Pop);
580 // Emits the expression into temporary field variable. The method
581 // should be used for await expressions only
583 public virtual Expression EmitToField (EmitContext ec)
586 // This is the await prepare Emit method. When emitting code like
587 // a + b we emit code like
593 // For await a + await b we have to interfere the flow to keep the
594 // stack clean because await yields from the expression. The emit
597 // a = a.EmitToField () // a is changed to temporary field access
598 // b = b.EmitToField ()
604 // The idea is to emit expression and leave the stack empty with
605 // result value still available.
607 // Expressions should override this default implementation when
608 // optimized version can be provided (e.g. FieldExpr)
611 // We can optimize for side-effect free expressions, they can be
612 // emitted out of order
614 if (IsSideEffectFree)
617 bool needs_temporary = ContainsEmitWithAwait ();
618 if (!needs_temporary)
621 // Emit original code
622 var field = EmitToFieldSource (ec);
625 // Store the result to temporary field when we
626 // cannot load `this' directly
628 field = ec.GetTemporaryField (type);
629 if (needs_temporary) {
631 // Create temporary local (we cannot load `this' before Emit)
633 var temp = ec.GetTemporaryLocal (type);
634 ec.Emit (OpCodes.Stloc, temp);
637 ec.Emit (OpCodes.Ldloc, temp);
638 field.EmitAssignFromStack (ec);
640 ec.FreeTemporaryLocal (temp, type);
642 field.EmitAssignFromStack (ec);
649 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
652 // Default implementation calls Emit method
658 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
660 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
661 bool contains_await = false;
663 for (int i = 1; i < expressions.Count; ++i) {
664 if (expressions[i].ContainsEmitWithAwait ()) {
665 contains_await = true;
670 if (contains_await) {
671 for (int i = 0; i < expressions.Count; ++i) {
672 expressions[i] = expressions[i].EmitToField (ec);
677 for (int i = 0; i < expressions.Count; ++i) {
678 expressions[i].Emit (ec);
683 /// Protected constructor. Only derivate types should
684 /// be able to be created
687 protected Expression ()
692 /// Returns a fully formed expression after a MemberLookup
695 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
697 if (spec is EventSpec)
698 return new EventExpr ((EventSpec) spec, loc);
699 if (spec is ConstSpec)
700 return new ConstantExpr ((ConstSpec) spec, loc);
701 if (spec is FieldSpec)
702 return new FieldExpr ((FieldSpec) spec, loc);
703 if (spec is PropertySpec)
704 return new PropertyExpr ((PropertySpec) spec, loc);
705 if (spec is TypeSpec)
706 return new TypeExpression (((TypeSpec) spec), loc);
711 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
713 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
716 case MemberKind.Struct:
717 rc.Report.SymbolRelatedToPreviousError (type);
718 // Report meaningful error for struct as they always have default ctor in C# context
719 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
721 case MemberKind.MissingType:
722 case MemberKind.InternalCompilerType:
725 rc.Report.SymbolRelatedToPreviousError (type);
726 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
727 type.GetSignatureForError ());
734 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
735 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
736 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
739 return r.ResolveMember<MethodSpec> (rc, ref args);
743 public enum MemberLookupRestrictions
752 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
753 // `qualifier_type' or null to lookup members in the current class.
755 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
757 var members = MemberCache.FindMembers (queried_type, name, false);
761 MemberSpec non_method = null;
762 MemberSpec ambig_non_method = null;
764 for (int i = 0; i < members.Count; ++i) {
765 var member = members[i];
767 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
768 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
771 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
774 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
778 if (!member.IsAccessible (rc))
782 // With runtime binder we can have a situation where queried type is inaccessible
783 // because it came via dynamic object, the check about inconsisted accessibility
784 // had no effect as the type was unknown during compilation
787 // private class N { }
789 // public dynamic Foo ()
795 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
799 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
800 if (member is MethodSpec) {
802 // Interface members that are hidden by class members are removed from the set. This
803 // step only has an effect if T is a type parameter and T has both an effective base
804 // class other than object and a non-empty effective interface set
806 var tps = queried_type as TypeParameterSpec;
807 if (tps != null && tps.HasTypeConstraint)
808 members = RemoveHiddenTypeParameterMethods (members);
810 return new MethodGroupExpr (members, queried_type, loc);
813 if (!Invocation.IsMemberInvocable (member))
817 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
819 } else if (!errorMode && !member.IsNotCSharpCompatible) {
821 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
822 // T has both an effective base class other than object and a non-empty effective interface set.
824 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
826 var tps = queried_type as TypeParameterSpec;
827 if (tps != null && tps.HasTypeConstraint) {
828 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
831 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
837 ambig_non_method = member;
841 if (non_method != null) {
842 if (ambig_non_method != null && rc != null) {
843 var report = rc.Module.Compiler.Report;
844 report.SymbolRelatedToPreviousError (non_method);
845 report.SymbolRelatedToPreviousError (ambig_non_method);
846 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
847 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
850 if (non_method is MethodSpec)
851 return new MethodGroupExpr (members, queried_type, loc);
853 return ExprClassFromMemberInfo (non_method, loc);
856 if (members[0].DeclaringType.BaseType == null)
859 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
861 } while (members != null);
866 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
868 if (members.Count < 2)
872 // If M is a method, then all non-method members declared in an interface declaration
873 // are removed from the set, and all methods with the same signature as M declared in
874 // an interface declaration are removed from the set
878 for (int i = 0; i < members.Count; ++i) {
879 var method = members[i] as MethodSpec;
880 if (method == null) {
883 members = new List<MemberSpec> (members);
886 members.RemoveAt (i--);
890 if (!method.DeclaringType.IsInterface)
893 for (int ii = 0; ii < members.Count; ++ii) {
894 var candidate = members[ii] as MethodSpec;
895 if (candidate == null || !candidate.DeclaringType.IsClass)
898 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
903 members = new List<MemberSpec> (members);
906 members.RemoveAt (i--);
914 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
916 throw new NotImplementedException ();
919 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
921 if (t == InternalType.ErrorType)
924 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
925 oper, t.GetSignatureForError ());
928 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
930 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
933 public virtual void FlowAnalysis (FlowAnalysisContext fc)
938 /// Returns an expression that can be used to invoke operator true
939 /// on the expression if it exists.
941 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
943 return GetOperatorTrueOrFalse (ec, e, true, loc);
947 /// Returns an expression that can be used to invoke operator false
948 /// on the expression if it exists.
950 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
952 return GetOperatorTrueOrFalse (ec, e, false, loc);
955 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
957 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
958 var methods = MemberCache.GetUserOperator (e.type, op, false);
962 Arguments arguments = new Arguments (1);
963 arguments.Add (new Argument (e));
965 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
966 var oper = res.ResolveOperator (ec, ref arguments);
971 return new UserOperatorCall (oper, arguments, null, loc);
974 public virtual string ExprClassName
978 case ExprClass.Unresolved:
980 case ExprClass.Value:
982 case ExprClass.Variable:
984 case ExprClass.Namespace:
988 case ExprClass.MethodGroup:
989 return "method group";
990 case ExprClass.PropertyAccess:
991 return "property access";
992 case ExprClass.EventAccess:
993 return "event access";
994 case ExprClass.IndexerAccess:
995 return "indexer access";
996 case ExprClass.Nothing:
998 case ExprClass.TypeParameter:
999 return "type parameter";
1001 throw new Exception ("Should not happen");
1006 /// Reports that we were expecting `expr' to be of class `expected'
1008 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1010 var name = memberExpr.GetSignatureForError ();
1012 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1015 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1017 string [] valid = new string [4];
1020 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1021 valid [count++] = "variable";
1022 valid [count++] = "value";
1025 if ((flags & ResolveFlags.Type) != 0)
1026 valid [count++] = "type";
1028 if ((flags & ResolveFlags.MethodGroup) != 0)
1029 valid [count++] = "method group";
1032 valid [count++] = "unknown";
1034 StringBuilder sb = new StringBuilder (valid [0]);
1035 for (int i = 1; i < count - 1; i++) {
1037 sb.Append (valid [i]);
1040 sb.Append ("' or `");
1041 sb.Append (valid [count - 1]);
1044 ec.Report.Error (119, loc,
1045 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1048 public static void UnsafeError (ResolveContext ec, Location loc)
1050 UnsafeError (ec.Report, loc);
1053 public static void UnsafeError (Report Report, Location loc)
1055 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1059 // Converts `source' to an int, uint, long or ulong.
1061 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, 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);
2318 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 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4627 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4628 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4629 // candidate was found use the set to report more details about what was wrong with lambda body.
4630 // The general idea is to distinguish between code errors and errors caused by
4631 // trial-and-error type inference
4633 if (lambda_conv_msgs == null) {
4634 for (int i = 0; i < arg_count; i++) {
4635 Argument a = arguments[i];
4639 var am = a.Expr as AnonymousMethodExpression;
4641 if (lambda_conv_msgs == null)
4642 lambda_conv_msgs = new SessionReportPrinter ();
4644 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4649 var ti = new TypeInference (arguments);
4650 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4653 return ti.InferenceScore - 20000;
4656 // Clear any error messages when the result was success
4658 if (lambda_conv_msgs != null)
4659 lambda_conv_msgs.ClearSession ();
4661 if (i_args.Length != 0) {
4662 ms = ms.MakeGenericMethod (ec, i_args);
4667 // Type arguments constraints have to match for the method to be applicable
4669 if (!CheckInflatedArguments (ms)) {
4671 return int.MaxValue - 25000;
4675 // We have a generic return type and at same time the method is override which
4676 // means we have to also inflate override return type in case the candidate is
4677 // best candidate and override return type is different to base return type.
4679 // virtual Foo<T, object> with override Foo<T, dynamic>
4681 if (candidate != pm) {
4682 MethodSpec override_ms = (MethodSpec) pm;
4683 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4684 returnType = inflator.Inflate (returnType);
4686 returnType = ms.ReturnType;
4693 if (type_arguments != null)
4694 return int.MaxValue - 15000;
4700 // 2. Each argument has to be implicitly convertible to method parameter
4702 Parameter.Modifier p_mod = 0;
4705 for (int i = 0; i < arg_count; i++) {
4706 Argument a = arguments[i];
4708 var fp = pd.FixedParameters[i];
4709 if (!fp.HasDefaultValue) {
4710 arguments = orig_args;
4711 return arg_count * 2 + 2;
4715 // Get the default value expression, we can use the same expression
4716 // if the type matches
4718 Expression e = fp.DefaultValue;
4720 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4722 // Restore for possible error reporting
4723 for (int ii = i; ii < arg_count; ++ii)
4724 arguments.RemoveAt (i);
4726 return (arg_count - i) * 2 + 1;
4730 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4732 // LAMESPEC: Attributes can be mixed together with build-in priority
4734 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4735 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4736 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4737 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4738 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4739 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4743 arguments[i] = new Argument (e, Argument.AType.Default);
4747 if (p_mod != Parameter.Modifier.PARAMS) {
4748 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4750 } else if (!params_expanded_form) {
4751 params_expanded_form = true;
4752 pt = ((ElementTypeSpec) pt).Element;
4758 if (!params_expanded_form) {
4759 if (a.ArgType == Argument.AType.ExtensionType) {
4761 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4763 // LAMESPEC: or implicit type parameter conversion
4766 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4767 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4768 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4773 score = IsArgumentCompatible (ec, a, p_mod, pt);
4776 dynamicArgument = true;
4781 // It can be applicable in expanded form (when not doing exact match like for delegates)
4783 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4784 if (!params_expanded_form) {
4785 pt = ((ElementTypeSpec) pt).Element;
4789 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4792 params_expanded_form = true;
4793 dynamicArgument = true;
4794 } else if (score == 0 || arg_count > pd.Count) {
4795 params_expanded_form = true;
4800 if (params_expanded_form)
4802 return (arg_count - i) * 2 + score;
4807 // When params parameter has no argument it will be provided later if the method is the best candidate
4809 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4810 params_expanded_form = true;
4813 // Restore original arguments for dynamic binder to keep the intention of original source code
4815 if (dynamicArgument)
4816 arguments = orig_args;
4821 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4823 if (e is Constant && e.Type == ptype)
4827 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4829 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4830 e = new MemberAccess (new MemberAccess (new MemberAccess (
4831 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4832 } else if (e is Constant) {
4834 // Handles int to int? conversions, DefaultParameterValue check
4836 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4840 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4843 return e.Resolve (ec);
4847 // Tests argument compatibility with the parameter
4848 // The possible return values are
4850 // 1 - modifier mismatch
4851 // 2 - type mismatch
4852 // -1 - dynamic binding required
4854 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4857 // Types have to be identical when ref or out modifer
4858 // is used and argument is not of dynamic type
4860 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4861 if (argument.Type != parameter) {
4863 // Do full equality check after quick path
4865 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4867 // Using dynamic for ref/out parameter can still succeed at runtime
4869 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4876 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4878 // Using dynamic for ref/out parameter can still succeed at runtime
4880 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4887 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4891 // Use implicit conversion in all modes to return same candidates when the expression
4892 // is used as argument or delegate conversion
4894 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4895 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4902 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4904 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4906 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4909 var ac_p = p as ArrayContainer;
4911 var ac_q = q as ArrayContainer;
4915 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4916 if (specific == ac_p.Element)
4918 if (specific == ac_q.Element)
4920 } else if (p.IsGeneric && q.IsGeneric) {
4921 var pargs = TypeManager.GetTypeArguments (p);
4922 var qargs = TypeManager.GetTypeArguments (q);
4924 bool p_specific_at_least_once = false;
4925 bool q_specific_at_least_once = false;
4927 for (int i = 0; i < pargs.Length; i++) {
4928 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4929 if (specific == pargs[i])
4930 p_specific_at_least_once = true;
4931 if (specific == qargs[i])
4932 q_specific_at_least_once = true;
4935 if (p_specific_at_least_once && !q_specific_at_least_once)
4937 if (!p_specific_at_least_once && q_specific_at_least_once)
4945 // Find the best method from candidate list
4947 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4949 List<AmbiguousCandidate> ambiguous_candidates = null;
4951 MemberSpec best_candidate;
4952 Arguments best_candidate_args = null;
4953 bool best_candidate_params = false;
4954 bool best_candidate_dynamic = false;
4955 int best_candidate_rate;
4956 IParametersMember best_parameter_member = null;
4958 int args_count = args != null ? args.Count : 0;
4960 Arguments candidate_args = args;
4961 bool error_mode = false;
4962 MemberSpec invocable_member = null;
4965 best_candidate = null;
4966 best_candidate_rate = int.MaxValue;
4968 var type_members = members;
4970 for (int i = 0; i < type_members.Count; ++i) {
4971 var member = type_members[i];
4974 // Methods in a base class are not candidates if any method in a derived
4975 // class is applicable
4977 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4981 if (!member.IsAccessible (rc))
4984 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4987 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4988 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4993 IParametersMember pm = member as IParametersMember;
4996 // Will use it later to report ambiguity between best method and invocable member
4998 if (Invocation.IsMemberInvocable (member))
4999 invocable_member = member;
5005 // Overload resolution is looking for base member but using parameter names
5006 // and default values from the closest member. That means to do expensive lookup
5007 // for the closest override for virtual or abstract members
5009 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5010 var override_params = base_provider.GetOverrideMemberParameters (member);
5011 if (override_params != null)
5012 pm = override_params;
5016 // Check if the member candidate is applicable
5018 bool params_expanded_form = false;
5019 bool dynamic_argument = false;
5020 TypeSpec rt = pm.MemberType;
5021 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
5023 if (lambda_conv_msgs != null)
5024 lambda_conv_msgs.EndSession ();
5027 // How does it score compare to others
5029 if (candidate_rate < best_candidate_rate) {
5031 // Fatal error (missing dependency), cannot continue
5032 if (candidate_rate < 0)
5035 best_candidate_rate = candidate_rate;
5036 best_candidate = member;
5037 best_candidate_args = candidate_args;
5038 best_candidate_params = params_expanded_form;
5039 best_candidate_dynamic = dynamic_argument;
5040 best_parameter_member = pm;
5041 best_candidate_return_type = rt;
5042 } else if (candidate_rate == 0) {
5044 // The member look is done per type for most operations but sometimes
5045 // it's not possible like for binary operators overload because they
5046 // are unioned between 2 sides
5048 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5049 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5054 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5056 // We pack all interface members into top level type which makes the overload resolution
5057 // more complicated for interfaces. We compensate it by removing methods with same
5058 // signature when building the cache hence this path should not really be hit often
5061 // interface IA { void Foo (int arg); }
5062 // interface IB : IA { void Foo (params int[] args); }
5064 // IB::Foo is the best overload when calling IB.Foo (1)
5067 if (ambiguous_candidates != null) {
5068 foreach (var amb_cand in ambiguous_candidates) {
5069 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5078 ambiguous_candidates = null;
5081 // Is the new candidate better
5082 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5086 best_candidate = member;
5087 best_candidate_args = candidate_args;
5088 best_candidate_params = params_expanded_form;
5089 best_candidate_dynamic = dynamic_argument;
5090 best_parameter_member = pm;
5091 best_candidate_return_type = rt;
5093 // It's not better but any other found later could be but we are not sure yet
5094 if (ambiguous_candidates == null)
5095 ambiguous_candidates = new List<AmbiguousCandidate> ();
5097 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5101 // Restore expanded arguments
5102 candidate_args = args;
5104 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5107 // We've found exact match
5109 if (best_candidate_rate == 0)
5113 // Try extension methods lookup when no ordinary method match was found and provider enables it
5116 var emg = base_provider.LookupExtensionMethod (rc);
5118 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5120 best_candidate_extension_group = emg;
5121 return (T) (MemberSpec) emg.BestCandidate;
5126 // Don't run expensive error reporting mode for probing
5133 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5136 lambda_conv_msgs = null;
5141 // No best member match found, report an error
5143 if (best_candidate_rate != 0 || error_mode) {
5144 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5148 if (best_candidate_dynamic) {
5149 if (args[0].ArgType == Argument.AType.ExtensionType) {
5150 rc.Report.Error (1973, loc,
5151 "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",
5152 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5156 // Check type constraints only when explicit type arguments are used
5158 if (best_candidate.IsGeneric && type_arguments != null) {
5159 MethodSpec bc = best_candidate as MethodSpec;
5160 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5161 ConstraintChecker cc = new ConstraintChecker (rc);
5162 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5166 BestCandidateIsDynamic = true;
5171 // These flags indicates we are running delegate probing conversion. No need to
5172 // do more expensive checks
5174 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5175 return (T) best_candidate;
5177 if (ambiguous_candidates != null) {
5179 // Now check that there are no ambiguities i.e the selected method
5180 // should be better than all the others
5182 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5183 var candidate = ambiguous_candidates [ix];
5185 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5186 var ambiguous = candidate.Member;
5187 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5188 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5189 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5190 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5191 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5194 return (T) best_candidate;
5199 if (invocable_member != null && !IsProbingOnly) {
5200 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5201 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5202 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5203 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5207 // And now check if the arguments are all
5208 // compatible, perform conversions if
5209 // necessary etc. and return if everything is
5212 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5215 if (best_candidate == null)
5219 // Don't run possibly expensive checks in probing mode
5221 if (!IsProbingOnly && !rc.IsInProbingMode) {
5223 // Check ObsoleteAttribute on the best method
5225 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5226 if (oa != null && !rc.IsObsolete)
5227 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5229 best_candidate.MemberDefinition.SetIsUsed ();
5232 args = best_candidate_args;
5233 return (T) best_candidate;
5236 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5238 return ResolveMember<MethodSpec> (rc, ref args);
5241 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5242 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5244 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5247 if (a.Type == InternalType.ErrorType)
5250 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5251 ec.Report.SymbolRelatedToPreviousError (method);
5252 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5253 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5254 TypeManager.CSharpSignature (method));
5257 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5258 TypeManager.CSharpSignature (method));
5259 } else if (IsDelegateInvoke) {
5260 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5261 DelegateType.GetSignatureForError ());
5263 ec.Report.SymbolRelatedToPreviousError (method);
5264 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5265 method.GetSignatureForError ());
5268 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5270 string index = (idx + 1).ToString ();
5271 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5272 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5273 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5274 index, Parameter.GetModifierSignature (a.Modifier));
5276 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5277 index, Parameter.GetModifierSignature (mod));
5279 string p1 = a.GetSignatureForError ();
5280 string p2 = paramType.GetSignatureForError ();
5283 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5284 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5287 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5288 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5289 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5292 ec.Report.Error (1503, a.Expr.Location,
5293 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5298 // We have failed to find exact match so we return error info about the closest match
5300 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5302 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5303 int arg_count = args == null ? 0 : args.Count;
5305 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5306 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5307 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5311 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5316 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5317 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5318 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5322 // For candidates which match on parameters count report more details about incorrect arguments
5325 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5326 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5327 // Reject any inaccessible member
5328 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5329 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5330 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5334 var ms = best_candidate as MethodSpec;
5335 if (ms != null && ms.IsGeneric) {
5336 bool constr_ok = true;
5337 if (ms.TypeArguments != null)
5338 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5340 if (ta_count == 0 && ms.TypeArguments == null) {
5341 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5345 rc.Report.Error (411, loc,
5346 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5347 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5354 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5360 // We failed to find any method with correct argument count, report best candidate
5362 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5365 if (best_candidate.Kind == MemberKind.Constructor) {
5366 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5367 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5368 } else if (IsDelegateInvoke) {
5369 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5370 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5371 DelegateType.GetSignatureForError (), arg_count.ToString ());
5373 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5374 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5375 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5376 name, arg_count.ToString ());
5380 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5382 var pd = pm.Parameters;
5383 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5385 Parameter.Modifier p_mod = 0;
5387 int a_idx = 0, a_pos = 0;
5389 ArrayInitializer params_initializers = null;
5390 bool has_unsafe_arg = pm.MemberType.IsPointer;
5391 int arg_count = args == null ? 0 : args.Count;
5393 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5398 if (p_mod != Parameter.Modifier.PARAMS) {
5399 p_mod = pd.FixedParameters[a_idx].ModFlags;
5401 has_unsafe_arg |= pt.IsPointer;
5403 if (p_mod == Parameter.Modifier.PARAMS) {
5404 if (chose_params_expanded) {
5405 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5406 pt = TypeManager.GetElementType (pt);
5412 // Types have to be identical when ref or out modifer is used
5414 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5415 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5418 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5424 NamedArgument na = a as NamedArgument;
5426 int name_index = pd.GetParameterIndexByName (na.Name);
5427 if (name_index < 0 || name_index >= pd.Count) {
5428 if (IsDelegateInvoke) {
5429 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5430 ec.Report.Error (1746, na.Location,
5431 "The delegate `{0}' does not contain a parameter named `{1}'",
5432 DelegateType.GetSignatureForError (), na.Name);
5434 ec.Report.SymbolRelatedToPreviousError (member);
5435 ec.Report.Error (1739, na.Location,
5436 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5437 TypeManager.CSharpSignature (member), na.Name);
5439 } else if (args[name_index] != a && args[name_index] != null) {
5440 if (IsDelegateInvoke)
5441 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5443 ec.Report.SymbolRelatedToPreviousError (member);
5445 ec.Report.Error (1744, na.Location,
5446 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5451 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5454 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5455 custom_errors.NoArgumentMatch (ec, member);
5460 if (a.ArgType == Argument.AType.ExtensionType) {
5461 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5464 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5466 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5469 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5476 // Convert params arguments to an array initializer
5478 if (params_initializers != null) {
5479 // we choose to use 'a.Expr' rather than 'conv' so that
5480 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5481 params_initializers.Add (a.Expr);
5482 args.RemoveAt (a_idx--);
5488 // Update the argument with the implicit conversion
5492 if (a_idx != arg_count) {
5493 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5498 // Fill not provided arguments required by params modifier
5500 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5502 args = new Arguments (1);
5504 pt = ptypes[pd.Count - 1];
5505 pt = TypeManager.GetElementType (pt);
5506 has_unsafe_arg |= pt.IsPointer;
5507 params_initializers = new ArrayInitializer (0, loc);
5511 // Append an array argument with all params arguments
5513 if (params_initializers != null) {
5514 args.Add (new Argument (
5515 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5519 if (has_unsafe_arg && !ec.IsUnsafe) {
5520 Expression.UnsafeError (ec, loc);
5524 // We could infer inaccesible type arguments
5526 if (type_arguments == null && member.IsGeneric) {
5527 var ms = (MethodSpec) member;
5528 foreach (var ta in ms.TypeArguments) {
5529 if (!ta.IsAccessible (ec)) {
5530 ec.Report.SymbolRelatedToPreviousError (ta);
5531 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5541 public class ConstantExpr : MemberExpr
5543 readonly ConstSpec constant;
5545 public ConstantExpr (ConstSpec constant, Location loc)
5547 this.constant = constant;
5551 public override string Name {
5552 get { throw new NotImplementedException (); }
5555 public override string KindName {
5556 get { return "constant"; }
5559 public override bool IsInstance {
5560 get { return !IsStatic; }
5563 public override bool IsStatic {
5564 get { return true; }
5567 protected override TypeSpec DeclaringType {
5568 get { return constant.DeclaringType; }
5571 public override Expression CreateExpressionTree (ResolveContext ec)
5573 throw new NotSupportedException ("ET");
5576 protected override Expression DoResolve (ResolveContext rc)
5578 ResolveInstanceExpression (rc, null);
5579 DoBestMemberChecks (rc, constant);
5581 var c = constant.GetConstant (rc);
5583 // Creates reference expression to the constant value
5584 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5587 public override void Emit (EmitContext ec)
5589 throw new NotSupportedException ();
5592 public override string GetSignatureForError ()
5594 return constant.GetSignatureForError ();
5597 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5599 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5604 // Fully resolved expression that references a Field
5606 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5608 protected FieldSpec spec;
5609 VariableInfo variable_info;
5611 LocalTemporary temp;
5614 protected FieldExpr (Location l)
5619 public FieldExpr (FieldSpec spec, Location loc)
5624 type = spec.MemberType;
5627 public FieldExpr (FieldBase fi, Location l)
5634 public override string Name {
5640 public bool IsHoisted {
5642 IVariableReference hv = InstanceExpression as IVariableReference;
5643 return hv != null && hv.IsHoisted;
5647 public override bool IsInstance {
5649 return !spec.IsStatic;
5653 public override bool IsStatic {
5655 return spec.IsStatic;
5659 public override string KindName {
5660 get { return "field"; }
5663 public FieldSpec Spec {
5669 protected override TypeSpec DeclaringType {
5671 return spec.DeclaringType;
5675 public VariableInfo VariableInfo {
5677 return variable_info;
5683 public override string GetSignatureForError ()
5685 return spec.GetSignatureForError ();
5688 public bool IsMarshalByRefAccess (ResolveContext rc)
5690 // Checks possible ldflda of field access expression
5691 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5692 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5693 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5696 public void SetHasAddressTaken ()
5698 IVariableReference vr = InstanceExpression as IVariableReference;
5700 vr.SetHasAddressTaken ();
5704 public override Expression CreateExpressionTree (ResolveContext ec)
5706 return CreateExpressionTree (ec, true);
5709 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5712 Expression instance;
5714 if (InstanceExpression == null) {
5715 instance = new NullLiteral (loc);
5716 } else if (convertInstance) {
5717 instance = InstanceExpression.CreateExpressionTree (ec);
5719 args = new Arguments (1);
5720 args.Add (new Argument (InstanceExpression));
5721 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5724 args = Arguments.CreateForExpressionTree (ec, null,
5726 CreateTypeOfExpression ());
5728 return CreateExpressionFactoryCall (ec, "Field", args);
5731 public Expression CreateTypeOfExpression ()
5733 return new TypeOfField (spec, loc);
5736 protected override Expression DoResolve (ResolveContext ec)
5738 spec.MemberDefinition.SetIsUsed ();
5740 return DoResolve (ec, null);
5743 Expression DoResolve (ResolveContext ec, Expression rhs)
5745 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5748 if (ResolveInstanceExpression (ec, rhs)) {
5749 // Resolve the field's instance expression while flow analysis is turned
5750 // off: when accessing a field "a.b", we must check whether the field
5751 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5753 if (lvalue_instance) {
5754 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5756 Expression right_side =
5757 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5759 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5761 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5764 if (InstanceExpression == null)
5768 DoBestMemberChecks (ec, spec);
5771 var fb = spec as FixedFieldSpec;
5772 IVariableReference var = InstanceExpression as IVariableReference;
5775 IFixedExpression fe = InstanceExpression as IFixedExpression;
5776 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5777 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5780 if (InstanceExpression.eclass != ExprClass.Variable) {
5781 ec.Report.SymbolRelatedToPreviousError (spec);
5782 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5783 TypeManager.GetFullNameSignature (spec));
5784 } else if (var != null && var.IsHoisted) {
5785 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5788 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5792 // Set flow-analysis variable info for struct member access. It will be check later
5793 // for precise error reporting
5795 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5796 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5799 eclass = ExprClass.Variable;
5803 public void SetFieldAssigned (FlowAnalysisContext fc)
5808 bool lvalue_instance = spec.DeclaringType.IsStruct;
5809 if (lvalue_instance) {
5810 var var = InstanceExpression as IVariableReference;
5811 if (var != null && var.VariableInfo != null) {
5812 fc.SetStructFieldAssigned (var.VariableInfo, Name);
5816 var fe = InstanceExpression as FieldExpr;
5818 Expression instance;
5821 instance = fe.InstanceExpression;
5822 var fe_instance = instance as FieldExpr;
5823 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
5824 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
5825 var var = InstanceExpression as IVariableReference;
5826 if (var != null && var.VariableInfo == null) {
5827 var var_inst = instance as IVariableReference;
5828 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
5829 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5833 if (fe_instance != null) {
5842 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
5843 instance.FlowAnalysis (fc);
5845 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
5846 InstanceExpression.FlowAnalysis (fc);
5851 public void VerifyAssignedStructField (FlowAnalysisContext fc)
5856 var var = fe.InstanceExpression as IVariableReference;
5858 var vi = var.VariableInfo;
5860 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, fe.Name) && !fe.type.IsStruct) {
5861 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5865 fe = fe.InstanceExpression as FieldExpr;
5867 } while (fe != null);
5870 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
5872 // The return value is always null. Returning a value simplifies calling code.
5874 if (right_side == EmptyExpression.OutAccess) {
5876 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5877 GetSignatureForError ());
5879 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5880 GetSignatureForError ());
5886 if (right_side == EmptyExpression.LValueMemberAccess) {
5887 // Already reported as CS1648/CS1650
5891 if (right_side == EmptyExpression.LValueMemberOutAccess) {
5893 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5894 GetSignatureForError ());
5896 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5897 GetSignatureForError ());
5903 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5904 GetSignatureForError ());
5906 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5907 GetSignatureForError ());
5913 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5915 if (spec is FixedFieldSpec) {
5916 // It could be much better error message but we want to be error compatible
5917 Error_ValueAssignment (ec, right_side);
5920 Expression e = DoResolve (ec, right_side);
5925 spec.MemberDefinition.SetIsAssigned ();
5927 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5928 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5929 ec.Report.Warning (420, 1, loc,
5930 "`{0}': A volatile field references will not be treated as volatile",
5931 spec.GetSignatureForError ());
5934 if (spec.IsReadOnly) {
5935 // InitOnly fields can only be assigned in constructors or initializers
5936 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5937 return Error_AssignToReadonly (ec, right_side);
5939 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5941 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5942 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5943 return Error_AssignToReadonly (ec, right_side);
5944 // static InitOnly fields cannot be assigned-to in an instance constructor
5945 if (IsStatic && !ec.IsStatic)
5946 return Error_AssignToReadonly (ec, right_side);
5947 // instance constructors can't modify InitOnly fields of other instances of the same type
5948 if (!IsStatic && !(InstanceExpression is This))
5949 return Error_AssignToReadonly (ec, right_side);
5953 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5954 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5955 ec.Report.Warning (197, 1, loc,
5956 "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",
5957 GetSignatureForError ());
5960 eclass = ExprClass.Variable;
5964 public override void FlowAnalysis (FlowAnalysisContext fc)
5966 var var = InstanceExpression as IVariableReference;
5968 var vi = var.VariableInfo;
5969 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
5970 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
5974 if (TypeSpec.IsValueType (InstanceExpression.Type))
5978 base.FlowAnalysis (fc);
5981 public override int GetHashCode ()
5983 return spec.GetHashCode ();
5986 public bool IsFixed {
5989 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5991 IVariableReference variable = InstanceExpression as IVariableReference;
5992 if (variable != null)
5993 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5995 IFixedExpression fe = InstanceExpression as IFixedExpression;
5996 return fe != null && fe.IsFixed;
6000 public override bool Equals (object obj)
6002 FieldExpr fe = obj as FieldExpr;
6006 if (spec != fe.spec)
6009 if (InstanceExpression == null || fe.InstanceExpression == null)
6012 return InstanceExpression.Equals (fe.InstanceExpression);
6015 public void Emit (EmitContext ec, bool leave_copy)
6017 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6021 ec.Emit (OpCodes.Volatile);
6023 ec.Emit (OpCodes.Ldsfld, spec);
6026 EmitInstance (ec, false);
6028 // Optimization for build-in types
6029 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6030 ec.EmitLoadFromPtr (type);
6032 var ff = spec as FixedFieldSpec;
6034 ec.Emit (OpCodes.Ldflda, spec);
6035 ec.Emit (OpCodes.Ldflda, ff.Element);
6038 ec.Emit (OpCodes.Volatile);
6040 ec.Emit (OpCodes.Ldfld, spec);
6046 ec.Emit (OpCodes.Dup);
6048 temp = new LocalTemporary (this.Type);
6054 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6056 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6057 if (isCompound && !(source is DynamicExpressionStatement)) {
6058 if (has_await_source) {
6060 InstanceExpression = InstanceExpression.EmitToField (ec);
6067 if (has_await_source)
6068 source = source.EmitToField (ec);
6070 EmitInstance (ec, prepared);
6076 ec.Emit (OpCodes.Dup);
6078 temp = new LocalTemporary (this.Type);
6083 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6084 ec.Emit (OpCodes.Volatile);
6086 spec.MemberDefinition.SetIsAssigned ();
6089 ec.Emit (OpCodes.Stsfld, spec);
6091 ec.Emit (OpCodes.Stfld, spec);
6101 // Emits store to field with prepared values on stack
6103 public void EmitAssignFromStack (EmitContext ec)
6106 ec.Emit (OpCodes.Stsfld, spec);
6108 ec.Emit (OpCodes.Stfld, spec);
6112 public override void Emit (EmitContext ec)
6117 public override void EmitSideEffect (EmitContext ec)
6119 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6121 if (is_volatile) // || is_marshal_by_ref ())
6122 base.EmitSideEffect (ec);
6125 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6127 if ((mode & AddressOp.Store) != 0)
6128 spec.MemberDefinition.SetIsAssigned ();
6129 if ((mode & AddressOp.Load) != 0)
6130 spec.MemberDefinition.SetIsUsed ();
6133 // Handle initonly fields specially: make a copy and then
6134 // get the address of the copy.
6137 if (spec.IsReadOnly){
6139 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6151 var temp = ec.GetTemporaryLocal (type);
6152 ec.Emit (OpCodes.Stloc, temp);
6153 ec.Emit (OpCodes.Ldloca, temp);
6154 ec.FreeTemporaryLocal (temp, type);
6160 ec.Emit (OpCodes.Ldsflda, spec);
6163 EmitInstance (ec, false);
6164 ec.Emit (OpCodes.Ldflda, spec);
6168 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6170 return MakeExpression (ctx);
6173 public override SLE.Expression MakeExpression (BuilderContext ctx)
6176 return base.MakeExpression (ctx);
6178 return SLE.Expression.Field (
6179 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6180 spec.GetMetaInfo ());
6184 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6186 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6192 // Expression that evaluates to a Property.
6194 // This is not an LValue because we need to re-write the expression. We
6195 // can not take data from the stack and store it.
6197 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6199 Arguments arguments;
6201 public PropertyExpr (PropertySpec spec, Location l)
6204 best_candidate = spec;
6205 type = spec.MemberType;
6210 protected override Arguments Arguments {
6219 protected override TypeSpec DeclaringType {
6221 return best_candidate.DeclaringType;
6225 public override string Name {
6227 return best_candidate.Name;
6231 public override bool IsInstance {
6237 public override bool IsStatic {
6239 return best_candidate.IsStatic;
6243 public override string KindName {
6244 get { return "property"; }
6247 public PropertySpec PropertyInfo {
6249 return best_candidate;
6255 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6257 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6260 var args_count = arguments == null ? 0 : arguments.Count;
6261 if (args_count != body.Parameters.Count && args_count == 0)
6264 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6265 mg.InstanceExpression = InstanceExpression;
6270 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6272 return new PropertyExpr (spec, loc) {
6278 public override Expression CreateExpressionTree (ResolveContext ec)
6281 if (IsSingleDimensionalArrayLength ()) {
6282 args = new Arguments (1);
6283 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6284 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6287 args = new Arguments (2);
6288 if (InstanceExpression == null)
6289 args.Add (new Argument (new NullLiteral (loc)));
6291 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6292 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6293 return CreateExpressionFactoryCall (ec, "Property", args);
6296 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6298 DoResolveLValue (rc, null);
6299 return new TypeOfMethod (Setter, loc);
6302 public override string GetSignatureForError ()
6304 return best_candidate.GetSignatureForError ();
6307 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6310 return base.MakeExpression (ctx);
6312 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6316 public override SLE.Expression MakeExpression (BuilderContext ctx)
6319 return base.MakeExpression (ctx);
6321 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6325 void Error_PropertyNotValid (ResolveContext ec)
6327 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6328 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6329 GetSignatureForError ());
6332 bool IsSingleDimensionalArrayLength ()
6334 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6337 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6338 return ac != null && ac.Rank == 1;
6341 public override void Emit (EmitContext ec, bool leave_copy)
6344 // Special case: length of single dimension array property is turned into ldlen
6346 if (IsSingleDimensionalArrayLength ()) {
6347 EmitInstance (ec, false);
6348 ec.Emit (OpCodes.Ldlen);
6349 ec.Emit (OpCodes.Conv_I4);
6353 base.Emit (ec, leave_copy);
6356 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6359 LocalTemporary await_source_arg = null;
6361 if (isCompound && !(source is DynamicExpressionStatement)) {
6362 emitting_compound_assignment = true;
6365 if (has_await_arguments) {
6366 await_source_arg = new LocalTemporary (Type);
6367 await_source_arg.Store (ec);
6369 args = new Arguments (1);
6370 args.Add (new Argument (await_source_arg));
6373 temp = await_source_arg;
6376 has_await_arguments = false;
6381 ec.Emit (OpCodes.Dup);
6382 temp = new LocalTemporary (this.Type);
6387 args = arguments ?? new Arguments (1);
6391 temp = new LocalTemporary (this.Type);
6393 args.Add (new Argument (temp));
6395 args.Add (new Argument (source));
6399 emitting_compound_assignment = false;
6401 var call = new CallEmitter ();
6402 call.InstanceExpression = InstanceExpression;
6404 call.InstanceExpressionOnStack = true;
6406 call.Emit (ec, Setter, args, loc);
6413 if (await_source_arg != null) {
6414 await_source_arg.Release (ec);
6418 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6420 eclass = ExprClass.PropertyAccess;
6422 if (best_candidate.IsNotCSharpCompatible) {
6423 Error_PropertyNotValid (rc);
6426 ResolveInstanceExpression (rc, right_side);
6428 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6429 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6430 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6432 type = p.MemberType;
6436 DoBestMemberChecks (rc, best_candidate);
6438 // Handling of com-imported properties with any number of default property parameters
6439 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6440 var p = best_candidate.Get.Parameters;
6441 arguments = new Arguments (p.Count);
6442 for (int i = 0; i < p.Count; ++i) {
6443 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6445 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6446 var p = best_candidate.Set.Parameters;
6447 arguments = new Arguments (p.Count - 1);
6448 for (int i = 0; i < p.Count - 1; ++i) {
6449 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6456 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6458 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6462 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6464 // getter and setter can be different for base calls
6465 MethodSpec getter, setter;
6466 protected T best_candidate;
6468 protected LocalTemporary temp;
6469 protected bool emitting_compound_assignment;
6470 protected bool has_await_arguments;
6472 protected PropertyOrIndexerExpr (Location l)
6479 protected abstract Arguments Arguments { get; set; }
6481 public MethodSpec Getter {
6490 public MethodSpec Setter {
6501 protected override Expression DoResolve (ResolveContext ec)
6503 if (eclass == ExprClass.Unresolved) {
6504 var expr = OverloadResolve (ec, null);
6509 return expr.Resolve (ec);
6512 if (!ResolveGetter (ec))
6518 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6520 if (right_side == EmptyExpression.OutAccess) {
6521 // TODO: best_candidate can be null at this point
6522 INamedBlockVariable variable = null;
6523 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6524 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6525 best_candidate.Name);
6527 right_side.DoResolveLValue (ec, this);
6532 if (eclass == ExprClass.Unresolved) {
6533 var expr = OverloadResolve (ec, right_side);
6538 return expr.ResolveLValue (ec, right_side);
6540 ResolveInstanceExpression (ec, right_side);
6543 if (!ResolveSetter (ec))
6550 // Implements the IAssignMethod interface for assignments
6552 public virtual void Emit (EmitContext ec, bool leave_copy)
6554 var call = new CallEmitter ();
6555 call.InstanceExpression = InstanceExpression;
6556 if (has_await_arguments)
6557 call.HasAwaitArguments = true;
6559 call.DuplicateArguments = emitting_compound_assignment;
6561 call.Emit (ec, Getter, Arguments, loc);
6563 if (call.HasAwaitArguments) {
6564 InstanceExpression = call.InstanceExpression;
6565 Arguments = call.EmittedArguments;
6566 has_await_arguments = true;
6570 ec.Emit (OpCodes.Dup);
6571 temp = new LocalTemporary (Type);
6576 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6578 public override void Emit (EmitContext ec)
6583 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6585 has_await_arguments = true;
6590 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6592 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6594 bool ResolveGetter (ResolveContext rc)
6596 if (!best_candidate.HasGet) {
6597 if (InstanceExpression != EmptyExpression.Null) {
6598 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6599 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6600 best_candidate.GetSignatureForError ());
6603 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6604 if (best_candidate.HasDifferentAccessibility) {
6605 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6606 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6607 TypeManager.CSharpSignature (best_candidate));
6609 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6610 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6614 if (best_candidate.HasDifferentAccessibility) {
6615 CheckProtectedMemberAccess (rc, best_candidate.Get);
6618 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6622 bool ResolveSetter (ResolveContext rc)
6624 if (!best_candidate.HasSet) {
6625 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6626 GetSignatureForError ());
6630 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
6631 if (best_candidate.HasDifferentAccessibility) {
6632 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6633 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6634 GetSignatureForError ());
6636 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6637 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6641 if (best_candidate.HasDifferentAccessibility)
6642 CheckProtectedMemberAccess (rc, best_candidate.Set);
6644 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6650 /// Fully resolved expression that evaluates to an Event
6652 public class EventExpr : MemberExpr, IAssignMethod
6654 readonly EventSpec spec;
6657 public EventExpr (EventSpec spec, Location loc)
6665 protected override TypeSpec DeclaringType {
6667 return spec.DeclaringType;
6671 public override string Name {
6677 public override bool IsInstance {
6679 return !spec.IsStatic;
6683 public override bool IsStatic {
6685 return spec.IsStatic;
6689 public override string KindName {
6690 get { return "event"; }
6693 public MethodSpec Operator {
6701 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6704 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6706 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6707 if (spec.BackingField != null &&
6708 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6710 spec.MemberDefinition.SetIsUsed ();
6712 if (!ec.IsObsolete) {
6713 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6715 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6718 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6719 Error_AssignmentEventOnly (ec);
6721 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6723 InstanceExpression = null;
6725 return ml.ResolveMemberAccess (ec, left, original);
6729 return base.ResolveMemberAccess (ec, left, original);
6732 public override Expression CreateExpressionTree (ResolveContext ec)
6734 throw new NotSupportedException ("ET");
6737 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6739 if (right_side == EmptyExpression.EventAddition) {
6740 op = spec.AccessorAdd;
6741 } else if (right_side == EmptyExpression.EventSubtraction) {
6742 op = spec.AccessorRemove;
6746 Error_AssignmentEventOnly (ec);
6750 op = CandidateToBaseOverride (ec, op);
6754 protected override Expression DoResolve (ResolveContext ec)
6756 eclass = ExprClass.EventAccess;
6757 type = spec.MemberType;
6759 ResolveInstanceExpression (ec, null);
6761 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6762 Error_AssignmentEventOnly (ec);
6765 DoBestMemberChecks (ec, spec);
6769 public override void Emit (EmitContext ec)
6771 throw new NotSupportedException ();
6772 //Error_CannotAssign ();
6775 #region IAssignMethod Members
6777 public void Emit (EmitContext ec, bool leave_copy)
6779 throw new NotImplementedException ();
6782 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6784 if (leave_copy || !isCompound)
6785 throw new NotImplementedException ("EventExpr::EmitAssign");
6787 Arguments args = new Arguments (1);
6788 args.Add (new Argument (source));
6790 var call = new CallEmitter ();
6791 call.InstanceExpression = InstanceExpression;
6792 call.Emit (ec, op, args, loc);
6797 void Error_AssignmentEventOnly (ResolveContext ec)
6799 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6800 ec.Report.Error (79, loc,
6801 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6802 GetSignatureForError ());
6804 ec.Report.Error (70, loc,
6805 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6806 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6810 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6812 name = name.Substring (0, name.LastIndexOf ('.'));
6813 base.Error_CannotCallAbstractBase (rc, name);
6816 public override string GetSignatureForError ()
6818 return TypeManager.CSharpSignature (spec);
6821 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6823 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6827 public class TemporaryVariableReference : VariableReference
6829 public class Declarator : Statement
6831 TemporaryVariableReference variable;
6833 public Declarator (TemporaryVariableReference variable)
6835 this.variable = variable;
6839 protected override void DoEmit (EmitContext ec)
6841 variable.li.CreateBuilder (ec);
6844 public override void Emit (EmitContext ec)
6846 // Don't create sequence point
6850 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
6855 protected override void CloneTo (CloneContext clonectx, Statement target)
6863 public TemporaryVariableReference (LocalVariable li, Location loc)
6866 this.type = li.Type;
6870 public override bool IsLockedByStatement {
6878 public LocalVariable LocalInfo {
6884 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6886 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6887 return new TemporaryVariableReference (li, loc);
6890 protected override Expression DoResolve (ResolveContext ec)
6892 eclass = ExprClass.Variable;
6895 // Don't capture temporary variables except when using
6896 // state machine redirection and block yields
6898 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
6899 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6900 ec.IsVariableCapturingRequired) {
6901 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6902 storey.CaptureLocalVariable (ec, li);
6908 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6910 return Resolve (ec);
6913 public override void Emit (EmitContext ec)
6915 li.CreateBuilder (ec);
6920 public void EmitAssign (EmitContext ec, Expression source)
6922 li.CreateBuilder (ec);
6924 EmitAssign (ec, source, false, false);
6927 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6929 return li.HoistedVariant;
6932 public override bool IsFixed {
6933 get { return true; }
6936 public override bool IsRef {
6937 get { return false; }
6940 public override string Name {
6941 get { throw new NotImplementedException (); }
6944 public override void SetHasAddressTaken ()
6946 throw new NotImplementedException ();
6949 protected override ILocalVariable Variable {
6953 public override VariableInfo VariableInfo {
6954 get { return null; }
6959 /// Handles `var' contextual keyword; var becomes a keyword only
6960 /// if no type called var exists in a variable scope
6962 class VarExpr : SimpleName
6964 public VarExpr (Location loc)
6969 public bool InferType (ResolveContext ec, Expression right_side)
6972 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6974 type = right_side.Type;
6975 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6976 ec.Report.Error (815, loc,
6977 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6978 type.GetSignatureForError ());
6982 eclass = ExprClass.Variable;
6986 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6988 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6989 base.Error_TypeOrNamespaceNotFound (ec);
6991 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");