2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, TypeManager.CSharpName (type));
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
288 string from_type = type.GetSignatureForError ();
289 string to_type = target.GetSignatureForError ();
290 if (from_type == to_type) {
291 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
292 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
296 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
301 ec.Report.DisableReporting ();
302 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
303 ec.Report.EnableReporting ();
306 ec.Report.Error (266, loc,
307 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
310 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
315 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
317 // Better message for possible generic expressions
318 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
319 var report = context.Module.Compiler.Report;
320 report.SymbolRelatedToPreviousError (member);
321 if (member is TypeSpec)
322 member = ((TypeSpec) member).GetDefinition ();
324 member = ((MethodSpec) member).GetGenericMethodDefinition ();
326 string name = member.Kind == MemberKind.Method ? "method" : "type";
327 if (member.IsGeneric) {
328 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
329 name, member.GetSignatureForError (), member.Arity.ToString ());
331 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
332 name, member.GetSignatureForError ());
335 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
339 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
341 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
345 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
347 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
350 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
352 ec.Report.SymbolRelatedToPreviousError (type);
353 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
354 TypeManager.CSharpName (type), name);
357 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
359 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
360 // Already reported as CS1612
362 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
366 protected void Error_VoidPointerOperation (ResolveContext rc)
368 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
371 public ResolveFlags ExprClassToResolveFlags {
375 case ExprClass.Namespace:
376 return ResolveFlags.Type;
378 case ExprClass.MethodGroup:
379 return ResolveFlags.MethodGroup;
381 case ExprClass.TypeParameter:
382 return ResolveFlags.TypeParameter;
384 case ExprClass.Value:
385 case ExprClass.Variable:
386 case ExprClass.PropertyAccess:
387 case ExprClass.EventAccess:
388 case ExprClass.IndexerAccess:
389 return ResolveFlags.VariableOrValue;
392 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
398 // Implements identical simple name and type-name resolution
400 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
403 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
406 // 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
407 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
409 if (left is MemberExpr || left is VariableReference) {
410 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
411 if (identical_type != null && identical_type.Type == left.Type)
412 return identical_type;
418 public virtual string GetSignatureForError ()
420 return type.GetDefinition ().GetSignatureForError ();
424 /// Resolves an expression and performs semantic analysis on it.
428 /// Currently Resolve wraps DoResolve to perform sanity
429 /// checking and assertion checking on what we expect from Resolve.
431 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
433 if (eclass != ExprClass.Unresolved)
443 if ((flags & e.ExprClassToResolveFlags) == 0) {
444 e.Error_UnexpectedKind (ec, flags, loc);
449 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
452 } catch (Exception ex) {
453 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
456 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
457 return ErrorExpression.Instance; // TODO: Add location
462 /// Resolves an expression and performs semantic analysis on it.
464 public Expression Resolve (ResolveContext rc)
466 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
470 /// Resolves an expression for LValue assignment
474 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
475 /// checking and assertion checking on what we expect from Resolve
477 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
479 int errors = ec.Report.Errors;
480 bool out_access = right_side == EmptyExpression.OutAccess;
482 Expression e = DoResolveLValue (ec, right_side);
484 if (e != null && out_access && !(e is IMemoryLocation)) {
485 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
486 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
488 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
489 // e.GetType () + " " + e.GetSignatureForError ());
494 if (errors == ec.Report.Errors) {
496 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
498 Error_ValueAssignment (ec, right_side);
503 if (e.eclass == ExprClass.Unresolved)
504 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
506 if ((e.type == null) && !(e is GenericTypeExpr))
507 throw new Exception ("Expression " + e + " did not set its type after Resolve");
512 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
514 rc.Module.Compiler.Report.Error (182, loc,
515 "An attribute argument must be a constant expression, typeof expression or array creation expression");
519 /// Emits the code for the expression
523 /// The Emit method is invoked to generate the code
524 /// for the expression.
526 public abstract void Emit (EmitContext ec);
529 // Emit code to branch to @target if this expression is equivalent to @on_true.
530 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
531 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
532 // including the use of conditional branches. Note also that a branch MUST be emitted
533 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
536 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
539 // Emit this expression for its side effects, not for its value.
540 // The default implementation is to emit the value, and then throw it away.
541 // Subclasses can provide more efficient implementations, but those MUST be equivalent
542 public virtual void EmitSideEffect (EmitContext ec)
545 ec.Emit (OpCodes.Pop);
549 // Emits the expression into temporary field variable. The method
550 // should be used for await expressions only
552 public virtual Expression EmitToField (EmitContext ec)
555 // This is the await prepare Emit method. When emitting code like
556 // a + b we emit code like
562 // For await a + await b we have to interfere the flow to keep the
563 // stack clean because await yields from the expression. The emit
566 // a = a.EmitToField () // a is changed to temporary field access
567 // b = b.EmitToField ()
573 // The idea is to emit expression and leave the stack empty with
574 // result value still available.
576 // Expressions should override this default implementation when
577 // optimized version can be provided (e.g. FieldExpr)
580 // We can optimize for side-effect free expressions, they can be
581 // emitted out of order
583 if (IsSideEffectFree)
586 bool needs_temporary = ContainsEmitWithAwait ();
587 if (!needs_temporary)
590 // Emit original code
591 var field = EmitToFieldSource (ec);
594 // Store the result to temporary field when we
595 // cannot load `this' directly
597 field = ec.GetTemporaryField (type);
598 if (needs_temporary) {
600 // Create temporary local (we cannot load `this' before Emit)
602 var temp = ec.GetTemporaryLocal (type);
603 ec.Emit (OpCodes.Stloc, temp);
606 ec.Emit (OpCodes.Ldloc, temp);
607 field.EmitAssignFromStack (ec);
609 ec.FreeTemporaryLocal (temp, type);
611 field.EmitAssignFromStack (ec);
618 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
621 // Default implementation calls Emit method
627 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
629 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
630 bool contains_await = false;
632 for (int i = 1; i < expressions.Count; ++i) {
633 if (expressions[i].ContainsEmitWithAwait ()) {
634 contains_await = true;
639 if (contains_await) {
640 for (int i = 0; i < expressions.Count; ++i) {
641 expressions[i] = expressions[i].EmitToField (ec);
646 for (int i = 0; i < expressions.Count; ++i) {
647 expressions[i].Emit (ec);
652 /// Protected constructor. Only derivate types should
653 /// be able to be created
656 protected Expression ()
661 /// Returns a fully formed expression after a MemberLookup
664 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
666 if (spec is EventSpec)
667 return new EventExpr ((EventSpec) spec, loc);
668 if (spec is ConstSpec)
669 return new ConstantExpr ((ConstSpec) spec, loc);
670 if (spec is FieldSpec)
671 return new FieldExpr ((FieldSpec) spec, loc);
672 if (spec is PropertySpec)
673 return new PropertyExpr ((PropertySpec) spec, loc);
674 if (spec is TypeSpec)
675 return new TypeExpression (((TypeSpec) spec), loc);
680 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
682 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
684 rc.Report.SymbolRelatedToPreviousError (type);
686 // Report meaningful error for struct as they always have default ctor in C# context
687 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
689 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
690 type.GetSignatureForError ());
696 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
697 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
698 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
701 return r.ResolveMember<MethodSpec> (rc, ref args);
705 public enum MemberLookupRestrictions
714 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
715 // `qualifier_type' or null to lookup members in the current class.
717 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
719 var members = MemberCache.FindMembers (queried_type, name, false);
723 MemberSpec non_method = null;
724 MemberSpec ambig_non_method = null;
726 for (int i = 0; i < members.Count; ++i) {
727 var member = members[i];
729 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
730 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
733 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
736 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
740 if (!member.IsAccessible (rc))
744 // With runtime binder we can have a situation where queried type is inaccessible
745 // because it came via dynamic object, the check about inconsisted accessibility
746 // had no effect as the type was unknown during compilation
749 // private class N { }
751 // public dynamic Foo ()
757 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
761 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
762 if (member is MethodSpec)
763 return new MethodGroupExpr (members, queried_type, loc);
765 if (!Invocation.IsMemberInvocable (member))
769 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
771 } else if (!errorMode && !member.IsNotCSharpCompatible) {
773 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
774 // T has both an effective base class other than object and a non-empty effective interface set.
776 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
778 var tps = queried_type as TypeParameterSpec;
779 if (tps != null && tps.HasTypeConstraint) {
780 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
783 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
789 ambig_non_method = member;
793 if (non_method != null) {
794 if (ambig_non_method != null && rc != null) {
795 var report = rc.Module.Compiler.Report;
796 report.SymbolRelatedToPreviousError (non_method);
797 report.SymbolRelatedToPreviousError (ambig_non_method);
798 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
799 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
802 if (non_method is MethodSpec)
803 return new MethodGroupExpr (members, queried_type, loc);
805 return ExprClassFromMemberInfo (non_method, loc);
808 if (members[0].DeclaringType.BaseType == null)
811 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
813 } while (members != null);
818 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
820 throw new NotImplementedException ();
823 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
825 if (t == InternalType.ErrorType)
828 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
829 oper, t.GetSignatureForError ());
832 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
834 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
838 /// Returns an expression that can be used to invoke operator true
839 /// on the expression if it exists.
841 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
843 return GetOperatorTrueOrFalse (ec, e, true, loc);
847 /// Returns an expression that can be used to invoke operator false
848 /// on the expression if it exists.
850 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
852 return GetOperatorTrueOrFalse (ec, e, false, loc);
855 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
857 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
858 var methods = MemberCache.GetUserOperator (e.type, op, false);
862 Arguments arguments = new Arguments (1);
863 arguments.Add (new Argument (e));
865 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
866 var oper = res.ResolveOperator (ec, ref arguments);
871 return new UserOperatorCall (oper, arguments, null, loc);
874 public virtual string ExprClassName
878 case ExprClass.Unresolved:
880 case ExprClass.Value:
882 case ExprClass.Variable:
884 case ExprClass.Namespace:
888 case ExprClass.MethodGroup:
889 return "method group";
890 case ExprClass.PropertyAccess:
891 return "property access";
892 case ExprClass.EventAccess:
893 return "event access";
894 case ExprClass.IndexerAccess:
895 return "indexer access";
896 case ExprClass.Nothing:
898 case ExprClass.TypeParameter:
899 return "type parameter";
901 throw new Exception ("Should not happen");
906 /// Reports that we were expecting `expr' to be of class `expected'
908 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
910 var name = memberExpr.GetSignatureForError ();
912 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
915 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
917 string [] valid = new string [4];
920 if ((flags & ResolveFlags.VariableOrValue) != 0) {
921 valid [count++] = "variable";
922 valid [count++] = "value";
925 if ((flags & ResolveFlags.Type) != 0)
926 valid [count++] = "type";
928 if ((flags & ResolveFlags.MethodGroup) != 0)
929 valid [count++] = "method group";
932 valid [count++] = "unknown";
934 StringBuilder sb = new StringBuilder (valid [0]);
935 for (int i = 1; i < count - 1; i++) {
937 sb.Append (valid [i]);
940 sb.Append ("' or `");
941 sb.Append (valid [count - 1]);
944 ec.Report.Error (119, loc,
945 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
948 public static void UnsafeError (ResolveContext ec, Location loc)
950 UnsafeError (ec.Report, loc);
953 public static void UnsafeError (Report Report, Location loc)
955 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
959 // Converts `source' to an int, uint, long or ulong.
961 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
963 var btypes = ec.BuiltinTypes;
965 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
966 Arguments args = new Arguments (1);
967 args.Add (new Argument (source));
968 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
971 Expression converted;
973 using (ec.Set (ResolveContext.Options.CheckedScope)) {
974 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
975 if (converted == null)
976 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
977 if (converted == null)
978 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
979 if (converted == null)
980 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
982 if (converted == null) {
983 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
989 // Only positive constants are allowed at compile time
991 Constant c = converted as Constant;
992 if (c != null && c.IsNegative)
993 Error_NegativeArrayIndex (ec, source.loc);
995 // No conversion needed to array index
996 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
999 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1003 // Derived classes implement this method by cloning the fields that
1004 // could become altered during the Resolve stage
1006 // Only expressions that are created for the parser need to implement
1009 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1011 throw new NotImplementedException (
1013 "CloneTo not implemented for expression {0}", this.GetType ()));
1017 // Clones an expression created by the parser.
1019 // We only support expressions created by the parser so far, not
1020 // expressions that have been resolved (many more classes would need
1021 // to implement CloneTo).
1023 // This infrastructure is here merely for Lambda expressions which
1024 // compile the same code using different type values for the same
1025 // arguments to find the correct overload
1027 public virtual Expression Clone (CloneContext clonectx)
1029 Expression cloned = (Expression) MemberwiseClone ();
1030 CloneTo (clonectx, cloned);
1036 // Implementation of expression to expression tree conversion
1038 public abstract Expression CreateExpressionTree (ResolveContext ec);
1040 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1042 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1045 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1047 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1050 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1052 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1055 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1057 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1061 return new TypeExpression (t, loc);
1065 // Implemented by all expressions which support conversion from
1066 // compiler expression to invokable runtime expression. Used by
1067 // dynamic C# binder.
1069 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1071 throw new NotImplementedException ("MakeExpression for " + GetType ());
1074 public virtual object Accept (StructuralVisitor visitor)
1076 return visitor.Visit (this);
1081 /// This is just a base class for expressions that can
1082 /// appear on statements (invocations, object creation,
1083 /// assignments, post/pre increment and decrement). The idea
1084 /// being that they would support an extra Emition interface that
1085 /// does not leave a result on the stack.
1087 public abstract class ExpressionStatement : Expression
1089 public ExpressionStatement ResolveStatement (BlockContext ec)
1091 Expression e = Resolve (ec);
1095 ExpressionStatement es = e as ExpressionStatement;
1097 Error_InvalidExpressionStatement (ec);
1100 // This is quite expensive warning, try to limit the damage
1102 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1103 WarningAsyncWithoutWait (ec, e);
1109 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1111 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1112 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1117 // Need to do full resolve because GetAwaiter can be extension method
1118 // available only in this context
1120 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1124 var arguments = new Arguments (0);
1125 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1130 // Use same check rules as for real await
1132 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1133 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1136 bc.Report.Warning (4014, 1, e.Location,
1137 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1141 var inv = e as Invocation;
1142 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1143 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1144 bc.Report.Warning (4014, 1, e.Location,
1145 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1151 /// Requests the expression to be emitted in a `statement'
1152 /// context. This means that no new value is left on the
1153 /// stack after invoking this method (constrasted with
1154 /// Emit that will always leave a value on the stack).
1156 public abstract void EmitStatement (EmitContext ec);
1158 public override void EmitSideEffect (EmitContext ec)
1165 /// This kind of cast is used to encapsulate the child
1166 /// whose type is child.Type into an expression that is
1167 /// reported to return "return_type". This is used to encapsulate
1168 /// expressions which have compatible types, but need to be dealt
1169 /// at higher levels with.
1171 /// For example, a "byte" expression could be encapsulated in one
1172 /// of these as an "unsigned int". The type for the expression
1173 /// would be "unsigned int".
1176 public abstract class TypeCast : Expression
1178 protected readonly Expression child;
1180 protected TypeCast (Expression child, TypeSpec return_type)
1182 eclass = child.eclass;
1183 loc = child.Location;
1188 public Expression Child {
1194 public override bool ContainsEmitWithAwait ()
1196 return child.ContainsEmitWithAwait ();
1199 public override Expression CreateExpressionTree (ResolveContext ec)
1201 Arguments args = new Arguments (2);
1202 args.Add (new Argument (child.CreateExpressionTree (ec)));
1203 args.Add (new Argument (new TypeOf (type, loc)));
1205 if (type.IsPointer || child.Type.IsPointer)
1206 Error_PointerInsideExpressionTree (ec);
1208 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1211 protected override Expression DoResolve (ResolveContext ec)
1213 // This should never be invoked, we are born in fully
1214 // initialized state.
1219 public override void Emit (EmitContext ec)
1224 public override SLE.Expression MakeExpression (BuilderContext ctx)
1227 return base.MakeExpression (ctx);
1229 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1230 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1231 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1235 protected override void CloneTo (CloneContext clonectx, Expression t)
1240 public override bool IsNull {
1241 get { return child.IsNull; }
1245 public class EmptyCast : TypeCast {
1246 EmptyCast (Expression child, TypeSpec target_type)
1247 : base (child, target_type)
1251 public static Expression Create (Expression child, TypeSpec type)
1253 Constant c = child as Constant;
1255 return new EmptyConstantCast (c, type);
1257 EmptyCast e = child as EmptyCast;
1259 return new EmptyCast (e.child, type);
1261 return new EmptyCast (child, type);
1264 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1266 child.EmitBranchable (ec, label, on_true);
1269 public override void EmitSideEffect (EmitContext ec)
1271 child.EmitSideEffect (ec);
1276 // Used for predefined type user operator (no obsolete check, etc.)
1278 public class OperatorCast : TypeCast
1280 readonly MethodSpec conversion_operator;
1282 public OperatorCast (Expression expr, TypeSpec target_type)
1283 : this (expr, target_type, target_type, false)
1287 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1288 : this (expr, target_type, target_type, find_explicit)
1292 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1293 : base (expr, returnType)
1295 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1296 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1299 foreach (MethodSpec oper in mi) {
1300 if (oper.ReturnType != returnType)
1303 if (oper.Parameters.Types[0] == expr.Type) {
1304 conversion_operator = oper;
1310 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1311 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1314 public override void Emit (EmitContext ec)
1317 ec.Emit (OpCodes.Call, conversion_operator);
1322 // Constant specialization of EmptyCast.
1323 // We need to special case this since an empty cast of
1324 // a constant is still a constant.
1326 public class EmptyConstantCast : Constant
1328 public readonly Constant child;
1330 public EmptyConstantCast (Constant child, TypeSpec type)
1331 : base (child.Location)
1334 throw new ArgumentNullException ("child");
1337 this.eclass = child.eclass;
1341 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1343 if (child.Type == target_type)
1346 // FIXME: check that 'type' can be converted to 'target_type' first
1347 return child.ConvertExplicitly (in_checked_context, target_type);
1350 public override Expression CreateExpressionTree (ResolveContext ec)
1352 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1353 child.CreateExpressionTree (ec),
1354 new TypeOf (type, loc));
1357 Error_PointerInsideExpressionTree (ec);
1359 return CreateExpressionFactoryCall (ec, "Convert", args);
1362 public override bool IsDefaultValue {
1363 get { return child.IsDefaultValue; }
1366 public override bool IsNegative {
1367 get { return child.IsNegative; }
1370 public override bool IsNull {
1371 get { return child.IsNull; }
1374 public override bool IsOneInteger {
1375 get { return child.IsOneInteger; }
1378 public override bool IsSideEffectFree {
1380 return child.IsSideEffectFree;
1384 public override bool IsZeroInteger {
1385 get { return child.IsZeroInteger; }
1388 public override void Emit (EmitContext ec)
1393 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1395 child.EmitBranchable (ec, label, on_true);
1397 // Only to make verifier happy
1398 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1399 ec.Emit (OpCodes.Unbox_Any, type);
1402 public override void EmitSideEffect (EmitContext ec)
1404 child.EmitSideEffect (ec);
1407 public override object GetValue ()
1409 return child.GetValue ();
1412 public override string GetValueAsLiteral ()
1414 return child.GetValueAsLiteral ();
1417 public override long GetValueAsLong ()
1419 return child.GetValueAsLong ();
1422 public override Constant ConvertImplicitly (TypeSpec target_type)
1424 if (type == target_type)
1427 // FIXME: Do we need to check user conversions?
1428 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1431 return child.ConvertImplicitly (target_type);
1436 /// This class is used to wrap literals which belong inside Enums
1438 public class EnumConstant : Constant
1440 public Constant Child;
1442 public EnumConstant (Constant child, TypeSpec enum_type)
1443 : base (child.Location)
1447 this.eclass = ExprClass.Value;
1448 this.type = enum_type;
1451 protected EnumConstant (Location loc)
1456 public override void Emit (EmitContext ec)
1461 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1463 Child.EncodeAttributeValue (rc, enc, Child.Type);
1466 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1468 Child.EmitBranchable (ec, label, on_true);
1471 public override void EmitSideEffect (EmitContext ec)
1473 Child.EmitSideEffect (ec);
1476 public override string GetSignatureForError()
1478 return TypeManager.CSharpName (Type);
1481 public override object GetValue ()
1483 return Child.GetValue ();
1487 public override object GetTypedValue ()
1490 // The method can be used in dynamic context only (on closed types)
1492 // System.Enum.ToObject cannot be called on dynamic types
1493 // EnumBuilder has to be used, but we cannot use EnumBuilder
1494 // because it does not properly support generics
1496 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1500 public override string GetValueAsLiteral ()
1502 return Child.GetValueAsLiteral ();
1505 public override long GetValueAsLong ()
1507 return Child.GetValueAsLong ();
1510 public EnumConstant Increment()
1512 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1515 public override bool IsDefaultValue {
1517 return Child.IsDefaultValue;
1521 public override bool IsSideEffectFree {
1523 return Child.IsSideEffectFree;
1527 public override bool IsZeroInteger {
1528 get { return Child.IsZeroInteger; }
1531 public override bool IsNegative {
1533 return Child.IsNegative;
1537 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1539 if (Child.Type == target_type)
1542 return Child.ConvertExplicitly (in_checked_context, target_type);
1545 public override Constant ConvertImplicitly (TypeSpec type)
1547 if (this.type == type) {
1551 if (!Convert.ImplicitStandardConversionExists (this, type)){
1555 return Child.ConvertImplicitly (type);
1560 /// This kind of cast is used to encapsulate Value Types in objects.
1562 /// The effect of it is to box the value type emitted by the previous
1565 public class BoxedCast : TypeCast {
1567 public BoxedCast (Expression expr, TypeSpec target_type)
1568 : base (expr, target_type)
1570 eclass = ExprClass.Value;
1573 protected override Expression DoResolve (ResolveContext ec)
1575 // This should never be invoked, we are born in fully
1576 // initialized state.
1581 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1583 // Only boxing to object type is supported
1584 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1585 base.EncodeAttributeValue (rc, enc, targetType);
1589 enc.Encode (child.Type);
1590 child.EncodeAttributeValue (rc, enc, child.Type);
1593 public override void Emit (EmitContext ec)
1597 ec.Emit (OpCodes.Box, child.Type);
1600 public override void EmitSideEffect (EmitContext ec)
1602 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1603 // so, we need to emit the box+pop instructions in most cases
1604 if (child.Type.IsStruct &&
1605 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1606 child.EmitSideEffect (ec);
1608 base.EmitSideEffect (ec);
1612 public class UnboxCast : TypeCast {
1613 public UnboxCast (Expression expr, TypeSpec return_type)
1614 : base (expr, return_type)
1618 protected override Expression DoResolve (ResolveContext ec)
1620 // This should never be invoked, we are born in fully
1621 // initialized state.
1626 public override void Emit (EmitContext ec)
1630 ec.Emit (OpCodes.Unbox_Any, type);
1635 /// This is used to perform explicit numeric conversions.
1637 /// Explicit numeric conversions might trigger exceptions in a checked
1638 /// context, so they should generate the conv.ovf opcodes instead of
1641 public class ConvCast : TypeCast {
1642 public enum Mode : byte {
1643 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1645 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1646 U2_I1, U2_U1, U2_I2, U2_CH,
1647 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1648 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1649 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1650 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1651 CH_I1, CH_U1, CH_I2,
1652 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1653 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1659 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1660 : base (child, return_type)
1665 protected override Expression DoResolve (ResolveContext ec)
1667 // This should never be invoked, we are born in fully
1668 // initialized state.
1673 public override string ToString ()
1675 return String.Format ("ConvCast ({0}, {1})", mode, child);
1678 public override void Emit (EmitContext ec)
1682 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1684 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1685 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1686 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1687 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1688 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1690 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1691 case Mode.U1_CH: /* nothing */ break;
1693 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1694 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1695 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1696 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1697 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1698 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1700 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1701 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1702 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1703 case Mode.U2_CH: /* nothing */ break;
1705 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1706 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1707 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1708 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1709 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1710 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1711 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1713 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1714 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1715 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1716 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1717 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1718 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1720 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1721 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1722 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1723 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1724 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1725 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1726 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1727 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1728 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1730 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1731 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1732 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1733 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1734 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1735 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1736 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1737 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1738 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1740 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1741 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1742 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1744 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1745 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1746 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1747 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1748 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1749 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1750 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1751 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1752 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1754 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1755 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1756 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1757 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1758 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1759 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1760 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1761 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1762 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1763 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1765 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1769 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1770 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1771 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1772 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1773 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1775 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1776 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1778 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1779 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1780 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1781 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1782 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1783 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1785 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1786 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1787 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1788 case Mode.U2_CH: /* nothing */ break;
1790 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1791 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1792 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1793 case Mode.I4_U4: /* nothing */ break;
1794 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1795 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1796 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1798 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1799 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1800 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1801 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1802 case Mode.U4_I4: /* nothing */ break;
1803 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1805 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1806 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1807 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1808 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1809 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1810 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1811 case Mode.I8_U8: /* nothing */ break;
1812 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1813 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1815 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1816 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1817 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1818 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1819 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1820 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1821 case Mode.U8_I8: /* nothing */ break;
1822 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1823 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1825 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1826 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1827 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1829 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1830 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1831 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1832 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1833 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1834 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1835 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1836 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1837 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1839 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1840 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1841 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1842 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1843 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1844 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1845 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1846 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1847 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1848 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1850 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1856 class OpcodeCast : TypeCast
1860 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1861 : base (child, return_type)
1866 protected override Expression DoResolve (ResolveContext ec)
1868 // This should never be invoked, we are born in fully
1869 // initialized state.
1874 public override void Emit (EmitContext ec)
1880 public TypeSpec UnderlyingType {
1881 get { return child.Type; }
1886 // Opcode casts expression with 2 opcodes but only
1887 // single expression tree node
1889 class OpcodeCastDuplex : OpcodeCast
1891 readonly OpCode second;
1893 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1894 : base (child, returnType, first)
1896 this.second = second;
1899 public override void Emit (EmitContext ec)
1907 /// This kind of cast is used to encapsulate a child and cast it
1908 /// to the class requested
1910 public sealed class ClassCast : TypeCast {
1911 readonly bool forced;
1913 public ClassCast (Expression child, TypeSpec return_type)
1914 : base (child, return_type)
1918 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1919 : base (child, return_type)
1921 this.forced = forced;
1924 public override void Emit (EmitContext ec)
1928 bool gen = TypeManager.IsGenericParameter (child.Type);
1930 ec.Emit (OpCodes.Box, child.Type);
1932 if (type.IsGenericParameter) {
1933 ec.Emit (OpCodes.Unbox_Any, type);
1940 ec.Emit (OpCodes.Castclass, type);
1945 // Created during resolving pahse when an expression is wrapped or constantified
1946 // and original expression can be used later (e.g. for expression trees)
1948 public class ReducedExpression : Expression
1950 sealed class ReducedConstantExpression : EmptyConstantCast
1952 readonly Expression orig_expr;
1954 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1955 : base (expr, expr.Type)
1957 this.orig_expr = orig_expr;
1960 public override Constant ConvertImplicitly (TypeSpec target_type)
1962 Constant c = base.ConvertImplicitly (target_type);
1964 c = new ReducedConstantExpression (c, orig_expr);
1969 public override Expression CreateExpressionTree (ResolveContext ec)
1971 return orig_expr.CreateExpressionTree (ec);
1974 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1976 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1978 c = new ReducedConstantExpression (c, orig_expr);
1982 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1985 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1987 if (orig_expr is Conditional)
1988 child.EncodeAttributeValue (rc, enc, targetType);
1990 base.EncodeAttributeValue (rc, enc, targetType);
1994 sealed class ReducedExpressionStatement : ExpressionStatement
1996 readonly Expression orig_expr;
1997 readonly ExpressionStatement stm;
1999 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2001 this.orig_expr = orig;
2003 this.eclass = stm.eclass;
2004 this.type = stm.Type;
2006 this.loc = orig.Location;
2009 public override bool ContainsEmitWithAwait ()
2011 return stm.ContainsEmitWithAwait ();
2014 public override Expression CreateExpressionTree (ResolveContext ec)
2016 return orig_expr.CreateExpressionTree (ec);
2019 protected override Expression DoResolve (ResolveContext ec)
2024 public override void Emit (EmitContext ec)
2029 public override void EmitStatement (EmitContext ec)
2031 stm.EmitStatement (ec);
2035 readonly Expression expr, orig_expr;
2037 private ReducedExpression (Expression expr, Expression orig_expr)
2040 this.eclass = expr.eclass;
2041 this.type = expr.Type;
2042 this.orig_expr = orig_expr;
2043 this.loc = orig_expr.Location;
2048 public override bool IsSideEffectFree {
2050 return expr.IsSideEffectFree;
2054 public Expression OriginalExpression {
2062 public override bool ContainsEmitWithAwait ()
2064 return expr.ContainsEmitWithAwait ();
2068 // Creates fully resolved expression switcher
2070 public static Constant Create (Constant expr, Expression original_expr)
2072 if (expr.eclass == ExprClass.Unresolved)
2073 throw new ArgumentException ("Unresolved expression");
2075 return new ReducedConstantExpression (expr, original_expr);
2078 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2080 return new ReducedExpressionStatement (s, orig);
2083 public static Expression Create (Expression expr, Expression original_expr)
2085 return Create (expr, original_expr, true);
2089 // Creates unresolved reduce expression. The original expression has to be
2090 // already resolved. Created expression is constant based based on `expr'
2091 // value unless canBeConstant is used
2093 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2095 if (canBeConstant) {
2096 Constant c = expr as Constant;
2098 return Create (c, original_expr);
2101 ExpressionStatement s = expr as ExpressionStatement;
2103 return Create (s, original_expr);
2105 if (expr.eclass == ExprClass.Unresolved)
2106 throw new ArgumentException ("Unresolved expression");
2108 return new ReducedExpression (expr, original_expr);
2111 public override Expression CreateExpressionTree (ResolveContext ec)
2113 return orig_expr.CreateExpressionTree (ec);
2116 protected override Expression DoResolve (ResolveContext ec)
2121 public override void Emit (EmitContext ec)
2126 public override Expression EmitToField (EmitContext ec)
2128 return expr.EmitToField(ec);
2131 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2133 expr.EmitBranchable (ec, target, on_true);
2136 public override SLE.Expression MakeExpression (BuilderContext ctx)
2138 return orig_expr.MakeExpression (ctx);
2143 // Standard composite pattern
2145 public abstract class CompositeExpression : Expression
2147 protected Expression expr;
2149 protected CompositeExpression (Expression expr)
2152 this.loc = expr.Location;
2155 public override bool ContainsEmitWithAwait ()
2157 return expr.ContainsEmitWithAwait ();
2160 public override Expression CreateExpressionTree (ResolveContext rc)
2162 return expr.CreateExpressionTree (rc);
2165 public Expression Child {
2166 get { return expr; }
2169 protected override Expression DoResolve (ResolveContext rc)
2171 expr = expr.Resolve (rc);
2174 eclass = expr.eclass;
2180 public override void Emit (EmitContext ec)
2185 public override bool IsNull {
2186 get { return expr.IsNull; }
2191 // Base of expressions used only to narrow resolve flow
2193 public abstract class ShimExpression : Expression
2195 protected Expression expr;
2197 protected ShimExpression (Expression expr)
2202 public Expression Expr {
2208 protected override void CloneTo (CloneContext clonectx, Expression t)
2213 ShimExpression target = (ShimExpression) t;
2214 target.expr = expr.Clone (clonectx);
2217 public override bool ContainsEmitWithAwait ()
2219 return expr.ContainsEmitWithAwait ();
2222 public override Expression CreateExpressionTree (ResolveContext ec)
2224 throw new NotSupportedException ("ET");
2227 public override void Emit (EmitContext ec)
2229 throw new InternalErrorException ("Missing Resolve call");
2235 // Unresolved type name expressions
2237 public abstract class ATypeNameExpression : FullNamedExpression
2240 protected TypeArguments targs;
2242 protected ATypeNameExpression (string name, Location l)
2248 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2255 protected ATypeNameExpression (string name, int arity, Location l)
2256 : this (name, new UnboundTypeArguments (arity), l)
2262 protected int Arity {
2264 return targs == null ? 0 : targs.Count;
2268 public bool HasTypeArguments {
2270 return targs != null && !targs.IsEmpty;
2274 public string Name {
2283 public TypeArguments TypeArguments {
2291 public override bool Equals (object obj)
2293 ATypeNameExpression atne = obj as ATypeNameExpression;
2294 return atne != null && atne.Name == Name &&
2295 (targs == null || targs.Equals (atne.targs));
2298 public override int GetHashCode ()
2300 return Name.GetHashCode ();
2303 // TODO: Move it to MemberCore
2304 public static string GetMemberType (MemberCore mc)
2310 if (mc is FieldBase)
2312 if (mc is MethodCore)
2314 if (mc is EnumMember)
2322 public override string GetSignatureForError ()
2324 if (targs != null) {
2325 return Name + "<" + targs.GetSignatureForError () + ">";
2331 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2335 /// SimpleName expressions are formed of a single word and only happen at the beginning
2336 /// of a dotted-name.
2338 public class SimpleName : ATypeNameExpression
2340 public SimpleName (string name, Location l)
2345 public SimpleName (string name, TypeArguments args, Location l)
2346 : base (name, args, l)
2350 public SimpleName (string name, int arity, Location l)
2351 : base (name, arity, l)
2355 public SimpleName GetMethodGroup ()
2357 return new SimpleName (Name, targs, loc);
2360 protected override Expression DoResolve (ResolveContext rc)
2362 var e = SimpleNameResolve (rc, null, false);
2364 var fe = e as FieldExpr;
2366 fe.VerifyAssignedStructField (rc, null);
2372 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2374 return SimpleNameResolve (ec, right_side, false);
2377 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2379 if (ctx.CurrentType != null) {
2380 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2381 if (member != null) {
2382 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2387 var report = ctx.Module.Compiler.Report;
2389 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2390 if (retval != null) {
2391 report.SymbolRelatedToPreviousError (retval.Type);
2392 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2396 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2397 if (retval != null) {
2398 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2402 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2403 if (ns_candidates != null) {
2404 if (ctx is UsingAliasNamespace.AliasContext) {
2405 report.Error (246, loc,
2406 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2407 ns_candidates[0], Name);
2409 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2410 report.Error (246, loc,
2411 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2415 report.Error (246, loc,
2416 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2421 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2423 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2426 if (fne.Type != null && Arity > 0) {
2427 if (HasTypeArguments) {
2428 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2429 if (ct.ResolveAsType (ec) == null)
2435 return new GenericOpenTypeExpr (fne.Type, loc);
2439 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2441 if (!(fne is Namespace))
2445 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2446 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2447 ec.Module.Compiler.Report.Error (1980, Location,
2448 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2449 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2452 fne = new DynamicTypeExpr (loc);
2453 fne.ResolveAsType (ec);
2459 Error_TypeOrNamespaceNotFound (ec);
2463 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2465 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2468 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2470 int lookup_arity = Arity;
2471 bool errorMode = false;
2473 Block current_block = rc.CurrentBlock;
2474 INamedBlockVariable variable = null;
2475 bool variable_found = false;
2479 // Stage 1: binding to local variables or parameters
2481 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2483 if (current_block != null && lookup_arity == 0) {
2484 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2485 if (!variable.IsDeclared) {
2486 // We found local name in accessible block but it's not
2487 // initialized yet, maybe the user wanted to bind to something else
2489 variable_found = true;
2491 e = variable.CreateReferenceExpression (rc, loc);
2494 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2503 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2505 TypeSpec member_type = rc.CurrentType;
2506 for (; member_type != null; member_type = member_type.DeclaringType) {
2507 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2511 var me = e as MemberExpr;
2513 // The name matches a type, defer to ResolveAsTypeStep
2521 if (variable != null) {
2522 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2523 rc.Report.Error (844, loc,
2524 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2525 Name, me.GetSignatureForError ());
2529 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2530 // Leave it to overload resolution to report correct error
2532 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2533 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2536 // LAMESPEC: again, ignores InvocableOnly
2537 if (variable != null) {
2538 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2539 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2543 // MemberLookup does not check accessors availability, this is actually needed for properties only
2545 var pe = me as PropertyExpr;
2548 // Break as there is no other overload available anyway
2549 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2550 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2553 pe.Getter = pe.PropertyInfo.Get;
2555 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2558 pe.Setter = pe.PropertyInfo.Set;
2563 // TODO: It's used by EventExpr -> FieldExpr transformation only
2564 // TODO: Should go to MemberAccess
2565 me = me.ResolveMemberAccess (rc, null, null);
2569 me.SetTypeArguments (rc, targs);
2576 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2578 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2579 if (IsPossibleTypeOrNamespace (rc)) {
2580 if (variable != null) {
2581 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2582 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2585 return ResolveAsTypeOrNamespace (rc);
2590 if (variable_found) {
2591 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2594 var tparams = rc.CurrentTypeParameters;
2595 if (tparams != null) {
2596 if (tparams.Find (Name) != null) {
2597 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2602 var ct = rc.CurrentType;
2604 if (ct.MemberDefinition.TypeParametersCount > 0) {
2605 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2606 if (ctp.Name == Name) {
2607 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2613 ct = ct.DeclaringType;
2614 } while (ct != null);
2617 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2618 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2620 rc.Report.SymbolRelatedToPreviousError (e.Type);
2621 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2625 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2627 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2628 return ErrorExpression.Instance;
2632 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2634 if (e.Type.Arity != Arity) {
2635 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2639 if (e is TypeExpr) {
2640 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2645 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2648 return ErrorExpression.Instance;
2651 if (rc.Module.Evaluator != null) {
2652 var fi = rc.Module.Evaluator.LookupField (Name);
2654 return new FieldExpr (fi.Item1, loc);
2662 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2664 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2669 if (right_side != null) {
2670 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2671 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2675 e = e.ResolveLValue (ec, right_side);
2683 public override object Accept (StructuralVisitor visitor)
2685 return visitor.Visit (this);
2690 /// Represents a namespace or a type. The name of the class was inspired by
2691 /// section 10.8.1 (Fully Qualified Names).
2693 public abstract class FullNamedExpression : Expression
2695 protected override void CloneTo (CloneContext clonectx, Expression target)
2697 // Do nothing, most unresolved type expressions cannot be
2698 // resolved to different type
2701 public override bool ContainsEmitWithAwait ()
2706 public override Expression CreateExpressionTree (ResolveContext ec)
2708 throw new NotSupportedException ("ET");
2711 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2714 // This is used to resolve the expression as a type, a null
2715 // value will be returned if the expression is not a type
2718 public override TypeSpec ResolveAsType (IMemberContext mc)
2720 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2725 TypeExpr te = fne as TypeExpr;
2727 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2735 var dep = type.GetMissingDependencies ();
2737 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2740 if (type.Kind == MemberKind.Void) {
2741 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2745 // Obsolete checks cannot be done when resolving base context as they
2746 // require type dependencies to be set but we are in process of resolving them
2748 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2749 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2750 if (obsolete_attr != null && !mc.IsObsolete) {
2751 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2759 public override void Emit (EmitContext ec)
2761 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2762 GetSignatureForError ());
2767 /// Expression that evaluates to a type
2769 public abstract class TypeExpr : FullNamedExpression
2771 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2777 protected sealed override Expression DoResolve (ResolveContext ec)
2783 public override bool Equals (object obj)
2785 TypeExpr tobj = obj as TypeExpr;
2789 return Type == tobj.Type;
2792 public override int GetHashCode ()
2794 return Type.GetHashCode ();
2799 /// Fully resolved Expression that already evaluated to a type
2801 public class TypeExpression : TypeExpr
2803 public TypeExpression (TypeSpec t, Location l)
2806 eclass = ExprClass.Type;
2810 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2817 /// This class denotes an expression which evaluates to a member
2818 /// of a struct or a class.
2820 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2823 // An instance expression associated with this member, if it's a
2824 // non-static member
2826 public Expression InstanceExpression;
2829 /// The name of this member.
2831 public abstract string Name {
2836 // When base.member is used
2838 public bool IsBase {
2839 get { return InstanceExpression is BaseThis; }
2843 /// Whether this is an instance member.
2845 public abstract bool IsInstance {
2850 /// Whether this is a static member.
2852 public abstract bool IsStatic {
2856 public abstract string KindName {
2860 protected abstract TypeSpec DeclaringType {
2864 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2866 return InstanceExpression.Type;
2871 // Converts best base candidate for virtual method starting from QueriedBaseType
2873 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2876 // Only when base.member is used and method is virtual
2882 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2883 // means for base.member access we have to find the closest match after we found best candidate
2885 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2887 // The method could already be what we are looking for
2889 TypeSpec[] targs = null;
2890 if (method.DeclaringType != InstanceExpression.Type) {
2891 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2892 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2893 if (base_override.IsGeneric)
2894 targs = method.TypeArguments;
2896 method = base_override;
2901 // When base access is used inside anonymous method/iterator/etc we need to
2902 // get back to the context of original type. We do it by emiting proxy
2903 // method in original class and rewriting base call to this compiler
2904 // generated method call which does the actual base invocation. This may
2905 // introduce redundant storey but with `this' only but it's tricky to avoid
2906 // at this stage as we don't know what expressions follow base
2908 if (rc.CurrentAnonymousMethod != null) {
2909 if (targs == null && method.IsGeneric) {
2910 targs = method.TypeArguments;
2911 method = method.GetGenericMethodDefinition ();
2914 if (method.Parameters.HasArglist)
2915 throw new NotImplementedException ("__arglist base call proxy");
2917 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2919 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2920 // get/set member expressions second call would fail to proxy because left expression
2921 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2922 // FIXME: The async check is another hack but will probably fail with mutators
2923 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2924 InstanceExpression = new This (loc).Resolve (rc);
2928 method = method.MakeGenericMethod (rc, targs);
2932 // Only base will allow this invocation to happen.
2934 if (method.IsAbstract) {
2935 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2941 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2943 if (InstanceExpression == null)
2946 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2947 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2948 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2953 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2955 if (InstanceExpression == null)
2958 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2961 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2963 var ct = rc.CurrentType;
2964 if (ct == qualifier)
2967 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2970 qualifier = qualifier.GetDefinition ();
2971 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2978 public override bool ContainsEmitWithAwait ()
2980 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2983 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2986 type = type.GetDefinition ();
2988 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2991 type = type.DeclaringType;
2992 } while (type != null);
2997 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2999 if (InstanceExpression != null) {
3000 InstanceExpression = InstanceExpression.Resolve (rc);
3001 CheckProtectedMemberAccess (rc, member);
3004 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3005 UnsafeError (rc, loc);
3008 var dep = member.GetMissingDependencies ();
3010 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3013 if (!rc.IsObsolete) {
3014 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3016 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3019 if (!(member is FieldSpec))
3020 member.MemberDefinition.SetIsUsed ();
3023 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3025 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3028 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3030 rc.Report.SymbolRelatedToPreviousError (member);
3031 rc.Report.Error (1540, loc,
3032 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3033 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3036 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3038 if (!ResolveInstanceExpressionCore (rc, rhs))
3042 // Check intermediate value modification which won't have any effect
3044 if (rhs != null && InstanceExpression.Type.IsStruct &&
3045 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3047 if (rc.CurrentInitializerVariable != null) {
3048 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3049 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3051 rc.Report.Error (1612, loc,
3052 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3053 InstanceExpression.GetSignatureForError ());
3060 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3063 if (InstanceExpression != null) {
3064 if (InstanceExpression is TypeExpr) {
3065 var t = InstanceExpression.Type;
3067 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3068 if (oa != null && !rc.IsObsolete) {
3069 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3072 t = t.DeclaringType;
3073 } while (t != null);
3075 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3076 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3077 rc.Report.Error (176, loc,
3078 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3079 GetSignatureForError ());
3083 InstanceExpression = null;
3089 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3090 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3091 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3092 rc.Report.Error (236, loc,
3093 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3094 GetSignatureForError ());
3096 rc.Report.Error (120, loc,
3097 "An object reference is required to access non-static member `{0}'",
3098 GetSignatureForError ());
3100 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3104 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3105 rc.Report.Error (38, loc,
3106 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3107 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3110 InstanceExpression = new This (loc);
3111 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3112 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3113 InstanceExpression = InstanceExpression.Resolve (rc);
3116 InstanceExpression = InstanceExpression.Resolve (rc);
3122 var me = InstanceExpression as MemberExpr;
3124 me.ResolveInstanceExpressionCore (rc, rhs);
3126 // Using this check to detect probing instance expression resolve
3127 if (!rc.OmitStructFlowAnalysis) {
3128 var fe = me as FieldExpr;
3129 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3130 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3131 rc.Report.Warning (1690, 1, loc,
3132 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3133 me.GetSignatureForError ());
3141 // Run member-access postponed check once we know that
3142 // the expression is not field expression which is the only
3143 // expression which can use uninitialized this
3145 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3146 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3150 // Additional checks for l-value member access
3153 if (InstanceExpression is UnboxCast) {
3154 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3161 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3163 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3164 ec.Report.Warning (1720, 1, left.Location,
3165 "Expression will always cause a `{0}'", "System.NullReferenceException");
3168 InstanceExpression = left;
3172 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3174 TypeSpec instance_type = InstanceExpression.Type;
3175 if (TypeSpec.IsValueType (instance_type)) {
3176 if (InstanceExpression is IMemoryLocation) {
3177 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3179 // Cannot release the temporary variable when its address
3180 // is required to be on stack for any parent
3181 LocalTemporary t = new LocalTemporary (instance_type);
3182 InstanceExpression.Emit (ec);
3184 t.AddressOf (ec, AddressOp.Store);
3187 InstanceExpression.Emit (ec);
3189 // Only to make verifier happy
3190 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3191 ec.Emit (OpCodes.Box, instance_type);
3194 if (prepare_for_load)
3195 ec.Emit (OpCodes.Dup);
3198 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3201 public class ExtensionMethodCandidates
3203 readonly NamespaceContainer container;
3204 readonly IList<MethodSpec> methods;
3206 readonly IMemberContext context;
3208 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3210 this.context = context;
3211 this.methods = methods;
3212 this.container = nsContainer;
3213 this.index = lookupIndex;
3216 public NamespaceContainer Container {
3222 public IMemberContext Context {
3228 public int LookupIndex {
3234 public IList<MethodSpec> Methods {
3242 // Represents a group of extension method candidates for whole namespace
3244 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3246 ExtensionMethodCandidates candidates;
3247 public Expression ExtensionExpression;
3249 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3250 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3252 this.candidates = candidates;
3253 this.ExtensionExpression = extensionExpr;
3256 public override bool IsStatic {
3257 get { return true; }
3261 // For extension methodgroup we are not looking for base members but parent
3262 // namespace extension methods
3264 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3266 // TODO: candidates are null only when doing error reporting, that's
3267 // incorrect. We have to discover same extension methods in error mode
3268 if (candidates == null)
3271 int arity = type_arguments == null ? 0 : type_arguments.Count;
3273 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3274 if (candidates == null)
3277 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3280 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3282 // We are already here
3286 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3288 if (arguments == null)
3289 arguments = new Arguments (1);
3291 ExtensionExpression = ExtensionExpression.Resolve (ec);
3292 if (ExtensionExpression == null)
3295 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3296 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3298 // Store resolved argument and restore original arguments
3300 // Clean-up modified arguments for error reporting
3301 arguments.RemoveAt (0);
3305 var me = ExtensionExpression as MemberExpr;
3307 me.ResolveInstanceExpression (ec, null);
3308 var fe = me as FieldExpr;
3310 fe.Spec.MemberDefinition.SetIsUsed ();
3313 InstanceExpression = null;
3317 #region IErrorHandler Members
3319 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3324 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3326 rc.Report.SymbolRelatedToPreviousError (best);
3327 rc.Report.Error (1928, loc,
3328 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3329 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3332 rc.Report.Error (1929, loc,
3333 "Extension method instance type `{0}' cannot be converted to `{1}'",
3334 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3340 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3345 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3354 /// MethodGroupExpr represents a group of method candidates which
3355 /// can be resolved to the best method overload
3357 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3359 protected IList<MemberSpec> Methods;
3360 MethodSpec best_candidate;
3361 TypeSpec best_candidate_return;
3362 protected TypeArguments type_arguments;
3364 SimpleName simple_name;
3365 protected TypeSpec queried_type;
3367 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3371 this.type = InternalType.MethodGroup;
3373 eclass = ExprClass.MethodGroup;
3374 queried_type = type;
3377 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3378 : this (new MemberSpec[] { m }, type, loc)
3384 public MethodSpec BestCandidate {
3386 return best_candidate;
3390 public TypeSpec BestCandidateReturnType {
3392 return best_candidate_return;
3396 public IList<MemberSpec> Candidates {
3402 protected override TypeSpec DeclaringType {
3404 return queried_type;
3408 public override bool IsInstance {
3410 if (best_candidate != null)
3411 return !best_candidate.IsStatic;
3417 public override bool IsStatic {
3419 if (best_candidate != null)
3420 return best_candidate.IsStatic;
3426 public override string KindName {
3427 get { return "method"; }
3430 public override string Name {
3432 if (best_candidate != null)
3433 return best_candidate.Name;
3436 return Methods.First ().Name;
3443 // When best candidate is already know this factory can be used
3444 // to avoid expensive overload resolution to be called
3446 // NOTE: InstanceExpression has to be set manually
3448 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3450 return new MethodGroupExpr (best, queriedType, loc) {
3451 best_candidate = best,
3452 best_candidate_return = best.ReturnType
3456 public override string GetSignatureForError ()
3458 if (best_candidate != null)
3459 return best_candidate.GetSignatureForError ();
3461 return Methods.First ().GetSignatureForError ();
3464 public override Expression CreateExpressionTree (ResolveContext ec)
3466 if (best_candidate == null) {
3467 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3471 if (best_candidate.IsConditionallyExcluded (ec, loc))
3472 ec.Report.Error (765, loc,
3473 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3475 return new TypeOfMethod (best_candidate, loc);
3478 protected override Expression DoResolve (ResolveContext ec)
3480 this.eclass = ExprClass.MethodGroup;
3482 if (InstanceExpression != null) {
3483 InstanceExpression = InstanceExpression.Resolve (ec);
3484 if (InstanceExpression == null)
3491 public override void Emit (EmitContext ec)
3493 throw new NotSupportedException ();
3496 public void EmitCall (EmitContext ec, Arguments arguments)
3498 var call = new CallEmitter ();
3499 call.InstanceExpression = InstanceExpression;
3500 call.Emit (ec, best_candidate, arguments, loc);
3503 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3505 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3506 Name, TypeManager.CSharpName (target));
3509 public static bool IsExtensionMethodArgument (Expression expr)
3512 // LAMESPEC: No details about which expressions are not allowed
3514 return !(expr is TypeExpr) && !(expr is BaseThis);
3518 /// Find the Applicable Function Members (7.4.2.1)
3520 /// me: Method Group expression with the members to select.
3521 /// it might contain constructors or methods (or anything
3522 /// that maps to a method).
3524 /// Arguments: ArrayList containing resolved Argument objects.
3526 /// loc: The location if we want an error to be reported, or a Null
3527 /// location for "probing" purposes.
3529 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3530 /// that is the best match of me on Arguments.
3533 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3535 // TODO: causes issues with probing mode, remove explicit Kind check
3536 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3539 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3540 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3541 r.BaseMembersProvider = this;
3542 r.InstanceQualifier = this;
3545 if (cerrors != null)
3546 r.CustomErrors = cerrors;
3548 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3549 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3550 if (best_candidate == null)
3551 return r.BestCandidateIsDynamic ? this : null;
3553 // Overload resolver had to create a new method group, all checks bellow have already been executed
3554 if (r.BestCandidateNewMethodGroup != null)
3555 return r.BestCandidateNewMethodGroup;
3557 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3558 if (InstanceExpression != null) {
3559 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3560 InstanceExpression = null;
3562 if (best_candidate.IsStatic && simple_name != null) {
3563 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3566 InstanceExpression.Resolve (ec);
3570 ResolveInstanceExpression (ec, null);
3573 var base_override = CandidateToBaseOverride (ec, best_candidate);
3574 if (base_override == best_candidate) {
3575 best_candidate_return = r.BestCandidateReturnType;
3577 best_candidate = base_override;
3578 best_candidate_return = best_candidate.ReturnType;
3581 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3582 ConstraintChecker cc = new ConstraintChecker (ec);
3583 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3587 // Additional check for possible imported base override method which
3588 // could not be done during IsOverrideMethodBaseTypeAccessible
3590 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3591 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3592 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3593 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3599 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3601 var fe = left as FieldExpr;
3604 // Using method-group on struct fields makes the struct assigned. I am not sure
3605 // why but that's what .net does
3607 fe.Spec.MemberDefinition.SetIsAssigned ();
3610 simple_name = original;
3611 return base.ResolveMemberAccess (ec, left, original);
3614 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3616 type_arguments = ta;
3619 #region IBaseMembersProvider Members
3621 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3623 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3626 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3628 if (queried_type == member.DeclaringType)
3631 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3632 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3636 // Extension methods lookup after ordinary methods candidates failed to apply
3638 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3640 if (InstanceExpression == null)
3643 InstanceExpression = InstanceExpression.Resolve (rc);
3644 if (!IsExtensionMethodArgument (InstanceExpression))
3647 int arity = type_arguments == null ? 0 : type_arguments.Count;
3648 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3649 if (methods == null)
3652 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3653 emg.SetTypeArguments (rc, type_arguments);
3660 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3662 public ConstructorInstanceQualifier (TypeSpec type)
3665 InstanceType = type;
3668 public TypeSpec InstanceType { get; private set; }
3670 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3672 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3676 public struct OverloadResolver
3679 public enum Restrictions
3683 ProbingOnly = 1 << 1,
3684 CovariantDelegate = 1 << 2,
3685 NoBaseMembers = 1 << 3,
3686 BaseMembersIncluded = 1 << 4
3689 public interface IBaseMembersProvider
3691 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3692 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3693 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3696 public interface IErrorHandler
3698 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3699 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3700 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3701 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3704 public interface IInstanceQualifier
3706 TypeSpec InstanceType { get; }
3707 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3710 sealed class NoBaseMembers : IBaseMembersProvider
3712 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3714 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3719 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3724 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3730 struct AmbiguousCandidate
3732 public readonly MemberSpec Member;
3733 public readonly bool Expanded;
3734 public readonly AParametersCollection Parameters;
3736 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3739 Parameters = parameters;
3740 Expanded = expanded;
3745 IList<MemberSpec> members;
3746 TypeArguments type_arguments;
3747 IBaseMembersProvider base_provider;
3748 IErrorHandler custom_errors;
3749 IInstanceQualifier instance_qualifier;
3750 Restrictions restrictions;
3751 MethodGroupExpr best_candidate_extension_group;
3752 TypeSpec best_candidate_return_type;
3754 SessionReportPrinter lambda_conv_msgs;
3756 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3757 : this (members, null, restrictions, loc)
3761 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3764 if (members == null || members.Count == 0)
3765 throw new ArgumentException ("empty members set");
3767 this.members = members;
3769 type_arguments = targs;
3770 this.restrictions = restrictions;
3771 if (IsDelegateInvoke)
3772 this.restrictions |= Restrictions.NoBaseMembers;
3774 base_provider = NoBaseMembers.Instance;
3779 public IBaseMembersProvider BaseMembersProvider {
3781 return base_provider;
3784 base_provider = value;
3788 public bool BestCandidateIsDynamic { get; set; }
3791 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3793 public MethodGroupExpr BestCandidateNewMethodGroup {
3795 return best_candidate_extension_group;
3800 // Return type can be different between best candidate and closest override
3802 public TypeSpec BestCandidateReturnType {
3804 return best_candidate_return_type;
3808 public IErrorHandler CustomErrors {
3810 return custom_errors;
3813 custom_errors = value;
3817 TypeSpec DelegateType {
3819 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3820 throw new InternalErrorException ("Not running in delegate mode", loc);
3822 return members [0].DeclaringType;
3826 public IInstanceQualifier InstanceQualifier {
3828 return instance_qualifier;
3831 instance_qualifier = value;
3835 bool IsProbingOnly {
3837 return (restrictions & Restrictions.ProbingOnly) != 0;
3841 bool IsDelegateInvoke {
3843 return (restrictions & Restrictions.DelegateInvoke) != 0;
3850 // 7.4.3.3 Better conversion from expression
3851 // Returns : 1 if a->p is better,
3852 // 2 if a->q is better,
3853 // 0 if neither is better
3855 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3857 TypeSpec argument_type = a.Type;
3860 // If argument is an anonymous function
3862 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3864 // p and q are delegate types or expression tree types
3866 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3867 if (q.MemberDefinition != p.MemberDefinition) {
3872 // Uwrap delegate from Expression<T>
3874 q = TypeManager.GetTypeArguments (q)[0];
3875 p = TypeManager.GetTypeArguments (p)[0];
3878 var p_m = Delegate.GetInvokeMethod (p);
3879 var q_m = Delegate.GetInvokeMethod (q);
3882 // With identical parameter lists
3884 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3893 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3895 if (p.Kind == MemberKind.Void) {
3896 return q.Kind != MemberKind.Void ? 2 : 0;
3900 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3902 if (q.Kind == MemberKind.Void) {
3903 return p.Kind != MemberKind.Void ? 1: 0;
3906 var am = (AnonymousMethodExpression) a.Expr;
3909 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3910 // better conversion is performed between underlying types Y1 and Y2
3912 if (p.IsGenericTask || q.IsGenericTask) {
3913 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3914 q = q.TypeArguments[0];
3915 p = p.TypeArguments[0];
3917 } else if (q != p) {
3919 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3921 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3922 var am_rt = am.InferReturnType (ec, null, orig_q);
3923 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3925 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3926 var am_rt = am.InferReturnType (ec, null, orig_p);
3927 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3933 // The parameters are identicial and return type is not void, use better type conversion
3934 // on return type to determine better one
3937 if (argument_type == p)
3940 if (argument_type == q)
3944 return BetterTypeConversion (ec, p, q);
3948 // 7.4.3.4 Better conversion from type
3950 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3952 if (p == null || q == null)
3953 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3955 switch (p.BuiltinType) {
3956 case BuiltinTypeSpec.Type.Int:
3957 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3960 case BuiltinTypeSpec.Type.Long:
3961 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3964 case BuiltinTypeSpec.Type.SByte:
3965 switch (q.BuiltinType) {
3966 case BuiltinTypeSpec.Type.Byte:
3967 case BuiltinTypeSpec.Type.UShort:
3968 case BuiltinTypeSpec.Type.UInt:
3969 case BuiltinTypeSpec.Type.ULong:
3973 case BuiltinTypeSpec.Type.Short:
3974 switch (q.BuiltinType) {
3975 case BuiltinTypeSpec.Type.UShort:
3976 case BuiltinTypeSpec.Type.UInt:
3977 case BuiltinTypeSpec.Type.ULong:
3981 case BuiltinTypeSpec.Type.Dynamic:
3982 // Dynamic is never better
3986 switch (q.BuiltinType) {
3987 case BuiltinTypeSpec.Type.Int:
3988 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3991 case BuiltinTypeSpec.Type.Long:
3992 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3995 case BuiltinTypeSpec.Type.SByte:
3996 switch (p.BuiltinType) {
3997 case BuiltinTypeSpec.Type.Byte:
3998 case BuiltinTypeSpec.Type.UShort:
3999 case BuiltinTypeSpec.Type.UInt:
4000 case BuiltinTypeSpec.Type.ULong:
4004 case BuiltinTypeSpec.Type.Short:
4005 switch (p.BuiltinType) {
4006 case BuiltinTypeSpec.Type.UShort:
4007 case BuiltinTypeSpec.Type.UInt:
4008 case BuiltinTypeSpec.Type.ULong:
4012 case BuiltinTypeSpec.Type.Dynamic:
4013 // Dynamic is never better
4017 // FIXME: handle lifted operators
4019 // TODO: this is expensive
4020 Expression p_tmp = new EmptyExpression (p);
4021 Expression q_tmp = new EmptyExpression (q);
4023 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4024 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4026 if (p_to_q && !q_to_p)
4029 if (q_to_p && !p_to_q)
4036 /// Determines "Better function" between candidate
4037 /// and the current best match
4040 /// Returns a boolean indicating :
4041 /// false if candidate ain't better
4042 /// true if candidate is better than the current best match
4044 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4045 MemberSpec best, AParametersCollection bparam, bool best_params)
4047 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4048 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4050 bool better_at_least_one = false;
4052 int args_count = args == null ? 0 : args.Count;
4056 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4059 // Default arguments are ignored for better decision
4060 if (a.IsDefaultArgument)
4064 // When comparing named argument the parameter type index has to be looked up
4065 // in original parameter set (override version for virtual members)
4067 NamedArgument na = a as NamedArgument;
4069 int idx = cparam.GetParameterIndexByName (na.Name);
4070 ct = candidate_pd.Types[idx];
4071 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4072 ct = TypeManager.GetElementType (ct);
4074 idx = bparam.GetParameterIndexByName (na.Name);
4075 bt = best_pd.Types[idx];
4076 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4077 bt = TypeManager.GetElementType (bt);
4079 ct = candidate_pd.Types[c_idx];
4080 bt = best_pd.Types[b_idx];
4082 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4083 ct = TypeManager.GetElementType (ct);
4087 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4088 bt = TypeManager.GetElementType (bt);
4093 if (TypeSpecComparer.IsEqual (ct, bt))
4097 int result = BetterExpressionConversion (ec, a, ct, bt);
4099 // for each argument, the conversion to 'ct' should be no worse than
4100 // the conversion to 'bt'.
4104 // for at least one argument, the conversion to 'ct' should be better than
4105 // the conversion to 'bt'.
4107 better_at_least_one = true;
4110 if (better_at_least_one)
4114 // This handles the case
4116 // Add (float f1, float f2, float f3);
4117 // Add (params decimal [] foo);
4119 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4120 // first candidate would've chosen as better.
4122 if (!same && !a.IsDefaultArgument)
4126 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4130 // This handles the following cases:
4132 // Foo (int i) is better than Foo (int i, long l = 0)
4133 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4134 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4136 // Prefer non-optional version
4138 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4140 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4141 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4144 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4147 return candidate_pd.Count >= best_pd.Count;
4151 // One is a non-generic method and second is a generic method, then non-generic is better
4153 if (best.IsGeneric != candidate.IsGeneric)
4154 return best.IsGeneric;
4157 // This handles the following cases:
4159 // Trim () is better than Trim (params char[] chars)
4160 // Concat (string s1, string s2, string s3) is better than
4161 // Concat (string s1, params string [] srest)
4162 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4164 // Prefer non-expanded version
4166 if (candidate_params != best_params)
4169 int candidate_param_count = candidate_pd.Count;
4170 int best_param_count = best_pd.Count;
4172 if (candidate_param_count != best_param_count)
4173 // can only happen if (candidate_params && best_params)
4174 return candidate_param_count > best_param_count && best_pd.HasParams;
4177 // Both methods have the same number of parameters, and the parameters have equal types
4178 // Pick the "more specific" signature using rules over original (non-inflated) types
4180 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4181 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4183 bool specific_at_least_once = false;
4184 for (j = 0; j < args_count; ++j) {
4185 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4187 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4188 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4190 ct = candidate_def_pd.Types[j];
4191 bt = best_def_pd.Types[j];
4196 TypeSpec specific = MoreSpecific (ct, bt);
4200 specific_at_least_once = true;
4203 if (specific_at_least_once)
4209 static bool CheckInflatedArguments (MethodSpec ms)
4211 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4214 // Setup constraint checker for probing only
4215 ConstraintChecker cc = new ConstraintChecker (null);
4217 var mp = ms.Parameters.Types;
4218 for (int i = 0; i < mp.Length; ++i) {
4219 var type = mp[i] as InflatedTypeSpec;
4223 var targs = type.TypeArguments;
4224 if (targs.Length == 0)
4227 // TODO: Checking inflated MVAR arguments should be enough
4228 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4235 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4237 rc.Report.Error (1729, loc,
4238 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4239 type.GetSignatureForError (), argCount.ToString ());
4243 // Determines if the candidate method is applicable to the given set of arguments
4244 // There could be two different set of parameters for same candidate where one
4245 // is the closest override for default values and named arguments checks and second
4246 // one being the virtual base for the parameter types and modifiers.
4248 // A return value rates candidate method compatibility,
4249 // 0 = the best, int.MaxValue = the worst
4252 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)
4254 // Parameters of most-derived type used mainly for named and optional parameters
4255 var pd = pm.Parameters;
4257 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4258 // params modifier instead of most-derived type
4259 var cpd = ((IParametersMember) candidate).Parameters;
4260 int param_count = pd.Count;
4261 int optional_count = 0;
4263 Arguments orig_args = arguments;
4265 if (arg_count != param_count) {
4267 // No arguments expansion when doing exact match for delegates
4269 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4270 for (int i = 0; i < pd.Count; ++i) {
4271 if (pd.FixedParameters[i].HasDefaultValue) {
4272 optional_count = pd.Count - i;
4278 if (optional_count != 0) {
4279 // Readjust expected number when params used
4280 if (cpd.HasParams) {
4282 if (arg_count < param_count)
4284 } else if (arg_count > param_count) {
4285 int args_gap = System.Math.Abs (arg_count - param_count);
4286 return int.MaxValue - 10000 + args_gap;
4287 } else if (arg_count < param_count - optional_count) {
4288 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4289 return int.MaxValue - 10000 + args_gap;
4291 } else if (arg_count != param_count) {
4292 int args_gap = System.Math.Abs (arg_count - param_count);
4294 return int.MaxValue - 10000 + args_gap;
4295 if (arg_count < param_count - 1)
4296 return int.MaxValue - 10000 + args_gap;
4299 // Resize to fit optional arguments
4300 if (optional_count != 0) {
4301 if (arguments == null) {
4302 arguments = new Arguments (optional_count);
4304 // Have to create a new container, so the next run can do same
4305 var resized = new Arguments (param_count);
4306 resized.AddRange (arguments);
4307 arguments = resized;
4310 for (int i = arg_count; i < param_count; ++i)
4311 arguments.Add (null);
4315 if (arg_count > 0) {
4317 // Shuffle named arguments to the right positions if there are any
4319 if (arguments[arg_count - 1] is NamedArgument) {
4320 arg_count = arguments.Count;
4322 for (int i = 0; i < arg_count; ++i) {
4323 bool arg_moved = false;
4325 NamedArgument na = arguments[i] as NamedArgument;
4329 int index = pd.GetParameterIndexByName (na.Name);
4331 // Named parameter not found
4335 // already reordered
4340 if (index >= param_count) {
4341 // When using parameters which should not be available to the user
4342 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4345 arguments.Add (null);
4349 temp = arguments[index];
4351 // The slot has been taken by positional argument
4352 if (temp != null && !(temp is NamedArgument))
4357 arguments = arguments.MarkOrderedArgument (na);
4361 arguments[index] = arguments[i];
4362 arguments[i] = temp;
4369 arg_count = arguments.Count;
4371 } else if (arguments != null) {
4372 arg_count = arguments.Count;
4376 // Don't do any expensive checks when the candidate cannot succeed
4378 if (arg_count != param_count && !cpd.HasParams)
4379 return (param_count - arg_count) * 2 + 1;
4381 var dep = candidate.GetMissingDependencies ();
4383 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4388 // 1. Handle generic method using type arguments when specified or type inference
4391 var ms = candidate as MethodSpec;
4392 if (ms != null && ms.IsGeneric) {
4393 if (type_arguments != null) {
4394 var g_args_count = ms.Arity;
4395 if (g_args_count != type_arguments.Count)
4396 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4398 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4401 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4402 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4403 // candidate was found use the set to report more details about what was wrong with lambda body.
4404 // The general idea is to distinguish between code errors and errors caused by
4405 // trial-and-error type inference
4407 if (lambda_conv_msgs == null) {
4408 for (int i = 0; i < arg_count; i++) {
4409 Argument a = arguments[i];
4413 var am = a.Expr as AnonymousMethodExpression;
4415 if (lambda_conv_msgs == null)
4416 lambda_conv_msgs = new SessionReportPrinter ();
4418 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4423 var ti = new TypeInference (arguments);
4424 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4427 return ti.InferenceScore - 20000;
4430 // Clear any error messages when the result was success
4432 if (lambda_conv_msgs != null)
4433 lambda_conv_msgs.ClearSession ();
4435 if (i_args.Length != 0) {
4436 ms = ms.MakeGenericMethod (ec, i_args);
4441 // Type arguments constraints have to match for the method to be applicable
4443 if (!CheckInflatedArguments (ms)) {
4445 return int.MaxValue - 25000;
4449 // We have a generic return type and at same time the method is override which
4450 // means we have to also inflate override return type in case the candidate is
4451 // best candidate and override return type is different to base return type.
4453 // virtual Foo<T, object> with override Foo<T, dynamic>
4455 if (candidate != pm) {
4456 MethodSpec override_ms = (MethodSpec) pm;
4457 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4458 returnType = inflator.Inflate (returnType);
4460 returnType = ms.ReturnType;
4467 if (type_arguments != null)
4468 return int.MaxValue - 15000;
4474 // 2. Each argument has to be implicitly convertible to method parameter
4476 Parameter.Modifier p_mod = 0;
4479 for (int i = 0; i < arg_count; i++) {
4480 Argument a = arguments[i];
4482 var fp = pd.FixedParameters[i];
4483 if (!fp.HasDefaultValue) {
4484 arguments = orig_args;
4485 return arg_count * 2 + 2;
4489 // Get the default value expression, we can use the same expression
4490 // if the type matches
4492 Expression e = fp.DefaultValue;
4494 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4496 // Restore for possible error reporting
4497 for (int ii = i; ii < arg_count; ++ii)
4498 arguments.RemoveAt (i);
4500 return (arg_count - i) * 2 + 1;
4504 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4506 // LAMESPEC: Attributes can be mixed together with build-in priority
4508 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4509 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4510 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4511 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4512 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4513 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4517 arguments[i] = new Argument (e, Argument.AType.Default);
4521 if (p_mod != Parameter.Modifier.PARAMS) {
4522 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4524 } else if (!params_expanded_form) {
4525 params_expanded_form = true;
4526 pt = ((ElementTypeSpec) pt).Element;
4532 if (!params_expanded_form) {
4533 if (a.ArgType == Argument.AType.ExtensionType) {
4535 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4537 // LAMESPEC: or implicit type parameter conversion
4540 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4541 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4542 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4547 score = IsArgumentCompatible (ec, a, p_mod, pt);
4550 dynamicArgument = true;
4555 // It can be applicable in expanded form (when not doing exact match like for delegates)
4557 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4558 if (!params_expanded_form) {
4559 pt = ((ElementTypeSpec) pt).Element;
4563 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4566 params_expanded_form = true;
4567 dynamicArgument = true;
4568 } else if (score == 0 || arg_count > pd.Count) {
4569 params_expanded_form = true;
4574 if (params_expanded_form)
4576 return (arg_count - i) * 2 + score;
4581 // When params parameter has no argument it will be provided later if the method is the best candidate
4583 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4584 params_expanded_form = true;
4587 // Restore original arguments for dynamic binder to keep the intention of original source code
4589 if (dynamicArgument)
4590 arguments = orig_args;
4595 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4597 if (e is Constant && e.Type == ptype)
4601 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4603 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4604 e = new MemberAccess (new MemberAccess (new MemberAccess (
4605 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4606 } else if (e is Constant) {
4608 // Handles int to int? conversions, DefaultParameterValue check
4610 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4614 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4617 return e.Resolve (ec);
4621 // Tests argument compatibility with the parameter
4622 // The possible return values are
4624 // 1 - modifier mismatch
4625 // 2 - type mismatch
4626 // -1 - dynamic binding required
4628 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4631 // Types have to be identical when ref or out modifer
4632 // is used and argument is not of dynamic type
4634 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4635 if (argument.Type != parameter) {
4637 // Do full equality check after quick path
4639 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4641 // Using dynamic for ref/out parameter can still succeed at runtime
4643 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4650 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4652 // Using dynamic for ref/out parameter can still succeed at runtime
4654 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4661 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4665 // Use implicit conversion in all modes to return same candidates when the expression
4666 // is used as argument or delegate conversion
4668 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4676 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4678 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4680 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4683 var ac_p = p as ArrayContainer;
4685 var ac_q = q as ArrayContainer;
4689 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4690 if (specific == ac_p.Element)
4692 if (specific == ac_q.Element)
4694 } else if (p.IsGeneric && q.IsGeneric) {
4695 var pargs = TypeManager.GetTypeArguments (p);
4696 var qargs = TypeManager.GetTypeArguments (q);
4698 bool p_specific_at_least_once = false;
4699 bool q_specific_at_least_once = false;
4701 for (int i = 0; i < pargs.Length; i++) {
4702 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4703 if (specific == pargs[i])
4704 p_specific_at_least_once = true;
4705 if (specific == qargs[i])
4706 q_specific_at_least_once = true;
4709 if (p_specific_at_least_once && !q_specific_at_least_once)
4711 if (!p_specific_at_least_once && q_specific_at_least_once)
4719 // Find the best method from candidate list
4721 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4723 List<AmbiguousCandidate> ambiguous_candidates = null;
4725 MemberSpec best_candidate;
4726 Arguments best_candidate_args = null;
4727 bool best_candidate_params = false;
4728 bool best_candidate_dynamic = false;
4729 int best_candidate_rate;
4730 IParametersMember best_parameter_member = null;
4732 int args_count = args != null ? args.Count : 0;
4734 Arguments candidate_args = args;
4735 bool error_mode = false;
4736 MemberSpec invocable_member = null;
4739 best_candidate = null;
4740 best_candidate_rate = int.MaxValue;
4742 var type_members = members;
4744 for (int i = 0; i < type_members.Count; ++i) {
4745 var member = type_members[i];
4748 // Methods in a base class are not candidates if any method in a derived
4749 // class is applicable
4751 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4755 if (!member.IsAccessible (rc))
4758 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4761 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4762 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4767 IParametersMember pm = member as IParametersMember;
4770 // Will use it later to report ambiguity between best method and invocable member
4772 if (Invocation.IsMemberInvocable (member))
4773 invocable_member = member;
4779 // Overload resolution is looking for base member but using parameter names
4780 // and default values from the closest member. That means to do expensive lookup
4781 // for the closest override for virtual or abstract members
4783 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4784 var override_params = base_provider.GetOverrideMemberParameters (member);
4785 if (override_params != null)
4786 pm = override_params;
4790 // Check if the member candidate is applicable
4792 bool params_expanded_form = false;
4793 bool dynamic_argument = false;
4794 TypeSpec rt = pm.MemberType;
4795 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4797 if (lambda_conv_msgs != null)
4798 lambda_conv_msgs.EndSession ();
4801 // How does it score compare to others
4803 if (candidate_rate < best_candidate_rate) {
4805 // Fatal error (missing dependency), cannot continue
4806 if (candidate_rate < 0)
4809 best_candidate_rate = candidate_rate;
4810 best_candidate = member;
4811 best_candidate_args = candidate_args;
4812 best_candidate_params = params_expanded_form;
4813 best_candidate_dynamic = dynamic_argument;
4814 best_parameter_member = pm;
4815 best_candidate_return_type = rt;
4816 } else if (candidate_rate == 0) {
4818 // The member look is done per type for most operations but sometimes
4819 // it's not possible like for binary operators overload because they
4820 // are unioned between 2 sides
4822 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4823 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4828 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4830 // We pack all interface members into top level type which makes the overload resolution
4831 // more complicated for interfaces. We compensate it by removing methods with same
4832 // signature when building the cache hence this path should not really be hit often
4835 // interface IA { void Foo (int arg); }
4836 // interface IB : IA { void Foo (params int[] args); }
4838 // IB::Foo is the best overload when calling IB.Foo (1)
4841 if (ambiguous_candidates != null) {
4842 foreach (var amb_cand in ambiguous_candidates) {
4843 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4852 ambiguous_candidates = null;
4855 // Is the new candidate better
4856 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4860 best_candidate = member;
4861 best_candidate_args = candidate_args;
4862 best_candidate_params = params_expanded_form;
4863 best_candidate_dynamic = dynamic_argument;
4864 best_parameter_member = pm;
4865 best_candidate_return_type = rt;
4867 // It's not better but any other found later could be but we are not sure yet
4868 if (ambiguous_candidates == null)
4869 ambiguous_candidates = new List<AmbiguousCandidate> ();
4871 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4875 // Restore expanded arguments
4876 if (candidate_args != args)
4877 candidate_args = args;
4879 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4882 // We've found exact match
4884 if (best_candidate_rate == 0)
4888 // Try extension methods lookup when no ordinary method match was found and provider enables it
4891 var emg = base_provider.LookupExtensionMethod (rc);
4893 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4895 best_candidate_extension_group = emg;
4896 return (T) (MemberSpec) emg.BestCandidate;
4901 // Don't run expensive error reporting mode for probing
4908 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4911 lambda_conv_msgs = null;
4916 // No best member match found, report an error
4918 if (best_candidate_rate != 0 || error_mode) {
4919 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4923 if (best_candidate_dynamic) {
4924 if (args[0].ArgType == Argument.AType.ExtensionType) {
4925 rc.Report.Error (1973, loc,
4926 "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",
4927 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4931 // Check type constraints only when explicit type arguments are used
4933 if (best_candidate.IsGeneric && type_arguments != null) {
4934 MethodSpec bc = best_candidate as MethodSpec;
4935 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4936 ConstraintChecker cc = new ConstraintChecker (rc);
4937 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4941 BestCandidateIsDynamic = true;
4946 // These flags indicates we are running delegate probing conversion. No need to
4947 // do more expensive checks
4949 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4950 return (T) best_candidate;
4952 if (ambiguous_candidates != null) {
4954 // Now check that there are no ambiguities i.e the selected method
4955 // should be better than all the others
4957 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4958 var candidate = ambiguous_candidates [ix];
4960 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4961 var ambiguous = candidate.Member;
4962 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4963 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4964 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4965 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4966 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4969 return (T) best_candidate;
4974 if (invocable_member != null && !IsProbingOnly) {
4975 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4976 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4977 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4978 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4982 // And now check if the arguments are all
4983 // compatible, perform conversions if
4984 // necessary etc. and return if everything is
4987 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4990 if (best_candidate == null)
4994 // Don't run possibly expensive checks in probing mode
4996 if (!IsProbingOnly && !rc.IsInProbingMode) {
4998 // Check ObsoleteAttribute on the best method
5000 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5001 if (oa != null && !rc.IsObsolete)
5002 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5004 best_candidate.MemberDefinition.SetIsUsed ();
5007 args = best_candidate_args;
5008 return (T) best_candidate;
5011 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5013 return ResolveMember<MethodSpec> (rc, ref args);
5016 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5017 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5019 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5022 if (a.Type == InternalType.ErrorType)
5025 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5026 ec.Report.SymbolRelatedToPreviousError (method);
5027 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5028 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5029 TypeManager.CSharpSignature (method));
5032 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5033 TypeManager.CSharpSignature (method));
5034 } else if (IsDelegateInvoke) {
5035 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5036 DelegateType.GetSignatureForError ());
5038 ec.Report.SymbolRelatedToPreviousError (method);
5039 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5040 method.GetSignatureForError ());
5043 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5045 string index = (idx + 1).ToString ();
5046 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5047 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5048 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5049 index, Parameter.GetModifierSignature (a.Modifier));
5051 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
5052 index, Parameter.GetModifierSignature (mod));
5054 string p1 = a.GetSignatureForError ();
5055 string p2 = TypeManager.CSharpName (paramType);
5058 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5059 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5062 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5063 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5064 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5067 ec.Report.Error (1503, a.Expr.Location,
5068 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5073 // We have failed to find exact match so we return error info about the closest match
5075 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5077 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5078 int arg_count = args == null ? 0 : args.Count;
5080 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5081 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5082 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5086 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5091 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5092 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5093 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5097 // For candidates which match on parameters count report more details about incorrect arguments
5100 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5101 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5102 // Reject any inaccessible member
5103 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5104 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5105 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5109 var ms = best_candidate as MethodSpec;
5110 if (ms != null && ms.IsGeneric) {
5111 bool constr_ok = true;
5112 if (ms.TypeArguments != null)
5113 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5115 if (ta_count == 0) {
5116 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5120 rc.Report.Error (411, loc,
5121 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5122 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5129 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5135 // We failed to find any method with correct argument count, report best candidate
5137 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5140 if (best_candidate.Kind == MemberKind.Constructor) {
5141 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5142 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5143 } else if (IsDelegateInvoke) {
5144 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5145 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5146 DelegateType.GetSignatureForError (), arg_count.ToString ());
5148 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5149 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5150 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5151 name, arg_count.ToString ());
5155 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5157 var pd = pm.Parameters;
5158 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5160 Parameter.Modifier p_mod = 0;
5162 int a_idx = 0, a_pos = 0;
5164 ArrayInitializer params_initializers = null;
5165 bool has_unsafe_arg = pm.MemberType.IsPointer;
5166 int arg_count = args == null ? 0 : args.Count;
5168 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5170 if (p_mod != Parameter.Modifier.PARAMS) {
5171 p_mod = pd.FixedParameters[a_idx].ModFlags;
5173 has_unsafe_arg |= pt.IsPointer;
5175 if (p_mod == Parameter.Modifier.PARAMS) {
5176 if (chose_params_expanded) {
5177 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5178 pt = TypeManager.GetElementType (pt);
5184 // Types have to be identical when ref or out modifer is used
5186 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5187 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5190 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5196 NamedArgument na = a as NamedArgument;
5198 int name_index = pd.GetParameterIndexByName (na.Name);
5199 if (name_index < 0 || name_index >= pd.Count) {
5200 if (IsDelegateInvoke) {
5201 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5202 ec.Report.Error (1746, na.Location,
5203 "The delegate `{0}' does not contain a parameter named `{1}'",
5204 DelegateType.GetSignatureForError (), na.Name);
5206 ec.Report.SymbolRelatedToPreviousError (member);
5207 ec.Report.Error (1739, na.Location,
5208 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5209 TypeManager.CSharpSignature (member), na.Name);
5211 } else if (args[name_index] != a) {
5212 if (IsDelegateInvoke)
5213 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5215 ec.Report.SymbolRelatedToPreviousError (member);
5217 ec.Report.Error (1744, na.Location,
5218 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5223 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5226 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5227 custom_errors.NoArgumentMatch (ec, member);
5231 Expression conv = null;
5232 if (a.ArgType == Argument.AType.ExtensionType) {
5233 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5236 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5238 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5241 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5248 // Convert params arguments to an array initializer
5250 if (params_initializers != null) {
5251 // we choose to use 'a.Expr' rather than 'conv' so that
5252 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5253 params_initializers.Add (a.Expr);
5254 args.RemoveAt (a_idx--);
5259 // Update the argument with the implicit conversion
5263 if (a_idx != arg_count) {
5264 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5269 // Fill not provided arguments required by params modifier
5271 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5273 args = new Arguments (1);
5275 pt = ptypes[pd.Count - 1];
5276 pt = TypeManager.GetElementType (pt);
5277 has_unsafe_arg |= pt.IsPointer;
5278 params_initializers = new ArrayInitializer (0, loc);
5282 // Append an array argument with all params arguments
5284 if (params_initializers != null) {
5285 args.Add (new Argument (
5286 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5290 if (has_unsafe_arg && !ec.IsUnsafe) {
5291 Expression.UnsafeError (ec, loc);
5295 // We could infer inaccesible type arguments
5297 if (type_arguments == null && member.IsGeneric) {
5298 var ms = (MethodSpec) member;
5299 foreach (var ta in ms.TypeArguments) {
5300 if (!ta.IsAccessible (ec)) {
5301 ec.Report.SymbolRelatedToPreviousError (ta);
5302 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5312 public class ConstantExpr : MemberExpr
5314 readonly ConstSpec constant;
5316 public ConstantExpr (ConstSpec constant, Location loc)
5318 this.constant = constant;
5322 public override string Name {
5323 get { throw new NotImplementedException (); }
5326 public override string KindName {
5327 get { return "constant"; }
5330 public override bool IsInstance {
5331 get { return !IsStatic; }
5334 public override bool IsStatic {
5335 get { return true; }
5338 protected override TypeSpec DeclaringType {
5339 get { return constant.DeclaringType; }
5342 public override Expression CreateExpressionTree (ResolveContext ec)
5344 throw new NotSupportedException ("ET");
5347 protected override Expression DoResolve (ResolveContext rc)
5349 ResolveInstanceExpression (rc, null);
5350 DoBestMemberChecks (rc, constant);
5352 var c = constant.GetConstant (rc);
5354 // Creates reference expression to the constant value
5355 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5358 public override void Emit (EmitContext ec)
5360 throw new NotSupportedException ();
5363 public override string GetSignatureForError ()
5365 return constant.GetSignatureForError ();
5368 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5370 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5375 // Fully resolved expression that references a Field
5377 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5379 protected FieldSpec spec;
5380 VariableInfo variable_info;
5382 LocalTemporary temp;
5385 protected FieldExpr (Location l)
5390 public FieldExpr (FieldSpec spec, Location loc)
5395 type = spec.MemberType;
5398 public FieldExpr (FieldBase fi, Location l)
5405 public override string Name {
5411 public bool IsHoisted {
5413 IVariableReference hv = InstanceExpression as IVariableReference;
5414 return hv != null && hv.IsHoisted;
5418 public override bool IsInstance {
5420 return !spec.IsStatic;
5424 public override bool IsStatic {
5426 return spec.IsStatic;
5430 public override string KindName {
5431 get { return "field"; }
5434 public FieldSpec Spec {
5440 protected override TypeSpec DeclaringType {
5442 return spec.DeclaringType;
5446 public VariableInfo VariableInfo {
5448 return variable_info;
5454 public override string GetSignatureForError ()
5456 return spec.GetSignatureForError ();
5459 public bool IsMarshalByRefAccess (ResolveContext rc)
5461 // Checks possible ldflda of field access expression
5462 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5463 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5464 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5467 public void SetHasAddressTaken ()
5469 IVariableReference vr = InstanceExpression as IVariableReference;
5471 vr.SetHasAddressTaken ();
5475 public override Expression CreateExpressionTree (ResolveContext ec)
5477 return CreateExpressionTree (ec, true);
5480 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5483 Expression instance;
5485 if (InstanceExpression == null) {
5486 instance = new NullLiteral (loc);
5487 } else if (convertInstance) {
5488 instance = InstanceExpression.CreateExpressionTree (ec);
5490 args = new Arguments (1);
5491 args.Add (new Argument (InstanceExpression));
5492 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5495 args = Arguments.CreateForExpressionTree (ec, null,
5497 CreateTypeOfExpression ());
5499 return CreateExpressionFactoryCall (ec, "Field", args);
5502 public Expression CreateTypeOfExpression ()
5504 return new TypeOfField (spec, loc);
5507 protected override Expression DoResolve (ResolveContext ec)
5509 spec.MemberDefinition.SetIsUsed ();
5511 return DoResolve (ec, null);
5514 Expression DoResolve (ResolveContext ec, Expression rhs)
5516 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5519 if (ResolveInstanceExpression (ec, rhs)) {
5520 // Resolve the field's instance expression while flow analysis is turned
5521 // off: when accessing a field "a.b", we must check whether the field
5522 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5524 if (lvalue_instance) {
5525 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5526 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5528 Expression right_side =
5529 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5531 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5534 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5535 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5539 if (InstanceExpression == null)
5543 DoBestMemberChecks (ec, spec);
5546 var fb = spec as FixedFieldSpec;
5547 IVariableReference var = InstanceExpression as IVariableReference;
5549 if (lvalue_instance && var != null && var.VariableInfo != null) {
5550 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5554 IFixedExpression fe = InstanceExpression as IFixedExpression;
5555 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5556 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5559 if (InstanceExpression.eclass != ExprClass.Variable) {
5560 ec.Report.SymbolRelatedToPreviousError (spec);
5561 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5562 TypeManager.GetFullNameSignature (spec));
5563 } else if (var != null && var.IsHoisted) {
5564 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5567 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5571 // Set flow-analysis variable info for struct member access. It will be check later
5572 // for precise error reporting
5574 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5575 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5576 if (rhs != null && variable_info != null)
5577 variable_info.SetStructFieldAssigned (ec, Name);
5580 eclass = ExprClass.Variable;
5584 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5589 var var = fe.InstanceExpression as IVariableReference;
5591 var vi = var.VariableInfo;
5593 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5595 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5597 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5604 fe = fe.InstanceExpression as FieldExpr;
5606 } while (fe != null);
5609 static readonly int [] codes = {
5610 191, // instance, write access
5611 192, // instance, out access
5612 198, // static, write access
5613 199, // static, out access
5614 1648, // member of value instance, write access
5615 1649, // member of value instance, out access
5616 1650, // member of value static, write access
5617 1651 // member of value static, out access
5620 static readonly string [] msgs = {
5621 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5622 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5623 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5624 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5625 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5626 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5627 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5628 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5631 // The return value is always null. Returning a value simplifies calling code.
5632 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5635 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5639 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5641 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5646 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5648 if (spec is FixedFieldSpec) {
5649 // It could be much better error message but we want to be error compatible
5650 Error_ValueAssignment (ec, right_side);
5653 Expression e = DoResolve (ec, right_side);
5658 spec.MemberDefinition.SetIsAssigned ();
5660 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5661 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5662 ec.Report.Warning (420, 1, loc,
5663 "`{0}': A volatile field references will not be treated as volatile",
5664 spec.GetSignatureForError ());
5667 if (spec.IsReadOnly) {
5668 // InitOnly fields can only be assigned in constructors or initializers
5669 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5670 return Report_AssignToReadonly (ec, right_side);
5672 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5674 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5675 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5676 return Report_AssignToReadonly (ec, right_side);
5677 // static InitOnly fields cannot be assigned-to in an instance constructor
5678 if (IsStatic && !ec.IsStatic)
5679 return Report_AssignToReadonly (ec, right_side);
5680 // instance constructors can't modify InitOnly fields of other instances of the same type
5681 if (!IsStatic && !(InstanceExpression is This))
5682 return Report_AssignToReadonly (ec, right_side);
5686 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5687 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5688 ec.Report.Warning (197, 1, loc,
5689 "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",
5690 GetSignatureForError ());
5693 eclass = ExprClass.Variable;
5697 public override int GetHashCode ()
5699 return spec.GetHashCode ();
5702 public bool IsFixed {
5705 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5707 IVariableReference variable = InstanceExpression as IVariableReference;
5708 if (variable != null)
5709 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5711 IFixedExpression fe = InstanceExpression as IFixedExpression;
5712 return fe != null && fe.IsFixed;
5716 public override bool Equals (object obj)
5718 FieldExpr fe = obj as FieldExpr;
5722 if (spec != fe.spec)
5725 if (InstanceExpression == null || fe.InstanceExpression == null)
5728 return InstanceExpression.Equals (fe.InstanceExpression);
5731 public void Emit (EmitContext ec, bool leave_copy)
5733 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5737 ec.Emit (OpCodes.Volatile);
5739 ec.Emit (OpCodes.Ldsfld, spec);
5742 EmitInstance (ec, false);
5744 // Optimization for build-in types
5745 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5746 ec.EmitLoadFromPtr (type);
5748 var ff = spec as FixedFieldSpec;
5750 ec.Emit (OpCodes.Ldflda, spec);
5751 ec.Emit (OpCodes.Ldflda, ff.Element);
5754 ec.Emit (OpCodes.Volatile);
5756 ec.Emit (OpCodes.Ldfld, spec);
5762 ec.Emit (OpCodes.Dup);
5764 temp = new LocalTemporary (this.Type);
5770 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5772 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5773 if (isCompound && !(source is DynamicExpressionStatement)) {
5774 if (has_await_source) {
5776 InstanceExpression = InstanceExpression.EmitToField (ec);
5783 if (has_await_source)
5784 source = source.EmitToField (ec);
5786 EmitInstance (ec, prepared);
5792 ec.Emit (OpCodes.Dup);
5794 temp = new LocalTemporary (this.Type);
5799 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5800 ec.Emit (OpCodes.Volatile);
5802 spec.MemberDefinition.SetIsAssigned ();
5805 ec.Emit (OpCodes.Stsfld, spec);
5807 ec.Emit (OpCodes.Stfld, spec);
5817 // Emits store to field with prepared values on stack
5819 public void EmitAssignFromStack (EmitContext ec)
5822 ec.Emit (OpCodes.Stsfld, spec);
5824 ec.Emit (OpCodes.Stfld, spec);
5828 public override void Emit (EmitContext ec)
5833 public override void EmitSideEffect (EmitContext ec)
5835 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5837 if (is_volatile) // || is_marshal_by_ref ())
5838 base.EmitSideEffect (ec);
5841 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5843 if ((mode & AddressOp.Store) != 0)
5844 spec.MemberDefinition.SetIsAssigned ();
5845 if ((mode & AddressOp.Load) != 0)
5846 spec.MemberDefinition.SetIsUsed ();
5849 // Handle initonly fields specially: make a copy and then
5850 // get the address of the copy.
5853 if (spec.IsReadOnly){
5855 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5867 var temp = ec.GetTemporaryLocal (type);
5868 ec.Emit (OpCodes.Stloc, temp);
5869 ec.Emit (OpCodes.Ldloca, temp);
5870 ec.FreeTemporaryLocal (temp, type);
5876 ec.Emit (OpCodes.Ldsflda, spec);
5879 EmitInstance (ec, false);
5880 ec.Emit (OpCodes.Ldflda, spec);
5884 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5886 return MakeExpression (ctx);
5889 public override SLE.Expression MakeExpression (BuilderContext ctx)
5892 return base.MakeExpression (ctx);
5894 return SLE.Expression.Field (
5895 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5896 spec.GetMetaInfo ());
5900 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5902 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5908 // Expression that evaluates to a Property.
5910 // This is not an LValue because we need to re-write the expression. We
5911 // can not take data from the stack and store it.
5913 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5915 Arguments arguments;
5917 public PropertyExpr (PropertySpec spec, Location l)
5920 best_candidate = spec;
5921 type = spec.MemberType;
5926 protected override Arguments Arguments {
5935 protected override TypeSpec DeclaringType {
5937 return best_candidate.DeclaringType;
5941 public override string Name {
5943 return best_candidate.Name;
5947 public override bool IsInstance {
5953 public override bool IsStatic {
5955 return best_candidate.IsStatic;
5959 public override string KindName {
5960 get { return "property"; }
5963 public PropertySpec PropertyInfo {
5965 return best_candidate;
5971 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5973 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
5976 var args_count = arguments == null ? 0 : arguments.Count;
5977 if (args_count != body.Parameters.Count && args_count == 0)
5980 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
5981 mg.InstanceExpression = InstanceExpression;
5986 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5988 return new PropertyExpr (spec, loc) {
5994 public override Expression CreateExpressionTree (ResolveContext ec)
5997 if (IsSingleDimensionalArrayLength ()) {
5998 args = new Arguments (1);
5999 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6000 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6003 args = new Arguments (2);
6004 if (InstanceExpression == null)
6005 args.Add (new Argument (new NullLiteral (loc)));
6007 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6008 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6009 return CreateExpressionFactoryCall (ec, "Property", args);
6012 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6014 DoResolveLValue (rc, null);
6015 return new TypeOfMethod (Setter, loc);
6018 public override string GetSignatureForError ()
6020 return best_candidate.GetSignatureForError ();
6023 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6026 return base.MakeExpression (ctx);
6028 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6032 public override SLE.Expression MakeExpression (BuilderContext ctx)
6035 return base.MakeExpression (ctx);
6037 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6041 void Error_PropertyNotValid (ResolveContext ec)
6043 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6044 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6045 GetSignatureForError ());
6048 bool IsSingleDimensionalArrayLength ()
6050 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6053 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6054 return ac != null && ac.Rank == 1;
6057 public override void Emit (EmitContext ec, bool leave_copy)
6060 // Special case: length of single dimension array property is turned into ldlen
6062 if (IsSingleDimensionalArrayLength ()) {
6063 EmitInstance (ec, false);
6064 ec.Emit (OpCodes.Ldlen);
6065 ec.Emit (OpCodes.Conv_I4);
6069 base.Emit (ec, leave_copy);
6072 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6075 LocalTemporary await_source_arg = null;
6077 if (isCompound && !(source is DynamicExpressionStatement)) {
6078 emitting_compound_assignment = true;
6081 if (has_await_arguments) {
6082 await_source_arg = new LocalTemporary (Type);
6083 await_source_arg.Store (ec);
6085 args = new Arguments (1);
6086 args.Add (new Argument (await_source_arg));
6089 temp = await_source_arg;
6092 has_await_arguments = false;
6097 ec.Emit (OpCodes.Dup);
6098 temp = new LocalTemporary (this.Type);
6103 args = arguments == null ? new Arguments (1) : arguments;
6107 temp = new LocalTemporary (this.Type);
6109 args.Add (new Argument (temp));
6111 args.Add (new Argument (source));
6115 emitting_compound_assignment = false;
6117 var call = new CallEmitter ();
6118 call.InstanceExpression = InstanceExpression;
6120 call.InstanceExpressionOnStack = true;
6122 call.Emit (ec, Setter, args, loc);
6129 if (await_source_arg != null) {
6130 await_source_arg.Release (ec);
6134 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6136 eclass = ExprClass.PropertyAccess;
6138 if (best_candidate.IsNotCSharpCompatible) {
6139 Error_PropertyNotValid (rc);
6142 ResolveInstanceExpression (rc, right_side);
6144 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6145 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6146 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6148 type = p.MemberType;
6152 DoBestMemberChecks (rc, best_candidate);
6154 // Handling of com-imported properties with any number of default property parameters
6155 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6156 var p = best_candidate.Get.Parameters;
6157 arguments = new Arguments (p.Count);
6158 for (int i = 0; i < p.Count; ++i) {
6159 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6161 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6162 var p = best_candidate.Set.Parameters;
6163 arguments = new Arguments (p.Count - 1);
6164 for (int i = 0; i < p.Count - 1; ++i) {
6165 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6172 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6174 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6178 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6180 // getter and setter can be different for base calls
6181 MethodSpec getter, setter;
6182 protected T best_candidate;
6184 protected LocalTemporary temp;
6185 protected bool emitting_compound_assignment;
6186 protected bool has_await_arguments;
6188 protected PropertyOrIndexerExpr (Location l)
6195 protected abstract Arguments Arguments { get; set; }
6197 public MethodSpec Getter {
6206 public MethodSpec Setter {
6217 protected override Expression DoResolve (ResolveContext ec)
6219 if (eclass == ExprClass.Unresolved) {
6220 var expr = OverloadResolve (ec, null);
6225 return expr.Resolve (ec);
6228 if (!ResolveGetter (ec))
6234 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6236 if (right_side == EmptyExpression.OutAccess) {
6237 // TODO: best_candidate can be null at this point
6238 INamedBlockVariable variable = null;
6239 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6240 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6241 best_candidate.Name);
6243 right_side.DoResolveLValue (ec, this);
6248 if (eclass == ExprClass.Unresolved) {
6249 var expr = OverloadResolve (ec, right_side);
6254 return expr.ResolveLValue (ec, right_side);
6257 if (!ResolveSetter (ec))
6264 // Implements the IAssignMethod interface for assignments
6266 public virtual void Emit (EmitContext ec, bool leave_copy)
6268 var call = new CallEmitter ();
6269 call.InstanceExpression = InstanceExpression;
6270 if (has_await_arguments)
6271 call.HasAwaitArguments = true;
6273 call.DuplicateArguments = emitting_compound_assignment;
6275 call.Emit (ec, Getter, Arguments, loc);
6277 if (call.HasAwaitArguments) {
6278 InstanceExpression = call.InstanceExpression;
6279 Arguments = call.EmittedArguments;
6280 has_await_arguments = true;
6284 ec.Emit (OpCodes.Dup);
6285 temp = new LocalTemporary (Type);
6290 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6292 public override void Emit (EmitContext ec)
6297 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6299 has_await_arguments = true;
6304 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6306 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6308 bool ResolveGetter (ResolveContext rc)
6310 if (!best_candidate.HasGet) {
6311 if (InstanceExpression != EmptyExpression.Null) {
6312 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6313 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6314 best_candidate.GetSignatureForError ());
6317 } else if (!best_candidate.Get.IsAccessible (rc)) {
6318 if (best_candidate.HasDifferentAccessibility) {
6319 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6320 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6321 TypeManager.CSharpSignature (best_candidate));
6323 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6324 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6328 if (best_candidate.HasDifferentAccessibility) {
6329 CheckProtectedMemberAccess (rc, best_candidate.Get);
6332 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6336 bool ResolveSetter (ResolveContext rc)
6338 if (!best_candidate.HasSet) {
6339 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6340 GetSignatureForError ());
6344 if (!best_candidate.Set.IsAccessible (rc)) {
6345 if (best_candidate.HasDifferentAccessibility) {
6346 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6347 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6348 GetSignatureForError ());
6350 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6351 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6355 if (best_candidate.HasDifferentAccessibility)
6356 CheckProtectedMemberAccess (rc, best_candidate.Set);
6358 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6364 /// Fully resolved expression that evaluates to an Event
6366 public class EventExpr : MemberExpr, IAssignMethod
6368 readonly EventSpec spec;
6371 public EventExpr (EventSpec spec, Location loc)
6379 protected override TypeSpec DeclaringType {
6381 return spec.DeclaringType;
6385 public override string Name {
6391 public override bool IsInstance {
6393 return !spec.IsStatic;
6397 public override bool IsStatic {
6399 return spec.IsStatic;
6403 public override string KindName {
6404 get { return "event"; }
6407 public MethodSpec Operator {
6415 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6418 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6420 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6421 if (spec.BackingField != null &&
6422 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6424 spec.MemberDefinition.SetIsUsed ();
6426 if (!ec.IsObsolete) {
6427 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6429 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6432 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6433 Error_AssignmentEventOnly (ec);
6435 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6437 InstanceExpression = null;
6439 return ml.ResolveMemberAccess (ec, left, original);
6443 return base.ResolveMemberAccess (ec, left, original);
6446 public override Expression CreateExpressionTree (ResolveContext ec)
6448 throw new NotSupportedException ("ET");
6451 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6453 if (right_side == EmptyExpression.EventAddition) {
6454 op = spec.AccessorAdd;
6455 } else if (right_side == EmptyExpression.EventSubtraction) {
6456 op = spec.AccessorRemove;
6460 Error_AssignmentEventOnly (ec);
6464 op = CandidateToBaseOverride (ec, op);
6468 protected override Expression DoResolve (ResolveContext ec)
6470 eclass = ExprClass.EventAccess;
6471 type = spec.MemberType;
6473 ResolveInstanceExpression (ec, null);
6475 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6476 Error_AssignmentEventOnly (ec);
6479 DoBestMemberChecks (ec, spec);
6483 public override void Emit (EmitContext ec)
6485 throw new NotSupportedException ();
6486 //Error_CannotAssign ();
6489 #region IAssignMethod Members
6491 public void Emit (EmitContext ec, bool leave_copy)
6493 throw new NotImplementedException ();
6496 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6498 if (leave_copy || !isCompound)
6499 throw new NotImplementedException ("EventExpr::EmitAssign");
6501 Arguments args = new Arguments (1);
6502 args.Add (new Argument (source));
6504 var call = new CallEmitter ();
6505 call.InstanceExpression = InstanceExpression;
6506 call.Emit (ec, op, args, loc);
6511 void Error_AssignmentEventOnly (ResolveContext ec)
6513 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6514 ec.Report.Error (79, loc,
6515 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6516 GetSignatureForError ());
6518 ec.Report.Error (70, loc,
6519 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6520 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6524 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6526 name = name.Substring (0, name.LastIndexOf ('.'));
6527 base.Error_CannotCallAbstractBase (rc, name);
6530 public override string GetSignatureForError ()
6532 return TypeManager.CSharpSignature (spec);
6535 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6537 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6541 public class TemporaryVariableReference : VariableReference
6543 public class Declarator : Statement
6545 TemporaryVariableReference variable;
6547 public Declarator (TemporaryVariableReference variable)
6549 this.variable = variable;
6553 protected override void DoEmit (EmitContext ec)
6555 variable.li.CreateBuilder (ec);
6558 public override void Emit (EmitContext ec)
6560 // Don't create sequence point
6564 protected override void CloneTo (CloneContext clonectx, Statement target)
6572 public TemporaryVariableReference (LocalVariable li, Location loc)
6575 this.type = li.Type;
6579 public override bool IsLockedByStatement {
6587 public LocalVariable LocalInfo {
6593 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6595 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6596 return new TemporaryVariableReference (li, loc);
6599 protected override Expression DoResolve (ResolveContext ec)
6601 eclass = ExprClass.Variable;
6604 // Don't capture temporary variables except when using
6605 // state machine redirection and block yields
6607 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6608 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6609 ec.IsVariableCapturingRequired) {
6610 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6611 storey.CaptureLocalVariable (ec, li);
6617 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6619 return Resolve (ec);
6622 public override void Emit (EmitContext ec)
6624 li.CreateBuilder (ec);
6629 public void EmitAssign (EmitContext ec, Expression source)
6631 li.CreateBuilder (ec);
6633 EmitAssign (ec, source, false, false);
6636 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6638 return li.HoistedVariant;
6641 public override bool IsFixed {
6642 get { return true; }
6645 public override bool IsRef {
6646 get { return false; }
6649 public override string Name {
6650 get { throw new NotImplementedException (); }
6653 public override void SetHasAddressTaken ()
6655 throw new NotImplementedException ();
6658 protected override ILocalVariable Variable {
6662 public override VariableInfo VariableInfo {
6663 get { return null; }
6666 public override void VerifyAssigned (ResolveContext rc)
6672 /// Handles `var' contextual keyword; var becomes a keyword only
6673 /// if no type called var exists in a variable scope
6675 class VarExpr : SimpleName
6677 public VarExpr (Location loc)
6682 public bool InferType (ResolveContext ec, Expression right_side)
6685 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6687 type = right_side.Type;
6688 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6689 ec.Report.Error (815, loc,
6690 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6691 type.GetSignatureForError ());
6695 eclass = ExprClass.Variable;
6699 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6701 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6702 base.Error_TypeOrNamespaceNotFound (ec);
6704 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");