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 virtual Constant ResolveAsPlayScriptConstant (ResolveContext rc)
246 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
248 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
251 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
253 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
256 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
258 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
259 name, type.GetSignatureForError ());
262 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
264 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
267 public void Error_InvalidExpressionStatement (BlockContext bc)
269 Error_InvalidExpressionStatement (bc.Report, loc);
272 public void Error_InvalidExpressionStatement (Report report)
274 Error_InvalidExpressionStatement (report, loc);
277 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
279 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
282 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
284 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
287 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
289 // The error was already reported as CS1660
290 if (type == InternalType.AnonymousMethod)
293 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
296 string from_type = type.GetSignatureForError ();
297 string to_type = target.GetSignatureForError ();
298 if (from_type == to_type) {
299 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
300 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
304 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
309 ec.Report.DisableReporting ();
310 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
311 ec.Report.EnableReporting ();
314 ec.Report.Error (266, loc,
315 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
318 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
323 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
325 // Better message for possible generic expressions
326 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
327 var report = context.Module.Compiler.Report;
328 report.SymbolRelatedToPreviousError (member);
329 if (member is TypeSpec)
330 member = ((TypeSpec) member).GetDefinition ();
332 member = ((MethodSpec) member).GetGenericMethodDefinition ();
334 string name = member.Kind == MemberKind.Method ? "method" : "type";
335 if (member.IsGeneric) {
336 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
337 name, member.GetSignatureForError (), member.Arity.ToString ());
339 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
340 name, member.GetSignatureForError ());
343 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
347 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
349 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
353 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
355 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
358 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
360 ec.Report.SymbolRelatedToPreviousError (type);
361 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
362 type.GetSignatureForError (), name);
365 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
367 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
368 // Already reported as CS1612
369 } else if (rhs == EmptyExpression.OutAccess) {
370 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
372 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
376 protected void Error_VoidPointerOperation (ResolveContext rc)
378 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
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)
472 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
473 return ErrorExpression.Instance; // TODO: Add location
478 /// Resolves an expression and performs semantic analysis on it.
480 public Expression Resolve (ResolveContext rc)
482 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
486 /// Resolves an expression for LValue assignment
490 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
491 /// checking and assertion checking on what we expect from Resolve
493 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
495 int errors = ec.Report.Errors;
496 bool out_access = right_side == EmptyExpression.OutAccess;
498 Expression e = DoResolveLValue (ec, right_side);
500 if (e != null && out_access && !(e is IMemoryLocation)) {
501 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
502 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
504 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
505 // e.GetType () + " " + e.GetSignatureForError ());
510 if (errors == ec.Report.Errors) {
511 Error_ValueAssignment (ec, right_side);
516 if (e.eclass == ExprClass.Unresolved)
517 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
519 if ((e.type == null) && !(e is GenericTypeExpr))
520 throw new Exception ("Expression " + e + " did not set its type after Resolve");
525 public Constant ResolveLabelConstant (ResolveContext rc)
527 var expr = Resolve (rc);
531 Constant c = expr as Constant;
533 if (c.type != InternalType.ErrorType)
534 rc.Report.Error (150, StartLocation, "A constant value is expected");
542 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
544 rc.Module.Compiler.Report.Error (182, loc,
545 "An attribute argument must be a constant expression, typeof expression or array creation expression");
549 /// Emits the code for the expression
553 /// The Emit method is invoked to generate the code
554 /// for the expression.
556 public abstract void Emit (EmitContext ec);
559 // Emit code to branch to @target if this expression is equivalent to @on_true.
560 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
561 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
562 // including the use of conditional branches. Note also that a branch MUST be emitted
563 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
566 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
569 // Emit this expression for its side effects, not for its value.
570 // The default implementation is to emit the value, and then throw it away.
571 // Subclasses can provide more efficient implementations, but those MUST be equivalent
572 public virtual void EmitSideEffect (EmitContext ec)
575 ec.Emit (OpCodes.Pop);
579 // Emits the expression into temporary field variable. The method
580 // should be used for await expressions only
582 public virtual Expression EmitToField (EmitContext ec)
585 // This is the await prepare Emit method. When emitting code like
586 // a + b we emit code like
592 // For await a + await b we have to interfere the flow to keep the
593 // stack clean because await yields from the expression. The emit
596 // a = a.EmitToField () // a is changed to temporary field access
597 // b = b.EmitToField ()
603 // The idea is to emit expression and leave the stack empty with
604 // result value still available.
606 // Expressions should override this default implementation when
607 // optimized version can be provided (e.g. FieldExpr)
610 // We can optimize for side-effect free expressions, they can be
611 // emitted out of order
613 if (IsSideEffectFree)
616 bool needs_temporary = ContainsEmitWithAwait ();
617 if (!needs_temporary)
620 // Emit original code
621 var field = EmitToFieldSource (ec);
624 // Store the result to temporary field when we
625 // cannot load `this' directly
627 field = ec.GetTemporaryField (type);
628 if (needs_temporary) {
630 // Create temporary local (we cannot load `this' before Emit)
632 var temp = ec.GetTemporaryLocal (type);
633 ec.Emit (OpCodes.Stloc, temp);
636 ec.Emit (OpCodes.Ldloc, temp);
637 field.EmitAssignFromStack (ec);
639 ec.FreeTemporaryLocal (temp, type);
641 field.EmitAssignFromStack (ec);
648 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
651 // Default implementation calls Emit method
657 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
659 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
660 bool contains_await = false;
662 for (int i = 1; i < expressions.Count; ++i) {
663 if (expressions[i].ContainsEmitWithAwait ()) {
664 contains_await = true;
669 if (contains_await) {
670 for (int i = 0; i < expressions.Count; ++i) {
671 expressions[i] = expressions[i].EmitToField (ec);
676 for (int i = 0; i < expressions.Count; ++i) {
677 expressions[i].Emit (ec);
682 /// Protected constructor. Only derivate types should
683 /// be able to be created
686 protected Expression ()
691 /// Returns a fully formed expression after a MemberLookup
694 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
696 if (spec is EventSpec)
697 return new EventExpr ((EventSpec) spec, loc);
698 if (spec is ConstSpec)
699 return new ConstantExpr ((ConstSpec) spec, loc);
700 if (spec is FieldSpec)
701 return new FieldExpr ((FieldSpec) spec, loc);
702 if (spec is PropertySpec)
703 return new PropertyExpr ((PropertySpec) spec, loc);
704 if (spec is TypeSpec)
705 return new TypeExpression (((TypeSpec) spec), loc);
710 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
712 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
714 rc.Report.SymbolRelatedToPreviousError (type);
716 // Report meaningful error for struct as they always have default ctor in C# context
717 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
719 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
720 type.GetSignatureForError ());
726 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
727 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
728 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
731 return r.ResolveMember<MethodSpec> (rc, ref args);
735 public enum MemberLookupRestrictions
741 PlayScriptConversion = 1 << 4
745 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
746 // `qualifier_type' or null to lookup members in the current class.
748 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
750 var members = MemberCache.FindMembers (queried_type, name, false);
754 MemberSpec non_method = null;
755 MemberSpec ambig_non_method = null;
757 for (int i = 0; i < members.Count; ++i) {
758 var member = members[i];
760 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
761 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
764 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
767 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
771 if (!member.IsAccessible (rc))
775 // With runtime binder we can have a situation where queried type is inaccessible
776 // because it came via dynamic object, the check about inconsisted accessibility
777 // had no effect as the type was unknown during compilation
780 // private class N { }
782 // public dynamic Foo ()
788 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
792 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
793 if (member is MethodSpec) {
795 // Interface members that are hidden by class members are removed from the set. This
796 // step only has an effect if T is a type parameter and T has both an effective base
797 // class other than object and a non-empty effective interface set
799 var tps = queried_type as TypeParameterSpec;
800 if (tps != null && tps.HasTypeConstraint)
801 members = RemoveHiddenTypeParameterMethods (members);
803 return new MethodGroupExpr (members, queried_type, loc);
806 if (!Invocation.IsMemberInvocable (member))
810 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
812 } else if (!errorMode && !member.IsNotCSharpCompatible) {
814 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
815 // T has both an effective base class other than object and a non-empty effective interface set.
817 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
819 var tps = queried_type as TypeParameterSpec;
820 if (tps != null && tps.HasTypeConstraint) {
821 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
824 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
830 ambig_non_method = member;
834 if (non_method != null) {
835 if (ambig_non_method != null && rc != null) {
836 var report = rc.Module.Compiler.Report;
837 report.SymbolRelatedToPreviousError (non_method);
838 report.SymbolRelatedToPreviousError (ambig_non_method);
839 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
840 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
843 if (non_method is MethodSpec)
844 return new MethodGroupExpr (members, queried_type, loc);
846 return ExprClassFromMemberInfo (non_method, loc);
849 if (members[0].DeclaringType.BaseType == null)
852 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
854 } while (members != null);
859 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
861 if (members.Count < 2)
865 // If M is a method, then all non-method members declared in an interface declaration
866 // are removed from the set, and all methods with the same signature as M declared in
867 // an interface declaration are removed from the set
871 for (int i = 0; i < members.Count; ++i) {
872 var method = members[i] as MethodSpec;
873 if (method == null) {
876 members = new List<MemberSpec> (members);
879 members.RemoveAt (i--);
883 if (!method.DeclaringType.IsInterface)
886 for (int ii = 0; ii < members.Count; ++ii) {
887 var candidate = members[ii] as MethodSpec;
888 if (candidate == null || !candidate.DeclaringType.IsClass)
891 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
896 members = new List<MemberSpec> (members);
899 members.RemoveAt (i--);
907 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
909 throw new NotImplementedException ();
912 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
914 if (t == InternalType.ErrorType)
917 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
918 oper, t.GetSignatureForError ());
921 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
923 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
927 /// Returns an expression that can be used to invoke operator true
928 /// on the expression if it exists.
930 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
932 return GetOperatorTrueOrFalse (ec, e, true, loc);
936 /// Returns an expression that can be used to invoke operator false
937 /// on the expression if it exists.
939 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
941 return GetOperatorTrueOrFalse (ec, e, false, loc);
944 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
946 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
947 var methods = MemberCache.GetUserOperator (e.type, op, false);
951 Arguments arguments = new Arguments (1);
952 arguments.Add (new Argument (e));
954 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
955 var oper = res.ResolveOperator (ec, ref arguments);
960 return new UserOperatorCall (oper, arguments, null, loc);
963 public virtual string ExprClassName
967 case ExprClass.Unresolved:
969 case ExprClass.Value:
971 case ExprClass.Variable:
973 case ExprClass.Namespace:
977 case ExprClass.MethodGroup:
978 return "method group";
979 case ExprClass.PropertyAccess:
980 return "property access";
981 case ExprClass.EventAccess:
982 return "event access";
983 case ExprClass.IndexerAccess:
984 return "indexer access";
985 case ExprClass.Nothing:
987 case ExprClass.TypeParameter:
988 return "type parameter";
990 throw new Exception ("Should not happen");
995 /// Reports that we were expecting `expr' to be of class `expected'
997 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
999 var name = memberExpr.GetSignatureForError ();
1001 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1004 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1006 string [] valid = new string [4];
1009 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1010 valid [count++] = "variable";
1011 valid [count++] = "value";
1014 if ((flags & ResolveFlags.Type) != 0)
1015 valid [count++] = "type";
1017 if ((flags & ResolveFlags.MethodGroup) != 0)
1018 valid [count++] = "method group";
1021 valid [count++] = "unknown";
1023 StringBuilder sb = new StringBuilder (valid [0]);
1024 for (int i = 1; i < count - 1; i++) {
1026 sb.Append (valid [i]);
1029 sb.Append ("' or `");
1030 sb.Append (valid [count - 1]);
1033 ec.Report.Error (119, loc,
1034 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1037 public static void UnsafeError (ResolveContext ec, Location loc)
1039 UnsafeError (ec.Report, loc);
1042 public static void UnsafeError (Report Report, Location loc)
1044 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1048 // Converts `source' to an int, uint, long or ulong.
1050 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
1052 var btypes = ec.BuiltinTypes;
1054 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1055 Arguments args = new Arguments (1);
1056 args.Add (new Argument (source));
1057 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1060 Expression converted;
1062 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1063 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1064 if (converted == null)
1065 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1066 if (converted == null)
1067 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1068 if (converted == null)
1069 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1071 if (converted == null) {
1072 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1078 // Only positive constants are allowed at compile time
1080 Constant c = converted as Constant;
1081 if (c != null && c.IsNegative)
1082 Error_NegativeArrayIndex (ec, source.loc);
1084 // No conversion needed to array index
1085 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1088 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1092 // Derived classes implement this method by cloning the fields that
1093 // could become altered during the Resolve stage
1095 // Only expressions that are created for the parser need to implement
1098 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1100 throw new NotImplementedException (
1102 "CloneTo not implemented for expression {0}", this.GetType ()));
1106 // Clones an expression created by the parser.
1108 // We only support expressions created by the parser so far, not
1109 // expressions that have been resolved (many more classes would need
1110 // to implement CloneTo).
1112 // This infrastructure is here merely for Lambda expressions which
1113 // compile the same code using different type values for the same
1114 // arguments to find the correct overload
1116 public virtual Expression Clone (CloneContext clonectx)
1118 Expression cloned = (Expression) MemberwiseClone ();
1119 CloneTo (clonectx, cloned);
1125 // Implementation of expression to expression tree conversion
1127 public abstract Expression CreateExpressionTree (ResolveContext ec);
1129 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1131 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1134 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1136 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1139 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1141 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1144 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1146 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1150 return new TypeExpression (t, loc);
1154 // Implemented by all expressions which support conversion from
1155 // compiler expression to invokable runtime expression. Used by
1156 // dynamic C# binder.
1158 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1160 throw new NotImplementedException ("MakeExpression for " + GetType ());
1163 public virtual object Accept (StructuralVisitor visitor)
1165 return visitor.Visit (this);
1170 /// This is just a base class for expressions that can
1171 /// appear on statements (invocations, object creation,
1172 /// assignments, post/pre increment and decrement). The idea
1173 /// being that they would support an extra Emition interface that
1174 /// does not leave a result on the stack.
1176 public abstract class ExpressionStatement : Expression
1178 public ExpressionStatement ResolveStatement (BlockContext ec)
1180 Expression e = Resolve (ec);
1184 ExpressionStatement es = e as ExpressionStatement;
1186 Error_InvalidExpressionStatement (ec);
1189 // This is quite expensive warning, try to limit the damage
1191 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1192 WarningAsyncWithoutWait (ec, e);
1198 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1200 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1201 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1206 // Need to do full resolve because GetAwaiter can be extension method
1207 // available only in this context
1209 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1213 var arguments = new Arguments (0);
1214 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1219 // Use same check rules as for real await
1221 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1222 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1225 bc.Report.Warning (4014, 1, e.Location,
1226 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1230 var inv = e as Invocation;
1231 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1232 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1233 bc.Report.Warning (4014, 1, e.Location,
1234 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1240 /// Requests the expression to be emitted in a `statement'
1241 /// context. This means that no new value is left on the
1242 /// stack after invoking this method (constrasted with
1243 /// Emit that will always leave a value on the stack).
1245 public abstract void EmitStatement (EmitContext ec);
1247 public override void EmitSideEffect (EmitContext ec)
1254 /// This kind of cast is used to encapsulate the child
1255 /// whose type is child.Type into an expression that is
1256 /// reported to return "return_type". This is used to encapsulate
1257 /// expressions which have compatible types, but need to be dealt
1258 /// at higher levels with.
1260 /// For example, a "byte" expression could be encapsulated in one
1261 /// of these as an "unsigned int". The type for the expression
1262 /// would be "unsigned int".
1265 public abstract class TypeCast : Expression
1267 protected readonly Expression child;
1269 protected TypeCast (Expression child, TypeSpec return_type)
1271 eclass = child.eclass;
1272 loc = child.Location;
1277 public Expression Child {
1283 public override bool ContainsEmitWithAwait ()
1285 return child.ContainsEmitWithAwait ();
1288 public override Expression CreateExpressionTree (ResolveContext ec)
1290 Arguments args = new Arguments (2);
1291 args.Add (new Argument (child.CreateExpressionTree (ec)));
1292 args.Add (new Argument (new TypeOf (type, loc)));
1294 if (type.IsPointer || child.Type.IsPointer)
1295 Error_PointerInsideExpressionTree (ec);
1297 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1300 protected override Expression DoResolve (ResolveContext ec)
1302 // This should never be invoked, we are born in fully
1303 // initialized state.
1308 public override void Emit (EmitContext ec)
1313 public override SLE.Expression MakeExpression (BuilderContext ctx)
1316 return base.MakeExpression (ctx);
1318 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1319 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1320 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1324 protected override void CloneTo (CloneContext clonectx, Expression t)
1329 public override bool IsNull {
1330 get { return child.IsNull; }
1334 public class EmptyCast : TypeCast {
1335 EmptyCast (Expression child, TypeSpec target_type)
1336 : base (child, target_type)
1340 public static Expression Create (Expression child, TypeSpec type)
1342 Constant c = child as Constant;
1344 var enum_constant = c as EnumConstant;
1345 if (enum_constant != null)
1346 c = enum_constant.Child;
1348 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1352 var res = c.ConvertImplicitly (type);
1358 EmptyCast e = child as EmptyCast;
1360 return new EmptyCast (e.child, type);
1362 return new EmptyCast (child, type);
1365 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1367 child.EmitBranchable (ec, label, on_true);
1370 public override void EmitSideEffect (EmitContext ec)
1372 child.EmitSideEffect (ec);
1377 // Used for predefined type user operator (no obsolete check, etc.)
1379 public class OperatorCast : TypeCast
1381 readonly MethodSpec conversion_operator;
1383 public OperatorCast (Expression expr, TypeSpec target_type)
1384 : this (expr, target_type, target_type, false)
1388 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1389 : this (expr, target_type, target_type, find_explicit)
1393 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1394 : base (expr, returnType)
1396 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1397 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1400 foreach (MethodSpec oper in mi) {
1401 if (oper.ReturnType != returnType)
1404 if (oper.Parameters.Types[0] == expr.Type) {
1405 conversion_operator = oper;
1411 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1412 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1415 public override void Emit (EmitContext ec)
1418 ec.Emit (OpCodes.Call, conversion_operator);
1423 // Constant specialization of EmptyCast.
1424 // We need to special case this since an empty cast of
1425 // a constant is still a constant.
1427 public class EmptyConstantCast : Constant
1429 public readonly Constant child;
1431 public EmptyConstantCast (Constant child, TypeSpec type)
1432 : base (child.Location)
1435 throw new ArgumentNullException ("child");
1438 this.eclass = child.eclass;
1442 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1444 if (child.Type == target_type)
1447 // FIXME: check that 'type' can be converted to 'target_type' first
1448 return child.ConvertExplicitly (in_checked_context, target_type);
1451 public override Expression CreateExpressionTree (ResolveContext ec)
1453 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1454 child.CreateExpressionTree (ec),
1455 new TypeOf (type, loc));
1458 Error_PointerInsideExpressionTree (ec);
1460 return CreateExpressionFactoryCall (ec, "Convert", args);
1463 public override bool IsDefaultValue {
1464 get { return child.IsDefaultValue; }
1467 public override bool IsNegative {
1468 get { return child.IsNegative; }
1471 public override bool IsNull {
1472 get { return child.IsNull; }
1475 public override bool IsOneInteger {
1476 get { return child.IsOneInteger; }
1479 public override bool IsSideEffectFree {
1481 return child.IsSideEffectFree;
1485 public override bool IsZeroInteger {
1486 get { return child.IsZeroInteger; }
1489 public override void Emit (EmitContext ec)
1494 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1496 child.EmitBranchable (ec, label, on_true);
1498 // Only to make verifier happy
1499 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1500 ec.Emit (OpCodes.Unbox_Any, type);
1503 public override void EmitSideEffect (EmitContext ec)
1505 child.EmitSideEffect (ec);
1508 public override object GetValue ()
1510 return child.GetValue ();
1513 public override string GetValueAsLiteral ()
1515 return child.GetValueAsLiteral ();
1518 public override long GetValueAsLong ()
1520 return child.GetValueAsLong ();
1523 public override Constant ConvertImplicitly (TypeSpec target_type)
1525 if (type == target_type)
1528 // FIXME: Do we need to check user conversions?
1529 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1532 return child.ConvertImplicitly (target_type);
1537 /// This class is used to wrap literals which belong inside Enums
1539 public class EnumConstant : Constant
1541 public Constant Child;
1543 public EnumConstant (Constant child, TypeSpec enum_type)
1544 : base (child.Location)
1548 this.eclass = ExprClass.Value;
1549 this.type = enum_type;
1552 protected EnumConstant (Location loc)
1557 public override void Emit (EmitContext ec)
1562 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1564 Child.EncodeAttributeValue (rc, enc, Child.Type);
1567 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1569 Child.EmitBranchable (ec, label, on_true);
1572 public override void EmitSideEffect (EmitContext ec)
1574 Child.EmitSideEffect (ec);
1577 public override string GetSignatureForError()
1579 return Type.GetSignatureForError ();
1582 public override object GetValue ()
1584 return Child.GetValue ();
1588 public override object GetTypedValue ()
1591 // The method can be used in dynamic context only (on closed types)
1593 // System.Enum.ToObject cannot be called on dynamic types
1594 // EnumBuilder has to be used, but we cannot use EnumBuilder
1595 // because it does not properly support generics
1597 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1601 public override string GetValueAsLiteral ()
1603 return Child.GetValueAsLiteral ();
1606 public override long GetValueAsLong ()
1608 return Child.GetValueAsLong ();
1611 public EnumConstant Increment()
1613 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1616 public override bool IsDefaultValue {
1618 return Child.IsDefaultValue;
1622 public override bool IsSideEffectFree {
1624 return Child.IsSideEffectFree;
1628 public override bool IsZeroInteger {
1629 get { return Child.IsZeroInteger; }
1632 public override bool IsNegative {
1634 return Child.IsNegative;
1638 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1640 if (Child.Type == target_type)
1643 return Child.ConvertExplicitly (in_checked_context, target_type);
1646 public override Constant ConvertImplicitly (TypeSpec type)
1648 if (this.type == type) {
1652 if (!Convert.ImplicitStandardConversionExists (this, type)){
1656 return Child.ConvertImplicitly (type);
1661 /// This kind of cast is used to encapsulate Value Types in objects.
1663 /// The effect of it is to box the value type emitted by the previous
1666 public class BoxedCast : TypeCast {
1668 public BoxedCast (Expression expr, TypeSpec target_type)
1669 : base (expr, target_type)
1671 eclass = ExprClass.Value;
1674 protected override Expression DoResolve (ResolveContext ec)
1676 // This should never be invoked, we are born in fully
1677 // initialized state.
1682 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1684 // Only boxing to object type is supported
1685 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1686 base.EncodeAttributeValue (rc, enc, targetType);
1690 enc.Encode (child.Type);
1691 child.EncodeAttributeValue (rc, enc, child.Type);
1694 public override void Emit (EmitContext ec)
1698 ec.Emit (OpCodes.Box, child.Type);
1701 public override void EmitSideEffect (EmitContext ec)
1703 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1704 // so, we need to emit the box+pop instructions in most cases
1705 if (child.Type.IsStruct &&
1706 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1707 child.EmitSideEffect (ec);
1709 base.EmitSideEffect (ec);
1713 public class UnboxCast : TypeCast {
1714 public UnboxCast (Expression expr, TypeSpec return_type)
1715 : base (expr, return_type)
1719 protected override Expression DoResolve (ResolveContext ec)
1721 // This should never be invoked, we are born in fully
1722 // initialized state.
1727 public override void Emit (EmitContext ec)
1731 ec.Emit (OpCodes.Unbox_Any, type);
1736 /// This is used to perform explicit numeric conversions.
1738 /// Explicit numeric conversions might trigger exceptions in a checked
1739 /// context, so they should generate the conv.ovf opcodes instead of
1742 public class ConvCast : TypeCast {
1743 public enum Mode : byte {
1744 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1746 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1747 U2_I1, U2_U1, U2_I2, U2_CH,
1748 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1749 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1750 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1751 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1752 CH_I1, CH_U1, CH_I2,
1753 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1754 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1760 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1761 : base (child, return_type)
1766 protected override Expression DoResolve (ResolveContext ec)
1768 // This should never be invoked, we are born in fully
1769 // initialized state.
1774 public override string ToString ()
1776 return String.Format ("ConvCast ({0}, {1})", mode, child);
1779 public override void Emit (EmitContext ec)
1785 public static void Emit (EmitContext ec, Mode mode)
1787 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1789 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1790 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1791 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1792 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1793 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1795 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1796 case Mode.U1_CH: /* nothing */ break;
1798 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1799 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1800 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1801 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1802 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1803 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1805 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1806 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1807 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1808 case Mode.U2_CH: /* nothing */ break;
1810 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1811 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1812 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1813 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1814 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1815 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1816 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1818 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1819 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1820 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1821 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1822 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1823 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1825 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1826 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1827 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1828 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1829 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1830 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1831 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1832 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1833 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1835 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1836 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1837 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1838 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1839 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1840 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1841 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1842 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1843 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1845 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1846 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1847 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1849 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1850 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1851 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1852 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1853 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1854 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1855 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1856 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1857 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1859 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1860 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1861 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1862 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1863 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1864 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1865 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1866 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1867 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1868 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1870 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1874 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1875 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1876 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1877 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1878 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1880 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1881 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1883 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1884 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1885 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1886 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1887 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1888 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1890 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1891 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1892 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1893 case Mode.U2_CH: /* nothing */ break;
1895 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1896 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1897 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1898 case Mode.I4_U4: /* nothing */ break;
1899 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1900 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1901 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1903 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1904 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1905 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1906 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1907 case Mode.U4_I4: /* nothing */ break;
1908 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1910 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1911 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1912 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1913 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1914 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1915 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1916 case Mode.I8_U8: /* nothing */ break;
1917 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1918 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1920 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1921 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1922 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1923 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1924 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1925 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1926 case Mode.U8_I8: /* nothing */ break;
1927 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1928 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1930 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1931 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1932 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1934 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1935 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1936 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1937 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1938 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1939 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1940 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1941 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1942 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1944 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1945 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1946 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1947 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1948 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1949 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1950 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1951 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1952 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1953 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1955 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1961 class OpcodeCast : TypeCast
1965 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1966 : base (child, return_type)
1971 protected override Expression DoResolve (ResolveContext ec)
1973 // This should never be invoked, we are born in fully
1974 // initialized state.
1979 public override void Emit (EmitContext ec)
1985 public TypeSpec UnderlyingType {
1986 get { return child.Type; }
1991 // Opcode casts expression with 2 opcodes but only
1992 // single expression tree node
1994 class OpcodeCastDuplex : OpcodeCast
1996 readonly OpCode second;
1998 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1999 : base (child, returnType, first)
2001 this.second = second;
2004 public override void Emit (EmitContext ec)
2012 /// This kind of cast is used to encapsulate a child and cast it
2013 /// to the class requested
2015 public sealed class ClassCast : TypeCast {
2016 readonly bool forced;
2018 public ClassCast (Expression child, TypeSpec return_type)
2019 : base (child, return_type)
2023 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2024 : base (child, return_type)
2026 this.forced = forced;
2029 public override void Emit (EmitContext ec)
2033 bool gen = TypeManager.IsGenericParameter (child.Type);
2035 ec.Emit (OpCodes.Box, child.Type);
2037 if (type.IsGenericParameter) {
2038 ec.Emit (OpCodes.Unbox_Any, type);
2045 ec.Emit (OpCodes.Castclass, type);
2050 // Created during resolving pahse when an expression is wrapped or constantified
2051 // and original expression can be used later (e.g. for expression trees)
2053 public class ReducedExpression : Expression
2055 public sealed class ReducedConstantExpression : EmptyConstantCast
2057 readonly Expression orig_expr;
2059 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2060 : base (expr, expr.Type)
2062 this.orig_expr = orig_expr;
2065 public override Constant ConvertImplicitly (TypeSpec target_type)
2067 Constant c = base.ConvertImplicitly (target_type);
2069 c = new ReducedConstantExpression (c, orig_expr);
2074 public override Expression CreateExpressionTree (ResolveContext ec)
2076 return orig_expr.CreateExpressionTree (ec);
2079 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2081 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2083 c = new ReducedConstantExpression (c, orig_expr);
2087 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2090 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2092 if (orig_expr is Conditional)
2093 child.EncodeAttributeValue (rc, enc, targetType);
2095 base.EncodeAttributeValue (rc, enc, targetType);
2099 sealed class ReducedExpressionStatement : ExpressionStatement
2101 readonly Expression orig_expr;
2102 readonly ExpressionStatement stm;
2104 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2106 this.orig_expr = orig;
2108 this.eclass = stm.eclass;
2109 this.type = stm.Type;
2111 this.loc = orig.Location;
2114 public override bool ContainsEmitWithAwait ()
2116 return stm.ContainsEmitWithAwait ();
2119 public override Expression CreateExpressionTree (ResolveContext ec)
2121 return orig_expr.CreateExpressionTree (ec);
2124 protected override Expression DoResolve (ResolveContext ec)
2129 public override void Emit (EmitContext ec)
2134 public override void EmitStatement (EmitContext ec)
2136 stm.EmitStatement (ec);
2140 readonly Expression expr, orig_expr;
2142 private ReducedExpression (Expression expr, Expression orig_expr)
2145 this.eclass = expr.eclass;
2146 this.type = expr.Type;
2147 this.orig_expr = orig_expr;
2148 this.loc = orig_expr.Location;
2153 public override bool IsSideEffectFree {
2155 return expr.IsSideEffectFree;
2159 public Expression OriginalExpression {
2167 public override bool ContainsEmitWithAwait ()
2169 return expr.ContainsEmitWithAwait ();
2173 // Creates fully resolved expression switcher
2175 public static Constant Create (Constant expr, Expression original_expr)
2177 if (expr.eclass == ExprClass.Unresolved)
2178 throw new ArgumentException ("Unresolved expression");
2180 return new ReducedConstantExpression (expr, original_expr);
2183 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2185 return new ReducedExpressionStatement (s, orig);
2188 public static Expression Create (Expression expr, Expression original_expr)
2190 return Create (expr, original_expr, true);
2194 // Creates unresolved reduce expression. The original expression has to be
2195 // already resolved. Created expression is constant based based on `expr'
2196 // value unless canBeConstant is used
2198 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2200 if (canBeConstant) {
2201 Constant c = expr as Constant;
2203 return Create (c, original_expr);
2206 ExpressionStatement s = expr as ExpressionStatement;
2208 return Create (s, original_expr);
2210 if (expr.eclass == ExprClass.Unresolved)
2211 throw new ArgumentException ("Unresolved expression");
2213 return new ReducedExpression (expr, original_expr);
2216 public override Expression CreateExpressionTree (ResolveContext ec)
2218 return orig_expr.CreateExpressionTree (ec);
2221 protected override Expression DoResolve (ResolveContext ec)
2226 public override void Emit (EmitContext ec)
2231 public override Expression EmitToField (EmitContext ec)
2233 return expr.EmitToField(ec);
2236 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2238 expr.EmitBranchable (ec, target, on_true);
2241 public override SLE.Expression MakeExpression (BuilderContext ctx)
2243 return orig_expr.MakeExpression (ctx);
2248 // Standard composite pattern
2250 public abstract class CompositeExpression : Expression
2252 protected Expression expr;
2254 protected CompositeExpression (Expression expr)
2257 this.loc = expr.Location;
2260 public override bool ContainsEmitWithAwait ()
2262 return expr.ContainsEmitWithAwait ();
2265 public override Expression CreateExpressionTree (ResolveContext rc)
2267 return expr.CreateExpressionTree (rc);
2270 public Expression Child {
2271 get { return expr; }
2274 protected override Expression DoResolve (ResolveContext rc)
2276 expr = expr.Resolve (rc);
2279 eclass = expr.eclass;
2285 public override void Emit (EmitContext ec)
2290 public override bool IsNull {
2291 get { return expr.IsNull; }
2296 // Base of expressions used only to narrow resolve flow
2298 public abstract class ShimExpression : Expression
2300 protected Expression expr;
2302 protected ShimExpression (Expression expr)
2307 public Expression Expr {
2313 protected override void CloneTo (CloneContext clonectx, Expression t)
2318 ShimExpression target = (ShimExpression) t;
2319 target.expr = expr.Clone (clonectx);
2322 public override bool ContainsEmitWithAwait ()
2324 return expr.ContainsEmitWithAwait ();
2327 public override Expression CreateExpressionTree (ResolveContext ec)
2329 throw new NotSupportedException ("ET");
2332 public override void Emit (EmitContext ec)
2334 throw new InternalErrorException ("Missing Resolve call");
2340 // Unresolved type name expressions
2342 public abstract class ATypeNameExpression : FullNamedExpression
2345 protected TypeArguments targs;
2347 protected ATypeNameExpression (string name, Location l)
2353 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2360 protected ATypeNameExpression (string name, int arity, Location l)
2361 : this (name, new UnboundTypeArguments (arity), l)
2367 protected int Arity {
2369 return targs == null ? 0 : targs.Count;
2373 public bool HasTypeArguments {
2375 return targs != null && !targs.IsEmpty;
2379 public string Name {
2388 public TypeArguments TypeArguments {
2396 public override bool Equals (object obj)
2398 ATypeNameExpression atne = obj as ATypeNameExpression;
2399 return atne != null && atne.Name == Name &&
2400 (targs == null || targs.Equals (atne.targs));
2403 public override int GetHashCode ()
2405 return Name.GetHashCode ();
2408 // TODO: Move it to MemberCore
2409 public static string GetMemberType (MemberCore mc)
2415 if (mc is FieldBase)
2417 if (mc is MethodCore)
2419 if (mc is EnumMember)
2427 public override string GetSignatureForError ()
2429 if (targs != null) {
2430 return Name + "<" + targs.GetSignatureForError () + ">";
2436 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2440 /// SimpleName expressions are formed of a single word and only happen at the beginning
2441 /// of a dotted-name.
2443 public class SimpleName : ATypeNameExpression
2445 public SimpleName (string name, Location l)
2450 public SimpleName (string name, TypeArguments args, Location l)
2451 : base (name, args, l)
2455 public SimpleName (string name, int arity, Location l)
2456 : base (name, arity, l)
2460 public SimpleName GetMethodGroup ()
2462 return new SimpleName (Name, targs, loc);
2465 protected override Expression DoResolve (ResolveContext rc)
2467 var e = SimpleNameResolve (rc, null);
2469 var fe = e as FieldExpr;
2471 fe.VerifyAssignedStructField (rc, null);
2477 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2479 return SimpleNameResolve (ec, right_side);
2482 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2484 if (ctx.CurrentType != null) {
2485 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2486 if (member != null) {
2487 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2492 var report = ctx.Module.Compiler.Report;
2494 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2495 if (retval != null) {
2496 report.SymbolRelatedToPreviousError (retval.Type);
2497 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2501 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2502 if (retval != null) {
2503 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2507 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2508 if (ns_candidates != null) {
2509 if (ctx is UsingAliasNamespace.AliasContext) {
2510 report.Error (246, loc,
2511 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2512 ns_candidates[0], Name);
2514 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2515 report.Error (246, loc,
2516 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2520 report.Error (246, loc,
2521 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2526 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2528 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2531 if (fne.Type != null && Arity > 0) {
2532 if (HasTypeArguments) {
2533 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2534 if (ct.ResolveAsType (mc) == null)
2540 return new GenericOpenTypeExpr (fne.Type, loc);
2544 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2546 if (!(fne is Namespace))
2550 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2551 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2552 mc.Module.Compiler.Report.Error (1980, Location,
2553 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2554 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2557 fne = new DynamicTypeExpr (loc);
2558 fne.ResolveAsType (mc);
2564 Error_TypeOrNamespaceNotFound (mc);
2568 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2570 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2573 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2575 int lookup_arity = Arity;
2576 bool errorMode = false;
2578 Block current_block = rc.CurrentBlock;
2579 INamedBlockVariable variable = null;
2580 bool variable_found = false;
2584 // Stage 1: binding to local variables or parameters
2586 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2588 if (current_block != null && lookup_arity == 0) {
2589 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2590 if (!variable.IsDeclared) {
2591 // We found local name in accessible block but it's not
2592 // initialized yet, maybe the user wanted to bind to something else
2594 variable_found = true;
2596 e = variable.CreateReferenceExpression (rc, loc);
2599 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2608 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2610 TypeSpec member_type = rc.CurrentType;
2611 for (; member_type != null; member_type = member_type.DeclaringType) {
2612 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2616 var me = e as MemberExpr;
2618 // The name matches a type, defer to ResolveAsTypeStep
2626 if (variable != null) {
2627 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2628 rc.Report.Error (844, loc,
2629 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2630 Name, me.GetSignatureForError ());
2634 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2635 // Leave it to overload resolution to report correct error
2637 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2638 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2641 // LAMESPEC: again, ignores InvocableOnly
2642 if (variable != null) {
2643 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2644 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2648 // MemberLookup does not check accessors availability, this is actually needed for properties only
2650 var pe = me as PropertyExpr;
2653 // Break as there is no other overload available anyway
2654 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2655 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2658 pe.Getter = pe.PropertyInfo.Get;
2660 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2663 pe.Setter = pe.PropertyInfo.Set;
2668 // TODO: It's used by EventExpr -> FieldExpr transformation only
2669 // TODO: Should go to MemberAccess
2670 me = me.ResolveMemberAccess (rc, null, null);
2674 me.SetTypeArguments (rc, targs);
2681 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2683 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2684 if (IsPossibleTypeOrNamespace (rc)) {
2685 if (variable != null) {
2686 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2687 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2690 return ResolveAsTypeOrNamespace (rc);
2695 if (variable_found) {
2696 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2699 var tparams = rc.CurrentTypeParameters;
2700 if (tparams != null) {
2701 if (tparams.Find (Name) != null) {
2702 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2707 var ct = rc.CurrentType;
2709 if (ct.MemberDefinition.TypeParametersCount > 0) {
2710 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2711 if (ctp.Name == Name) {
2712 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2718 ct = ct.DeclaringType;
2719 } while (ct != null);
2722 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2723 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2725 rc.Report.SymbolRelatedToPreviousError (e.Type);
2726 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2730 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2732 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2733 return ErrorExpression.Instance;
2737 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2739 if (e.Type.Arity != Arity) {
2740 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2744 if (e is TypeExpr) {
2745 // TypeExpression does not have correct location
2746 if (e is TypeExpression)
2747 e = new TypeExpression (e.Type, loc);
2753 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2756 return ErrorExpression.Instance;
2759 if (rc.Module.Evaluator != null) {
2760 var fi = rc.Module.Evaluator.LookupField (Name);
2762 return new FieldExpr (fi.Item1, loc);
2770 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2772 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2777 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2778 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2782 if (right_side != null) {
2783 e = e.ResolveLValue (ec, right_side);
2791 public override object Accept (StructuralVisitor visitor)
2793 return visitor.Visit (this);
2798 /// Represents a namespace or a type. The name of the class was inspired by
2799 /// section 10.8.1 (Fully Qualified Names).
2801 public abstract class FullNamedExpression : Expression
2803 protected override void CloneTo (CloneContext clonectx, Expression target)
2805 // Do nothing, most unresolved type expressions cannot be
2806 // resolved to different type
2809 public override bool ContainsEmitWithAwait ()
2814 public override Expression CreateExpressionTree (ResolveContext ec)
2816 throw new NotSupportedException ("ET");
2819 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2822 // This is used to resolve the expression as a type, a null
2823 // value will be returned if the expression is not a type
2826 public override TypeSpec ResolveAsType (IMemberContext mc)
2828 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2833 TypeExpr te = fne as TypeExpr;
2835 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2843 var dep = type.GetMissingDependencies ();
2845 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2848 if (type.Kind == MemberKind.Void) {
2849 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2853 // Obsolete checks cannot be done when resolving base context as they
2854 // require type dependencies to be set but we are in process of resolving them
2856 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2857 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2858 if (obsolete_attr != null && !mc.IsObsolete) {
2859 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2867 public override void Emit (EmitContext ec)
2869 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2870 GetSignatureForError ());
2875 /// Expression that evaluates to a type
2877 public abstract class TypeExpr : FullNamedExpression
2879 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2885 protected sealed override Expression DoResolve (ResolveContext ec)
2891 public override bool Equals (object obj)
2893 TypeExpr tobj = obj as TypeExpr;
2897 return Type == tobj.Type;
2900 public override int GetHashCode ()
2902 return Type.GetHashCode ();
2907 /// Fully resolved Expression that already evaluated to a type
2909 public class TypeExpression : TypeExpr
2911 public TypeExpression (TypeSpec t, Location l)
2914 eclass = ExprClass.Type;
2918 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2925 /// This class denotes an expression which evaluates to a member
2926 /// of a struct or a class.
2928 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2931 // An instance expression associated with this member, if it's a
2932 // non-static member
2934 public Expression InstanceExpression;
2937 /// The name of this member.
2939 public abstract string Name {
2944 // When base.member is used
2946 public bool IsBase {
2947 get { return InstanceExpression is BaseThis; }
2951 /// Whether this is an instance member.
2953 public abstract bool IsInstance {
2958 /// Whether this is a static member.
2960 public abstract bool IsStatic {
2964 public abstract string KindName {
2968 protected abstract TypeSpec DeclaringType {
2972 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2974 return InstanceExpression.Type;
2979 // Converts best base candidate for virtual method starting from QueriedBaseType
2981 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2984 // Only when base.member is used and method is virtual
2990 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2991 // means for base.member access we have to find the closest match after we found best candidate
2993 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2995 // The method could already be what we are looking for
2997 TypeSpec[] targs = null;
2998 if (method.DeclaringType != InstanceExpression.Type) {
2999 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3000 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3001 if (base_override.IsGeneric)
3002 targs = method.TypeArguments;
3004 method = base_override;
3009 // When base access is used inside anonymous method/iterator/etc we need to
3010 // get back to the context of original type. We do it by emiting proxy
3011 // method in original class and rewriting base call to this compiler
3012 // generated method call which does the actual base invocation. This may
3013 // introduce redundant storey but with `this' only but it's tricky to avoid
3014 // at this stage as we don't know what expressions follow base
3016 if (rc.CurrentAnonymousMethod != null) {
3017 if (targs == null && method.IsGeneric) {
3018 targs = method.TypeArguments;
3019 method = method.GetGenericMethodDefinition ();
3022 if (method.Parameters.HasArglist)
3023 throw new NotImplementedException ("__arglist base call proxy");
3025 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3027 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3028 // get/set member expressions second call would fail to proxy because left expression
3029 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3030 // FIXME: The async check is another hack but will probably fail with mutators
3031 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3032 InstanceExpression = new This (loc).Resolve (rc);
3036 method = method.MakeGenericMethod (rc, targs);
3040 // Only base will allow this invocation to happen.
3042 if (method.IsAbstract) {
3043 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3049 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3051 if (InstanceExpression == null)
3054 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3055 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3056 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3061 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3063 if (InstanceExpression == null)
3066 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3069 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3071 var ct = rc.CurrentType;
3072 if (ct == qualifier)
3075 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3078 qualifier = qualifier.GetDefinition ();
3079 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3086 public override bool ContainsEmitWithAwait ()
3088 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3091 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3094 type = type.GetDefinition ();
3096 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3099 type = type.DeclaringType;
3100 } while (type != null);
3105 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3107 if (InstanceExpression != null) {
3108 InstanceExpression = InstanceExpression.Resolve (rc);
3109 CheckProtectedMemberAccess (rc, member);
3112 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3113 UnsafeError (rc, loc);
3116 var dep = member.GetMissingDependencies ();
3118 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3121 if (!rc.IsObsolete) {
3122 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3124 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3127 if (!(member is FieldSpec))
3128 member.MemberDefinition.SetIsUsed ();
3131 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3133 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3136 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3138 rc.Report.SymbolRelatedToPreviousError (member);
3139 rc.Report.Error (1540, loc,
3140 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3141 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3144 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3146 if (!ResolveInstanceExpressionCore (rc, rhs))
3150 // Check intermediate value modification which won't have any effect
3152 if (rhs != null && InstanceExpression.Type.IsStruct &&
3153 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3155 if (rc.CurrentInitializerVariable != null) {
3156 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3157 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3159 rc.Report.Error (1612, loc,
3160 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3161 InstanceExpression.GetSignatureForError ());
3168 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3171 if (InstanceExpression != null) {
3172 if (InstanceExpression is TypeExpr) {
3173 var t = InstanceExpression.Type;
3175 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3176 if (oa != null && !rc.IsObsolete) {
3177 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3180 t = t.DeclaringType;
3181 } while (t != null);
3183 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3184 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3185 rc.Report.Error (176, loc,
3186 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3187 GetSignatureForError ());
3191 InstanceExpression = null;
3197 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3198 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3199 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3200 rc.Report.Error (236, loc,
3201 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3202 GetSignatureForError ());
3204 rc.Report.Error (120, loc,
3205 "An object reference is required to access non-static member `{0}'",
3206 GetSignatureForError ());
3208 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3212 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3213 rc.Report.Error (38, loc,
3214 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3215 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3218 InstanceExpression = new This (loc);
3219 if (this is FieldExpr && rc.CurrentBlock != null && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3220 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3221 InstanceExpression = InstanceExpression.Resolve (rc);
3224 InstanceExpression = InstanceExpression.Resolve (rc);
3230 var me = InstanceExpression as MemberExpr;
3232 me.ResolveInstanceExpressionCore (rc, rhs);
3234 // Using this check to detect probing instance expression resolve
3235 if (!rc.OmitStructFlowAnalysis) {
3236 var fe = me as FieldExpr;
3237 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3238 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3239 rc.Report.Warning (1690, 1, loc,
3240 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3241 me.GetSignatureForError ());
3249 // Run member-access postponed check once we know that
3250 // the expression is not field expression which is the only
3251 // expression which can use uninitialized this
3253 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3254 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3258 // Additional checks for l-value member access
3261 if (InstanceExpression is UnboxCast) {
3262 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3269 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3271 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3272 ec.Report.Warning (1720, 1, left.Location,
3273 "Expression will always cause a `{0}'", "System.NullReferenceException");
3276 InstanceExpression = left;
3280 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3282 TypeSpec instance_type = InstanceExpression.Type;
3283 if (TypeSpec.IsValueType (instance_type)) {
3284 if (InstanceExpression is IMemoryLocation) {
3285 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3287 // Cannot release the temporary variable when its address
3288 // is required to be on stack for any parent
3289 LocalTemporary t = new LocalTemporary (instance_type);
3290 InstanceExpression.Emit (ec);
3292 t.AddressOf (ec, AddressOp.Store);
3295 InstanceExpression.Emit (ec);
3297 // Only to make verifier happy
3298 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3299 ec.Emit (OpCodes.Box, instance_type);
3302 if (prepare_for_load)
3303 ec.Emit (OpCodes.Dup);
3306 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3309 public class ExtensionMethodCandidates
3311 readonly NamespaceContainer container;
3312 readonly IList<MethodSpec> methods;
3314 readonly IMemberContext context;
3316 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3318 this.context = context;
3319 this.methods = methods;
3320 this.container = nsContainer;
3321 this.index = lookupIndex;
3324 public NamespaceContainer Container {
3330 public IMemberContext Context {
3336 public int LookupIndex {
3342 public IList<MethodSpec> Methods {
3350 // Represents a group of extension method candidates for whole namespace
3352 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3354 ExtensionMethodCandidates candidates;
3355 public Expression ExtensionExpression;
3357 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3358 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3360 this.candidates = candidates;
3361 this.ExtensionExpression = extensionExpr;
3364 public override bool IsStatic {
3365 get { return true; }
3369 // For extension methodgroup we are not looking for base members but parent
3370 // namespace extension methods
3372 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3374 // TODO: candidates are null only when doing error reporting, that's
3375 // incorrect. We have to discover same extension methods in error mode
3376 if (candidates == null)
3379 int arity = type_arguments == null ? 0 : type_arguments.Count;
3381 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3382 if (candidates == null)
3385 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3388 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3390 // We are already here
3394 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3396 if (arguments == null)
3397 arguments = new Arguments (1);
3399 ExtensionExpression = ExtensionExpression.Resolve (ec);
3400 if (ExtensionExpression == null)
3403 var cand = candidates;
3404 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3405 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3407 // Restore candidates in case we are running in probing mode
3410 // Store resolved argument and restore original arguments
3412 // Clean-up modified arguments for error reporting
3413 arguments.RemoveAt (0);
3417 var me = ExtensionExpression as MemberExpr;
3419 me.ResolveInstanceExpression (ec, null);
3420 var fe = me as FieldExpr;
3422 fe.Spec.MemberDefinition.SetIsUsed ();
3425 InstanceExpression = null;
3429 #region IErrorHandler Members
3431 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3436 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3438 rc.Report.SymbolRelatedToPreviousError (best);
3439 rc.Report.Error (1928, loc,
3440 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3441 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3444 rc.Report.Error (1929, loc,
3445 "Extension method instance type `{0}' cannot be converted to `{1}'",
3446 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3452 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3457 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3466 /// MethodGroupExpr represents a group of method candidates which
3467 /// can be resolved to the best method overload
3469 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3471 protected IList<MemberSpec> Methods;
3472 MethodSpec best_candidate;
3473 TypeSpec best_candidate_return;
3474 protected TypeArguments type_arguments;
3476 SimpleName simple_name;
3477 protected TypeSpec queried_type;
3479 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3483 this.type = InternalType.MethodGroup;
3485 eclass = ExprClass.MethodGroup;
3486 queried_type = type;
3489 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3490 : this (new MemberSpec[] { m }, type, loc)
3496 public MethodSpec BestCandidate {
3498 return best_candidate;
3502 public TypeSpec BestCandidateReturnType {
3504 return best_candidate_return;
3508 public IList<MemberSpec> Candidates {
3514 protected override TypeSpec DeclaringType {
3516 return queried_type;
3520 public override bool IsInstance {
3522 if (best_candidate != null)
3523 return !best_candidate.IsStatic;
3529 public override bool IsStatic {
3531 if (best_candidate != null)
3532 return best_candidate.IsStatic;
3538 public override string KindName {
3539 get { return "method"; }
3542 public override string Name {
3544 if (best_candidate != null)
3545 return best_candidate.Name;
3548 return Methods.First ().Name;
3555 // When best candidate is already know this factory can be used
3556 // to avoid expensive overload resolution to be called
3558 // NOTE: InstanceExpression has to be set manually
3560 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3562 return new MethodGroupExpr (best, queriedType, loc) {
3563 best_candidate = best,
3564 best_candidate_return = best.ReturnType
3568 public override string GetSignatureForError ()
3570 if (best_candidate != null)
3571 return best_candidate.GetSignatureForError ();
3573 return Methods.First ().GetSignatureForError ();
3576 public override Expression CreateExpressionTree (ResolveContext ec)
3578 if (best_candidate == null) {
3579 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3583 if (best_candidate.IsConditionallyExcluded (ec, loc))
3584 ec.Report.Error (765, loc,
3585 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3587 return new TypeOfMethod (best_candidate, loc);
3590 protected override Expression DoResolve (ResolveContext ec)
3592 this.eclass = ExprClass.MethodGroup;
3594 if (InstanceExpression != null) {
3595 InstanceExpression = InstanceExpression.Resolve (ec);
3596 if (InstanceExpression == null)
3603 public override void Emit (EmitContext ec)
3605 throw new NotSupportedException ();
3608 public void EmitCall (EmitContext ec, Arguments arguments)
3610 var call = new CallEmitter ();
3611 call.InstanceExpression = InstanceExpression;
3612 call.Emit (ec, best_candidate, arguments, loc);
3615 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3617 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3618 Name, target.GetSignatureForError ());
3621 public static bool IsExtensionMethodArgument (Expression expr)
3624 // LAMESPEC: No details about which expressions are not allowed
3626 return !(expr is TypeExpr) && !(expr is BaseThis);
3630 /// Find the Applicable Function Members (7.4.2.1)
3632 /// me: Method Group expression with the members to select.
3633 /// it might contain constructors or methods (or anything
3634 /// that maps to a method).
3636 /// Arguments: ArrayList containing resolved Argument objects.
3638 /// loc: The location if we want an error to be reported, or a Null
3639 /// location for "probing" purposes.
3641 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3642 /// that is the best match of me on Arguments.
3645 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3647 // TODO: causes issues with probing mode, remove explicit Kind check
3648 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3651 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3652 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3653 r.BaseMembersProvider = this;
3654 r.InstanceQualifier = this;
3657 if (cerrors != null)
3658 r.CustomErrors = cerrors;
3660 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3661 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3662 if (best_candidate == null)
3663 return r.BestCandidateIsDynamic ? this : null;
3665 // Overload resolver had to create a new method group, all checks bellow have already been executed
3666 if (r.BestCandidateNewMethodGroup != null)
3667 return r.BestCandidateNewMethodGroup;
3669 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3670 if (InstanceExpression != null) {
3671 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3672 InstanceExpression = null;
3674 if (best_candidate.IsStatic && simple_name != null) {
3675 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3678 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
3682 ResolveInstanceExpression (ec, null);
3685 var base_override = CandidateToBaseOverride (ec, best_candidate);
3686 if (base_override == best_candidate) {
3687 best_candidate_return = r.BestCandidateReturnType;
3689 best_candidate = base_override;
3690 best_candidate_return = best_candidate.ReturnType;
3693 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3694 ConstraintChecker cc = new ConstraintChecker (ec);
3695 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3699 // Additional check for possible imported base override method which
3700 // could not be done during IsOverrideMethodBaseTypeAccessible
3702 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3703 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3704 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3705 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3711 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3713 var fe = left as FieldExpr;
3716 // Using method-group on struct fields makes the struct assigned. I am not sure
3717 // why but that's what .net does
3719 fe.Spec.MemberDefinition.SetIsAssigned ();
3722 simple_name = original;
3723 return base.ResolveMemberAccess (ec, left, original);
3726 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3728 type_arguments = ta;
3731 #region IBaseMembersProvider Members
3733 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3735 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3738 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3740 if (queried_type == member.DeclaringType)
3743 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3744 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3748 // Extension methods lookup after ordinary methods candidates failed to apply
3750 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3752 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
3755 InstanceExpression = InstanceExpression.Resolve (rc);
3756 if (!IsExtensionMethodArgument (InstanceExpression))
3759 int arity = type_arguments == null ? 0 : type_arguments.Count;
3760 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3761 if (methods == null)
3764 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3765 emg.SetTypeArguments (rc, type_arguments);
3772 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3774 public ConstructorInstanceQualifier (TypeSpec type)
3777 InstanceType = type;
3780 public TypeSpec InstanceType { get; private set; }
3782 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3784 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3788 public struct OverloadResolver
3791 public enum Restrictions
3795 ProbingOnly = 1 << 1,
3796 CovariantDelegate = 1 << 2,
3797 NoBaseMembers = 1 << 3,
3798 BaseMembersIncluded = 1 << 4
3801 public interface IBaseMembersProvider
3803 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3804 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3805 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3808 public interface IErrorHandler
3810 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3811 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3812 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3813 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3816 public interface IInstanceQualifier
3818 TypeSpec InstanceType { get; }
3819 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3822 sealed class NoBaseMembers : IBaseMembersProvider
3824 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3826 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3831 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3836 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3842 struct AmbiguousCandidate
3844 public readonly MemberSpec Member;
3845 public readonly bool Expanded;
3846 public readonly AParametersCollection Parameters;
3848 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3851 Parameters = parameters;
3852 Expanded = expanded;
3857 IList<MemberSpec> members;
3858 TypeArguments type_arguments;
3859 IBaseMembersProvider base_provider;
3860 IErrorHandler custom_errors;
3861 IInstanceQualifier instance_qualifier;
3862 Restrictions restrictions;
3863 MethodGroupExpr best_candidate_extension_group;
3864 TypeSpec best_candidate_return_type;
3866 SessionReportPrinter lambda_conv_msgs;
3868 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3869 : this (members, null, restrictions, loc)
3873 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3876 if (members == null || members.Count == 0)
3877 throw new ArgumentException ("empty members set");
3879 this.members = members;
3881 type_arguments = targs;
3882 this.restrictions = restrictions;
3883 if (IsDelegateInvoke)
3884 this.restrictions |= Restrictions.NoBaseMembers;
3886 base_provider = NoBaseMembers.Instance;
3891 public IBaseMembersProvider BaseMembersProvider {
3893 return base_provider;
3896 base_provider = value;
3900 public bool BestCandidateIsDynamic { get; set; }
3903 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3905 public MethodGroupExpr BestCandidateNewMethodGroup {
3907 return best_candidate_extension_group;
3912 // Return type can be different between best candidate and closest override
3914 public TypeSpec BestCandidateReturnType {
3916 return best_candidate_return_type;
3920 public IErrorHandler CustomErrors {
3922 return custom_errors;
3925 custom_errors = value;
3929 TypeSpec DelegateType {
3931 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3932 throw new InternalErrorException ("Not running in delegate mode", loc);
3934 return members [0].DeclaringType;
3938 public IInstanceQualifier InstanceQualifier {
3940 return instance_qualifier;
3943 instance_qualifier = value;
3947 bool IsProbingOnly {
3949 return (restrictions & Restrictions.ProbingOnly) != 0;
3953 bool IsDelegateInvoke {
3955 return (restrictions & Restrictions.DelegateInvoke) != 0;
3962 // 7.4.3.3 Better conversion from expression
3963 // Returns : 1 if a->p is better,
3964 // 2 if a->q is better,
3965 // 0 if neither is better
3967 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3969 TypeSpec argument_type = a.Type;
3972 // If argument is an anonymous function
3974 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3976 // p and q are delegate types or expression tree types
3978 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3979 if (q.MemberDefinition != p.MemberDefinition) {
3984 // Uwrap delegate from Expression<T>
3986 q = TypeManager.GetTypeArguments (q)[0];
3987 p = TypeManager.GetTypeArguments (p)[0];
3990 var p_m = Delegate.GetInvokeMethod (p);
3991 var q_m = Delegate.GetInvokeMethod (q);
3994 // With identical parameter lists
3996 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4005 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4007 if (p.Kind == MemberKind.Void) {
4008 return q.Kind != MemberKind.Void ? 2 : 0;
4012 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4014 if (q.Kind == MemberKind.Void) {
4015 return p.Kind != MemberKind.Void ? 1: 0;
4018 var am = (AnonymousMethodExpression) a.Expr;
4021 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4022 // better conversion is performed between underlying types Y1 and Y2
4024 if (p.IsGenericTask || q.IsGenericTask) {
4025 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4026 q = q.TypeArguments[0];
4027 p = p.TypeArguments[0];
4029 } else if (q != p) {
4031 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
4033 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
4034 var am_rt = am.InferReturnType (ec, null, orig_q);
4035 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4037 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
4038 var am_rt = am.InferReturnType (ec, null, orig_p);
4039 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4045 // The parameters are identicial and return type is not void, use better type conversion
4046 // on return type to determine better one
4049 if (argument_type == p)
4052 if (argument_type == q)
4056 return BetterTypeConversion (ec, p, q);
4060 // 7.4.3.4 Better conversion from type
4062 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4064 if (p == null || q == null)
4065 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4067 switch (p.BuiltinType) {
4068 case BuiltinTypeSpec.Type.Int:
4069 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4072 case BuiltinTypeSpec.Type.Long:
4073 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4076 case BuiltinTypeSpec.Type.SByte:
4077 switch (q.BuiltinType) {
4078 case BuiltinTypeSpec.Type.Byte:
4079 case BuiltinTypeSpec.Type.UShort:
4080 case BuiltinTypeSpec.Type.UInt:
4081 case BuiltinTypeSpec.Type.ULong:
4085 case BuiltinTypeSpec.Type.Short:
4086 switch (q.BuiltinType) {
4087 case BuiltinTypeSpec.Type.UShort:
4088 case BuiltinTypeSpec.Type.UInt:
4089 case BuiltinTypeSpec.Type.ULong:
4093 case BuiltinTypeSpec.Type.Dynamic:
4094 // Dynamic is never better
4098 switch (q.BuiltinType) {
4099 case BuiltinTypeSpec.Type.Int:
4100 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4103 case BuiltinTypeSpec.Type.Long:
4104 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4107 case BuiltinTypeSpec.Type.SByte:
4108 switch (p.BuiltinType) {
4109 case BuiltinTypeSpec.Type.Byte:
4110 case BuiltinTypeSpec.Type.UShort:
4111 case BuiltinTypeSpec.Type.UInt:
4112 case BuiltinTypeSpec.Type.ULong:
4116 case BuiltinTypeSpec.Type.Short:
4117 switch (p.BuiltinType) {
4118 case BuiltinTypeSpec.Type.UShort:
4119 case BuiltinTypeSpec.Type.UInt:
4120 case BuiltinTypeSpec.Type.ULong:
4124 case BuiltinTypeSpec.Type.Dynamic:
4125 // Dynamic is never better
4129 // FIXME: handle lifted operators
4131 // TODO: this is expensive
4132 Expression p_tmp = new EmptyExpression (p);
4133 Expression q_tmp = new EmptyExpression (q);
4135 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4136 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4138 if (p_to_q && !q_to_p)
4141 if (q_to_p && !p_to_q)
4148 /// Determines "Better function" between candidate
4149 /// and the current best match
4152 /// Returns a boolean indicating :
4153 /// false if candidate ain't better
4154 /// true if candidate is better than the current best match
4156 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4157 MemberSpec best, AParametersCollection bparam, bool best_params)
4159 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4160 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4162 bool better_at_least_one = false;
4164 int args_count = args == null ? 0 : args.Count;
4168 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4171 // Default arguments are ignored for better decision
4172 if (a.IsDefaultArgument)
4176 // When comparing named argument the parameter type index has to be looked up
4177 // in original parameter set (override version for virtual members)
4179 NamedArgument na = a as NamedArgument;
4181 int idx = cparam.GetParameterIndexByName (na.Name);
4182 ct = candidate_pd.Types[idx];
4183 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4184 ct = TypeManager.GetElementType (ct);
4186 idx = bparam.GetParameterIndexByName (na.Name);
4187 bt = best_pd.Types[idx];
4188 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4189 bt = TypeManager.GetElementType (bt);
4191 ct = candidate_pd.Types[c_idx];
4192 bt = best_pd.Types[b_idx];
4194 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4195 ct = TypeManager.GetElementType (ct);
4199 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4200 bt = TypeManager.GetElementType (bt);
4205 if (TypeSpecComparer.IsEqual (ct, bt))
4209 int result = BetterExpressionConversion (ec, a, ct, bt);
4211 // for each argument, the conversion to 'ct' should be no worse than
4212 // the conversion to 'bt'.
4216 // for at least one argument, the conversion to 'ct' should be better than
4217 // the conversion to 'bt'.
4219 better_at_least_one = true;
4222 if (better_at_least_one)
4226 // This handles the case
4228 // Add (float f1, float f2, float f3);
4229 // Add (params decimal [] foo);
4231 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4232 // first candidate would've chosen as better.
4234 if (!same && !a.IsDefaultArgument)
4238 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4242 // This handles the following cases:
4244 // Foo (int i) is better than Foo (int i, long l = 0)
4245 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4246 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4248 // Prefer non-optional version
4250 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4252 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4253 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4256 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4259 return candidate_pd.Count >= best_pd.Count;
4263 // One is a non-generic method and second is a generic method, then non-generic is better
4265 if (best.IsGeneric != candidate.IsGeneric)
4266 return best.IsGeneric;
4269 // This handles the following cases:
4271 // Trim () is better than Trim (params char[] chars)
4272 // Concat (string s1, string s2, string s3) is better than
4273 // Concat (string s1, params string [] srest)
4274 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4276 // Prefer non-expanded version
4278 if (candidate_params != best_params)
4281 int candidate_param_count = candidate_pd.Count;
4282 int best_param_count = best_pd.Count;
4284 if (candidate_param_count != best_param_count)
4285 // can only happen if (candidate_params && best_params)
4286 return candidate_param_count > best_param_count && best_pd.HasParams;
4289 // Both methods have the same number of parameters, and the parameters have equal types
4290 // Pick the "more specific" signature using rules over original (non-inflated) types
4292 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4293 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4295 bool specific_at_least_once = false;
4296 for (j = 0; j < args_count; ++j) {
4297 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4299 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4300 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4302 ct = candidate_def_pd.Types[j];
4303 bt = best_def_pd.Types[j];
4308 TypeSpec specific = MoreSpecific (ct, bt);
4312 specific_at_least_once = true;
4315 if (specific_at_least_once)
4321 static bool CheckInflatedArguments (MethodSpec ms)
4323 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4326 // Setup constraint checker for probing only
4327 ConstraintChecker cc = new ConstraintChecker (null);
4329 var mp = ms.Parameters.Types;
4330 for (int i = 0; i < mp.Length; ++i) {
4331 var type = mp[i] as InflatedTypeSpec;
4335 var targs = type.TypeArguments;
4336 if (targs.Length == 0)
4339 // TODO: Checking inflated MVAR arguments should be enough
4340 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4347 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4349 rc.Report.Error (1729, loc,
4350 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4351 type.GetSignatureForError (), argCount.ToString ());
4355 // Determines if the candidate method is applicable to the given set of arguments
4356 // There could be two different set of parameters for same candidate where one
4357 // is the closest override for default values and named arguments checks and second
4358 // one being the virtual base for the parameter types and modifiers.
4360 // A return value rates candidate method compatibility,
4361 // 0 = the best, int.MaxValue = the worst
4364 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)
4366 // Parameters of most-derived type used mainly for named and optional parameters
4367 var pd = pm.Parameters;
4369 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4370 // params modifier instead of most-derived type
4371 var cpd = ((IParametersMember) candidate).Parameters;
4372 int param_count = pd.Count;
4373 int optional_count = 0;
4375 Arguments orig_args = arguments;
4377 if (arg_count != param_count) {
4379 // No arguments expansion when doing exact match for delegates
4381 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4382 for (int i = 0; i < pd.Count; ++i) {
4383 if (pd.FixedParameters[i].HasDefaultValue) {
4384 optional_count = pd.Count - i;
4390 if (optional_count != 0) {
4391 // Readjust expected number when params used
4392 if (cpd.HasParams) {
4394 if (arg_count < param_count)
4396 } else if (arg_count > param_count) {
4397 int args_gap = System.Math.Abs (arg_count - param_count);
4398 return int.MaxValue - 10000 + args_gap;
4399 } else if (arg_count < param_count - optional_count) {
4400 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4401 return int.MaxValue - 10000 + args_gap;
4403 } else if (arg_count != param_count) {
4404 int args_gap = System.Math.Abs (arg_count - param_count);
4406 return int.MaxValue - 10000 + args_gap;
4407 if (arg_count < param_count - 1)
4408 return int.MaxValue - 10000 + args_gap;
4411 // Resize to fit optional arguments
4412 if (optional_count != 0) {
4413 if (arguments == null) {
4414 arguments = new Arguments (optional_count);
4416 // Have to create a new container, so the next run can do same
4417 var resized = new Arguments (param_count);
4418 resized.AddRange (arguments);
4419 arguments = resized;
4422 for (int i = arg_count; i < param_count; ++i)
4423 arguments.Add (null);
4427 if (arg_count > 0) {
4429 // Shuffle named arguments to the right positions if there are any
4431 if (arguments[arg_count - 1] is NamedArgument) {
4432 arg_count = arguments.Count;
4434 for (int i = 0; i < arg_count; ++i) {
4435 bool arg_moved = false;
4437 NamedArgument na = arguments[i] as NamedArgument;
4441 int index = pd.GetParameterIndexByName (na.Name);
4443 // Named parameter not found
4447 // already reordered
4452 if (index >= param_count) {
4453 // When using parameters which should not be available to the user
4454 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4457 arguments.Add (null);
4461 temp = arguments[index];
4463 // The slot has been taken by positional argument
4464 if (temp != null && !(temp is NamedArgument))
4469 arguments = arguments.MarkOrderedArgument (na);
4473 arguments[index] = arguments[i];
4474 arguments[i] = temp;
4481 arg_count = arguments.Count;
4483 } else if (arguments != null) {
4484 arg_count = arguments.Count;
4488 // Don't do any expensive checks when the candidate cannot succeed
4490 if (arg_count != param_count && !cpd.HasParams)
4491 return (param_count - arg_count) * 2 + 1;
4493 var dep = candidate.GetMissingDependencies ();
4495 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4500 // 1. Handle generic method using type arguments when specified or type inference
4503 var ms = candidate as MethodSpec;
4504 if (ms != null && ms.IsGeneric) {
4505 if (type_arguments != null) {
4506 var g_args_count = ms.Arity;
4507 if (g_args_count != type_arguments.Count)
4508 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4510 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4513 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4514 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4515 // candidate was found use the set to report more details about what was wrong with lambda body.
4516 // The general idea is to distinguish between code errors and errors caused by
4517 // trial-and-error type inference
4519 if (lambda_conv_msgs == null) {
4520 for (int i = 0; i < arg_count; i++) {
4521 Argument a = arguments[i];
4525 var am = a.Expr as AnonymousMethodExpression;
4527 if (lambda_conv_msgs == null)
4528 lambda_conv_msgs = new SessionReportPrinter ();
4530 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4535 var ti = new TypeInference (arguments);
4536 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4539 return ti.InferenceScore - 20000;
4542 // Clear any error messages when the result was success
4544 if (lambda_conv_msgs != null)
4545 lambda_conv_msgs.ClearSession ();
4547 if (i_args.Length != 0) {
4548 ms = ms.MakeGenericMethod (ec, i_args);
4553 // Type arguments constraints have to match for the method to be applicable
4555 if (!CheckInflatedArguments (ms)) {
4557 return int.MaxValue - 25000;
4561 // We have a generic return type and at same time the method is override which
4562 // means we have to also inflate override return type in case the candidate is
4563 // best candidate and override return type is different to base return type.
4565 // virtual Foo<T, object> with override Foo<T, dynamic>
4567 if (candidate != pm) {
4568 MethodSpec override_ms = (MethodSpec) pm;
4569 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4570 returnType = inflator.Inflate (returnType);
4572 returnType = ms.ReturnType;
4579 if (type_arguments != null)
4580 return int.MaxValue - 15000;
4586 // 2. Each argument has to be implicitly convertible to method parameter
4588 Parameter.Modifier p_mod = 0;
4591 for (int i = 0; i < arg_count; i++) {
4592 Argument a = arguments[i];
4594 var fp = pd.FixedParameters[i];
4595 if (!fp.HasDefaultValue) {
4596 arguments = orig_args;
4597 return arg_count * 2 + 2;
4601 // Get the default value expression, we can use the same expression
4602 // if the type matches
4604 Expression e = fp.DefaultValue;
4606 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4608 // Restore for possible error reporting
4609 for (int ii = i; ii < arg_count; ++ii)
4610 arguments.RemoveAt (i);
4612 return (arg_count - i) * 2 + 1;
4616 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4618 // LAMESPEC: Attributes can be mixed together with build-in priority
4620 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4621 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4622 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4623 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4624 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4625 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4629 arguments[i] = new Argument (e, Argument.AType.Default);
4633 if ((p_mod & Parameter.Modifier.VariableArgumentsMask) == 0) {
4634 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.VariableArgumentsMask) |
4635 (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.VariableArgumentsMask);
4637 } else if (!params_expanded_form) {
4638 params_expanded_form = true;
4640 var array = pt as ArrayContainer;
4644 pt = ec.Module.PlayscriptTypes.Object;
4651 if (!params_expanded_form) {
4652 if (a.ArgType == Argument.AType.ExtensionType) {
4654 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4656 // LAMESPEC: or implicit type parameter conversion
4659 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4660 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4661 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4666 score = IsArgumentCompatible (ec, a, p_mod, pt);
4669 dynamicArgument = true;
4674 // It can be applicable in expanded form (when not doing exact match like for delegates)
4676 if (score != 0 && (p_mod & Parameter.Modifier.VariableArgumentsMask) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4677 if (!params_expanded_form) {
4678 if (p_mod == Parameter.Modifier.PARAMS)
4679 pt = ((ArrayContainer) pt).Element;
4681 pt = ec.Module.PlayscriptTypes.Object;
4685 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4688 params_expanded_form = true;
4689 dynamicArgument = true;
4690 } else if (score == 0 || arg_count > pd.Count) {
4691 params_expanded_form = true;
4696 if (params_expanded_form)
4698 return (arg_count - i) * 2 + score;
4703 // When params parameter has no argument it will be provided later if the method is the best candidate
4705 // ActionScript has different logic for params style arguments when argument count matches. It still
4706 // created an Array with 1 element even if argument type is convertible to array
4708 if ((arg_count + 1 == pd.Count && cpd.HasParams) ||
4709 (arg_count > 0 && arg_count == param_count && pd.FixedParameters[param_count - 1].ModFlags == Parameter.Modifier.RestArray))
4710 params_expanded_form = true;
4714 // Restore original arguments for dynamic binder to keep the intention of original source code
4716 if (dynamicArgument)
4717 arguments = orig_args;
4722 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4724 if (e is Constant && e.Type == ptype)
4728 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4730 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4731 e = new MemberAccess (new MemberAccess (new MemberAccess (
4732 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4733 } else if (e is Constant) {
4735 // Handles int to int? conversions, DefaultParameterValue check
4737 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4741 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4744 return e.Resolve (ec);
4748 // Tests argument compatibility with the parameter
4749 // The possible return values are
4751 // 1 - modifier mismatch
4752 // 2 - type mismatch
4753 // -1 - dynamic binding required
4755 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4758 // Types have to be identical when ref or out modifer
4759 // is used and argument is not of dynamic type
4761 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4762 if (argument.Type != parameter) {
4764 // Do full equality check after quick path
4766 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4768 // Using dynamic for ref/out parameter can still succeed at runtime
4770 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4777 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4779 // Using dynamic for ref/out parameter can still succeed at runtime
4781 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4788 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4792 // Use implicit conversion in all modes to return same candidates when the expression
4793 // is used as argument or delegate conversion
4795 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4796 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
4803 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4805 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4807 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4810 var ac_p = p as ArrayContainer;
4812 var ac_q = q as ArrayContainer;
4816 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4817 if (specific == ac_p.Element)
4819 if (specific == ac_q.Element)
4821 } else if (p.IsGeneric && q.IsGeneric) {
4822 var pargs = TypeManager.GetTypeArguments (p);
4823 var qargs = TypeManager.GetTypeArguments (q);
4825 bool p_specific_at_least_once = false;
4826 bool q_specific_at_least_once = false;
4828 for (int i = 0; i < pargs.Length; i++) {
4829 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4830 if (specific == pargs[i])
4831 p_specific_at_least_once = true;
4832 if (specific == qargs[i])
4833 q_specific_at_least_once = true;
4836 if (p_specific_at_least_once && !q_specific_at_least_once)
4838 if (!p_specific_at_least_once && q_specific_at_least_once)
4846 // Find the best method from candidate list
4848 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4850 List<AmbiguousCandidate> ambiguous_candidates = null;
4852 MemberSpec best_candidate;
4853 Arguments best_candidate_args = null;
4854 bool best_candidate_params = false;
4855 bool best_candidate_dynamic = false;
4856 int best_candidate_rate;
4857 IParametersMember best_parameter_member = null;
4859 int args_count = args != null ? args.Count : 0;
4861 Arguments candidate_args = args;
4862 bool error_mode = false;
4863 MemberSpec invocable_member = null;
4866 best_candidate = null;
4867 best_candidate_rate = int.MaxValue;
4869 var type_members = members;
4871 for (int i = 0; i < type_members.Count; ++i) {
4872 var member = type_members[i];
4875 // Methods in a base class are not candidates if any method in a derived
4876 // class is applicable
4878 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4882 if (!member.IsAccessible (rc))
4885 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4888 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4889 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4894 IParametersMember pm = member as IParametersMember;
4897 // Will use it later to report ambiguity between best method and invocable member
4899 if (Invocation.IsMemberInvocable (member))
4900 invocable_member = member;
4906 // Overload resolution is looking for base member but using parameter names
4907 // and default values from the closest member. That means to do expensive lookup
4908 // for the closest override for virtual or abstract members
4910 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4911 var override_params = base_provider.GetOverrideMemberParameters (member);
4912 if (override_params != null)
4913 pm = override_params;
4917 // Check if the member candidate is applicable
4919 bool params_expanded_form = false;
4920 bool dynamic_argument = false;
4921 TypeSpec rt = pm.MemberType;
4922 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4924 if (lambda_conv_msgs != null)
4925 lambda_conv_msgs.EndSession ();
4928 // How does it score compare to others
4930 if (candidate_rate < best_candidate_rate) {
4932 // Fatal error (missing dependency), cannot continue
4933 if (candidate_rate < 0)
4936 best_candidate_rate = candidate_rate;
4937 best_candidate = member;
4938 best_candidate_args = candidate_args;
4939 best_candidate_params = params_expanded_form;
4940 best_candidate_dynamic = dynamic_argument;
4941 best_parameter_member = pm;
4942 best_candidate_return_type = rt;
4943 } else if (candidate_rate == 0) {
4945 // The member look is done per type for most operations but sometimes
4946 // it's not possible like for binary operators overload because they
4947 // are unioned between 2 sides
4949 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4950 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4955 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4957 // We pack all interface members into top level type which makes the overload resolution
4958 // more complicated for interfaces. We compensate it by removing methods with same
4959 // signature when building the cache hence this path should not really be hit often
4962 // interface IA { void Foo (int arg); }
4963 // interface IB : IA { void Foo (params int[] args); }
4965 // IB::Foo is the best overload when calling IB.Foo (1)
4968 if (ambiguous_candidates != null) {
4969 foreach (var amb_cand in ambiguous_candidates) {
4970 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4979 ambiguous_candidates = null;
4982 // Is the new candidate better
4983 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4987 best_candidate = member;
4988 best_candidate_args = candidate_args;
4989 best_candidate_params = params_expanded_form;
4990 best_candidate_dynamic = dynamic_argument;
4991 best_parameter_member = pm;
4992 best_candidate_return_type = rt;
4994 // It's not better but any other found later could be but we are not sure yet
4995 if (ambiguous_candidates == null)
4996 ambiguous_candidates = new List<AmbiguousCandidate> ();
4998 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5002 // Restore expanded arguments
5003 if (candidate_args != args)
5004 candidate_args = args;
5006 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5009 // We've found exact match
5011 if (best_candidate_rate == 0)
5015 // Try extension methods lookup when no ordinary method match was found and provider enables it
5018 var emg = base_provider.LookupExtensionMethod (rc);
5020 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5022 best_candidate_extension_group = emg;
5023 return (T) (MemberSpec) emg.BestCandidate;
5028 // Don't run expensive error reporting mode for probing
5035 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5038 lambda_conv_msgs = null;
5043 // No best member match found, report an error
5045 if (best_candidate_rate != 0 || error_mode) {
5046 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5050 if (best_candidate_dynamic) {
5051 if (args[0].ArgType == Argument.AType.ExtensionType) {
5052 rc.Report.Error (1973, loc,
5053 "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",
5054 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5058 // Check type constraints only when explicit type arguments are used
5060 if (best_candidate.IsGeneric && type_arguments != null) {
5061 MethodSpec bc = best_candidate as MethodSpec;
5062 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5063 ConstraintChecker cc = new ConstraintChecker (rc);
5064 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5068 BestCandidateIsDynamic = true;
5073 // These flags indicates we are running delegate probing conversion. No need to
5074 // do more expensive checks
5076 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5077 return (T) best_candidate;
5079 if (ambiguous_candidates != null) {
5081 // Now check that there are no ambiguities i.e the selected method
5082 // should be better than all the others
5084 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5085 var candidate = ambiguous_candidates [ix];
5087 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5088 var ambiguous = candidate.Member;
5089 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5090 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5091 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5092 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5093 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5096 return (T) best_candidate;
5101 if (invocable_member != null && !IsProbingOnly) {
5102 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5103 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5104 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5105 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5109 // And now check if the arguments are all
5110 // compatible, perform conversions if
5111 // necessary etc. and return if everything is
5114 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5117 if (best_candidate == null)
5121 // Don't run possibly expensive checks in probing mode
5123 if (!IsProbingOnly && !rc.IsInProbingMode) {
5125 // Check ObsoleteAttribute on the best method
5127 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5128 if (oa != null && !rc.IsObsolete)
5129 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5131 best_candidate.MemberDefinition.SetIsUsed ();
5134 args = best_candidate_args;
5135 return (T) best_candidate;
5138 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5140 return ResolveMember<MethodSpec> (rc, ref args);
5143 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5144 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5146 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5149 if (a.Type == InternalType.ErrorType)
5152 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5153 ec.Report.SymbolRelatedToPreviousError (method);
5154 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5155 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5156 TypeManager.CSharpSignature (method));
5159 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5160 TypeManager.CSharpSignature (method));
5161 } else if (IsDelegateInvoke) {
5162 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5163 DelegateType.GetSignatureForError ());
5165 ec.Report.SymbolRelatedToPreviousError (method);
5166 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5167 method.GetSignatureForError ());
5170 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5172 string index = (idx + 1).ToString ();
5173 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5174 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5175 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5176 index, Parameter.GetModifierSignature (a.Modifier));
5178 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5179 index, Parameter.GetModifierSignature (mod));
5181 string p1 = a.GetSignatureForError ();
5182 string p2 = paramType.GetSignatureForError ();
5185 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5186 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5189 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5190 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5191 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5194 ec.Report.Error (1503, a.Expr.Location,
5195 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5200 // We have failed to find exact match so we return error info about the closest match
5202 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5204 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5205 int arg_count = args == null ? 0 : args.Count;
5207 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5208 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5209 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5213 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5218 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5219 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5220 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5224 // For candidates which match on parameters count report more details about incorrect arguments
5227 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5228 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5229 // Reject any inaccessible member
5230 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5231 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5232 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5236 var ms = best_candidate as MethodSpec;
5237 if (ms != null && ms.IsGeneric) {
5238 bool constr_ok = true;
5239 if (ms.TypeArguments != null)
5240 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5242 if (ta_count == 0) {
5243 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5247 rc.Report.Error (411, loc,
5248 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5249 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5256 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5262 // We failed to find any method with correct argument count, report best candidate
5264 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5267 if (best_candidate.Kind == MemberKind.Constructor) {
5268 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5269 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5270 } else if (IsDelegateInvoke) {
5271 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5272 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5273 DelegateType.GetSignatureForError (), arg_count.ToString ());
5275 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5276 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5277 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5278 name, arg_count.ToString ());
5282 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5284 var pd = pm.Parameters;
5285 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5287 Parameter.Modifier p_mod = 0;
5289 int a_idx = 0, a_pos = 0;
5291 ArrayInitializer params_initializers = null;
5292 bool has_unsafe_arg = pm.MemberType.IsPointer;
5293 int arg_count = args == null ? 0 : args.Count;
5294 bool playscript_params = false;
5296 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5298 if ((p_mod & Parameter.Modifier.VariableArgumentsMask) == 0) {
5299 p_mod = pd.FixedParameters[a_idx].ModFlags;
5301 has_unsafe_arg |= pt.IsPointer;
5303 if (chose_params_expanded && (p_mod & Parameter.Modifier.VariableArgumentsMask) != 0) {
5304 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5305 if (p_mod == Parameter.Modifier.PARAMS) {
5306 pt = ((ArrayContainer) pt).Element;
5308 playscript_params = true;
5309 pt = ec.Module.PlayscriptTypes.Object;
5315 // Types have to be identical when ref or out modifer is used
5317 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5318 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5321 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5327 NamedArgument na = a as NamedArgument;
5329 int name_index = pd.GetParameterIndexByName (na.Name);
5330 if (name_index < 0 || name_index >= pd.Count) {
5331 if (IsDelegateInvoke) {
5332 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5333 ec.Report.Error (1746, na.Location,
5334 "The delegate `{0}' does not contain a parameter named `{1}'",
5335 DelegateType.GetSignatureForError (), na.Name);
5337 ec.Report.SymbolRelatedToPreviousError (member);
5338 ec.Report.Error (1739, na.Location,
5339 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5340 TypeManager.CSharpSignature (member), na.Name);
5342 } else if (args[name_index] != a) {
5343 if (IsDelegateInvoke)
5344 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5346 ec.Report.SymbolRelatedToPreviousError (member);
5348 ec.Report.Error (1744, na.Location,
5349 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5354 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5357 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5358 custom_errors.NoArgumentMatch (ec, member);
5362 Expression conv = null;
5363 if (a.ArgType == Argument.AType.ExtensionType) {
5364 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5367 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5369 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5372 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5379 // Convert params arguments to an array initializer
5381 if (params_initializers != null) {
5382 // we choose to use 'a.Expr' rather than 'conv' so that
5383 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5384 params_initializers.Add (a.Expr);
5385 args.RemoveAt (a_idx--);
5390 // Update the argument with the implicit conversion
5394 if (a_idx != arg_count) {
5395 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5400 // Fill not provided arguments required by params modifier
5402 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5404 args = new Arguments (1);
5406 pt = ptypes[pd.Count - 1];
5407 var array = pt as ArrayContainer;
5408 if (array != null) {
5410 has_unsafe_arg |= pt.IsPointer;
5412 playscript_params = true;
5415 params_initializers = new ArrayInitializer (0, loc);
5419 // Append an array argument with all params arguments
5421 if (params_initializers != null) {
5422 Expression array_init;
5423 if (playscript_params)
5424 array_init = new PlayScript.ArrayCreation (params_initializers);
5426 array_init = new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc);
5428 args.Add (new Argument (array_init.Resolve (ec)));
5432 if (has_unsafe_arg && !ec.IsUnsafe) {
5433 Expression.UnsafeError (ec, loc);
5437 // We could infer inaccesible type arguments
5439 if (type_arguments == null && member.IsGeneric) {
5440 var ms = (MethodSpec) member;
5441 foreach (var ta in ms.TypeArguments) {
5442 if (!ta.IsAccessible (ec)) {
5443 ec.Report.SymbolRelatedToPreviousError (ta);
5444 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5454 public class ConstantExpr : MemberExpr
5456 readonly ConstSpec constant;
5458 public ConstantExpr (ConstSpec constant, Location loc)
5460 this.constant = constant;
5464 public override string Name {
5465 get { throw new NotImplementedException (); }
5468 public override string KindName {
5469 get { return "constant"; }
5472 public override bool IsInstance {
5473 get { return !IsStatic; }
5476 public override bool IsStatic {
5477 get { return true; }
5480 protected override TypeSpec DeclaringType {
5481 get { return constant.DeclaringType; }
5484 public override Expression CreateExpressionTree (ResolveContext ec)
5486 throw new NotSupportedException ("ET");
5489 protected override Expression DoResolve (ResolveContext rc)
5491 ResolveInstanceExpression (rc, null);
5492 DoBestMemberChecks (rc, constant);
5494 var c = constant.GetConstant (rc);
5496 // Creates reference expression to the constant value
5497 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5500 public override void Emit (EmitContext ec)
5502 throw new NotSupportedException ();
5505 public override string GetSignatureForError ()
5507 return constant.GetSignatureForError ();
5510 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5512 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5517 // Fully resolved expression that references a Field
5519 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5521 protected FieldSpec spec;
5522 VariableInfo variable_info;
5524 LocalTemporary temp;
5527 protected FieldExpr (Location l)
5532 public FieldExpr (FieldSpec spec, Location loc)
5537 type = spec.MemberType;
5540 public FieldExpr (FieldBase fi, Location l)
5547 public override string Name {
5553 public bool IsHoisted {
5555 IVariableReference hv = InstanceExpression as IVariableReference;
5556 return hv != null && hv.IsHoisted;
5560 public override bool IsInstance {
5562 return !spec.IsStatic;
5566 public override bool IsStatic {
5568 return spec.IsStatic;
5572 public override string KindName {
5573 get { return "field"; }
5576 public FieldSpec Spec {
5582 protected override TypeSpec DeclaringType {
5584 return spec.DeclaringType;
5588 public VariableInfo VariableInfo {
5590 return variable_info;
5596 public override string GetSignatureForError ()
5598 return spec.GetSignatureForError ();
5601 public bool IsMarshalByRefAccess (ResolveContext rc)
5603 // Checks possible ldflda of field access expression
5604 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5605 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5606 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5609 public void SetHasAddressTaken ()
5611 IVariableReference vr = InstanceExpression as IVariableReference;
5613 vr.SetHasAddressTaken ();
5617 public override Expression CreateExpressionTree (ResolveContext ec)
5619 return CreateExpressionTree (ec, true);
5622 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5625 Expression instance;
5627 if (InstanceExpression == null) {
5628 instance = new NullLiteral (loc);
5629 } else if (convertInstance) {
5630 instance = InstanceExpression.CreateExpressionTree (ec);
5632 args = new Arguments (1);
5633 args.Add (new Argument (InstanceExpression));
5634 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5637 args = Arguments.CreateForExpressionTree (ec, null,
5639 CreateTypeOfExpression ());
5641 return CreateExpressionFactoryCall (ec, "Field", args);
5644 public Expression CreateTypeOfExpression ()
5646 return new TypeOfField (spec, loc);
5649 protected override Expression DoResolve (ResolveContext ec)
5651 spec.MemberDefinition.SetIsUsed ();
5653 return DoResolve (ec, null);
5656 Expression DoResolve (ResolveContext ec, Expression rhs)
5658 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5661 if (ResolveInstanceExpression (ec, rhs)) {
5662 // Resolve the field's instance expression while flow analysis is turned
5663 // off: when accessing a field "a.b", we must check whether the field
5664 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5666 if (lvalue_instance) {
5667 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5668 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5670 Expression right_side =
5671 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5673 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5676 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5677 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5681 if (InstanceExpression == null)
5685 DoBestMemberChecks (ec, spec);
5688 var fb = spec as FixedFieldSpec;
5689 IVariableReference var = InstanceExpression as IVariableReference;
5691 if (lvalue_instance && var != null && var.VariableInfo != null) {
5692 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5696 IFixedExpression fe = InstanceExpression as IFixedExpression;
5697 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5698 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5701 if (InstanceExpression.eclass != ExprClass.Variable) {
5702 ec.Report.SymbolRelatedToPreviousError (spec);
5703 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5704 TypeManager.GetFullNameSignature (spec));
5705 } else if (var != null && var.IsHoisted) {
5706 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5709 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5713 // Set flow-analysis variable info for struct member access. It will be check later
5714 // for precise error reporting
5716 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5717 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5718 if (rhs != null && variable_info != null)
5719 variable_info.SetStructFieldAssigned (ec, Name);
5722 eclass = ExprClass.Variable;
5726 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5731 var var = fe.InstanceExpression as IVariableReference;
5733 var vi = var.VariableInfo;
5735 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5737 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5739 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5746 fe = fe.InstanceExpression as FieldExpr;
5748 } while (fe != null);
5751 static readonly int [] codes = {
5752 191, // instance, write access
5753 192, // instance, out access
5754 198, // static, write access
5755 199, // static, out access
5756 1648, // member of value instance, write access
5757 1649, // member of value instance, out access
5758 1650, // member of value static, write access
5759 1651 // member of value static, out access
5762 static readonly string [] msgs = {
5763 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5764 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5765 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5766 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5767 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5768 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5769 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5770 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5773 // The return value is always null. Returning a value simplifies calling code.
5774 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5777 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5781 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5783 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5788 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5790 if (spec is FixedFieldSpec) {
5791 // It could be much better error message but we want to be error compatible
5792 Error_ValueAssignment (ec, right_side);
5795 Expression e = DoResolve (ec, right_side);
5800 spec.MemberDefinition.SetIsAssigned ();
5802 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5803 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5804 ec.Report.Warning (420, 1, loc,
5805 "`{0}': A volatile field references will not be treated as volatile",
5806 spec.GetSignatureForError ());
5809 if (spec.IsReadOnly) {
5810 // InitOnly fields can only be assigned in constructors or initializers
5811 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5812 return Report_AssignToReadonly (ec, right_side);
5814 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5816 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5817 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5818 return Report_AssignToReadonly (ec, right_side);
5819 // static InitOnly fields cannot be assigned-to in an instance constructor
5820 if (IsStatic && !ec.IsStatic)
5821 return Report_AssignToReadonly (ec, right_side);
5822 // instance constructors can't modify InitOnly fields of other instances of the same type
5823 if (!IsStatic && !(InstanceExpression is This))
5824 return Report_AssignToReadonly (ec, right_side);
5828 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5829 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5830 ec.Report.Warning (197, 1, loc,
5831 "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",
5832 GetSignatureForError ());
5835 eclass = ExprClass.Variable;
5839 public override int GetHashCode ()
5841 return spec.GetHashCode ();
5844 public bool IsFixed {
5847 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5849 IVariableReference variable = InstanceExpression as IVariableReference;
5850 if (variable != null)
5851 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5853 IFixedExpression fe = InstanceExpression as IFixedExpression;
5854 return fe != null && fe.IsFixed;
5858 public override bool Equals (object obj)
5860 FieldExpr fe = obj as FieldExpr;
5864 if (spec != fe.spec)
5867 if (InstanceExpression == null || fe.InstanceExpression == null)
5870 return InstanceExpression.Equals (fe.InstanceExpression);
5873 public void Emit (EmitContext ec, bool leave_copy)
5875 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5879 ec.Emit (OpCodes.Volatile);
5881 ec.Emit (OpCodes.Ldsfld, spec);
5884 EmitInstance (ec, false);
5886 // Optimization for build-in types
5887 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5888 ec.EmitLoadFromPtr (type);
5890 var ff = spec as FixedFieldSpec;
5892 ec.Emit (OpCodes.Ldflda, spec);
5893 ec.Emit (OpCodes.Ldflda, ff.Element);
5896 ec.Emit (OpCodes.Volatile);
5898 ec.Emit (OpCodes.Ldfld, spec);
5904 ec.Emit (OpCodes.Dup);
5906 temp = new LocalTemporary (this.Type);
5912 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5914 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5915 if (isCompound && !(source is DynamicExpressionStatement)) {
5916 if (has_await_source) {
5918 InstanceExpression = InstanceExpression.EmitToField (ec);
5925 if (has_await_source)
5926 source = source.EmitToField (ec);
5928 EmitInstance (ec, prepared);
5934 ec.Emit (OpCodes.Dup);
5936 temp = new LocalTemporary (this.Type);
5941 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5942 ec.Emit (OpCodes.Volatile);
5944 spec.MemberDefinition.SetIsAssigned ();
5947 ec.Emit (OpCodes.Stsfld, spec);
5949 ec.Emit (OpCodes.Stfld, spec);
5959 // Emits store to field with prepared values on stack
5961 public void EmitAssignFromStack (EmitContext ec)
5964 ec.Emit (OpCodes.Stsfld, spec);
5966 ec.Emit (OpCodes.Stfld, spec);
5970 public override void Emit (EmitContext ec)
5975 public override void EmitSideEffect (EmitContext ec)
5977 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5979 if (is_volatile) // || is_marshal_by_ref ())
5980 base.EmitSideEffect (ec);
5983 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5985 if ((mode & AddressOp.Store) != 0)
5986 spec.MemberDefinition.SetIsAssigned ();
5987 if ((mode & AddressOp.Load) != 0)
5988 spec.MemberDefinition.SetIsUsed ();
5991 // Handle initonly fields specially: make a copy and then
5992 // get the address of the copy.
5995 if (spec.IsReadOnly){
5997 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6009 var temp = ec.GetTemporaryLocal (type);
6010 ec.Emit (OpCodes.Stloc, temp);
6011 ec.Emit (OpCodes.Ldloca, temp);
6012 ec.FreeTemporaryLocal (temp, type);
6018 ec.Emit (OpCodes.Ldsflda, spec);
6021 EmitInstance (ec, false);
6022 ec.Emit (OpCodes.Ldflda, spec);
6026 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6028 return MakeExpression (ctx);
6031 public override SLE.Expression MakeExpression (BuilderContext ctx)
6034 return base.MakeExpression (ctx);
6036 return SLE.Expression.Field (
6037 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6038 spec.GetMetaInfo ());
6042 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6044 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6049 // Expression that evaluates to a Property.
6051 // This is not an LValue because we need to re-write the expression. We
6052 // can not take data from the stack and store it.
6054 public sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6056 Arguments arguments;
6058 public PropertyExpr (PropertySpec spec, Location l)
6061 best_candidate = spec;
6062 type = spec.MemberType;
6067 protected override Arguments Arguments {
6076 protected override TypeSpec DeclaringType {
6078 return best_candidate.DeclaringType;
6082 public override string Name {
6084 return best_candidate.Name;
6088 public override bool IsInstance {
6094 public override bool IsStatic {
6096 return best_candidate.IsStatic;
6100 public override string KindName {
6101 get { return "property"; }
6104 public PropertySpec PropertyInfo {
6106 return best_candidate;
6112 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6114 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6117 var args_count = arguments == null ? 0 : arguments.Count;
6118 if (args_count != body.Parameters.Count && args_count == 0)
6121 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6122 mg.InstanceExpression = InstanceExpression;
6127 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6129 return new PropertyExpr (spec, loc) {
6135 public override Expression CreateExpressionTree (ResolveContext ec)
6138 if (IsSingleDimensionalArrayLength ()) {
6139 args = new Arguments (1);
6140 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6141 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6144 args = new Arguments (2);
6145 if (InstanceExpression == null)
6146 args.Add (new Argument (new NullLiteral (loc)));
6148 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6149 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6150 return CreateExpressionFactoryCall (ec, "Property", args);
6153 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6155 DoResolveLValue (rc, null);
6156 return new TypeOfMethod (Setter, loc);
6159 public override string GetSignatureForError ()
6161 return best_candidate.GetSignatureForError ();
6164 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6167 return base.MakeExpression (ctx);
6169 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6173 public override SLE.Expression MakeExpression (BuilderContext ctx)
6176 return base.MakeExpression (ctx);
6178 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6182 void Error_PropertyNotValid (ResolveContext ec)
6184 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6185 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6186 GetSignatureForError ());
6189 bool IsSingleDimensionalArrayLength ()
6191 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6194 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6195 return ac != null && ac.Rank == 1;
6198 public override void Emit (EmitContext ec, bool leave_copy)
6201 // Special case: length of single dimension array property is turned into ldlen
6203 if (IsSingleDimensionalArrayLength ()) {
6204 EmitInstance (ec, false);
6205 ec.Emit (OpCodes.Ldlen);
6206 ec.Emit (OpCodes.Conv_I4);
6210 base.Emit (ec, leave_copy);
6213 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6216 LocalTemporary await_source_arg = null;
6218 if (isCompound && !(source is DynamicExpressionStatement)) {
6219 emitting_compound_assignment = true;
6222 if (has_await_arguments) {
6223 await_source_arg = new LocalTemporary (Type);
6224 await_source_arg.Store (ec);
6226 args = new Arguments (1);
6227 args.Add (new Argument (await_source_arg));
6230 temp = await_source_arg;
6233 has_await_arguments = false;
6238 ec.Emit (OpCodes.Dup);
6239 temp = new LocalTemporary (this.Type);
6244 args = arguments == null ? new Arguments (1) : arguments;
6248 temp = new LocalTemporary (this.Type);
6250 args.Add (new Argument (temp));
6252 args.Add (new Argument (source));
6256 emitting_compound_assignment = false;
6258 var call = new CallEmitter ();
6259 call.InstanceExpression = InstanceExpression;
6261 call.InstanceExpressionOnStack = true;
6263 call.Emit (ec, Setter, args, loc);
6270 if (await_source_arg != null) {
6271 await_source_arg.Release (ec);
6275 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6277 eclass = ExprClass.PropertyAccess;
6279 if (best_candidate.IsNotCSharpCompatible) {
6280 Error_PropertyNotValid (rc);
6283 ResolveInstanceExpression (rc, right_side);
6285 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6286 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6287 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6289 type = p.MemberType;
6293 DoBestMemberChecks (rc, best_candidate);
6295 // Handling of com-imported properties with any number of default property parameters
6296 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6297 var p = best_candidate.Get.Parameters;
6298 arguments = new Arguments (p.Count);
6299 for (int i = 0; i < p.Count; ++i) {
6300 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6302 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6303 var p = best_candidate.Set.Parameters;
6304 arguments = new Arguments (p.Count - 1);
6305 for (int i = 0; i < p.Count - 1; ++i) {
6306 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6313 public override Constant ResolveAsPlayScriptConstant (ResolveContext rc)
6315 var prop = best_candidate.MemberDefinition as PlayScript.IConstantProperty;
6317 return prop.Initializer.ResolveAsPlayScriptConstant (rc);
6322 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6324 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6328 public abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6330 // getter and setter can be different for base calls
6331 MethodSpec getter, setter;
6332 protected T best_candidate;
6334 protected LocalTemporary temp;
6335 protected bool emitting_compound_assignment;
6336 protected bool has_await_arguments;
6338 protected PropertyOrIndexerExpr (Location l)
6345 protected abstract Arguments Arguments { get; set; }
6347 public MethodSpec Getter {
6356 public MethodSpec Setter {
6367 protected override Expression DoResolve (ResolveContext ec)
6369 if (eclass == ExprClass.Unresolved) {
6370 var expr = OverloadResolve (ec, null);
6375 return expr.Resolve (ec);
6378 if (!ResolveGetter (ec))
6384 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6386 if (right_side == EmptyExpression.OutAccess) {
6387 // TODO: best_candidate can be null at this point
6388 INamedBlockVariable variable = null;
6389 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6390 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6391 best_candidate.Name);
6393 right_side.DoResolveLValue (ec, this);
6398 if (eclass == ExprClass.Unresolved) {
6399 var expr = OverloadResolve (ec, right_side);
6404 return expr.ResolveLValue (ec, right_side);
6407 if (!ResolveSetter (ec))
6414 // Implements the IAssignMethod interface for assignments
6416 public virtual void Emit (EmitContext ec, bool leave_copy)
6418 var call = new CallEmitter ();
6419 call.InstanceExpression = InstanceExpression;
6420 if (has_await_arguments)
6421 call.HasAwaitArguments = true;
6423 call.DuplicateArguments = emitting_compound_assignment;
6425 call.Emit (ec, Getter, Arguments, loc);
6427 if (call.HasAwaitArguments) {
6428 InstanceExpression = call.InstanceExpression;
6429 Arguments = call.EmittedArguments;
6430 has_await_arguments = true;
6434 ec.Emit (OpCodes.Dup);
6435 temp = new LocalTemporary (Type);
6440 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6442 public override void Emit (EmitContext ec)
6447 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6449 has_await_arguments = true;
6454 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6456 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6458 bool ResolveGetter (ResolveContext rc)
6460 if (!best_candidate.HasGet) {
6461 if (InstanceExpression != EmptyExpression.Null) {
6462 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6463 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6464 best_candidate.GetSignatureForError ());
6467 } else if (!best_candidate.Get.IsAccessible (rc)) {
6468 if (best_candidate.HasDifferentAccessibility) {
6469 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6470 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6471 TypeManager.CSharpSignature (best_candidate));
6473 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6474 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6478 if (best_candidate.HasDifferentAccessibility) {
6479 CheckProtectedMemberAccess (rc, best_candidate.Get);
6482 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6486 bool ResolveSetter (ResolveContext rc)
6488 if (!best_candidate.HasSet) {
6489 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6490 GetSignatureForError ());
6494 if (!best_candidate.Set.IsAccessible (rc)) {
6495 if (best_candidate.HasDifferentAccessibility) {
6496 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6497 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6498 GetSignatureForError ());
6500 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6501 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6505 if (best_candidate.HasDifferentAccessibility)
6506 CheckProtectedMemberAccess (rc, best_candidate.Set);
6508 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6514 /// Fully resolved expression that evaluates to an Event
6516 public class EventExpr : MemberExpr, IAssignMethod
6518 readonly EventSpec spec;
6521 public EventExpr (EventSpec spec, Location loc)
6529 protected override TypeSpec DeclaringType {
6531 return spec.DeclaringType;
6535 public override string Name {
6541 public override bool IsInstance {
6543 return !spec.IsStatic;
6547 public override bool IsStatic {
6549 return spec.IsStatic;
6553 public override string KindName {
6554 get { return "event"; }
6557 public MethodSpec Operator {
6565 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6568 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6570 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6571 if (spec.BackingField != null &&
6572 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6574 spec.MemberDefinition.SetIsUsed ();
6576 if (!ec.IsObsolete) {
6577 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6579 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6582 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6583 Error_AssignmentEventOnly (ec);
6585 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6587 InstanceExpression = null;
6589 return ml.ResolveMemberAccess (ec, left, original);
6593 return base.ResolveMemberAccess (ec, left, original);
6596 public override Expression CreateExpressionTree (ResolveContext ec)
6598 throw new NotSupportedException ("ET");
6601 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6603 if (right_side == EmptyExpression.EventAddition) {
6604 op = spec.AccessorAdd;
6605 } else if (right_side == EmptyExpression.EventSubtraction) {
6606 op = spec.AccessorRemove;
6610 Error_AssignmentEventOnly (ec);
6614 op = CandidateToBaseOverride (ec, op);
6618 protected override Expression DoResolve (ResolveContext ec)
6620 eclass = ExprClass.EventAccess;
6621 type = spec.MemberType;
6623 ResolveInstanceExpression (ec, null);
6625 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6626 Error_AssignmentEventOnly (ec);
6629 DoBestMemberChecks (ec, spec);
6633 public override void Emit (EmitContext ec)
6635 throw new NotSupportedException ();
6636 //Error_CannotAssign ();
6639 #region IAssignMethod Members
6641 public void Emit (EmitContext ec, bool leave_copy)
6643 throw new NotImplementedException ();
6646 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6648 if (leave_copy || !isCompound)
6649 throw new NotImplementedException ("EventExpr::EmitAssign");
6651 Arguments args = new Arguments (1);
6652 args.Add (new Argument (source));
6654 var call = new CallEmitter ();
6655 call.InstanceExpression = InstanceExpression;
6656 call.Emit (ec, op, args, loc);
6661 void Error_AssignmentEventOnly (ResolveContext ec)
6663 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6664 ec.Report.Error (79, loc,
6665 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6666 GetSignatureForError ());
6668 ec.Report.Error (70, loc,
6669 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6670 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6674 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6676 name = name.Substring (0, name.LastIndexOf ('.'));
6677 base.Error_CannotCallAbstractBase (rc, name);
6680 public override string GetSignatureForError ()
6682 return TypeManager.CSharpSignature (spec);
6685 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6687 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6691 public class TemporaryVariableReference : VariableReference
6693 public class Declarator : Statement
6695 TemporaryVariableReference variable;
6697 public Declarator (TemporaryVariableReference variable)
6699 this.variable = variable;
6703 protected override void DoEmit (EmitContext ec)
6705 variable.li.CreateBuilder (ec);
6708 public override void Emit (EmitContext ec)
6710 // Don't create sequence point
6714 protected override void CloneTo (CloneContext clonectx, Statement target)
6722 public TemporaryVariableReference (LocalVariable li, Location loc)
6725 this.type = li.Type;
6729 public override bool IsLockedByStatement {
6737 public LocalVariable LocalInfo {
6743 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6745 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6746 return new TemporaryVariableReference (li, loc);
6749 protected override Expression DoResolve (ResolveContext ec)
6751 eclass = ExprClass.Variable;
6754 // Don't capture temporary variables except when using
6755 // state machine redirection and block yields
6757 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6758 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6759 ec.IsVariableCapturingRequired) {
6760 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6761 storey.CaptureLocalVariable (ec, li);
6767 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6769 return Resolve (ec);
6772 public override void Emit (EmitContext ec)
6774 li.CreateBuilder (ec);
6779 public void EmitAssign (EmitContext ec, Expression source)
6781 li.CreateBuilder (ec);
6783 EmitAssign (ec, source, false, false);
6786 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6788 return li.HoistedVariant;
6791 public override bool IsFixed {
6792 get { return true; }
6795 public override bool IsRef {
6796 get { return false; }
6799 public override string Name {
6800 get { throw new NotImplementedException (); }
6803 public override void SetHasAddressTaken ()
6805 throw new NotImplementedException ();
6808 protected override ILocalVariable Variable {
6812 public override VariableInfo VariableInfo {
6813 get { return null; }
6816 public override void VerifyAssigned (ResolveContext rc)
6822 /// Handles `var' contextual keyword; var becomes a keyword only
6823 /// if no type called var exists in a variable scope
6825 class VarExpr : SimpleName
6827 public VarExpr (Location loc)
6832 public bool InferType (ResolveContext ec, Expression right_side)
6835 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6837 type = right_side.Type;
6838 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6839 ec.Report.Error (815, loc,
6840 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6841 type.GetSignatureForError ());
6845 eclass = ExprClass.Variable;
6849 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6851 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6852 base.Error_TypeOrNamespaceNotFound (ec);
6854 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");