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 {
166 // Returns true when the expression during Emit phase breaks stack
167 // by using await expression
169 public virtual bool ContainsEmitWithAwait ()
175 /// Performs semantic analysis on the Expression
179 /// The Resolve method is invoked to perform the semantic analysis
182 /// The return value is an expression (it can be the
183 /// same expression in some cases) or a new
184 /// expression that better represents this node.
186 /// For example, optimizations of Unary (LiteralInt)
187 /// would return a new LiteralInt with a negated
190 /// If there is an error during semantic analysis,
191 /// then an error should be reported (using Report)
192 /// and a null value should be returned.
194 /// There are two side effects expected from calling
195 /// Resolve(): the the field variable "eclass" should
196 /// be set to any value of the enumeration
197 /// `ExprClass' and the type variable should be set
198 /// to a valid type (this is the type of the
201 protected abstract Expression DoResolve (ResolveContext rc);
203 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
209 // This is used if the expression should be resolved as a type or namespace name.
210 // the default implementation fails.
212 public virtual TypeSpec ResolveAsType (IMemberContext mc)
214 ResolveContext ec = new ResolveContext (mc);
215 Expression e = Resolve (ec);
217 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
222 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
224 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
227 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
229 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
232 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
234 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
235 name, TypeManager.CSharpName (type));
238 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
240 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
243 public void Error_InvalidExpressionStatement (BlockContext bc)
245 Error_InvalidExpressionStatement (bc.Report, loc);
248 public void Error_InvalidExpressionStatement (Report report)
250 Error_InvalidExpressionStatement (report, loc);
253 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
255 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
258 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
260 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
263 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
265 // The error was already reported as CS1660
266 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
269 string from_type = type.GetSignatureForError ();
270 string to_type = target.GetSignatureForError ();
271 if (from_type == to_type) {
272 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
273 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
277 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
282 ec.Report.DisableReporting ();
283 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
284 ec.Report.EnableReporting ();
287 ec.Report.Error (266, loc,
288 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
291 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
296 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
298 // Better message for possible generic expressions
299 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
300 var report = context.Module.Compiler.Report;
301 report.SymbolRelatedToPreviousError (member);
302 if (member is TypeSpec)
303 member = ((TypeSpec) member).GetDefinition ();
305 member = ((MethodSpec) member).GetGenericMethodDefinition ();
307 string name = member.Kind == MemberKind.Method ? "method" : "type";
308 if (member.IsGeneric) {
309 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
310 name, member.GetSignatureForError (), member.Arity.ToString ());
312 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
313 name, member.GetSignatureForError ());
316 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
320 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
322 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
326 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
328 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
331 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
333 ec.Report.SymbolRelatedToPreviousError (type);
334 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
335 TypeManager.CSharpName (type), name);
338 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
340 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
341 // Already reported as CS1612
343 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
347 protected void Error_VoidPointerOperation (ResolveContext rc)
349 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
352 public ResolveFlags ExprClassToResolveFlags {
356 case ExprClass.Namespace:
357 return ResolveFlags.Type;
359 case ExprClass.MethodGroup:
360 return ResolveFlags.MethodGroup;
362 case ExprClass.TypeParameter:
363 return ResolveFlags.TypeParameter;
365 case ExprClass.Value:
366 case ExprClass.Variable:
367 case ExprClass.PropertyAccess:
368 case ExprClass.EventAccess:
369 case ExprClass.IndexerAccess:
370 return ResolveFlags.VariableOrValue;
373 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
379 // Implements identical simple name and type-name resolution
381 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
384 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
387 // 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
388 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
390 if (left is MemberExpr || left is VariableReference) {
391 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
392 if (identical_type != null && identical_type.Type == left.Type)
393 return identical_type;
399 public virtual string GetSignatureForError ()
401 return type.GetDefinition ().GetSignatureForError ();
405 /// Resolves an expression and performs semantic analysis on it.
409 /// Currently Resolve wraps DoResolve to perform sanity
410 /// checking and assertion checking on what we expect from Resolve.
412 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
414 if (eclass != ExprClass.Unresolved)
424 if ((flags & e.ExprClassToResolveFlags) == 0) {
425 e.Error_UnexpectedKind (ec, flags, loc);
430 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
433 } catch (Exception ex) {
434 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
437 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
438 return ErrorExpression.Instance; // TODO: Add location
443 /// Resolves an expression and performs semantic analysis on it.
445 public Expression Resolve (ResolveContext rc)
447 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
451 /// Resolves an expression for LValue assignment
455 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
456 /// checking and assertion checking on what we expect from Resolve
458 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
460 int errors = ec.Report.Errors;
461 bool out_access = right_side == EmptyExpression.OutAccess;
463 Expression e = DoResolveLValue (ec, right_side);
465 if (e != null && out_access && !(e is IMemoryLocation)) {
466 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
467 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
469 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
470 // e.GetType () + " " + e.GetSignatureForError ());
475 if (errors == ec.Report.Errors) {
477 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
479 Error_ValueAssignment (ec, right_side);
484 if (e.eclass == ExprClass.Unresolved)
485 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
487 if ((e.type == null) && !(e is GenericTypeExpr))
488 throw new Exception ("Expression " + e + " did not set its type after Resolve");
493 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
495 rc.Module.Compiler.Report.Error (182, loc,
496 "An attribute argument must be a constant expression, typeof expression or array creation expression");
500 /// Emits the code for the expression
504 /// The Emit method is invoked to generate the code
505 /// for the expression.
507 public abstract void Emit (EmitContext ec);
510 // Emit code to branch to @target if this expression is equivalent to @on_true.
511 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
512 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
513 // including the use of conditional branches. Note also that a branch MUST be emitted
514 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
517 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
520 // Emit this expression for its side effects, not for its value.
521 // The default implementation is to emit the value, and then throw it away.
522 // Subclasses can provide more efficient implementations, but those MUST be equivalent
523 public virtual void EmitSideEffect (EmitContext ec)
526 ec.Emit (OpCodes.Pop);
530 // Emits the expression into temporary field variable. The method
531 // should be used for await expressions only
533 public virtual Expression EmitToField (EmitContext ec)
536 // This is the await prepare Emit method. When emitting code like
537 // a + b we emit code like
543 // For await a + await b we have to interfere the flow to keep the
544 // stack clean because await yields from the expression. The emit
547 // a = a.EmitToField () // a is changed to temporary field access
548 // b = b.EmitToField ()
554 // The idea is to emit expression and leave the stack empty with
555 // result value still available.
557 // Expressions should override this default implementation when
558 // optimized version can be provided (e.g. FieldExpr)
561 // We can optimize for side-effect free expressions, they can be
562 // emitted out of order
564 if (IsSideEffectFree)
567 bool needs_temporary = ContainsEmitWithAwait ();
568 if (!needs_temporary)
571 // Emit original code
572 var field = EmitToFieldSource (ec);
575 // Store the result to temporary field when we
576 // cannot load `this' directly
578 field = ec.GetTemporaryField (type);
579 if (needs_temporary) {
581 // Create temporary local (we cannot load `this' before Emit)
583 var temp = ec.GetTemporaryLocal (type);
584 ec.Emit (OpCodes.Stloc, temp);
587 ec.Emit (OpCodes.Ldloc, temp);
588 field.EmitAssignFromStack (ec);
590 ec.FreeTemporaryLocal (temp, type);
592 field.EmitAssignFromStack (ec);
599 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
602 // Default implementation calls Emit method
608 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
610 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
611 bool contains_await = false;
613 for (int i = 1; i < expressions.Count; ++i) {
614 if (expressions[i].ContainsEmitWithAwait ()) {
615 contains_await = true;
620 if (contains_await) {
621 for (int i = 0; i < expressions.Count; ++i) {
622 expressions[i] = expressions[i].EmitToField (ec);
627 for (int i = 0; i < expressions.Count; ++i) {
628 expressions[i].Emit (ec);
633 /// Protected constructor. Only derivate types should
634 /// be able to be created
637 protected Expression ()
642 /// Returns a fully formed expression after a MemberLookup
645 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
647 if (spec is EventSpec)
648 return new EventExpr ((EventSpec) spec, loc);
649 if (spec is ConstSpec)
650 return new ConstantExpr ((ConstSpec) spec, loc);
651 if (spec is FieldSpec)
652 return new FieldExpr ((FieldSpec) spec, loc);
653 if (spec is PropertySpec)
654 return new PropertyExpr ((PropertySpec) spec, loc);
655 if (spec is TypeSpec)
656 return new TypeExpression (((TypeSpec) spec), loc);
661 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
663 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
665 rc.Report.SymbolRelatedToPreviousError (type);
667 // Report meaningful error for struct as they always have default ctor in C# context
668 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
670 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
671 type.GetSignatureForError ());
677 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
678 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
679 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
682 return r.ResolveMember<MethodSpec> (rc, ref args);
686 public enum MemberLookupRestrictions
695 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
696 // `qualifier_type' or null to lookup members in the current class.
698 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
700 var members = MemberCache.FindMembers (queried_type, name, false);
704 MemberSpec non_method = null;
705 MemberSpec ambig_non_method = null;
707 for (int i = 0; i < members.Count; ++i) {
708 var member = members[i];
710 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
711 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
714 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
717 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
721 if (!member.IsAccessible (rc))
725 // With runtime binder we can have a situation where queried type is inaccessible
726 // because it came via dynamic object, the check about inconsisted accessibility
727 // had no effect as the type was unknown during compilation
730 // private class N { }
732 // public dynamic Foo ()
738 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
742 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
743 if (member is MethodSpec)
744 return new MethodGroupExpr (members, queried_type, loc);
746 if (!Invocation.IsMemberInvocable (member))
750 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
752 } else if (!errorMode && !member.IsNotCSharpCompatible) {
754 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
755 // T has both an effective base class other than object and a non-empty effective interface set.
757 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
759 var tps = queried_type as TypeParameterSpec;
760 if (tps != null && tps.HasTypeConstraint) {
761 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
764 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
770 ambig_non_method = member;
774 if (non_method != null) {
775 if (ambig_non_method != null && rc != null) {
776 var report = rc.Module.Compiler.Report;
777 report.SymbolRelatedToPreviousError (non_method);
778 report.SymbolRelatedToPreviousError (ambig_non_method);
779 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
780 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
783 if (non_method is MethodSpec)
784 return new MethodGroupExpr (members, queried_type, loc);
786 return ExprClassFromMemberInfo (non_method, loc);
789 if (members[0].DeclaringType.BaseType == null)
792 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
794 } while (members != null);
799 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
801 throw new NotImplementedException ();
804 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
806 if (t == InternalType.ErrorType)
809 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
810 oper, t.GetSignatureForError ());
813 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
815 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
819 /// Returns an expression that can be used to invoke operator true
820 /// on the expression if it exists.
822 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
824 return GetOperatorTrueOrFalse (ec, e, true, loc);
828 /// Returns an expression that can be used to invoke operator false
829 /// on the expression if it exists.
831 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
833 return GetOperatorTrueOrFalse (ec, e, false, loc);
836 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
838 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
839 var methods = MemberCache.GetUserOperator (e.type, op, false);
843 Arguments arguments = new Arguments (1);
844 arguments.Add (new Argument (e));
846 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
847 var oper = res.ResolveOperator (ec, ref arguments);
852 return new UserOperatorCall (oper, arguments, null, loc);
855 public virtual string ExprClassName
859 case ExprClass.Unresolved:
861 case ExprClass.Value:
863 case ExprClass.Variable:
865 case ExprClass.Namespace:
869 case ExprClass.MethodGroup:
870 return "method group";
871 case ExprClass.PropertyAccess:
872 return "property access";
873 case ExprClass.EventAccess:
874 return "event access";
875 case ExprClass.IndexerAccess:
876 return "indexer access";
877 case ExprClass.Nothing:
879 case ExprClass.TypeParameter:
880 return "type parameter";
882 throw new Exception ("Should not happen");
887 /// Reports that we were expecting `expr' to be of class `expected'
889 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
891 var name = memberExpr.GetSignatureForError ();
893 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
896 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
898 string [] valid = new string [4];
901 if ((flags & ResolveFlags.VariableOrValue) != 0) {
902 valid [count++] = "variable";
903 valid [count++] = "value";
906 if ((flags & ResolveFlags.Type) != 0)
907 valid [count++] = "type";
909 if ((flags & ResolveFlags.MethodGroup) != 0)
910 valid [count++] = "method group";
913 valid [count++] = "unknown";
915 StringBuilder sb = new StringBuilder (valid [0]);
916 for (int i = 1; i < count - 1; i++) {
918 sb.Append (valid [i]);
921 sb.Append ("' or `");
922 sb.Append (valid [count - 1]);
925 ec.Report.Error (119, loc,
926 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
929 public static void UnsafeError (ResolveContext ec, Location loc)
931 UnsafeError (ec.Report, loc);
934 public static void UnsafeError (Report Report, Location loc)
936 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
940 // Converts `source' to an int, uint, long or ulong.
942 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
944 var btypes = ec.BuiltinTypes;
946 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
947 Arguments args = new Arguments (1);
948 args.Add (new Argument (source));
949 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
952 Expression converted;
954 using (ec.Set (ResolveContext.Options.CheckedScope)) {
955 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
956 if (converted == null)
957 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
958 if (converted == null)
959 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
960 if (converted == null)
961 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
963 if (converted == null) {
964 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
970 // Only positive constants are allowed at compile time
972 Constant c = converted as Constant;
973 if (c != null && c.IsNegative)
974 Error_NegativeArrayIndex (ec, source.loc);
976 // No conversion needed to array index
977 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
980 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
984 // Derived classes implement this method by cloning the fields that
985 // could become altered during the Resolve stage
987 // Only expressions that are created for the parser need to implement
990 protected virtual void CloneTo (CloneContext clonectx, Expression target)
992 throw new NotImplementedException (
994 "CloneTo not implemented for expression {0}", this.GetType ()));
998 // Clones an expression created by the parser.
1000 // We only support expressions created by the parser so far, not
1001 // expressions that have been resolved (many more classes would need
1002 // to implement CloneTo).
1004 // This infrastructure is here merely for Lambda expressions which
1005 // compile the same code using different type values for the same
1006 // arguments to find the correct overload
1008 public virtual Expression Clone (CloneContext clonectx)
1010 Expression cloned = (Expression) MemberwiseClone ();
1011 CloneTo (clonectx, cloned);
1017 // Implementation of expression to expression tree conversion
1019 public abstract Expression CreateExpressionTree (ResolveContext ec);
1021 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1023 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1026 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1028 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1031 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1033 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1036 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1038 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1042 return new TypeExpression (t, loc);
1046 // Implemented by all expressions which support conversion from
1047 // compiler expression to invokable runtime expression. Used by
1048 // dynamic C# binder.
1050 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1052 throw new NotImplementedException ("MakeExpression for " + GetType ());
1055 public virtual object Accept (StructuralVisitor visitor)
1057 return visitor.Visit (this);
1062 /// This is just a base class for expressions that can
1063 /// appear on statements (invocations, object creation,
1064 /// assignments, post/pre increment and decrement). The idea
1065 /// being that they would support an extra Emition interface that
1066 /// does not leave a result on the stack.
1068 public abstract class ExpressionStatement : Expression
1070 public ExpressionStatement ResolveStatement (BlockContext ec)
1072 Expression e = Resolve (ec);
1076 ExpressionStatement es = e as ExpressionStatement;
1078 Error_InvalidExpressionStatement (ec);
1081 // This is quite expensive warning, try to limit the damage
1083 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1084 WarningAsyncWithoutWait (ec, e);
1090 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1092 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1093 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1098 // Need to do full resolve because GetAwaiter can be extension method
1099 // available only in this context
1101 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1105 var arguments = new Arguments (0);
1106 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1111 // Use same check rules as for real await
1113 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1114 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1117 bc.Report.Warning (4014, 1, e.Location,
1118 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1122 var inv = e as Invocation;
1123 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1124 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1125 bc.Report.Warning (4014, 1, e.Location,
1126 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1132 /// Requests the expression to be emitted in a `statement'
1133 /// context. This means that no new value is left on the
1134 /// stack after invoking this method (constrasted with
1135 /// Emit that will always leave a value on the stack).
1137 public abstract void EmitStatement (EmitContext ec);
1139 public override void EmitSideEffect (EmitContext ec)
1146 /// This kind of cast is used to encapsulate the child
1147 /// whose type is child.Type into an expression that is
1148 /// reported to return "return_type". This is used to encapsulate
1149 /// expressions which have compatible types, but need to be dealt
1150 /// at higher levels with.
1152 /// For example, a "byte" expression could be encapsulated in one
1153 /// of these as an "unsigned int". The type for the expression
1154 /// would be "unsigned int".
1157 public abstract class TypeCast : Expression
1159 protected readonly Expression child;
1161 protected TypeCast (Expression child, TypeSpec return_type)
1163 eclass = child.eclass;
1164 loc = child.Location;
1169 public Expression Child {
1175 public override bool ContainsEmitWithAwait ()
1177 return child.ContainsEmitWithAwait ();
1180 public override Expression CreateExpressionTree (ResolveContext ec)
1182 Arguments args = new Arguments (2);
1183 args.Add (new Argument (child.CreateExpressionTree (ec)));
1184 args.Add (new Argument (new TypeOf (type, loc)));
1186 if (type.IsPointer || child.Type.IsPointer)
1187 Error_PointerInsideExpressionTree (ec);
1189 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1192 protected override Expression DoResolve (ResolveContext ec)
1194 // This should never be invoked, we are born in fully
1195 // initialized state.
1200 public override void Emit (EmitContext ec)
1205 public override SLE.Expression MakeExpression (BuilderContext ctx)
1208 return base.MakeExpression (ctx);
1210 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1211 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1212 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1216 protected override void CloneTo (CloneContext clonectx, Expression t)
1221 public override bool IsNull {
1222 get { return child.IsNull; }
1226 public class EmptyCast : TypeCast {
1227 EmptyCast (Expression child, TypeSpec target_type)
1228 : base (child, target_type)
1232 public static Expression Create (Expression child, TypeSpec type)
1234 Constant c = child as Constant;
1236 return new EmptyConstantCast (c, type);
1238 EmptyCast e = child as EmptyCast;
1240 return new EmptyCast (e.child, type);
1242 return new EmptyCast (child, type);
1245 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1247 child.EmitBranchable (ec, label, on_true);
1250 public override void EmitSideEffect (EmitContext ec)
1252 child.EmitSideEffect (ec);
1257 // Used for predefined type user operator (no obsolete check, etc.)
1259 public class OperatorCast : TypeCast
1261 readonly MethodSpec conversion_operator;
1263 public OperatorCast (Expression expr, TypeSpec target_type)
1264 : this (expr, target_type, target_type, false)
1268 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1269 : this (expr, target_type, target_type, find_explicit)
1273 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1274 : base (expr, returnType)
1276 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1277 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1280 foreach (MethodSpec oper in mi) {
1281 if (oper.ReturnType != returnType)
1284 if (oper.Parameters.Types[0] == expr.Type) {
1285 conversion_operator = oper;
1291 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1292 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1295 public override void Emit (EmitContext ec)
1298 ec.Emit (OpCodes.Call, conversion_operator);
1303 // Constant specialization of EmptyCast.
1304 // We need to special case this since an empty cast of
1305 // a constant is still a constant.
1307 public class EmptyConstantCast : Constant
1309 public readonly Constant child;
1311 public EmptyConstantCast (Constant child, TypeSpec type)
1312 : base (child.Location)
1315 throw new ArgumentNullException ("child");
1318 this.eclass = child.eclass;
1322 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1324 if (child.Type == target_type)
1327 // FIXME: check that 'type' can be converted to 'target_type' first
1328 return child.ConvertExplicitly (in_checked_context, target_type);
1331 public override Expression CreateExpressionTree (ResolveContext ec)
1333 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1334 child.CreateExpressionTree (ec),
1335 new TypeOf (type, loc));
1338 Error_PointerInsideExpressionTree (ec);
1340 return CreateExpressionFactoryCall (ec, "Convert", args);
1343 public override bool IsDefaultValue {
1344 get { return child.IsDefaultValue; }
1347 public override bool IsNegative {
1348 get { return child.IsNegative; }
1351 public override bool IsNull {
1352 get { return child.IsNull; }
1355 public override bool IsOneInteger {
1356 get { return child.IsOneInteger; }
1359 public override bool IsSideEffectFree {
1361 return child.IsSideEffectFree;
1365 public override bool IsZeroInteger {
1366 get { return child.IsZeroInteger; }
1369 public override void Emit (EmitContext ec)
1374 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1376 child.EmitBranchable (ec, label, on_true);
1378 // Only to make verifier happy
1379 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1380 ec.Emit (OpCodes.Unbox_Any, type);
1383 public override void EmitSideEffect (EmitContext ec)
1385 child.EmitSideEffect (ec);
1388 public override object GetValue ()
1390 return child.GetValue ();
1393 public override string GetValueAsLiteral ()
1395 return child.GetValueAsLiteral ();
1398 public override long GetValueAsLong ()
1400 return child.GetValueAsLong ();
1403 public override Constant ConvertImplicitly (TypeSpec target_type)
1405 if (type == target_type)
1408 // FIXME: Do we need to check user conversions?
1409 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1412 return child.ConvertImplicitly (target_type);
1417 /// This class is used to wrap literals which belong inside Enums
1419 public class EnumConstant : Constant
1421 public Constant Child;
1423 public EnumConstant (Constant child, TypeSpec enum_type)
1424 : base (child.Location)
1428 this.eclass = ExprClass.Value;
1429 this.type = enum_type;
1432 protected EnumConstant (Location loc)
1437 public override void Emit (EmitContext ec)
1442 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1444 Child.EncodeAttributeValue (rc, enc, Child.Type);
1447 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1449 Child.EmitBranchable (ec, label, on_true);
1452 public override void EmitSideEffect (EmitContext ec)
1454 Child.EmitSideEffect (ec);
1457 public override string GetSignatureForError()
1459 return TypeManager.CSharpName (Type);
1462 public override object GetValue ()
1464 return Child.GetValue ();
1468 public override object GetTypedValue ()
1471 // The method can be used in dynamic context only (on closed types)
1473 // System.Enum.ToObject cannot be called on dynamic types
1474 // EnumBuilder has to be used, but we cannot use EnumBuilder
1475 // because it does not properly support generics
1477 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1481 public override string GetValueAsLiteral ()
1483 return Child.GetValueAsLiteral ();
1486 public override long GetValueAsLong ()
1488 return Child.GetValueAsLong ();
1491 public EnumConstant Increment()
1493 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1496 public override bool IsDefaultValue {
1498 return Child.IsDefaultValue;
1502 public override bool IsSideEffectFree {
1504 return Child.IsSideEffectFree;
1508 public override bool IsZeroInteger {
1509 get { return Child.IsZeroInteger; }
1512 public override bool IsNegative {
1514 return Child.IsNegative;
1518 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1520 if (Child.Type == target_type)
1523 return Child.ConvertExplicitly (in_checked_context, target_type);
1526 public override Constant ConvertImplicitly (TypeSpec type)
1528 if (this.type == type) {
1532 if (!Convert.ImplicitStandardConversionExists (this, type)){
1536 return Child.ConvertImplicitly (type);
1541 /// This kind of cast is used to encapsulate Value Types in objects.
1543 /// The effect of it is to box the value type emitted by the previous
1546 public class BoxedCast : TypeCast {
1548 public BoxedCast (Expression expr, TypeSpec target_type)
1549 : base (expr, target_type)
1551 eclass = ExprClass.Value;
1554 protected override Expression DoResolve (ResolveContext ec)
1556 // This should never be invoked, we are born in fully
1557 // initialized state.
1562 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1564 // Only boxing to object type is supported
1565 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1566 base.EncodeAttributeValue (rc, enc, targetType);
1570 enc.Encode (child.Type);
1571 child.EncodeAttributeValue (rc, enc, child.Type);
1574 public override void Emit (EmitContext ec)
1578 ec.Emit (OpCodes.Box, child.Type);
1581 public override void EmitSideEffect (EmitContext ec)
1583 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1584 // so, we need to emit the box+pop instructions in most cases
1585 if (child.Type.IsStruct &&
1586 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1587 child.EmitSideEffect (ec);
1589 base.EmitSideEffect (ec);
1593 public class UnboxCast : TypeCast {
1594 public UnboxCast (Expression expr, TypeSpec return_type)
1595 : base (expr, return_type)
1599 protected override Expression DoResolve (ResolveContext ec)
1601 // This should never be invoked, we are born in fully
1602 // initialized state.
1607 public override void Emit (EmitContext ec)
1611 ec.Emit (OpCodes.Unbox_Any, type);
1616 /// This is used to perform explicit numeric conversions.
1618 /// Explicit numeric conversions might trigger exceptions in a checked
1619 /// context, so they should generate the conv.ovf opcodes instead of
1622 public class ConvCast : TypeCast {
1623 public enum Mode : byte {
1624 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1626 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1627 U2_I1, U2_U1, U2_I2, U2_CH,
1628 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1629 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1630 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1631 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1632 CH_I1, CH_U1, CH_I2,
1633 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1634 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1640 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1641 : base (child, return_type)
1646 protected override Expression DoResolve (ResolveContext ec)
1648 // This should never be invoked, we are born in fully
1649 // initialized state.
1654 public override string ToString ()
1656 return String.Format ("ConvCast ({0}, {1})", mode, child);
1659 public override void Emit (EmitContext ec)
1663 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1665 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1666 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1667 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1668 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1669 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1671 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1672 case Mode.U1_CH: /* nothing */ break;
1674 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1675 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1676 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1677 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1678 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1679 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1681 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1682 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1683 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1684 case Mode.U2_CH: /* nothing */ break;
1686 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1687 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1688 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1689 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1690 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1691 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1692 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1694 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1695 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1696 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1697 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1698 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1699 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1701 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1702 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1703 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1704 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1705 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1706 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1707 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1708 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1709 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1711 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1712 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1713 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1714 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1715 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1716 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1717 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1718 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1719 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1721 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1722 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1723 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1725 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1726 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1727 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1728 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1729 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1730 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1731 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1732 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1733 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1735 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1736 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1737 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1738 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1739 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1740 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1741 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1742 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1743 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1744 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1746 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1750 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1751 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1752 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1753 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1754 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1756 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1757 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1759 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1760 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1761 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1762 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1763 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1764 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1766 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1767 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1768 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1769 case Mode.U2_CH: /* nothing */ break;
1771 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1772 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1773 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1774 case Mode.I4_U4: /* nothing */ break;
1775 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1776 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1777 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1779 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1780 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1781 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1782 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1783 case Mode.U4_I4: /* nothing */ break;
1784 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1786 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1787 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1788 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1789 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1790 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1791 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1792 case Mode.I8_U8: /* nothing */ break;
1793 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1794 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1796 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1797 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1798 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1799 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1800 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1801 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1802 case Mode.U8_I8: /* nothing */ break;
1803 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1804 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1806 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1807 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1808 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1810 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1811 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1812 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1813 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1814 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1815 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1816 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1817 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1818 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1820 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1821 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1822 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1823 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1824 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1825 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1826 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1827 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1828 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1829 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1831 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1837 class OpcodeCast : TypeCast
1841 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1842 : base (child, return_type)
1847 protected override Expression DoResolve (ResolveContext ec)
1849 // This should never be invoked, we are born in fully
1850 // initialized state.
1855 public override void Emit (EmitContext ec)
1861 public TypeSpec UnderlyingType {
1862 get { return child.Type; }
1867 // Opcode casts expression with 2 opcodes but only
1868 // single expression tree node
1870 class OpcodeCastDuplex : OpcodeCast
1872 readonly OpCode second;
1874 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1875 : base (child, returnType, first)
1877 this.second = second;
1880 public override void Emit (EmitContext ec)
1888 /// This kind of cast is used to encapsulate a child and cast it
1889 /// to the class requested
1891 public sealed class ClassCast : TypeCast {
1892 readonly bool forced;
1894 public ClassCast (Expression child, TypeSpec return_type)
1895 : base (child, return_type)
1899 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1900 : base (child, return_type)
1902 this.forced = forced;
1905 public override void Emit (EmitContext ec)
1909 bool gen = TypeManager.IsGenericParameter (child.Type);
1911 ec.Emit (OpCodes.Box, child.Type);
1913 if (type.IsGenericParameter) {
1914 ec.Emit (OpCodes.Unbox_Any, type);
1921 ec.Emit (OpCodes.Castclass, type);
1926 // Created during resolving pahse when an expression is wrapped or constantified
1927 // and original expression can be used later (e.g. for expression trees)
1929 public class ReducedExpression : Expression
1931 sealed class ReducedConstantExpression : EmptyConstantCast
1933 readonly Expression orig_expr;
1935 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1936 : base (expr, expr.Type)
1938 this.orig_expr = orig_expr;
1941 public override Constant ConvertImplicitly (TypeSpec target_type)
1943 Constant c = base.ConvertImplicitly (target_type);
1945 c = new ReducedConstantExpression (c, orig_expr);
1950 public override Expression CreateExpressionTree (ResolveContext ec)
1952 return orig_expr.CreateExpressionTree (ec);
1955 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1957 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1959 c = new ReducedConstantExpression (c, orig_expr);
1963 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1966 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1968 if (orig_expr is Conditional)
1969 child.EncodeAttributeValue (rc, enc, targetType);
1971 base.EncodeAttributeValue (rc, enc, targetType);
1975 sealed class ReducedExpressionStatement : ExpressionStatement
1977 readonly Expression orig_expr;
1978 readonly ExpressionStatement stm;
1980 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
1982 this.orig_expr = orig;
1984 this.eclass = stm.eclass;
1985 this.type = stm.Type;
1987 this.loc = orig.Location;
1990 public override bool ContainsEmitWithAwait ()
1992 return stm.ContainsEmitWithAwait ();
1995 public override Expression CreateExpressionTree (ResolveContext ec)
1997 return orig_expr.CreateExpressionTree (ec);
2000 protected override Expression DoResolve (ResolveContext ec)
2005 public override void Emit (EmitContext ec)
2010 public override void EmitStatement (EmitContext ec)
2012 stm.EmitStatement (ec);
2016 readonly Expression expr, orig_expr;
2018 private ReducedExpression (Expression expr, Expression orig_expr)
2021 this.eclass = expr.eclass;
2022 this.type = expr.Type;
2023 this.orig_expr = orig_expr;
2024 this.loc = orig_expr.Location;
2029 public override bool IsSideEffectFree {
2031 return expr.IsSideEffectFree;
2035 public Expression OriginalExpression {
2043 public override bool ContainsEmitWithAwait ()
2045 return expr.ContainsEmitWithAwait ();
2049 // Creates fully resolved expression switcher
2051 public static Constant Create (Constant expr, Expression original_expr)
2053 if (expr.eclass == ExprClass.Unresolved)
2054 throw new ArgumentException ("Unresolved expression");
2056 return new ReducedConstantExpression (expr, original_expr);
2059 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2061 return new ReducedExpressionStatement (s, orig);
2064 public static Expression Create (Expression expr, Expression original_expr)
2066 return Create (expr, original_expr, true);
2070 // Creates unresolved reduce expression. The original expression has to be
2071 // already resolved. Created expression is constant based based on `expr'
2072 // value unless canBeConstant is used
2074 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2076 if (canBeConstant) {
2077 Constant c = expr as Constant;
2079 return Create (c, original_expr);
2082 ExpressionStatement s = expr as ExpressionStatement;
2084 return Create (s, original_expr);
2086 if (expr.eclass == ExprClass.Unresolved)
2087 throw new ArgumentException ("Unresolved expression");
2089 return new ReducedExpression (expr, original_expr);
2092 public override Expression CreateExpressionTree (ResolveContext ec)
2094 return orig_expr.CreateExpressionTree (ec);
2097 protected override Expression DoResolve (ResolveContext ec)
2102 public override void Emit (EmitContext ec)
2107 public override Expression EmitToField (EmitContext ec)
2109 return expr.EmitToField(ec);
2112 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2114 expr.EmitBranchable (ec, target, on_true);
2117 public override SLE.Expression MakeExpression (BuilderContext ctx)
2119 return orig_expr.MakeExpression (ctx);
2124 // Standard composite pattern
2126 public abstract class CompositeExpression : Expression
2128 protected Expression expr;
2130 protected CompositeExpression (Expression expr)
2133 this.loc = expr.Location;
2136 public override bool ContainsEmitWithAwait ()
2138 return expr.ContainsEmitWithAwait ();
2141 public override Expression CreateExpressionTree (ResolveContext rc)
2143 return expr.CreateExpressionTree (rc);
2146 public Expression Child {
2147 get { return expr; }
2150 protected override Expression DoResolve (ResolveContext rc)
2152 expr = expr.Resolve (rc);
2155 eclass = expr.eclass;
2161 public override void Emit (EmitContext ec)
2166 public override bool IsNull {
2167 get { return expr.IsNull; }
2172 // Base of expressions used only to narrow resolve flow
2174 public abstract class ShimExpression : Expression
2176 protected Expression expr;
2178 protected ShimExpression (Expression expr)
2183 public Expression Expr {
2189 protected override void CloneTo (CloneContext clonectx, Expression t)
2194 ShimExpression target = (ShimExpression) t;
2195 target.expr = expr.Clone (clonectx);
2198 public override bool ContainsEmitWithAwait ()
2200 return expr.ContainsEmitWithAwait ();
2203 public override Expression CreateExpressionTree (ResolveContext ec)
2205 throw new NotSupportedException ("ET");
2208 public override void Emit (EmitContext ec)
2210 throw new InternalErrorException ("Missing Resolve call");
2216 // Unresolved type name expressions
2218 public abstract class ATypeNameExpression : FullNamedExpression
2221 protected TypeArguments targs;
2223 protected ATypeNameExpression (string name, Location l)
2229 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2236 protected ATypeNameExpression (string name, int arity, Location l)
2237 : this (name, new UnboundTypeArguments (arity), l)
2243 protected int Arity {
2245 return targs == null ? 0 : targs.Count;
2249 public bool HasTypeArguments {
2251 return targs != null && !targs.IsEmpty;
2255 public string Name {
2264 public TypeArguments TypeArguments {
2272 public override bool Equals (object obj)
2274 ATypeNameExpression atne = obj as ATypeNameExpression;
2275 return atne != null && atne.Name == Name &&
2276 (targs == null || targs.Equals (atne.targs));
2279 public override int GetHashCode ()
2281 return Name.GetHashCode ();
2284 // TODO: Move it to MemberCore
2285 public static string GetMemberType (MemberCore mc)
2291 if (mc is FieldBase)
2293 if (mc is MethodCore)
2295 if (mc is EnumMember)
2303 public override string GetSignatureForError ()
2305 if (targs != null) {
2306 return Name + "<" + targs.GetSignatureForError () + ">";
2312 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2316 /// SimpleName expressions are formed of a single word and only happen at the beginning
2317 /// of a dotted-name.
2319 public class SimpleName : ATypeNameExpression
2321 public SimpleName (string name, Location l)
2326 public SimpleName (string name, TypeArguments args, Location l)
2327 : base (name, args, l)
2331 public SimpleName (string name, int arity, Location l)
2332 : base (name, arity, l)
2336 public SimpleName GetMethodGroup ()
2338 return new SimpleName (Name, targs, loc);
2341 protected override Expression DoResolve (ResolveContext rc)
2343 var e = SimpleNameResolve (rc, null, false);
2345 var fe = e as FieldExpr;
2347 fe.VerifyAssignedStructField (rc, null);
2353 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2355 return SimpleNameResolve (ec, right_side, false);
2358 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2360 if (ctx.CurrentType != null) {
2361 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2362 if (member != null) {
2363 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2368 var report = ctx.Module.Compiler.Report;
2370 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2371 if (retval != null) {
2372 report.SymbolRelatedToPreviousError (retval.Type);
2373 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2377 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2378 if (retval != null) {
2379 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2383 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2384 if (ns_candidates != null) {
2385 if (ctx is UsingAliasNamespace.AliasContext) {
2386 report.Error (246, loc,
2387 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2388 ns_candidates[0], Name);
2390 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2391 report.Error (246, loc,
2392 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2396 report.Error (246, loc,
2397 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2402 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2404 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2407 if (fne.Type != null && Arity > 0) {
2408 if (HasTypeArguments) {
2409 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2410 if (ct.ResolveAsType (ec) == null)
2416 return new GenericOpenTypeExpr (fne.Type, loc);
2420 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2422 if (!(fne is Namespace))
2426 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2427 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2428 ec.Module.Compiler.Report.Error (1980, Location,
2429 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2430 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2433 fne = new DynamicTypeExpr (loc);
2434 fne.ResolveAsType (ec);
2440 Error_TypeOrNamespaceNotFound (ec);
2444 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2446 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2449 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2451 int lookup_arity = Arity;
2452 bool errorMode = false;
2454 Block current_block = rc.CurrentBlock;
2455 INamedBlockVariable variable = null;
2456 bool variable_found = false;
2460 // Stage 1: binding to local variables or parameters
2462 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2464 if (current_block != null && lookup_arity == 0) {
2465 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2466 if (!variable.IsDeclared) {
2467 // We found local name in accessible block but it's not
2468 // initialized yet, maybe the user wanted to bind to something else
2470 variable_found = true;
2472 e = variable.CreateReferenceExpression (rc, loc);
2475 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2484 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2486 TypeSpec member_type = rc.CurrentType;
2487 for (; member_type != null; member_type = member_type.DeclaringType) {
2488 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2492 var me = e as MemberExpr;
2494 // The name matches a type, defer to ResolveAsTypeStep
2502 if (variable != null) {
2503 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2504 rc.Report.Error (844, loc,
2505 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2506 Name, me.GetSignatureForError ());
2510 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2511 // Leave it to overload resolution to report correct error
2513 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2514 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2517 // LAMESPEC: again, ignores InvocableOnly
2518 if (variable != null) {
2519 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2520 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2524 // MemberLookup does not check accessors availability, this is actually needed for properties only
2526 var pe = me as PropertyExpr;
2529 // Break as there is no other overload available anyway
2530 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2531 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2534 pe.Getter = pe.PropertyInfo.Get;
2536 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2539 pe.Setter = pe.PropertyInfo.Set;
2544 // TODO: It's used by EventExpr -> FieldExpr transformation only
2545 // TODO: Should go to MemberAccess
2546 me = me.ResolveMemberAccess (rc, null, null);
2550 me.SetTypeArguments (rc, targs);
2557 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2559 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2560 if (IsPossibleTypeOrNamespace (rc)) {
2561 if (variable != null) {
2562 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2563 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2566 return ResolveAsTypeOrNamespace (rc);
2571 if (variable_found) {
2572 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2575 var tparams = rc.CurrentTypeParameters;
2576 if (tparams != null) {
2577 if (tparams.Find (Name) != null) {
2578 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2583 var ct = rc.CurrentType;
2585 if (ct.MemberDefinition.TypeParametersCount > 0) {
2586 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2587 if (ctp.Name == Name) {
2588 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2594 ct = ct.DeclaringType;
2595 } while (ct != null);
2598 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2599 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2601 rc.Report.SymbolRelatedToPreviousError (e.Type);
2602 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2606 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2608 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2609 return ErrorExpression.Instance;
2613 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2615 if (e.Type.Arity != Arity) {
2616 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2620 if (e is TypeExpr) {
2621 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2626 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2629 return ErrorExpression.Instance;
2632 if (rc.Module.Evaluator != null) {
2633 var fi = rc.Module.Evaluator.LookupField (Name);
2635 return new FieldExpr (fi.Item1, loc);
2643 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2645 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2650 if (right_side != null) {
2651 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2652 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2656 e = e.ResolveLValue (ec, right_side);
2664 public override object Accept (StructuralVisitor visitor)
2666 return visitor.Visit (this);
2671 /// Represents a namespace or a type. The name of the class was inspired by
2672 /// section 10.8.1 (Fully Qualified Names).
2674 public abstract class FullNamedExpression : Expression
2676 protected override void CloneTo (CloneContext clonectx, Expression target)
2678 // Do nothing, most unresolved type expressions cannot be
2679 // resolved to different type
2682 public override bool ContainsEmitWithAwait ()
2687 public override Expression CreateExpressionTree (ResolveContext ec)
2689 throw new NotSupportedException ("ET");
2692 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2695 // This is used to resolve the expression as a type, a null
2696 // value will be returned if the expression is not a type
2699 public override TypeSpec ResolveAsType (IMemberContext mc)
2701 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2706 TypeExpr te = fne as TypeExpr;
2708 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2716 var dep = type.GetMissingDependencies ();
2718 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2721 if (type.Kind == MemberKind.Void) {
2722 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2726 // Obsolete checks cannot be done when resolving base context as they
2727 // require type dependencies to be set but we are in process of resolving them
2729 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2730 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2731 if (obsolete_attr != null && !mc.IsObsolete) {
2732 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2740 public override void Emit (EmitContext ec)
2742 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2743 GetSignatureForError ());
2748 /// Expression that evaluates to a type
2750 public abstract class TypeExpr : FullNamedExpression
2752 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2758 protected sealed override Expression DoResolve (ResolveContext ec)
2764 public override bool Equals (object obj)
2766 TypeExpr tobj = obj as TypeExpr;
2770 return Type == tobj.Type;
2773 public override int GetHashCode ()
2775 return Type.GetHashCode ();
2780 /// Fully resolved Expression that already evaluated to a type
2782 public class TypeExpression : TypeExpr
2784 public TypeExpression (TypeSpec t, Location l)
2787 eclass = ExprClass.Type;
2791 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2798 /// This class denotes an expression which evaluates to a member
2799 /// of a struct or a class.
2801 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2804 // An instance expression associated with this member, if it's a
2805 // non-static member
2807 public Expression InstanceExpression;
2810 /// The name of this member.
2812 public abstract string Name {
2817 // When base.member is used
2819 public bool IsBase {
2820 get { return InstanceExpression is BaseThis; }
2824 /// Whether this is an instance member.
2826 public abstract bool IsInstance {
2831 /// Whether this is a static member.
2833 public abstract bool IsStatic {
2837 public abstract string KindName {
2841 protected abstract TypeSpec DeclaringType {
2845 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2847 return InstanceExpression.Type;
2852 // Converts best base candidate for virtual method starting from QueriedBaseType
2854 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2857 // Only when base.member is used and method is virtual
2863 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2864 // means for base.member access we have to find the closest match after we found best candidate
2866 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2868 // The method could already be what we are looking for
2870 TypeSpec[] targs = null;
2871 if (method.DeclaringType != InstanceExpression.Type) {
2872 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2873 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2874 if (base_override.IsGeneric)
2875 targs = method.TypeArguments;
2877 method = base_override;
2882 // When base access is used inside anonymous method/iterator/etc we need to
2883 // get back to the context of original type. We do it by emiting proxy
2884 // method in original class and rewriting base call to this compiler
2885 // generated method call which does the actual base invocation. This may
2886 // introduce redundant storey but with `this' only but it's tricky to avoid
2887 // at this stage as we don't know what expressions follow base
2889 if (rc.CurrentAnonymousMethod != null) {
2890 if (targs == null && method.IsGeneric) {
2891 targs = method.TypeArguments;
2892 method = method.GetGenericMethodDefinition ();
2895 if (method.Parameters.HasArglist)
2896 throw new NotImplementedException ("__arglist base call proxy");
2898 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2900 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2901 // get/set member expressions second call would fail to proxy because left expression
2902 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2903 // FIXME: The async check is another hack but will probably fail with mutators
2904 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2905 InstanceExpression = new This (loc).Resolve (rc);
2909 method = method.MakeGenericMethod (rc, targs);
2913 // Only base will allow this invocation to happen.
2915 if (method.IsAbstract) {
2916 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2922 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2924 if (InstanceExpression == null)
2927 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2928 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2929 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2934 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2936 if (InstanceExpression == null)
2939 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2942 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2944 var ct = rc.CurrentType;
2945 if (ct == qualifier)
2948 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2951 qualifier = qualifier.GetDefinition ();
2952 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2959 public override bool ContainsEmitWithAwait ()
2961 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2964 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2967 type = type.GetDefinition ();
2969 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2972 type = type.DeclaringType;
2973 } while (type != null);
2978 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2980 if (InstanceExpression != null) {
2981 InstanceExpression = InstanceExpression.Resolve (rc);
2982 CheckProtectedMemberAccess (rc, member);
2985 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
2986 UnsafeError (rc, loc);
2989 var dep = member.GetMissingDependencies ();
2991 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
2994 if (!rc.IsObsolete) {
2995 ObsoleteAttribute oa = member.GetAttributeObsolete ();
2997 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3000 if (!(member is FieldSpec))
3001 member.MemberDefinition.SetIsUsed ();
3004 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3006 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3009 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3011 rc.Report.SymbolRelatedToPreviousError (member);
3012 rc.Report.Error (1540, loc,
3013 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3014 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3017 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3019 if (!ResolveInstanceExpressionCore (rc, rhs))
3023 // Check intermediate value modification which won't have any effect
3025 if (rhs != null && InstanceExpression.Type.IsStruct &&
3026 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3028 if (rc.CurrentInitializerVariable != null) {
3029 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3030 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3032 rc.Report.Error (1612, loc,
3033 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3034 InstanceExpression.GetSignatureForError ());
3041 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3044 if (InstanceExpression != null) {
3045 if (InstanceExpression is TypeExpr) {
3046 var t = InstanceExpression.Type;
3048 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3049 if (oa != null && !rc.IsObsolete) {
3050 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3053 t = t.DeclaringType;
3054 } while (t != null);
3056 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3057 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3058 rc.Report.Error (176, loc,
3059 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3060 GetSignatureForError ());
3064 InstanceExpression = null;
3070 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3071 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3072 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3073 rc.Report.Error (236, loc,
3074 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3075 GetSignatureForError ());
3077 rc.Report.Error (120, loc,
3078 "An object reference is required to access non-static member `{0}'",
3079 GetSignatureForError ());
3081 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3085 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3086 rc.Report.Error (38, loc,
3087 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3088 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3091 InstanceExpression = new This (loc);
3092 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3093 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3094 InstanceExpression = InstanceExpression.Resolve (rc);
3097 InstanceExpression = InstanceExpression.Resolve (rc);
3103 var me = InstanceExpression as MemberExpr;
3105 me.ResolveInstanceExpressionCore (rc, rhs);
3107 // Using this check to detect probing instance expression resolve
3108 if (!rc.OmitStructFlowAnalysis) {
3109 var fe = me as FieldExpr;
3110 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3111 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3112 rc.Report.Warning (1690, 1, loc,
3113 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3114 me.GetSignatureForError ());
3122 // Run member-access postponed check once we know that
3123 // the expression is not field expression which is the only
3124 // expression which can use uninitialized this
3126 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3127 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3131 // Additional checks for l-value member access
3134 if (InstanceExpression is UnboxCast) {
3135 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3142 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3144 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3145 ec.Report.Warning (1720, 1, left.Location,
3146 "Expression will always cause a `{0}'", "System.NullReferenceException");
3149 InstanceExpression = left;
3153 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3155 TypeSpec instance_type = InstanceExpression.Type;
3156 if (TypeSpec.IsValueType (instance_type)) {
3157 if (InstanceExpression is IMemoryLocation) {
3158 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3160 // Cannot release the temporary variable when its address
3161 // is required to be on stack for any parent
3162 LocalTemporary t = new LocalTemporary (instance_type);
3163 InstanceExpression.Emit (ec);
3165 t.AddressOf (ec, AddressOp.Store);
3168 InstanceExpression.Emit (ec);
3170 // Only to make verifier happy
3171 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3172 ec.Emit (OpCodes.Box, instance_type);
3175 if (prepare_for_load)
3176 ec.Emit (OpCodes.Dup);
3179 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3182 public class ExtensionMethodCandidates
3184 readonly NamespaceContainer container;
3185 readonly IList<MethodSpec> methods;
3187 readonly IMemberContext context;
3189 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3191 this.context = context;
3192 this.methods = methods;
3193 this.container = nsContainer;
3194 this.index = lookupIndex;
3197 public NamespaceContainer Container {
3203 public IMemberContext Context {
3209 public int LookupIndex {
3215 public IList<MethodSpec> Methods {
3223 // Represents a group of extension method candidates for whole namespace
3225 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3227 ExtensionMethodCandidates candidates;
3228 public readonly Expression ExtensionExpression;
3230 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3231 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3233 this.candidates = candidates;
3234 this.ExtensionExpression = extensionExpr;
3237 public override bool IsStatic {
3238 get { return true; }
3242 // For extension methodgroup we are not looking for base members but parent
3243 // namespace extension methods
3245 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3247 // TODO: candidates are null only when doing error reporting, that's
3248 // incorrect. We have to discover same extension methods in error mode
3249 if (candidates == null)
3252 int arity = type_arguments == null ? 0 : type_arguments.Count;
3254 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3255 if (candidates == null)
3258 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3261 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3263 // We are already here
3267 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3269 if (arguments == null)
3270 arguments = new Arguments (1);
3272 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3273 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3275 // Store resolved argument and restore original arguments
3277 // Clean-up modified arguments for error reporting
3278 arguments.RemoveAt (0);
3282 var me = ExtensionExpression as MemberExpr;
3284 me.ResolveInstanceExpression (ec, null);
3285 var fe = me as FieldExpr;
3287 fe.Spec.MemberDefinition.SetIsUsed ();
3290 InstanceExpression = null;
3294 #region IErrorHandler Members
3296 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3301 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3303 rc.Report.SymbolRelatedToPreviousError (best);
3304 rc.Report.Error (1928, loc,
3305 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3306 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3309 rc.Report.Error (1929, loc,
3310 "Extension method instance type `{0}' cannot be converted to `{1}'",
3311 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3317 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3322 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3331 /// MethodGroupExpr represents a group of method candidates which
3332 /// can be resolved to the best method overload
3334 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3336 protected IList<MemberSpec> Methods;
3337 MethodSpec best_candidate;
3338 TypeSpec best_candidate_return;
3339 protected TypeArguments type_arguments;
3341 SimpleName simple_name;
3342 protected TypeSpec queried_type;
3344 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3348 this.type = InternalType.MethodGroup;
3350 eclass = ExprClass.MethodGroup;
3351 queried_type = type;
3354 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3355 : this (new MemberSpec[] { m }, type, loc)
3361 public MethodSpec BestCandidate {
3363 return best_candidate;
3367 public TypeSpec BestCandidateReturnType {
3369 return best_candidate_return;
3373 public IList<MemberSpec> Candidates {
3379 protected override TypeSpec DeclaringType {
3381 return queried_type;
3385 public override bool IsInstance {
3387 if (best_candidate != null)
3388 return !best_candidate.IsStatic;
3394 public override bool IsStatic {
3396 if (best_candidate != null)
3397 return best_candidate.IsStatic;
3403 public override string KindName {
3404 get { return "method"; }
3407 public override string Name {
3409 if (best_candidate != null)
3410 return best_candidate.Name;
3413 return Methods.First ().Name;
3420 // When best candidate is already know this factory can be used
3421 // to avoid expensive overload resolution to be called
3423 // NOTE: InstanceExpression has to be set manually
3425 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3427 return new MethodGroupExpr (best, queriedType, loc) {
3428 best_candidate = best,
3429 best_candidate_return = best.ReturnType
3433 public override string GetSignatureForError ()
3435 if (best_candidate != null)
3436 return best_candidate.GetSignatureForError ();
3438 return Methods.First ().GetSignatureForError ();
3441 public override Expression CreateExpressionTree (ResolveContext ec)
3443 if (best_candidate == null) {
3444 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3448 if (best_candidate.IsConditionallyExcluded (ec, loc))
3449 ec.Report.Error (765, loc,
3450 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3452 return new TypeOfMethod (best_candidate, loc);
3455 protected override Expression DoResolve (ResolveContext ec)
3457 this.eclass = ExprClass.MethodGroup;
3459 if (InstanceExpression != null) {
3460 InstanceExpression = InstanceExpression.Resolve (ec);
3461 if (InstanceExpression == null)
3468 public override void Emit (EmitContext ec)
3470 throw new NotSupportedException ();
3473 public void EmitCall (EmitContext ec, Arguments arguments)
3475 var call = new CallEmitter ();
3476 call.InstanceExpression = InstanceExpression;
3477 call.Emit (ec, best_candidate, arguments, loc);
3480 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3482 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3483 Name, TypeManager.CSharpName (target));
3486 public static bool IsExtensionMethodArgument (Expression expr)
3489 // LAMESPEC: No details about which expressions are not allowed
3491 return !(expr is TypeExpr) && !(expr is BaseThis);
3495 /// Find the Applicable Function Members (7.4.2.1)
3497 /// me: Method Group expression with the members to select.
3498 /// it might contain constructors or methods (or anything
3499 /// that maps to a method).
3501 /// Arguments: ArrayList containing resolved Argument objects.
3503 /// loc: The location if we want an error to be reported, or a Null
3504 /// location for "probing" purposes.
3506 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3507 /// that is the best match of me on Arguments.
3510 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3512 // TODO: causes issues with probing mode, remove explicit Kind check
3513 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3516 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3517 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3518 r.BaseMembersProvider = this;
3519 r.InstanceQualifier = this;
3522 if (cerrors != null)
3523 r.CustomErrors = cerrors;
3525 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3526 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3527 if (best_candidate == null)
3528 return r.BestCandidateIsDynamic ? this : null;
3530 // Overload resolver had to create a new method group, all checks bellow have already been executed
3531 if (r.BestCandidateNewMethodGroup != null)
3532 return r.BestCandidateNewMethodGroup;
3534 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3535 if (InstanceExpression != null) {
3536 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3537 InstanceExpression = null;
3539 if (best_candidate.IsStatic && simple_name != null) {
3540 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3543 InstanceExpression.Resolve (ec);
3547 ResolveInstanceExpression (ec, null);
3550 var base_override = CandidateToBaseOverride (ec, best_candidate);
3551 if (base_override == best_candidate) {
3552 best_candidate_return = r.BestCandidateReturnType;
3554 best_candidate = base_override;
3555 best_candidate_return = best_candidate.ReturnType;
3558 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3559 ConstraintChecker cc = new ConstraintChecker (ec);
3560 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3564 // Additional check for possible imported base override method which
3565 // could not be done during IsOverrideMethodBaseTypeAccessible
3567 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3568 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3569 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3570 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3576 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3578 var fe = left as FieldExpr;
3581 // Using method-group on struct fields makes the struct assigned. I am not sure
3582 // why but that's what .net does
3584 fe.Spec.MemberDefinition.SetIsAssigned ();
3587 simple_name = original;
3588 return base.ResolveMemberAccess (ec, left, original);
3591 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3593 type_arguments = ta;
3596 #region IBaseMembersProvider Members
3598 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3600 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3603 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3605 if (queried_type == member.DeclaringType)
3608 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3609 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3613 // Extension methods lookup after ordinary methods candidates failed to apply
3615 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3617 if (InstanceExpression == null)
3620 InstanceExpression = InstanceExpression.Resolve (rc);
3621 if (!IsExtensionMethodArgument (InstanceExpression))
3624 int arity = type_arguments == null ? 0 : type_arguments.Count;
3625 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3626 if (methods == null)
3629 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3630 emg.SetTypeArguments (rc, type_arguments);
3637 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3639 public ConstructorInstanceQualifier (TypeSpec type)
3642 InstanceType = type;
3645 public TypeSpec InstanceType { get; private set; }
3647 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3649 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3653 public struct OverloadResolver
3656 public enum Restrictions
3660 ProbingOnly = 1 << 1,
3661 CovariantDelegate = 1 << 2,
3662 NoBaseMembers = 1 << 3,
3663 BaseMembersIncluded = 1 << 4
3666 public interface IBaseMembersProvider
3668 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3669 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3670 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3673 public interface IErrorHandler
3675 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3676 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3677 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3678 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3681 public interface IInstanceQualifier
3683 TypeSpec InstanceType { get; }
3684 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3687 sealed class NoBaseMembers : IBaseMembersProvider
3689 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3691 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3696 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3701 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3707 struct AmbiguousCandidate
3709 public readonly MemberSpec Member;
3710 public readonly bool Expanded;
3711 public readonly AParametersCollection Parameters;
3713 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3716 Parameters = parameters;
3717 Expanded = expanded;
3722 IList<MemberSpec> members;
3723 TypeArguments type_arguments;
3724 IBaseMembersProvider base_provider;
3725 IErrorHandler custom_errors;
3726 IInstanceQualifier instance_qualifier;
3727 Restrictions restrictions;
3728 MethodGroupExpr best_candidate_extension_group;
3729 TypeSpec best_candidate_return_type;
3731 SessionReportPrinter lambda_conv_msgs;
3733 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3734 : this (members, null, restrictions, loc)
3738 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3741 if (members == null || members.Count == 0)
3742 throw new ArgumentException ("empty members set");
3744 this.members = members;
3746 type_arguments = targs;
3747 this.restrictions = restrictions;
3748 if (IsDelegateInvoke)
3749 this.restrictions |= Restrictions.NoBaseMembers;
3751 base_provider = NoBaseMembers.Instance;
3756 public IBaseMembersProvider BaseMembersProvider {
3758 return base_provider;
3761 base_provider = value;
3765 public bool BestCandidateIsDynamic { get; set; }
3768 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3770 public MethodGroupExpr BestCandidateNewMethodGroup {
3772 return best_candidate_extension_group;
3777 // Return type can be different between best candidate and closest override
3779 public TypeSpec BestCandidateReturnType {
3781 return best_candidate_return_type;
3785 public IErrorHandler CustomErrors {
3787 return custom_errors;
3790 custom_errors = value;
3794 TypeSpec DelegateType {
3796 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3797 throw new InternalErrorException ("Not running in delegate mode", loc);
3799 return members [0].DeclaringType;
3803 public IInstanceQualifier InstanceQualifier {
3805 return instance_qualifier;
3808 instance_qualifier = value;
3812 bool IsProbingOnly {
3814 return (restrictions & Restrictions.ProbingOnly) != 0;
3818 bool IsDelegateInvoke {
3820 return (restrictions & Restrictions.DelegateInvoke) != 0;
3827 // 7.4.3.3 Better conversion from expression
3828 // Returns : 1 if a->p is better,
3829 // 2 if a->q is better,
3830 // 0 if neither is better
3832 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3834 TypeSpec argument_type = a.Type;
3837 // If argument is an anonymous function
3839 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3841 // p and q are delegate types or expression tree types
3843 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3844 if (q.MemberDefinition != p.MemberDefinition) {
3849 // Uwrap delegate from Expression<T>
3851 q = TypeManager.GetTypeArguments (q)[0];
3852 p = TypeManager.GetTypeArguments (p)[0];
3855 var p_m = Delegate.GetInvokeMethod (p);
3856 var q_m = Delegate.GetInvokeMethod (q);
3859 // With identical parameter lists
3861 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3870 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3872 if (p.Kind == MemberKind.Void) {
3873 return q.Kind != MemberKind.Void ? 2 : 0;
3877 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3879 if (q.Kind == MemberKind.Void) {
3880 return p.Kind != MemberKind.Void ? 1: 0;
3883 var am = (AnonymousMethodExpression) a.Expr;
3886 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3887 // better conversion is performed between underlying types Y1 and Y2
3889 if (p.IsGenericTask || q.IsGenericTask) {
3890 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3891 q = q.TypeArguments[0];
3892 p = p.TypeArguments[0];
3894 } else if (q != p) {
3896 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3898 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3899 var am_rt = am.InferReturnType (ec, null, orig_q);
3900 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3902 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3903 var am_rt = am.InferReturnType (ec, null, orig_p);
3904 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3910 // The parameters are identicial and return type is not void, use better type conversion
3911 // on return type to determine better one
3914 if (argument_type == p)
3917 if (argument_type == q)
3921 return BetterTypeConversion (ec, p, q);
3925 // 7.4.3.4 Better conversion from type
3927 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3929 if (p == null || q == null)
3930 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3932 switch (p.BuiltinType) {
3933 case BuiltinTypeSpec.Type.Int:
3934 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3937 case BuiltinTypeSpec.Type.Long:
3938 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3941 case BuiltinTypeSpec.Type.SByte:
3942 switch (q.BuiltinType) {
3943 case BuiltinTypeSpec.Type.Byte:
3944 case BuiltinTypeSpec.Type.UShort:
3945 case BuiltinTypeSpec.Type.UInt:
3946 case BuiltinTypeSpec.Type.ULong:
3950 case BuiltinTypeSpec.Type.Short:
3951 switch (q.BuiltinType) {
3952 case BuiltinTypeSpec.Type.UShort:
3953 case BuiltinTypeSpec.Type.UInt:
3954 case BuiltinTypeSpec.Type.ULong:
3958 case BuiltinTypeSpec.Type.Dynamic:
3959 // Dynamic is never better
3963 switch (q.BuiltinType) {
3964 case BuiltinTypeSpec.Type.Int:
3965 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3968 case BuiltinTypeSpec.Type.Long:
3969 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3972 case BuiltinTypeSpec.Type.SByte:
3973 switch (p.BuiltinType) {
3974 case BuiltinTypeSpec.Type.Byte:
3975 case BuiltinTypeSpec.Type.UShort:
3976 case BuiltinTypeSpec.Type.UInt:
3977 case BuiltinTypeSpec.Type.ULong:
3981 case BuiltinTypeSpec.Type.Short:
3982 switch (p.BuiltinType) {
3983 case BuiltinTypeSpec.Type.UShort:
3984 case BuiltinTypeSpec.Type.UInt:
3985 case BuiltinTypeSpec.Type.ULong:
3989 case BuiltinTypeSpec.Type.Dynamic:
3990 // Dynamic is never better
3994 // FIXME: handle lifted operators
3996 // TODO: this is expensive
3997 Expression p_tmp = new EmptyExpression (p);
3998 Expression q_tmp = new EmptyExpression (q);
4000 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4001 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4003 if (p_to_q && !q_to_p)
4006 if (q_to_p && !p_to_q)
4013 /// Determines "Better function" between candidate
4014 /// and the current best match
4017 /// Returns a boolean indicating :
4018 /// false if candidate ain't better
4019 /// true if candidate is better than the current best match
4021 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4022 MemberSpec best, AParametersCollection bparam, bool best_params)
4024 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4025 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4027 bool better_at_least_one = false;
4029 int args_count = args == null ? 0 : args.Count;
4033 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4036 // Default arguments are ignored for better decision
4037 if (a.IsDefaultArgument)
4041 // When comparing named argument the parameter type index has to be looked up
4042 // in original parameter set (override version for virtual members)
4044 NamedArgument na = a as NamedArgument;
4046 int idx = cparam.GetParameterIndexByName (na.Name);
4047 ct = candidate_pd.Types[idx];
4048 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4049 ct = TypeManager.GetElementType (ct);
4051 idx = bparam.GetParameterIndexByName (na.Name);
4052 bt = best_pd.Types[idx];
4053 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4054 bt = TypeManager.GetElementType (bt);
4056 ct = candidate_pd.Types[c_idx];
4057 bt = best_pd.Types[b_idx];
4059 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4060 ct = TypeManager.GetElementType (ct);
4064 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4065 bt = TypeManager.GetElementType (bt);
4070 if (TypeSpecComparer.IsEqual (ct, bt))
4074 int result = BetterExpressionConversion (ec, a, ct, bt);
4076 // for each argument, the conversion to 'ct' should be no worse than
4077 // the conversion to 'bt'.
4081 // for at least one argument, the conversion to 'ct' should be better than
4082 // the conversion to 'bt'.
4084 better_at_least_one = true;
4087 if (better_at_least_one)
4091 // This handles the case
4093 // Add (float f1, float f2, float f3);
4094 // Add (params decimal [] foo);
4096 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4097 // first candidate would've chosen as better.
4099 if (!same && !a.IsDefaultArgument)
4103 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4107 // This handles the following cases:
4109 // Foo (int i) is better than Foo (int i, long l = 0)
4110 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4111 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4113 // Prefer non-optional version
4115 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4117 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4118 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4121 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4124 return candidate_pd.Count >= best_pd.Count;
4128 // One is a non-generic method and second is a generic method, then non-generic is better
4130 if (best.IsGeneric != candidate.IsGeneric)
4131 return best.IsGeneric;
4134 // This handles the following cases:
4136 // Trim () is better than Trim (params char[] chars)
4137 // Concat (string s1, string s2, string s3) is better than
4138 // Concat (string s1, params string [] srest)
4139 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4141 // Prefer non-expanded version
4143 if (candidate_params != best_params)
4146 int candidate_param_count = candidate_pd.Count;
4147 int best_param_count = best_pd.Count;
4149 if (candidate_param_count != best_param_count)
4150 // can only happen if (candidate_params && best_params)
4151 return candidate_param_count > best_param_count && best_pd.HasParams;
4154 // Both methods have the same number of parameters, and the parameters have equal types
4155 // Pick the "more specific" signature using rules over original (non-inflated) types
4157 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4158 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4160 bool specific_at_least_once = false;
4161 for (j = 0; j < args_count; ++j) {
4162 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4164 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4165 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4167 ct = candidate_def_pd.Types[j];
4168 bt = best_def_pd.Types[j];
4173 TypeSpec specific = MoreSpecific (ct, bt);
4177 specific_at_least_once = true;
4180 if (specific_at_least_once)
4186 static bool CheckInflatedArguments (MethodSpec ms)
4188 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4191 // Setup constraint checker for probing only
4192 ConstraintChecker cc = new ConstraintChecker (null);
4194 var mp = ms.Parameters.Types;
4195 for (int i = 0; i < mp.Length; ++i) {
4196 var type = mp[i] as InflatedTypeSpec;
4200 var targs = type.TypeArguments;
4201 if (targs.Length == 0)
4204 // TODO: Checking inflated MVAR arguments should be enough
4205 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4212 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4214 rc.Report.Error (1729, loc,
4215 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4216 type.GetSignatureForError (), argCount.ToString ());
4220 // Determines if the candidate method is applicable to the given set of arguments
4221 // There could be two different set of parameters for same candidate where one
4222 // is the closest override for default values and named arguments checks and second
4223 // one being the virtual base for the parameter types and modifiers.
4225 // A return value rates candidate method compatibility,
4226 // 0 = the best, int.MaxValue = the worst
4229 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)
4231 // Parameters of most-derived type used mainly for named and optional parameters
4232 var pd = pm.Parameters;
4234 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4235 // params modifier instead of most-derived type
4236 var cpd = ((IParametersMember) candidate).Parameters;
4237 int param_count = pd.Count;
4238 int optional_count = 0;
4240 Arguments orig_args = arguments;
4242 if (arg_count != param_count) {
4244 // No arguments expansion when doing exact match for delegates
4246 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4247 for (int i = 0; i < pd.Count; ++i) {
4248 if (pd.FixedParameters[i].HasDefaultValue) {
4249 optional_count = pd.Count - i;
4255 if (optional_count != 0) {
4256 // Readjust expected number when params used
4257 if (cpd.HasParams) {
4259 if (arg_count < param_count)
4261 } else if (arg_count > param_count) {
4262 int args_gap = System.Math.Abs (arg_count - param_count);
4263 return int.MaxValue - 10000 + args_gap;
4264 } else if (arg_count < param_count - optional_count) {
4265 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4266 return int.MaxValue - 10000 + args_gap;
4268 } else if (arg_count != param_count) {
4269 int args_gap = System.Math.Abs (arg_count - param_count);
4271 return int.MaxValue - 10000 + args_gap;
4272 if (arg_count < param_count - 1)
4273 return int.MaxValue - 10000 + args_gap;
4276 // Resize to fit optional arguments
4277 if (optional_count != 0) {
4278 if (arguments == null) {
4279 arguments = new Arguments (optional_count);
4281 // Have to create a new container, so the next run can do same
4282 var resized = new Arguments (param_count);
4283 resized.AddRange (arguments);
4284 arguments = resized;
4287 for (int i = arg_count; i < param_count; ++i)
4288 arguments.Add (null);
4292 if (arg_count > 0) {
4294 // Shuffle named arguments to the right positions if there are any
4296 if (arguments[arg_count - 1] is NamedArgument) {
4297 arg_count = arguments.Count;
4299 for (int i = 0; i < arg_count; ++i) {
4300 bool arg_moved = false;
4302 NamedArgument na = arguments[i] as NamedArgument;
4306 int index = pd.GetParameterIndexByName (na.Name);
4308 // Named parameter not found
4312 // already reordered
4317 if (index >= param_count) {
4318 // When using parameters which should not be available to the user
4319 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4322 arguments.Add (null);
4326 temp = arguments[index];
4328 // The slot has been taken by positional argument
4329 if (temp != null && !(temp is NamedArgument))
4334 arguments = arguments.MarkOrderedArgument (na);
4338 arguments[index] = arguments[i];
4339 arguments[i] = temp;
4346 arg_count = arguments.Count;
4348 } else if (arguments != null) {
4349 arg_count = arguments.Count;
4353 // Don't do any expensive checks when the candidate cannot succeed
4355 if (arg_count != param_count && !cpd.HasParams)
4356 return (param_count - arg_count) * 2 + 1;
4358 var dep = candidate.GetMissingDependencies ();
4360 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4365 // 1. Handle generic method using type arguments when specified or type inference
4368 var ms = candidate as MethodSpec;
4369 if (ms != null && ms.IsGeneric) {
4370 if (type_arguments != null) {
4371 var g_args_count = ms.Arity;
4372 if (g_args_count != type_arguments.Count)
4373 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4375 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4378 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4379 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4380 // candidate was found use the set to report more details about what was wrong with lambda body.
4381 // The general idea is to distinguish between code errors and errors caused by
4382 // trial-and-error type inference
4384 if (lambda_conv_msgs == null) {
4385 for (int i = 0; i < arg_count; i++) {
4386 Argument a = arguments[i];
4390 var am = a.Expr as AnonymousMethodExpression;
4392 if (lambda_conv_msgs == null)
4393 lambda_conv_msgs = new SessionReportPrinter ();
4395 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4400 var ti = new TypeInference (arguments);
4401 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4404 return ti.InferenceScore - 20000;
4407 // Clear any error messages when the result was success
4409 if (lambda_conv_msgs != null)
4410 lambda_conv_msgs.ClearSession ();
4412 if (i_args.Length != 0) {
4413 ms = ms.MakeGenericMethod (ec, i_args);
4418 // Type arguments constraints have to match for the method to be applicable
4420 if (!CheckInflatedArguments (ms)) {
4422 return int.MaxValue - 25000;
4426 // We have a generic return type and at same time the method is override which
4427 // means we have to also inflate override return type in case the candidate is
4428 // best candidate and override return type is different to base return type.
4430 // virtual Foo<T, object> with override Foo<T, dynamic>
4432 if (candidate != pm) {
4433 MethodSpec override_ms = (MethodSpec) pm;
4434 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4435 returnType = inflator.Inflate (returnType);
4437 returnType = ms.ReturnType;
4444 if (type_arguments != null)
4445 return int.MaxValue - 15000;
4451 // 2. Each argument has to be implicitly convertible to method parameter
4453 Parameter.Modifier p_mod = 0;
4456 for (int i = 0; i < arg_count; i++) {
4457 Argument a = arguments[i];
4459 var fp = pd.FixedParameters[i];
4460 if (!fp.HasDefaultValue) {
4461 arguments = orig_args;
4462 return arg_count * 2 + 2;
4466 // Get the default value expression, we can use the same expression
4467 // if the type matches
4469 Expression e = fp.DefaultValue;
4471 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4473 // Restore for possible error reporting
4474 for (int ii = i; ii < arg_count; ++ii)
4475 arguments.RemoveAt (i);
4477 return (arg_count - i) * 2 + 1;
4481 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4483 // LAMESPEC: Attributes can be mixed together with build-in priority
4485 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4486 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4487 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4488 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4489 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4490 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4494 arguments[i] = new Argument (e, Argument.AType.Default);
4498 if (p_mod != Parameter.Modifier.PARAMS) {
4499 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4501 } else if (!params_expanded_form) {
4502 params_expanded_form = true;
4503 pt = ((ElementTypeSpec) pt).Element;
4509 if (!params_expanded_form) {
4510 if (a.ArgType == Argument.AType.ExtensionType) {
4512 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4514 // LAMESPEC: or implicit type parameter conversion
4517 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4518 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4519 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4524 score = IsArgumentCompatible (ec, a, p_mod, pt);
4527 dynamicArgument = true;
4532 // It can be applicable in expanded form (when not doing exact match like for delegates)
4534 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4535 if (!params_expanded_form)
4536 pt = ((ElementTypeSpec) pt).Element;
4539 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4542 params_expanded_form = true;
4543 } else if (score < 0) {
4544 params_expanded_form = true;
4545 dynamicArgument = true;
4550 if (params_expanded_form)
4552 return (arg_count - i) * 2 + score;
4557 // When params parameter has no argument it will be provided later if the method is the best candidate
4559 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4560 params_expanded_form = true;
4563 // Restore original arguments for dynamic binder to keep the intention of original source code
4565 if (dynamicArgument)
4566 arguments = orig_args;
4571 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4573 if (e is Constant && e.Type == ptype)
4577 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4579 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4580 e = new MemberAccess (new MemberAccess (new MemberAccess (
4581 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4582 } else if (e is Constant) {
4584 // Handles int to int? conversions, DefaultParameterValue check
4586 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4590 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4593 return e.Resolve (ec);
4597 // Tests argument compatibility with the parameter
4598 // The possible return values are
4600 // 1 - modifier mismatch
4601 // 2 - type mismatch
4602 // -1 - dynamic binding required
4604 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4607 // Types have to be identical when ref or out modifer
4608 // is used and argument is not of dynamic type
4610 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4611 if (argument.Type != parameter) {
4613 // Do full equality check after quick path
4615 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4617 // Using dynamic for ref/out parameter can still succeed at runtime
4619 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4626 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4628 // Using dynamic for ref/out parameter can still succeed at runtime
4630 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4637 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4641 // Use implicit conversion in all modes to return same candidates when the expression
4642 // is used as argument or delegate conversion
4644 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4652 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4654 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4656 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4659 var ac_p = p as ArrayContainer;
4661 var ac_q = q as ArrayContainer;
4665 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4666 if (specific == ac_p.Element)
4668 if (specific == ac_q.Element)
4670 } else if (p.IsGeneric && q.IsGeneric) {
4671 var pargs = TypeManager.GetTypeArguments (p);
4672 var qargs = TypeManager.GetTypeArguments (q);
4674 bool p_specific_at_least_once = false;
4675 bool q_specific_at_least_once = false;
4677 for (int i = 0; i < pargs.Length; i++) {
4678 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4679 if (specific == pargs[i])
4680 p_specific_at_least_once = true;
4681 if (specific == qargs[i])
4682 q_specific_at_least_once = true;
4685 if (p_specific_at_least_once && !q_specific_at_least_once)
4687 if (!p_specific_at_least_once && q_specific_at_least_once)
4695 // Find the best method from candidate list
4697 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4699 List<AmbiguousCandidate> ambiguous_candidates = null;
4701 MemberSpec best_candidate;
4702 Arguments best_candidate_args = null;
4703 bool best_candidate_params = false;
4704 bool best_candidate_dynamic = false;
4705 int best_candidate_rate;
4706 IParametersMember best_parameter_member = null;
4708 int args_count = args != null ? args.Count : 0;
4710 Arguments candidate_args = args;
4711 bool error_mode = false;
4712 MemberSpec invocable_member = null;
4715 best_candidate = null;
4716 best_candidate_rate = int.MaxValue;
4718 var type_members = members;
4720 for (int i = 0; i < type_members.Count; ++i) {
4721 var member = type_members[i];
4724 // Methods in a base class are not candidates if any method in a derived
4725 // class is applicable
4727 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4731 if (!member.IsAccessible (rc))
4734 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4737 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4738 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4743 IParametersMember pm = member as IParametersMember;
4746 // Will use it later to report ambiguity between best method and invocable member
4748 if (Invocation.IsMemberInvocable (member))
4749 invocable_member = member;
4755 // Overload resolution is looking for base member but using parameter names
4756 // and default values from the closest member. That means to do expensive lookup
4757 // for the closest override for virtual or abstract members
4759 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4760 var override_params = base_provider.GetOverrideMemberParameters (member);
4761 if (override_params != null)
4762 pm = override_params;
4766 // Check if the member candidate is applicable
4768 bool params_expanded_form = false;
4769 bool dynamic_argument = false;
4770 TypeSpec rt = pm.MemberType;
4771 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4773 if (lambda_conv_msgs != null)
4774 lambda_conv_msgs.EndSession ();
4777 // How does it score compare to others
4779 if (candidate_rate < best_candidate_rate) {
4781 // Fatal error (missing dependency), cannot continue
4782 if (candidate_rate < 0)
4785 best_candidate_rate = candidate_rate;
4786 best_candidate = member;
4787 best_candidate_args = candidate_args;
4788 best_candidate_params = params_expanded_form;
4789 best_candidate_dynamic = dynamic_argument;
4790 best_parameter_member = pm;
4791 best_candidate_return_type = rt;
4792 } else if (candidate_rate == 0) {
4794 // The member look is done per type for most operations but sometimes
4795 // it's not possible like for binary operators overload because they
4796 // are unioned between 2 sides
4798 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4799 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4804 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4806 // We pack all interface members into top level type which makes the overload resolution
4807 // more complicated for interfaces. We compensate it by removing methods with same
4808 // signature when building the cache hence this path should not really be hit often
4811 // interface IA { void Foo (int arg); }
4812 // interface IB : IA { void Foo (params int[] args); }
4814 // IB::Foo is the best overload when calling IB.Foo (1)
4817 if (ambiguous_candidates != null) {
4818 foreach (var amb_cand in ambiguous_candidates) {
4819 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4828 ambiguous_candidates = null;
4831 // Is the new candidate better
4832 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4836 best_candidate = member;
4837 best_candidate_args = candidate_args;
4838 best_candidate_params = params_expanded_form;
4839 best_candidate_dynamic = dynamic_argument;
4840 best_parameter_member = pm;
4841 best_candidate_return_type = rt;
4843 // It's not better but any other found later could be but we are not sure yet
4844 if (ambiguous_candidates == null)
4845 ambiguous_candidates = new List<AmbiguousCandidate> ();
4847 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4851 // Restore expanded arguments
4852 if (candidate_args != args)
4853 candidate_args = args;
4855 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4858 // We've found exact match
4860 if (best_candidate_rate == 0)
4864 // Try extension methods lookup when no ordinary method match was found and provider enables it
4867 var emg = base_provider.LookupExtensionMethod (rc);
4869 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4871 best_candidate_extension_group = emg;
4872 return (T) (MemberSpec) emg.BestCandidate;
4877 // Don't run expensive error reporting mode for probing
4884 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4887 lambda_conv_msgs = null;
4892 // No best member match found, report an error
4894 if (best_candidate_rate != 0 || error_mode) {
4895 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4899 if (best_candidate_dynamic) {
4900 if (args[0].ArgType == Argument.AType.ExtensionType) {
4901 rc.Report.Error (1973, loc,
4902 "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",
4903 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4907 // Check type constraints only when explicit type arguments are used
4909 if (best_candidate.IsGeneric && type_arguments != null) {
4910 MethodSpec bc = best_candidate as MethodSpec;
4911 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4912 ConstraintChecker cc = new ConstraintChecker (rc);
4913 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4917 BestCandidateIsDynamic = true;
4922 // These flags indicates we are running delegate probing conversion. No need to
4923 // do more expensive checks
4925 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4926 return (T) best_candidate;
4928 if (ambiguous_candidates != null) {
4930 // Now check that there are no ambiguities i.e the selected method
4931 // should be better than all the others
4933 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4934 var candidate = ambiguous_candidates [ix];
4936 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4937 var ambiguous = candidate.Member;
4938 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4939 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4940 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4941 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4942 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4945 return (T) best_candidate;
4950 if (invocable_member != null && !IsProbingOnly) {
4951 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4952 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4953 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4954 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4958 // And now check if the arguments are all
4959 // compatible, perform conversions if
4960 // necessary etc. and return if everything is
4963 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4966 if (best_candidate == null)
4970 // Don't run possibly expensive checks in probing mode
4972 if (!IsProbingOnly && !rc.IsInProbingMode) {
4974 // Check ObsoleteAttribute on the best method
4976 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4977 if (oa != null && !rc.IsObsolete)
4978 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4980 best_candidate.MemberDefinition.SetIsUsed ();
4983 args = best_candidate_args;
4984 return (T) best_candidate;
4987 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
4989 return ResolveMember<MethodSpec> (rc, ref args);
4992 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
4993 Argument a, AParametersCollection expected_par, TypeSpec paramType)
4995 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
4998 if (a.Type == InternalType.ErrorType)
5001 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5002 ec.Report.SymbolRelatedToPreviousError (method);
5003 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5004 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5005 TypeManager.CSharpSignature (method));
5008 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5009 TypeManager.CSharpSignature (method));
5010 } else if (IsDelegateInvoke) {
5011 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5012 DelegateType.GetSignatureForError ());
5014 ec.Report.SymbolRelatedToPreviousError (method);
5015 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5016 method.GetSignatureForError ());
5019 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5021 string index = (idx + 1).ToString ();
5022 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5023 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5024 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5025 index, Parameter.GetModifierSignature (a.Modifier));
5027 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
5028 index, Parameter.GetModifierSignature (mod));
5030 string p1 = a.GetSignatureForError ();
5031 string p2 = TypeManager.CSharpName (paramType);
5034 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5035 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5038 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5039 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5040 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5043 ec.Report.Error (1503, a.Expr.Location,
5044 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5049 // We have failed to find exact match so we return error info about the closest match
5051 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5053 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5054 int arg_count = args == null ? 0 : args.Count;
5056 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5057 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5058 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5062 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5067 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5068 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5069 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5073 // For candidates which match on parameters count report more details about incorrect arguments
5076 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5077 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5078 // Reject any inaccessible member
5079 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5080 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5081 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5085 var ms = best_candidate as MethodSpec;
5086 if (ms != null && ms.IsGeneric) {
5087 bool constr_ok = true;
5088 if (ms.TypeArguments != null)
5089 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5091 if (ta_count == 0) {
5092 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5096 rc.Report.Error (411, loc,
5097 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5098 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5105 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5111 // We failed to find any method with correct argument count, report best candidate
5113 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5116 if (best_candidate.Kind == MemberKind.Constructor) {
5117 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5118 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5119 } else if (IsDelegateInvoke) {
5120 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5121 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5122 DelegateType.GetSignatureForError (), arg_count.ToString ());
5124 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5125 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5126 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5127 name, arg_count.ToString ());
5131 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5133 var pd = pm.Parameters;
5134 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5136 Parameter.Modifier p_mod = 0;
5138 int a_idx = 0, a_pos = 0;
5140 ArrayInitializer params_initializers = null;
5141 bool has_unsafe_arg = pm.MemberType.IsPointer;
5142 int arg_count = args == null ? 0 : args.Count;
5144 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5146 if (p_mod != Parameter.Modifier.PARAMS) {
5147 p_mod = pd.FixedParameters[a_idx].ModFlags;
5149 has_unsafe_arg |= pt.IsPointer;
5151 if (p_mod == Parameter.Modifier.PARAMS) {
5152 if (chose_params_expanded) {
5153 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5154 pt = TypeManager.GetElementType (pt);
5160 // Types have to be identical when ref or out modifer is used
5162 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5163 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5166 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5172 NamedArgument na = a as NamedArgument;
5174 int name_index = pd.GetParameterIndexByName (na.Name);
5175 if (name_index < 0 || name_index >= pd.Count) {
5176 if (IsDelegateInvoke) {
5177 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5178 ec.Report.Error (1746, na.Location,
5179 "The delegate `{0}' does not contain a parameter named `{1}'",
5180 DelegateType.GetSignatureForError (), na.Name);
5182 ec.Report.SymbolRelatedToPreviousError (member);
5183 ec.Report.Error (1739, na.Location,
5184 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5185 TypeManager.CSharpSignature (member), na.Name);
5187 } else if (args[name_index] != a) {
5188 if (IsDelegateInvoke)
5189 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5191 ec.Report.SymbolRelatedToPreviousError (member);
5193 ec.Report.Error (1744, na.Location,
5194 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5199 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5202 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5203 custom_errors.NoArgumentMatch (ec, member);
5207 Expression conv = null;
5208 if (a.ArgType == Argument.AType.ExtensionType) {
5209 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5212 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5214 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5217 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5224 // Convert params arguments to an array initializer
5226 if (params_initializers != null) {
5227 // we choose to use 'a.Expr' rather than 'conv' so that
5228 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5229 params_initializers.Add (a.Expr);
5230 args.RemoveAt (a_idx--);
5235 // Update the argument with the implicit conversion
5239 if (a_idx != arg_count) {
5240 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5245 // Fill not provided arguments required by params modifier
5247 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5249 args = new Arguments (1);
5251 pt = ptypes[pd.Count - 1];
5252 pt = TypeManager.GetElementType (pt);
5253 has_unsafe_arg |= pt.IsPointer;
5254 params_initializers = new ArrayInitializer (0, loc);
5258 // Append an array argument with all params arguments
5260 if (params_initializers != null) {
5261 args.Add (new Argument (
5262 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5266 if (has_unsafe_arg && !ec.IsUnsafe) {
5267 Expression.UnsafeError (ec, loc);
5271 // We could infer inaccesible type arguments
5273 if (type_arguments == null && member.IsGeneric) {
5274 var ms = (MethodSpec) member;
5275 foreach (var ta in ms.TypeArguments) {
5276 if (!ta.IsAccessible (ec)) {
5277 ec.Report.SymbolRelatedToPreviousError (ta);
5278 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5288 public class ConstantExpr : MemberExpr
5290 readonly ConstSpec constant;
5292 public ConstantExpr (ConstSpec constant, Location loc)
5294 this.constant = constant;
5298 public override string Name {
5299 get { throw new NotImplementedException (); }
5302 public override string KindName {
5303 get { return "constant"; }
5306 public override bool IsInstance {
5307 get { return !IsStatic; }
5310 public override bool IsStatic {
5311 get { return true; }
5314 protected override TypeSpec DeclaringType {
5315 get { return constant.DeclaringType; }
5318 public override Expression CreateExpressionTree (ResolveContext ec)
5320 throw new NotSupportedException ("ET");
5323 protected override Expression DoResolve (ResolveContext rc)
5325 ResolveInstanceExpression (rc, null);
5326 DoBestMemberChecks (rc, constant);
5328 var c = constant.GetConstant (rc);
5330 // Creates reference expression to the constant value
5331 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5334 public override void Emit (EmitContext ec)
5336 throw new NotSupportedException ();
5339 public override string GetSignatureForError ()
5341 return constant.GetSignatureForError ();
5344 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5346 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5351 // Fully resolved expression that references a Field
5353 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5355 protected FieldSpec spec;
5356 VariableInfo variable_info;
5358 LocalTemporary temp;
5361 protected FieldExpr (Location l)
5366 public FieldExpr (FieldSpec spec, Location loc)
5371 type = spec.MemberType;
5374 public FieldExpr (FieldBase fi, Location l)
5381 public override string Name {
5387 public bool IsHoisted {
5389 IVariableReference hv = InstanceExpression as IVariableReference;
5390 return hv != null && hv.IsHoisted;
5394 public override bool IsInstance {
5396 return !spec.IsStatic;
5400 public override bool IsStatic {
5402 return spec.IsStatic;
5406 public override string KindName {
5407 get { return "field"; }
5410 public FieldSpec Spec {
5416 protected override TypeSpec DeclaringType {
5418 return spec.DeclaringType;
5422 public VariableInfo VariableInfo {
5424 return variable_info;
5430 public override string GetSignatureForError ()
5432 return spec.GetSignatureForError ();
5435 public bool IsMarshalByRefAccess (ResolveContext rc)
5437 // Checks possible ldflda of field access expression
5438 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5439 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5440 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5443 public void SetHasAddressTaken ()
5445 IVariableReference vr = InstanceExpression as IVariableReference;
5447 vr.SetHasAddressTaken ();
5451 public override Expression CreateExpressionTree (ResolveContext ec)
5453 return CreateExpressionTree (ec, true);
5456 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5459 Expression instance;
5461 if (InstanceExpression == null) {
5462 instance = new NullLiteral (loc);
5463 } else if (convertInstance) {
5464 instance = InstanceExpression.CreateExpressionTree (ec);
5466 args = new Arguments (1);
5467 args.Add (new Argument (InstanceExpression));
5468 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5471 args = Arguments.CreateForExpressionTree (ec, null,
5473 CreateTypeOfExpression ());
5475 return CreateExpressionFactoryCall (ec, "Field", args);
5478 public Expression CreateTypeOfExpression ()
5480 return new TypeOfField (spec, loc);
5483 protected override Expression DoResolve (ResolveContext ec)
5485 spec.MemberDefinition.SetIsUsed ();
5487 return DoResolve (ec, null);
5490 Expression DoResolve (ResolveContext ec, Expression rhs)
5492 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5495 if (ResolveInstanceExpression (ec, rhs)) {
5496 // Resolve the field's instance expression while flow analysis is turned
5497 // off: when accessing a field "a.b", we must check whether the field
5498 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5500 if (lvalue_instance) {
5501 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5502 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5504 Expression right_side =
5505 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5507 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5510 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5511 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5515 if (InstanceExpression == null)
5519 DoBestMemberChecks (ec, spec);
5522 var fb = spec as FixedFieldSpec;
5523 IVariableReference var = InstanceExpression as IVariableReference;
5525 if (lvalue_instance && var != null && var.VariableInfo != null) {
5526 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5530 IFixedExpression fe = InstanceExpression as IFixedExpression;
5531 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5532 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5535 if (InstanceExpression.eclass != ExprClass.Variable) {
5536 ec.Report.SymbolRelatedToPreviousError (spec);
5537 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5538 TypeManager.GetFullNameSignature (spec));
5539 } else if (var != null && var.IsHoisted) {
5540 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5543 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5547 // Set flow-analysis variable info for struct member access. It will be check later
5548 // for precise error reporting
5550 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5551 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5552 if (rhs != null && variable_info != null)
5553 variable_info.SetStructFieldAssigned (ec, Name);
5556 eclass = ExprClass.Variable;
5560 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5565 var var = fe.InstanceExpression as IVariableReference;
5567 var vi = var.VariableInfo;
5569 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5571 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5573 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5580 fe = fe.InstanceExpression as FieldExpr;
5582 } while (fe != null);
5585 static readonly int [] codes = {
5586 191, // instance, write access
5587 192, // instance, out access
5588 198, // static, write access
5589 199, // static, out access
5590 1648, // member of value instance, write access
5591 1649, // member of value instance, out access
5592 1650, // member of value static, write access
5593 1651 // member of value static, out access
5596 static readonly string [] msgs = {
5597 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5598 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5599 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5600 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5601 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5602 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5603 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5604 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5607 // The return value is always null. Returning a value simplifies calling code.
5608 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5611 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5615 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5617 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5622 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5624 if (spec is FixedFieldSpec) {
5625 // It could be much better error message but we want to be error compatible
5626 Error_ValueAssignment (ec, right_side);
5629 Expression e = DoResolve (ec, right_side);
5634 spec.MemberDefinition.SetIsAssigned ();
5636 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5637 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5638 ec.Report.Warning (420, 1, loc,
5639 "`{0}': A volatile field references will not be treated as volatile",
5640 spec.GetSignatureForError ());
5643 if (spec.IsReadOnly) {
5644 // InitOnly fields can only be assigned in constructors or initializers
5645 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5646 return Report_AssignToReadonly (ec, right_side);
5648 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5650 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5651 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5652 return Report_AssignToReadonly (ec, right_side);
5653 // static InitOnly fields cannot be assigned-to in an instance constructor
5654 if (IsStatic && !ec.IsStatic)
5655 return Report_AssignToReadonly (ec, right_side);
5656 // instance constructors can't modify InitOnly fields of other instances of the same type
5657 if (!IsStatic && !(InstanceExpression is This))
5658 return Report_AssignToReadonly (ec, right_side);
5662 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5663 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5664 ec.Report.Warning (197, 1, loc,
5665 "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",
5666 GetSignatureForError ());
5669 eclass = ExprClass.Variable;
5673 public override int GetHashCode ()
5675 return spec.GetHashCode ();
5678 public bool IsFixed {
5681 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5683 IVariableReference variable = InstanceExpression as IVariableReference;
5684 if (variable != null)
5685 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5687 IFixedExpression fe = InstanceExpression as IFixedExpression;
5688 return fe != null && fe.IsFixed;
5692 public override bool Equals (object obj)
5694 FieldExpr fe = obj as FieldExpr;
5698 if (spec != fe.spec)
5701 if (InstanceExpression == null || fe.InstanceExpression == null)
5704 return InstanceExpression.Equals (fe.InstanceExpression);
5707 public void Emit (EmitContext ec, bool leave_copy)
5709 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5713 ec.Emit (OpCodes.Volatile);
5715 ec.Emit (OpCodes.Ldsfld, spec);
5718 EmitInstance (ec, false);
5720 // Optimization for build-in types
5721 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5722 ec.EmitLoadFromPtr (type);
5724 var ff = spec as FixedFieldSpec;
5726 ec.Emit (OpCodes.Ldflda, spec);
5727 ec.Emit (OpCodes.Ldflda, ff.Element);
5730 ec.Emit (OpCodes.Volatile);
5732 ec.Emit (OpCodes.Ldfld, spec);
5738 ec.Emit (OpCodes.Dup);
5740 temp = new LocalTemporary (this.Type);
5746 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5748 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5749 if (isCompound && !(source is DynamicExpressionStatement)) {
5750 if (has_await_source) {
5752 InstanceExpression = InstanceExpression.EmitToField (ec);
5759 if (has_await_source)
5760 source = source.EmitToField (ec);
5762 EmitInstance (ec, prepared);
5768 ec.Emit (OpCodes.Dup);
5770 temp = new LocalTemporary (this.Type);
5775 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5776 ec.Emit (OpCodes.Volatile);
5778 spec.MemberDefinition.SetIsAssigned ();
5781 ec.Emit (OpCodes.Stsfld, spec);
5783 ec.Emit (OpCodes.Stfld, spec);
5793 // Emits store to field with prepared values on stack
5795 public void EmitAssignFromStack (EmitContext ec)
5798 ec.Emit (OpCodes.Stsfld, spec);
5800 ec.Emit (OpCodes.Stfld, spec);
5804 public override void Emit (EmitContext ec)
5809 public override void EmitSideEffect (EmitContext ec)
5811 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5813 if (is_volatile) // || is_marshal_by_ref ())
5814 base.EmitSideEffect (ec);
5817 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5819 if ((mode & AddressOp.Store) != 0)
5820 spec.MemberDefinition.SetIsAssigned ();
5821 if ((mode & AddressOp.Load) != 0)
5822 spec.MemberDefinition.SetIsUsed ();
5825 // Handle initonly fields specially: make a copy and then
5826 // get the address of the copy.
5829 if (spec.IsReadOnly){
5831 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5843 var temp = ec.GetTemporaryLocal (type);
5844 ec.Emit (OpCodes.Stloc, temp);
5845 ec.Emit (OpCodes.Ldloca, temp);
5846 ec.FreeTemporaryLocal (temp, type);
5852 ec.Emit (OpCodes.Ldsflda, spec);
5855 EmitInstance (ec, false);
5856 ec.Emit (OpCodes.Ldflda, spec);
5860 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5862 return MakeExpression (ctx);
5865 public override SLE.Expression MakeExpression (BuilderContext ctx)
5868 return base.MakeExpression (ctx);
5870 return SLE.Expression.Field (
5871 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5872 spec.GetMetaInfo ());
5876 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5878 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5884 // Expression that evaluates to a Property.
5886 // This is not an LValue because we need to re-write the expression. We
5887 // can not take data from the stack and store it.
5889 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5891 Arguments arguments;
5893 public PropertyExpr (PropertySpec spec, Location l)
5896 best_candidate = spec;
5897 type = spec.MemberType;
5902 protected override Arguments Arguments {
5911 protected override TypeSpec DeclaringType {
5913 return best_candidate.DeclaringType;
5917 public override string Name {
5919 return best_candidate.Name;
5923 public override bool IsInstance {
5929 public override bool IsStatic {
5931 return best_candidate.IsStatic;
5935 public override string KindName {
5936 get { return "property"; }
5939 public PropertySpec PropertyInfo {
5941 return best_candidate;
5947 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5949 return new PropertyExpr (spec, loc) {
5955 public override Expression CreateExpressionTree (ResolveContext ec)
5958 if (IsSingleDimensionalArrayLength ()) {
5959 args = new Arguments (1);
5960 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5961 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5964 args = new Arguments (2);
5965 if (InstanceExpression == null)
5966 args.Add (new Argument (new NullLiteral (loc)));
5968 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5969 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
5970 return CreateExpressionFactoryCall (ec, "Property", args);
5973 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
5975 DoResolveLValue (rc, null);
5976 return new TypeOfMethod (Setter, loc);
5979 public override string GetSignatureForError ()
5981 return best_candidate.GetSignatureForError ();
5984 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5987 return base.MakeExpression (ctx);
5989 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
5993 public override SLE.Expression MakeExpression (BuilderContext ctx)
5996 return base.MakeExpression (ctx);
5998 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6002 void Error_PropertyNotValid (ResolveContext ec)
6004 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6005 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6006 GetSignatureForError ());
6009 bool IsSingleDimensionalArrayLength ()
6011 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6014 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6015 return ac != null && ac.Rank == 1;
6018 public override void Emit (EmitContext ec, bool leave_copy)
6021 // Special case: length of single dimension array property is turned into ldlen
6023 if (IsSingleDimensionalArrayLength ()) {
6024 EmitInstance (ec, false);
6025 ec.Emit (OpCodes.Ldlen);
6026 ec.Emit (OpCodes.Conv_I4);
6030 base.Emit (ec, leave_copy);
6033 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6036 LocalTemporary await_source_arg = null;
6038 if (isCompound && !(source is DynamicExpressionStatement)) {
6039 emitting_compound_assignment = true;
6042 if (has_await_arguments) {
6043 await_source_arg = new LocalTemporary (Type);
6044 await_source_arg.Store (ec);
6046 args = new Arguments (1);
6047 args.Add (new Argument (await_source_arg));
6050 temp = await_source_arg;
6053 has_await_arguments = false;
6058 ec.Emit (OpCodes.Dup);
6059 temp = new LocalTemporary (this.Type);
6064 args = arguments == null ? new Arguments (1) : arguments;
6068 temp = new LocalTemporary (this.Type);
6070 args.Add (new Argument (temp));
6072 args.Add (new Argument (source));
6076 emitting_compound_assignment = false;
6078 var call = new CallEmitter ();
6079 call.InstanceExpression = InstanceExpression;
6081 call.InstanceExpressionOnStack = true;
6083 call.Emit (ec, Setter, args, loc);
6090 if (await_source_arg != null) {
6091 await_source_arg.Release (ec);
6095 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6097 eclass = ExprClass.PropertyAccess;
6099 if (best_candidate.IsNotCSharpCompatible) {
6100 Error_PropertyNotValid (rc);
6103 ResolveInstanceExpression (rc, right_side);
6105 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6106 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6107 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6109 type = p.MemberType;
6113 DoBestMemberChecks (rc, best_candidate);
6115 // Handling of com-imported properties with any number of default property parameters
6116 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6117 var p = best_candidate.Get.Parameters;
6118 arguments = new Arguments (p.Count);
6119 for (int i = 0; i < p.Count; ++i) {
6120 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6122 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6123 var p = best_candidate.Set.Parameters;
6124 arguments = new Arguments (p.Count - 1);
6125 for (int i = 0; i < p.Count - 1; ++i) {
6126 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6133 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6135 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6139 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6141 // getter and setter can be different for base calls
6142 MethodSpec getter, setter;
6143 protected T best_candidate;
6145 protected LocalTemporary temp;
6146 protected bool emitting_compound_assignment;
6147 protected bool has_await_arguments;
6149 protected PropertyOrIndexerExpr (Location l)
6156 protected abstract Arguments Arguments { get; set; }
6158 public MethodSpec Getter {
6167 public MethodSpec Setter {
6178 protected override Expression DoResolve (ResolveContext ec)
6180 if (eclass == ExprClass.Unresolved) {
6181 var expr = OverloadResolve (ec, null);
6186 return expr.Resolve (ec);
6189 if (!ResolveGetter (ec))
6195 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6197 if (right_side == EmptyExpression.OutAccess) {
6198 // TODO: best_candidate can be null at this point
6199 INamedBlockVariable variable = null;
6200 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6201 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6202 best_candidate.Name);
6204 right_side.DoResolveLValue (ec, this);
6209 if (eclass == ExprClass.Unresolved) {
6210 var expr = OverloadResolve (ec, right_side);
6215 return expr.ResolveLValue (ec, right_side);
6218 if (!ResolveSetter (ec))
6225 // Implements the IAssignMethod interface for assignments
6227 public virtual void Emit (EmitContext ec, bool leave_copy)
6229 var call = new CallEmitter ();
6230 call.InstanceExpression = InstanceExpression;
6231 if (has_await_arguments)
6232 call.HasAwaitArguments = true;
6234 call.DuplicateArguments = emitting_compound_assignment;
6236 call.Emit (ec, Getter, Arguments, loc);
6238 if (call.HasAwaitArguments) {
6239 InstanceExpression = call.InstanceExpression;
6240 Arguments = call.EmittedArguments;
6241 has_await_arguments = true;
6245 ec.Emit (OpCodes.Dup);
6246 temp = new LocalTemporary (Type);
6251 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6253 public override void Emit (EmitContext ec)
6258 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6260 has_await_arguments = true;
6265 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6267 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6269 bool ResolveGetter (ResolveContext rc)
6271 if (!best_candidate.HasGet) {
6272 if (InstanceExpression != EmptyExpression.Null) {
6273 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6274 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6275 best_candidate.GetSignatureForError ());
6278 } else if (!best_candidate.Get.IsAccessible (rc)) {
6279 if (best_candidate.HasDifferentAccessibility) {
6280 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6281 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6282 TypeManager.CSharpSignature (best_candidate));
6284 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6285 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6289 if (best_candidate.HasDifferentAccessibility) {
6290 CheckProtectedMemberAccess (rc, best_candidate.Get);
6293 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6297 bool ResolveSetter (ResolveContext rc)
6299 if (!best_candidate.HasSet) {
6300 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6301 GetSignatureForError ());
6305 if (!best_candidate.Set.IsAccessible (rc)) {
6306 if (best_candidate.HasDifferentAccessibility) {
6307 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6308 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6309 GetSignatureForError ());
6311 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6312 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6316 if (best_candidate.HasDifferentAccessibility)
6317 CheckProtectedMemberAccess (rc, best_candidate.Set);
6319 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6325 /// Fully resolved expression that evaluates to an Event
6327 public class EventExpr : MemberExpr, IAssignMethod
6329 readonly EventSpec spec;
6332 public EventExpr (EventSpec spec, Location loc)
6340 protected override TypeSpec DeclaringType {
6342 return spec.DeclaringType;
6346 public override string Name {
6352 public override bool IsInstance {
6354 return !spec.IsStatic;
6358 public override bool IsStatic {
6360 return spec.IsStatic;
6364 public override string KindName {
6365 get { return "event"; }
6368 public MethodSpec Operator {
6376 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6379 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6381 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6382 if (spec.BackingField != null &&
6383 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6385 spec.MemberDefinition.SetIsUsed ();
6387 if (!ec.IsObsolete) {
6388 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6390 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6393 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6394 Error_AssignmentEventOnly (ec);
6396 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6398 InstanceExpression = null;
6400 return ml.ResolveMemberAccess (ec, left, original);
6404 return base.ResolveMemberAccess (ec, left, original);
6407 public override Expression CreateExpressionTree (ResolveContext ec)
6409 throw new NotSupportedException ("ET");
6412 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6414 if (right_side == EmptyExpression.EventAddition) {
6415 op = spec.AccessorAdd;
6416 } else if (right_side == EmptyExpression.EventSubtraction) {
6417 op = spec.AccessorRemove;
6421 Error_AssignmentEventOnly (ec);
6425 op = CandidateToBaseOverride (ec, op);
6429 protected override Expression DoResolve (ResolveContext ec)
6431 eclass = ExprClass.EventAccess;
6432 type = spec.MemberType;
6434 ResolveInstanceExpression (ec, null);
6436 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6437 Error_AssignmentEventOnly (ec);
6440 DoBestMemberChecks (ec, spec);
6444 public override void Emit (EmitContext ec)
6446 throw new NotSupportedException ();
6447 //Error_CannotAssign ();
6450 #region IAssignMethod Members
6452 public void Emit (EmitContext ec, bool leave_copy)
6454 throw new NotImplementedException ();
6457 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6459 if (leave_copy || !isCompound)
6460 throw new NotImplementedException ("EventExpr::EmitAssign");
6462 Arguments args = new Arguments (1);
6463 args.Add (new Argument (source));
6465 var call = new CallEmitter ();
6466 call.InstanceExpression = InstanceExpression;
6467 call.Emit (ec, op, args, loc);
6472 void Error_AssignmentEventOnly (ResolveContext ec)
6474 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6475 ec.Report.Error (79, loc,
6476 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6477 GetSignatureForError ());
6479 ec.Report.Error (70, loc,
6480 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6481 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6485 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6487 name = name.Substring (0, name.LastIndexOf ('.'));
6488 base.Error_CannotCallAbstractBase (rc, name);
6491 public override string GetSignatureForError ()
6493 return TypeManager.CSharpSignature (spec);
6496 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6498 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6502 public class TemporaryVariableReference : VariableReference
6504 public class Declarator : Statement
6506 TemporaryVariableReference variable;
6508 public Declarator (TemporaryVariableReference variable)
6510 this.variable = variable;
6514 protected override void DoEmit (EmitContext ec)
6516 variable.li.CreateBuilder (ec);
6519 public override void Emit (EmitContext ec)
6521 // Don't create sequence point
6525 protected override void CloneTo (CloneContext clonectx, Statement target)
6533 public TemporaryVariableReference (LocalVariable li, Location loc)
6536 this.type = li.Type;
6540 public override bool IsLockedByStatement {
6548 public LocalVariable LocalInfo {
6554 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6556 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6557 return new TemporaryVariableReference (li, loc);
6560 protected override Expression DoResolve (ResolveContext ec)
6562 eclass = ExprClass.Variable;
6565 // Don't capture temporary variables except when using
6566 // state machine redirection and block yields
6568 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6569 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6570 ec.IsVariableCapturingRequired) {
6571 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6572 storey.CaptureLocalVariable (ec, li);
6578 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6580 return Resolve (ec);
6583 public override void Emit (EmitContext ec)
6585 li.CreateBuilder (ec);
6590 public void EmitAssign (EmitContext ec, Expression source)
6592 li.CreateBuilder (ec);
6594 EmitAssign (ec, source, false, false);
6597 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6599 return li.HoistedVariant;
6602 public override bool IsFixed {
6603 get { return true; }
6606 public override bool IsRef {
6607 get { return false; }
6610 public override string Name {
6611 get { throw new NotImplementedException (); }
6614 public override void SetHasAddressTaken ()
6616 throw new NotImplementedException ();
6619 protected override ILocalVariable Variable {
6623 public override VariableInfo VariableInfo {
6624 get { return null; }
6627 public override void VerifyAssigned (ResolveContext rc)
6633 /// Handles `var' contextual keyword; var becomes a keyword only
6634 /// if no type called var exists in a variable scope
6636 class VarExpr : SimpleName
6638 public VarExpr (Location loc)
6643 public bool InferType (ResolveContext ec, Expression right_side)
6646 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6648 type = right_side.Type;
6649 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6650 ec.Report.Error (815, loc,
6651 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6652 type.GetSignatureForError ());
6656 eclass = ExprClass.Variable;
6660 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6662 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6663 base.Error_TypeOrNamespaceNotFound (ec);
6665 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");