2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, TypeManager.CSharpName (type));
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod || type == InternalType.ErrorType)
288 string from_type = type.GetSignatureForError ();
289 string to_type = target.GetSignatureForError ();
290 if (from_type == to_type) {
291 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
292 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
296 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
301 ec.Report.DisableReporting ();
302 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
303 ec.Report.EnableReporting ();
306 ec.Report.Error (266, loc,
307 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
310 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
315 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
317 // Better message for possible generic expressions
318 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
319 var report = context.Module.Compiler.Report;
320 report.SymbolRelatedToPreviousError (member);
321 if (member is TypeSpec)
322 member = ((TypeSpec) member).GetDefinition ();
324 member = ((MethodSpec) member).GetGenericMethodDefinition ();
326 string name = member.Kind == MemberKind.Method ? "method" : "type";
327 if (member.IsGeneric) {
328 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
329 name, member.GetSignatureForError (), member.Arity.ToString ());
331 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
332 name, member.GetSignatureForError ());
335 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
339 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
341 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
345 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
347 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
350 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
352 ec.Report.SymbolRelatedToPreviousError (type);
353 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
354 TypeManager.CSharpName (type), name);
357 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
359 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
360 // Already reported as CS1612
362 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
366 protected void Error_VoidPointerOperation (ResolveContext rc)
368 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
371 public ResolveFlags ExprClassToResolveFlags {
375 case ExprClass.Namespace:
376 return ResolveFlags.Type;
378 case ExprClass.MethodGroup:
379 return ResolveFlags.MethodGroup;
381 case ExprClass.TypeParameter:
382 return ResolveFlags.TypeParameter;
384 case ExprClass.Value:
385 case ExprClass.Variable:
386 case ExprClass.PropertyAccess:
387 case ExprClass.EventAccess:
388 case ExprClass.IndexerAccess:
389 return ResolveFlags.VariableOrValue;
392 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
398 // Implements identical simple name and type-name resolution
400 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
403 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
406 // In a member access of the form E.I, if E is a single identifier, and if the meaning of E as a simple-name is
407 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
409 if (left is MemberExpr || left is VariableReference) {
410 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
411 if (identical_type != null && identical_type.Type == left.Type)
412 return identical_type;
418 public virtual string GetSignatureForError ()
420 return type.GetDefinition ().GetSignatureForError ();
424 /// Resolves an expression and performs semantic analysis on it.
428 /// Currently Resolve wraps DoResolve to perform sanity
429 /// checking and assertion checking on what we expect from Resolve.
431 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
433 if (eclass != ExprClass.Unresolved)
443 if ((flags & e.ExprClassToResolveFlags) == 0) {
444 e.Error_UnexpectedKind (ec, flags, loc);
449 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
452 } catch (Exception ex) {
453 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
456 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
457 return ErrorExpression.Instance; // TODO: Add location
462 /// Resolves an expression and performs semantic analysis on it.
464 public Expression Resolve (ResolveContext rc)
466 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
470 /// Resolves an expression for LValue assignment
474 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
475 /// checking and assertion checking on what we expect from Resolve
477 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
479 int errors = ec.Report.Errors;
480 bool out_access = right_side == EmptyExpression.OutAccess;
482 Expression e = DoResolveLValue (ec, right_side);
484 if (e != null && out_access && !(e is IMemoryLocation)) {
485 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
486 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
488 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
489 // e.GetType () + " " + e.GetSignatureForError ());
494 if (errors == ec.Report.Errors) {
496 ec.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
498 Error_ValueAssignment (ec, right_side);
503 if (e.eclass == ExprClass.Unresolved)
504 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
506 if ((e.type == null) && !(e is GenericTypeExpr))
507 throw new Exception ("Expression " + e + " did not set its type after Resolve");
512 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
514 rc.Module.Compiler.Report.Error (182, loc,
515 "An attribute argument must be a constant expression, typeof expression or array creation expression");
519 /// Emits the code for the expression
523 /// The Emit method is invoked to generate the code
524 /// for the expression.
526 public abstract void Emit (EmitContext ec);
529 // Emit code to branch to @target if this expression is equivalent to @on_true.
530 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
531 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
532 // including the use of conditional branches. Note also that a branch MUST be emitted
533 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
536 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
539 // Emit this expression for its side effects, not for its value.
540 // The default implementation is to emit the value, and then throw it away.
541 // Subclasses can provide more efficient implementations, but those MUST be equivalent
542 public virtual void EmitSideEffect (EmitContext ec)
545 ec.Emit (OpCodes.Pop);
549 // Emits the expression into temporary field variable. The method
550 // should be used for await expressions only
552 public virtual Expression EmitToField (EmitContext ec)
555 // This is the await prepare Emit method. When emitting code like
556 // a + b we emit code like
562 // For await a + await b we have to interfere the flow to keep the
563 // stack clean because await yields from the expression. The emit
566 // a = a.EmitToField () // a is changed to temporary field access
567 // b = b.EmitToField ()
573 // The idea is to emit expression and leave the stack empty with
574 // result value still available.
576 // Expressions should override this default implementation when
577 // optimized version can be provided (e.g. FieldExpr)
580 // We can optimize for side-effect free expressions, they can be
581 // emitted out of order
583 if (IsSideEffectFree)
586 bool needs_temporary = ContainsEmitWithAwait ();
587 if (!needs_temporary)
590 // Emit original code
591 var field = EmitToFieldSource (ec);
594 // Store the result to temporary field when we
595 // cannot load `this' directly
597 field = ec.GetTemporaryField (type);
598 if (needs_temporary) {
600 // Create temporary local (we cannot load `this' before Emit)
602 var temp = ec.GetTemporaryLocal (type);
603 ec.Emit (OpCodes.Stloc, temp);
606 ec.Emit (OpCodes.Ldloc, temp);
607 field.EmitAssignFromStack (ec);
609 ec.FreeTemporaryLocal (temp, type);
611 field.EmitAssignFromStack (ec);
618 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
621 // Default implementation calls Emit method
627 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
629 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
630 bool contains_await = false;
632 for (int i = 1; i < expressions.Count; ++i) {
633 if (expressions[i].ContainsEmitWithAwait ()) {
634 contains_await = true;
639 if (contains_await) {
640 for (int i = 0; i < expressions.Count; ++i) {
641 expressions[i] = expressions[i].EmitToField (ec);
646 for (int i = 0; i < expressions.Count; ++i) {
647 expressions[i].Emit (ec);
652 /// Protected constructor. Only derivate types should
653 /// be able to be created
656 protected Expression ()
661 /// Returns a fully formed expression after a MemberLookup
664 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
666 if (spec is EventSpec)
667 return new EventExpr ((EventSpec) spec, loc);
668 if (spec is ConstSpec)
669 return new ConstantExpr ((ConstSpec) spec, loc);
670 if (spec is FieldSpec)
671 return new FieldExpr ((FieldSpec) spec, loc);
672 if (spec is PropertySpec)
673 return new PropertyExpr ((PropertySpec) spec, loc);
674 if (spec is TypeSpec)
675 return new TypeExpression (((TypeSpec) spec), loc);
680 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
682 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
684 rc.Report.SymbolRelatedToPreviousError (type);
686 // Report meaningful error for struct as they always have default ctor in C# context
687 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
689 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
690 type.GetSignatureForError ());
696 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
697 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
698 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
701 return r.ResolveMember<MethodSpec> (rc, ref args);
705 public enum MemberLookupRestrictions
714 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
715 // `qualifier_type' or null to lookup members in the current class.
717 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
719 var members = MemberCache.FindMembers (queried_type, name, false);
723 MemberSpec non_method = null;
724 MemberSpec ambig_non_method = null;
726 for (int i = 0; i < members.Count; ++i) {
727 var member = members[i];
729 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
730 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
733 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
736 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
740 if (!member.IsAccessible (rc))
744 // With runtime binder we can have a situation where queried type is inaccessible
745 // because it came via dynamic object, the check about inconsisted accessibility
746 // had no effect as the type was unknown during compilation
749 // private class N { }
751 // public dynamic Foo ()
757 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
761 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
762 if (member is MethodSpec)
763 return new MethodGroupExpr (members, queried_type, loc);
765 if (!Invocation.IsMemberInvocable (member))
769 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
771 } else if (!errorMode && !member.IsNotCSharpCompatible) {
773 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
774 // T has both an effective base class other than object and a non-empty effective interface set.
776 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
778 var tps = queried_type as TypeParameterSpec;
779 if (tps != null && tps.HasTypeConstraint) {
780 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
783 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
789 ambig_non_method = member;
793 if (non_method != null) {
794 if (ambig_non_method != null && rc != null) {
795 var report = rc.Module.Compiler.Report;
796 report.SymbolRelatedToPreviousError (non_method);
797 report.SymbolRelatedToPreviousError (ambig_non_method);
798 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
799 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
802 if (non_method is MethodSpec)
803 return new MethodGroupExpr (members, queried_type, loc);
805 return ExprClassFromMemberInfo (non_method, loc);
808 if (members[0].DeclaringType.BaseType == null)
811 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
813 } while (members != null);
818 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
820 throw new NotImplementedException ();
823 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
825 if (t == InternalType.ErrorType)
828 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
829 oper, t.GetSignatureForError ());
832 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
834 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
838 /// Returns an expression that can be used to invoke operator true
839 /// on the expression if it exists.
841 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
843 return GetOperatorTrueOrFalse (ec, e, true, loc);
847 /// Returns an expression that can be used to invoke operator false
848 /// on the expression if it exists.
850 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
852 return GetOperatorTrueOrFalse (ec, e, false, loc);
855 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
857 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
858 var methods = MemberCache.GetUserOperator (e.type, op, false);
862 Arguments arguments = new Arguments (1);
863 arguments.Add (new Argument (e));
865 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
866 var oper = res.ResolveOperator (ec, ref arguments);
871 return new UserOperatorCall (oper, arguments, null, loc);
874 public virtual string ExprClassName
878 case ExprClass.Unresolved:
880 case ExprClass.Value:
882 case ExprClass.Variable:
884 case ExprClass.Namespace:
888 case ExprClass.MethodGroup:
889 return "method group";
890 case ExprClass.PropertyAccess:
891 return "property access";
892 case ExprClass.EventAccess:
893 return "event access";
894 case ExprClass.IndexerAccess:
895 return "indexer access";
896 case ExprClass.Nothing:
898 case ExprClass.TypeParameter:
899 return "type parameter";
901 throw new Exception ("Should not happen");
906 /// Reports that we were expecting `expr' to be of class `expected'
908 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
910 var name = memberExpr.GetSignatureForError ();
912 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
915 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
917 string [] valid = new string [4];
920 if ((flags & ResolveFlags.VariableOrValue) != 0) {
921 valid [count++] = "variable";
922 valid [count++] = "value";
925 if ((flags & ResolveFlags.Type) != 0)
926 valid [count++] = "type";
928 if ((flags & ResolveFlags.MethodGroup) != 0)
929 valid [count++] = "method group";
932 valid [count++] = "unknown";
934 StringBuilder sb = new StringBuilder (valid [0]);
935 for (int i = 1; i < count - 1; i++) {
937 sb.Append (valid [i]);
940 sb.Append ("' or `");
941 sb.Append (valid [count - 1]);
944 ec.Report.Error (119, loc,
945 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
948 public static void UnsafeError (ResolveContext ec, Location loc)
950 UnsafeError (ec.Report, loc);
953 public static void UnsafeError (Report Report, Location loc)
955 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
959 // Converts `source' to an int, uint, long or ulong.
961 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
963 var btypes = ec.BuiltinTypes;
965 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
966 Arguments args = new Arguments (1);
967 args.Add (new Argument (source));
968 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
971 Expression converted;
973 using (ec.Set (ResolveContext.Options.CheckedScope)) {
974 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
975 if (converted == null)
976 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
977 if (converted == null)
978 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
979 if (converted == null)
980 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
982 if (converted == null) {
983 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
989 // Only positive constants are allowed at compile time
991 Constant c = converted as Constant;
992 if (c != null && c.IsNegative)
993 Error_NegativeArrayIndex (ec, source.loc);
995 // No conversion needed to array index
996 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
999 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1003 // Derived classes implement this method by cloning the fields that
1004 // could become altered during the Resolve stage
1006 // Only expressions that are created for the parser need to implement
1009 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1011 throw new NotImplementedException (
1013 "CloneTo not implemented for expression {0}", this.GetType ()));
1017 // Clones an expression created by the parser.
1019 // We only support expressions created by the parser so far, not
1020 // expressions that have been resolved (many more classes would need
1021 // to implement CloneTo).
1023 // This infrastructure is here merely for Lambda expressions which
1024 // compile the same code using different type values for the same
1025 // arguments to find the correct overload
1027 public virtual Expression Clone (CloneContext clonectx)
1029 Expression cloned = (Expression) MemberwiseClone ();
1030 CloneTo (clonectx, cloned);
1036 // Implementation of expression to expression tree conversion
1038 public abstract Expression CreateExpressionTree (ResolveContext ec);
1040 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1042 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1045 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1047 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1050 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1052 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1055 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1057 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1061 return new TypeExpression (t, loc);
1065 // Implemented by all expressions which support conversion from
1066 // compiler expression to invokable runtime expression. Used by
1067 // dynamic C# binder.
1069 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1071 throw new NotImplementedException ("MakeExpression for " + GetType ());
1074 public virtual object Accept (StructuralVisitor visitor)
1076 return visitor.Visit (this);
1081 /// This is just a base class for expressions that can
1082 /// appear on statements (invocations, object creation,
1083 /// assignments, post/pre increment and decrement). The idea
1084 /// being that they would support an extra Emition interface that
1085 /// does not leave a result on the stack.
1087 public abstract class ExpressionStatement : Expression
1089 public ExpressionStatement ResolveStatement (BlockContext ec)
1091 Expression e = Resolve (ec);
1095 ExpressionStatement es = e as ExpressionStatement;
1097 Error_InvalidExpressionStatement (ec);
1100 // This is quite expensive warning, try to limit the damage
1102 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1103 WarningAsyncWithoutWait (ec, e);
1109 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1111 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1112 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1117 // Need to do full resolve because GetAwaiter can be extension method
1118 // available only in this context
1120 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1124 var arguments = new Arguments (0);
1125 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1130 // Use same check rules as for real await
1132 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1133 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1136 bc.Report.Warning (4014, 1, e.Location,
1137 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1141 var inv = e as Invocation;
1142 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1143 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1144 bc.Report.Warning (4014, 1, e.Location,
1145 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1151 /// Requests the expression to be emitted in a `statement'
1152 /// context. This means that no new value is left on the
1153 /// stack after invoking this method (constrasted with
1154 /// Emit that will always leave a value on the stack).
1156 public abstract void EmitStatement (EmitContext ec);
1158 public override void EmitSideEffect (EmitContext ec)
1165 /// This kind of cast is used to encapsulate the child
1166 /// whose type is child.Type into an expression that is
1167 /// reported to return "return_type". This is used to encapsulate
1168 /// expressions which have compatible types, but need to be dealt
1169 /// at higher levels with.
1171 /// For example, a "byte" expression could be encapsulated in one
1172 /// of these as an "unsigned int". The type for the expression
1173 /// would be "unsigned int".
1176 public abstract class TypeCast : Expression
1178 protected readonly Expression child;
1180 protected TypeCast (Expression child, TypeSpec return_type)
1182 eclass = child.eclass;
1183 loc = child.Location;
1188 public Expression Child {
1194 public override bool ContainsEmitWithAwait ()
1196 return child.ContainsEmitWithAwait ();
1199 public override Expression CreateExpressionTree (ResolveContext ec)
1201 Arguments args = new Arguments (2);
1202 args.Add (new Argument (child.CreateExpressionTree (ec)));
1203 args.Add (new Argument (new TypeOf (type, loc)));
1205 if (type.IsPointer || child.Type.IsPointer)
1206 Error_PointerInsideExpressionTree (ec);
1208 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1211 protected override Expression DoResolve (ResolveContext ec)
1213 // This should never be invoked, we are born in fully
1214 // initialized state.
1219 public override void Emit (EmitContext ec)
1224 public override SLE.Expression MakeExpression (BuilderContext ctx)
1227 return base.MakeExpression (ctx);
1229 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1230 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1231 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1235 protected override void CloneTo (CloneContext clonectx, Expression t)
1240 public override bool IsNull {
1241 get { return child.IsNull; }
1245 public class EmptyCast : TypeCast {
1246 EmptyCast (Expression child, TypeSpec target_type)
1247 : base (child, target_type)
1251 public static Expression Create (Expression child, TypeSpec type)
1253 Constant c = child as Constant;
1255 return new EmptyConstantCast (c, type);
1257 EmptyCast e = child as EmptyCast;
1259 return new EmptyCast (e.child, type);
1261 return new EmptyCast (child, type);
1264 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1266 child.EmitBranchable (ec, label, on_true);
1269 public override void EmitSideEffect (EmitContext ec)
1271 child.EmitSideEffect (ec);
1276 // Used for predefined type user operator (no obsolete check, etc.)
1278 public class OperatorCast : TypeCast
1280 readonly MethodSpec conversion_operator;
1282 public OperatorCast (Expression expr, TypeSpec target_type)
1283 : this (expr, target_type, target_type, false)
1287 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1288 : this (expr, target_type, target_type, find_explicit)
1292 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1293 : base (expr, returnType)
1295 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1296 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1299 foreach (MethodSpec oper in mi) {
1300 if (oper.ReturnType != returnType)
1303 if (oper.Parameters.Types[0] == expr.Type) {
1304 conversion_operator = oper;
1310 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1311 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1314 public override void Emit (EmitContext ec)
1317 ec.Emit (OpCodes.Call, conversion_operator);
1322 // Constant specialization of EmptyCast.
1323 // We need to special case this since an empty cast of
1324 // a constant is still a constant.
1326 public class EmptyConstantCast : Constant
1328 public readonly Constant child;
1330 public EmptyConstantCast (Constant child, TypeSpec type)
1331 : base (child.Location)
1334 throw new ArgumentNullException ("child");
1337 this.eclass = child.eclass;
1341 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1343 if (child.Type == target_type)
1346 // FIXME: check that 'type' can be converted to 'target_type' first
1347 return child.ConvertExplicitly (in_checked_context, target_type);
1350 public override Expression CreateExpressionTree (ResolveContext ec)
1352 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1353 child.CreateExpressionTree (ec),
1354 new TypeOf (type, loc));
1357 Error_PointerInsideExpressionTree (ec);
1359 return CreateExpressionFactoryCall (ec, "Convert", args);
1362 public override bool IsDefaultValue {
1363 get { return child.IsDefaultValue; }
1366 public override bool IsNegative {
1367 get { return child.IsNegative; }
1370 public override bool IsNull {
1371 get { return child.IsNull; }
1374 public override bool IsOneInteger {
1375 get { return child.IsOneInteger; }
1378 public override bool IsSideEffectFree {
1380 return child.IsSideEffectFree;
1384 public override bool IsZeroInteger {
1385 get { return child.IsZeroInteger; }
1388 public override void Emit (EmitContext ec)
1393 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1395 child.EmitBranchable (ec, label, on_true);
1397 // Only to make verifier happy
1398 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1399 ec.Emit (OpCodes.Unbox_Any, type);
1402 public override void EmitSideEffect (EmitContext ec)
1404 child.EmitSideEffect (ec);
1407 public override object GetValue ()
1409 return child.GetValue ();
1412 public override string GetValueAsLiteral ()
1414 return child.GetValueAsLiteral ();
1417 public override long GetValueAsLong ()
1419 return child.GetValueAsLong ();
1422 public override Constant ConvertImplicitly (TypeSpec target_type)
1424 if (type == target_type)
1427 // FIXME: Do we need to check user conversions?
1428 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1431 return child.ConvertImplicitly (target_type);
1436 /// This class is used to wrap literals which belong inside Enums
1438 public class EnumConstant : Constant
1440 public Constant Child;
1442 public EnumConstant (Constant child, TypeSpec enum_type)
1443 : base (child.Location)
1447 this.eclass = ExprClass.Value;
1448 this.type = enum_type;
1451 protected EnumConstant (Location loc)
1456 public override void Emit (EmitContext ec)
1461 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1463 Child.EncodeAttributeValue (rc, enc, Child.Type);
1466 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1468 Child.EmitBranchable (ec, label, on_true);
1471 public override void EmitSideEffect (EmitContext ec)
1473 Child.EmitSideEffect (ec);
1476 public override string GetSignatureForError()
1478 return TypeManager.CSharpName (Type);
1481 public override object GetValue ()
1483 return Child.GetValue ();
1487 public override object GetTypedValue ()
1490 // The method can be used in dynamic context only (on closed types)
1492 // System.Enum.ToObject cannot be called on dynamic types
1493 // EnumBuilder has to be used, but we cannot use EnumBuilder
1494 // because it does not properly support generics
1496 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1500 public override string GetValueAsLiteral ()
1502 return Child.GetValueAsLiteral ();
1505 public override long GetValueAsLong ()
1507 return Child.GetValueAsLong ();
1510 public EnumConstant Increment()
1512 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1515 public override bool IsDefaultValue {
1517 return Child.IsDefaultValue;
1521 public override bool IsSideEffectFree {
1523 return Child.IsSideEffectFree;
1527 public override bool IsZeroInteger {
1528 get { return Child.IsZeroInteger; }
1531 public override bool IsNegative {
1533 return Child.IsNegative;
1537 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1539 if (Child.Type == target_type)
1542 return Child.ConvertExplicitly (in_checked_context, target_type);
1545 public override Constant ConvertImplicitly (TypeSpec type)
1547 if (this.type == type) {
1551 if (!Convert.ImplicitStandardConversionExists (this, type)){
1555 return Child.ConvertImplicitly (type);
1560 /// This kind of cast is used to encapsulate Value Types in objects.
1562 /// The effect of it is to box the value type emitted by the previous
1565 public class BoxedCast : TypeCast {
1567 public BoxedCast (Expression expr, TypeSpec target_type)
1568 : base (expr, target_type)
1570 eclass = ExprClass.Value;
1573 protected override Expression DoResolve (ResolveContext ec)
1575 // This should never be invoked, we are born in fully
1576 // initialized state.
1581 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1583 // Only boxing to object type is supported
1584 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1585 base.EncodeAttributeValue (rc, enc, targetType);
1589 enc.Encode (child.Type);
1590 child.EncodeAttributeValue (rc, enc, child.Type);
1593 public override void Emit (EmitContext ec)
1597 ec.Emit (OpCodes.Box, child.Type);
1600 public override void EmitSideEffect (EmitContext ec)
1602 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1603 // so, we need to emit the box+pop instructions in most cases
1604 if (child.Type.IsStruct &&
1605 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1606 child.EmitSideEffect (ec);
1608 base.EmitSideEffect (ec);
1612 public class UnboxCast : TypeCast {
1613 public UnboxCast (Expression expr, TypeSpec return_type)
1614 : base (expr, return_type)
1618 protected override Expression DoResolve (ResolveContext ec)
1620 // This should never be invoked, we are born in fully
1621 // initialized state.
1626 public override void Emit (EmitContext ec)
1630 ec.Emit (OpCodes.Unbox_Any, type);
1635 /// This is used to perform explicit numeric conversions.
1637 /// Explicit numeric conversions might trigger exceptions in a checked
1638 /// context, so they should generate the conv.ovf opcodes instead of
1641 public class ConvCast : TypeCast {
1642 public enum Mode : byte {
1643 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1645 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1646 U2_I1, U2_U1, U2_I2, U2_CH,
1647 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1648 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1649 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1650 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1651 CH_I1, CH_U1, CH_I2,
1652 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1653 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1659 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1660 : base (child, return_type)
1665 protected override Expression DoResolve (ResolveContext ec)
1667 // This should never be invoked, we are born in fully
1668 // initialized state.
1673 public override string ToString ()
1675 return String.Format ("ConvCast ({0}, {1})", mode, child);
1678 public override void Emit (EmitContext ec)
1682 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1684 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1685 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1686 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1687 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1688 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1690 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1691 case Mode.U1_CH: /* nothing */ break;
1693 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1694 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1695 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1696 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1697 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1698 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1700 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1701 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1702 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1703 case Mode.U2_CH: /* nothing */ break;
1705 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1706 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1707 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1708 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1709 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1710 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1711 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1713 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1714 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1715 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1716 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1717 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1718 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1720 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1721 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1722 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1723 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1724 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1725 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1726 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1727 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1728 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1730 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1731 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1732 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1733 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1734 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1735 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1736 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1737 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1738 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1740 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1741 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1742 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1744 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1745 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1746 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1747 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1748 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1749 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1750 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1751 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1752 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1754 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1755 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1756 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1757 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1758 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1759 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1760 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1761 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1762 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1763 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1765 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1769 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1770 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1771 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1772 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1773 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1775 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1776 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1778 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1779 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1780 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1781 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1782 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1783 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1785 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1786 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1787 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1788 case Mode.U2_CH: /* nothing */ break;
1790 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1791 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1792 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1793 case Mode.I4_U4: /* nothing */ break;
1794 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1795 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1796 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1798 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1799 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1800 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1801 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1802 case Mode.U4_I4: /* nothing */ break;
1803 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1805 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1806 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1807 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1808 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1809 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1810 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1811 case Mode.I8_U8: /* nothing */ break;
1812 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1813 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1815 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1816 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1817 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1818 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1819 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1820 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1821 case Mode.U8_I8: /* nothing */ break;
1822 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1823 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1825 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1826 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1827 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1829 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1830 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1831 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1832 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1833 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1834 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1835 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1836 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1837 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1839 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1840 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1841 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1842 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1843 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1844 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1845 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1846 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1847 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1848 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1850 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1856 class OpcodeCast : TypeCast
1860 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1861 : base (child, return_type)
1866 protected override Expression DoResolve (ResolveContext ec)
1868 // This should never be invoked, we are born in fully
1869 // initialized state.
1874 public override void Emit (EmitContext ec)
1880 public TypeSpec UnderlyingType {
1881 get { return child.Type; }
1886 // Opcode casts expression with 2 opcodes but only
1887 // single expression tree node
1889 class OpcodeCastDuplex : OpcodeCast
1891 readonly OpCode second;
1893 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1894 : base (child, returnType, first)
1896 this.second = second;
1899 public override void Emit (EmitContext ec)
1907 /// This kind of cast is used to encapsulate a child and cast it
1908 /// to the class requested
1910 public sealed class ClassCast : TypeCast {
1911 readonly bool forced;
1913 public ClassCast (Expression child, TypeSpec return_type)
1914 : base (child, return_type)
1918 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1919 : base (child, return_type)
1921 this.forced = forced;
1924 public override void Emit (EmitContext ec)
1928 bool gen = TypeManager.IsGenericParameter (child.Type);
1930 ec.Emit (OpCodes.Box, child.Type);
1932 if (type.IsGenericParameter) {
1933 ec.Emit (OpCodes.Unbox_Any, type);
1940 ec.Emit (OpCodes.Castclass, type);
1945 // Created during resolving pahse when an expression is wrapped or constantified
1946 // and original expression can be used later (e.g. for expression trees)
1948 public class ReducedExpression : Expression
1950 sealed class ReducedConstantExpression : EmptyConstantCast
1952 readonly Expression orig_expr;
1954 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1955 : base (expr, expr.Type)
1957 this.orig_expr = orig_expr;
1960 public override Constant ConvertImplicitly (TypeSpec target_type)
1962 Constant c = base.ConvertImplicitly (target_type);
1964 c = new ReducedConstantExpression (c, orig_expr);
1969 public override Expression CreateExpressionTree (ResolveContext ec)
1971 return orig_expr.CreateExpressionTree (ec);
1974 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1976 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1978 c = new ReducedConstantExpression (c, orig_expr);
1982 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1985 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1987 if (orig_expr is Conditional)
1988 child.EncodeAttributeValue (rc, enc, targetType);
1990 base.EncodeAttributeValue (rc, enc, targetType);
1994 sealed class ReducedExpressionStatement : ExpressionStatement
1996 readonly Expression orig_expr;
1997 readonly ExpressionStatement stm;
1999 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2001 this.orig_expr = orig;
2003 this.eclass = stm.eclass;
2004 this.type = stm.Type;
2006 this.loc = orig.Location;
2009 public override bool ContainsEmitWithAwait ()
2011 return stm.ContainsEmitWithAwait ();
2014 public override Expression CreateExpressionTree (ResolveContext ec)
2016 return orig_expr.CreateExpressionTree (ec);
2019 protected override Expression DoResolve (ResolveContext ec)
2024 public override void Emit (EmitContext ec)
2029 public override void EmitStatement (EmitContext ec)
2031 stm.EmitStatement (ec);
2035 readonly Expression expr, orig_expr;
2037 private ReducedExpression (Expression expr, Expression orig_expr)
2040 this.eclass = expr.eclass;
2041 this.type = expr.Type;
2042 this.orig_expr = orig_expr;
2043 this.loc = orig_expr.Location;
2048 public override bool IsSideEffectFree {
2050 return expr.IsSideEffectFree;
2054 public Expression OriginalExpression {
2062 public override bool ContainsEmitWithAwait ()
2064 return expr.ContainsEmitWithAwait ();
2068 // Creates fully resolved expression switcher
2070 public static Constant Create (Constant expr, Expression original_expr)
2072 if (expr.eclass == ExprClass.Unresolved)
2073 throw new ArgumentException ("Unresolved expression");
2075 return new ReducedConstantExpression (expr, original_expr);
2078 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2080 return new ReducedExpressionStatement (s, orig);
2083 public static Expression Create (Expression expr, Expression original_expr)
2085 return Create (expr, original_expr, true);
2089 // Creates unresolved reduce expression. The original expression has to be
2090 // already resolved. Created expression is constant based based on `expr'
2091 // value unless canBeConstant is used
2093 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2095 if (canBeConstant) {
2096 Constant c = expr as Constant;
2098 return Create (c, original_expr);
2101 ExpressionStatement s = expr as ExpressionStatement;
2103 return Create (s, original_expr);
2105 if (expr.eclass == ExprClass.Unresolved)
2106 throw new ArgumentException ("Unresolved expression");
2108 return new ReducedExpression (expr, original_expr);
2111 public override Expression CreateExpressionTree (ResolveContext ec)
2113 return orig_expr.CreateExpressionTree (ec);
2116 protected override Expression DoResolve (ResolveContext ec)
2121 public override void Emit (EmitContext ec)
2126 public override Expression EmitToField (EmitContext ec)
2128 return expr.EmitToField(ec);
2131 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2133 expr.EmitBranchable (ec, target, on_true);
2136 public override SLE.Expression MakeExpression (BuilderContext ctx)
2138 return orig_expr.MakeExpression (ctx);
2143 // Standard composite pattern
2145 public abstract class CompositeExpression : Expression
2147 protected Expression expr;
2149 protected CompositeExpression (Expression expr)
2152 this.loc = expr.Location;
2155 public override bool ContainsEmitWithAwait ()
2157 return expr.ContainsEmitWithAwait ();
2160 public override Expression CreateExpressionTree (ResolveContext rc)
2162 return expr.CreateExpressionTree (rc);
2165 public Expression Child {
2166 get { return expr; }
2169 protected override Expression DoResolve (ResolveContext rc)
2171 expr = expr.Resolve (rc);
2174 eclass = expr.eclass;
2180 public override void Emit (EmitContext ec)
2185 public override bool IsNull {
2186 get { return expr.IsNull; }
2191 // Base of expressions used only to narrow resolve flow
2193 public abstract class ShimExpression : Expression
2195 protected Expression expr;
2197 protected ShimExpression (Expression expr)
2202 public Expression Expr {
2208 protected override void CloneTo (CloneContext clonectx, Expression t)
2213 ShimExpression target = (ShimExpression) t;
2214 target.expr = expr.Clone (clonectx);
2217 public override bool ContainsEmitWithAwait ()
2219 return expr.ContainsEmitWithAwait ();
2222 public override Expression CreateExpressionTree (ResolveContext ec)
2224 throw new NotSupportedException ("ET");
2227 public override void Emit (EmitContext ec)
2229 throw new InternalErrorException ("Missing Resolve call");
2235 // Unresolved type name expressions
2237 public abstract class ATypeNameExpression : FullNamedExpression
2240 protected TypeArguments targs;
2242 protected ATypeNameExpression (string name, Location l)
2248 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2255 protected ATypeNameExpression (string name, int arity, Location l)
2256 : this (name, new UnboundTypeArguments (arity), l)
2262 protected int Arity {
2264 return targs == null ? 0 : targs.Count;
2268 public bool HasTypeArguments {
2270 return targs != null && !targs.IsEmpty;
2274 public string Name {
2283 public TypeArguments TypeArguments {
2291 public override bool Equals (object obj)
2293 ATypeNameExpression atne = obj as ATypeNameExpression;
2294 return atne != null && atne.Name == Name &&
2295 (targs == null || targs.Equals (atne.targs));
2298 public override int GetHashCode ()
2300 return Name.GetHashCode ();
2303 // TODO: Move it to MemberCore
2304 public static string GetMemberType (MemberCore mc)
2310 if (mc is FieldBase)
2312 if (mc is MethodCore)
2314 if (mc is EnumMember)
2322 public override string GetSignatureForError ()
2324 if (targs != null) {
2325 return Name + "<" + targs.GetSignatureForError () + ">";
2331 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2335 /// SimpleName expressions are formed of a single word and only happen at the beginning
2336 /// of a dotted-name.
2338 public class SimpleName : ATypeNameExpression
2340 public SimpleName (string name, Location l)
2345 public SimpleName (string name, TypeArguments args, Location l)
2346 : base (name, args, l)
2350 public SimpleName (string name, int arity, Location l)
2351 : base (name, arity, l)
2355 public SimpleName GetMethodGroup ()
2357 return new SimpleName (Name, targs, loc);
2360 protected override Expression DoResolve (ResolveContext rc)
2362 var e = SimpleNameResolve (rc, null, false);
2364 var fe = e as FieldExpr;
2366 fe.VerifyAssignedStructField (rc, null);
2372 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2374 return SimpleNameResolve (ec, right_side, false);
2377 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2379 if (ctx.CurrentType != null) {
2380 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2381 if (member != null) {
2382 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2387 var report = ctx.Module.Compiler.Report;
2389 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2390 if (retval != null) {
2391 report.SymbolRelatedToPreviousError (retval.Type);
2392 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2396 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2397 if (retval != null) {
2398 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2402 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2403 if (ns_candidates != null) {
2404 if (ctx is UsingAliasNamespace.AliasContext) {
2405 report.Error (246, loc,
2406 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2407 ns_candidates[0], Name);
2409 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2410 report.Error (246, loc,
2411 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2415 report.Error (246, loc,
2416 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2421 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2423 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2426 if (fne.Type != null && Arity > 0) {
2427 if (HasTypeArguments) {
2428 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2429 if (ct.ResolveAsType (ec) == null)
2435 return new GenericOpenTypeExpr (fne.Type, loc);
2439 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2441 if (!(fne is Namespace))
2445 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2446 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2447 ec.Module.Compiler.Report.Error (1980, Location,
2448 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2449 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2452 fne = new DynamicTypeExpr (loc);
2453 fne.ResolveAsType (ec);
2459 Error_TypeOrNamespaceNotFound (ec);
2463 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2465 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2468 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2470 int lookup_arity = Arity;
2471 bool errorMode = false;
2473 Block current_block = rc.CurrentBlock;
2474 INamedBlockVariable variable = null;
2475 bool variable_found = false;
2479 // Stage 1: binding to local variables or parameters
2481 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2483 if (current_block != null && lookup_arity == 0) {
2484 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2485 if (!variable.IsDeclared) {
2486 // We found local name in accessible block but it's not
2487 // initialized yet, maybe the user wanted to bind to something else
2489 variable_found = true;
2491 e = variable.CreateReferenceExpression (rc, loc);
2494 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2503 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2505 TypeSpec member_type = rc.CurrentType;
2506 for (; member_type != null; member_type = member_type.DeclaringType) {
2507 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2511 var me = e as MemberExpr;
2513 // The name matches a type, defer to ResolveAsTypeStep
2521 if (variable != null) {
2522 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2523 rc.Report.Error (844, loc,
2524 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2525 Name, me.GetSignatureForError ());
2529 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2530 // Leave it to overload resolution to report correct error
2532 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2533 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2536 // LAMESPEC: again, ignores InvocableOnly
2537 if (variable != null) {
2538 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2539 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2543 // MemberLookup does not check accessors availability, this is actually needed for properties only
2545 var pe = me as PropertyExpr;
2548 // Break as there is no other overload available anyway
2549 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2550 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2553 pe.Getter = pe.PropertyInfo.Get;
2555 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2558 pe.Setter = pe.PropertyInfo.Set;
2563 // TODO: It's used by EventExpr -> FieldExpr transformation only
2564 // TODO: Should go to MemberAccess
2565 me = me.ResolveMemberAccess (rc, null, null);
2569 me.SetTypeArguments (rc, targs);
2576 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2578 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2579 if (IsPossibleTypeOrNamespace (rc)) {
2580 if (variable != null) {
2581 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2582 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2585 return ResolveAsTypeOrNamespace (rc);
2590 if (variable_found) {
2591 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2594 var tparams = rc.CurrentTypeParameters;
2595 if (tparams != null) {
2596 if (tparams.Find (Name) != null) {
2597 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2602 var ct = rc.CurrentType;
2604 if (ct.MemberDefinition.TypeParametersCount > 0) {
2605 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2606 if (ctp.Name == Name) {
2607 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2613 ct = ct.DeclaringType;
2614 } while (ct != null);
2617 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2618 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2620 rc.Report.SymbolRelatedToPreviousError (e.Type);
2621 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2625 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2627 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2628 return ErrorExpression.Instance;
2632 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2634 if (e.Type.Arity != Arity) {
2635 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2639 if (e is TypeExpr) {
2640 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2645 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2648 return ErrorExpression.Instance;
2651 if (rc.Module.Evaluator != null) {
2652 var fi = rc.Module.Evaluator.LookupField (Name);
2654 return new FieldExpr (fi.Item1, loc);
2662 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2664 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2669 if (right_side != null) {
2670 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2671 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2675 e = e.ResolveLValue (ec, right_side);
2683 public override object Accept (StructuralVisitor visitor)
2685 return visitor.Visit (this);
2690 /// Represents a namespace or a type. The name of the class was inspired by
2691 /// section 10.8.1 (Fully Qualified Names).
2693 public abstract class FullNamedExpression : Expression
2695 protected override void CloneTo (CloneContext clonectx, Expression target)
2697 // Do nothing, most unresolved type expressions cannot be
2698 // resolved to different type
2701 public override bool ContainsEmitWithAwait ()
2706 public override Expression CreateExpressionTree (ResolveContext ec)
2708 throw new NotSupportedException ("ET");
2711 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2714 // This is used to resolve the expression as a type, a null
2715 // value will be returned if the expression is not a type
2718 public override TypeSpec ResolveAsType (IMemberContext mc)
2720 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2725 TypeExpr te = fne as TypeExpr;
2727 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2735 var dep = type.GetMissingDependencies ();
2737 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2740 if (type.Kind == MemberKind.Void) {
2741 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2745 // Obsolete checks cannot be done when resolving base context as they
2746 // require type dependencies to be set but we are in process of resolving them
2748 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2749 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2750 if (obsolete_attr != null && !mc.IsObsolete) {
2751 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2759 public override void Emit (EmitContext ec)
2761 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2762 GetSignatureForError ());
2767 /// Expression that evaluates to a type
2769 public abstract class TypeExpr : FullNamedExpression
2771 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2777 protected sealed override Expression DoResolve (ResolveContext ec)
2783 public override bool Equals (object obj)
2785 TypeExpr tobj = obj as TypeExpr;
2789 return Type == tobj.Type;
2792 public override int GetHashCode ()
2794 return Type.GetHashCode ();
2799 /// Fully resolved Expression that already evaluated to a type
2801 public class TypeExpression : TypeExpr
2803 public TypeExpression (TypeSpec t, Location l)
2806 eclass = ExprClass.Type;
2810 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2817 /// This class denotes an expression which evaluates to a member
2818 /// of a struct or a class.
2820 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2823 // An instance expression associated with this member, if it's a
2824 // non-static member
2826 public Expression InstanceExpression;
2829 /// The name of this member.
2831 public abstract string Name {
2836 // When base.member is used
2838 public bool IsBase {
2839 get { return InstanceExpression is BaseThis; }
2843 /// Whether this is an instance member.
2845 public abstract bool IsInstance {
2850 /// Whether this is a static member.
2852 public abstract bool IsStatic {
2856 public abstract string KindName {
2860 protected abstract TypeSpec DeclaringType {
2864 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2866 return InstanceExpression.Type;
2871 // Converts best base candidate for virtual method starting from QueriedBaseType
2873 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2876 // Only when base.member is used and method is virtual
2882 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2883 // means for base.member access we have to find the closest match after we found best candidate
2885 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2887 // The method could already be what we are looking for
2889 TypeSpec[] targs = null;
2890 if (method.DeclaringType != InstanceExpression.Type) {
2891 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2892 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2893 if (base_override.IsGeneric)
2894 targs = method.TypeArguments;
2896 method = base_override;
2901 // When base access is used inside anonymous method/iterator/etc we need to
2902 // get back to the context of original type. We do it by emiting proxy
2903 // method in original class and rewriting base call to this compiler
2904 // generated method call which does the actual base invocation. This may
2905 // introduce redundant storey but with `this' only but it's tricky to avoid
2906 // at this stage as we don't know what expressions follow base
2908 if (rc.CurrentAnonymousMethod != null) {
2909 if (targs == null && method.IsGeneric) {
2910 targs = method.TypeArguments;
2911 method = method.GetGenericMethodDefinition ();
2914 if (method.Parameters.HasArglist)
2915 throw new NotImplementedException ("__arglist base call proxy");
2917 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2919 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2920 // get/set member expressions second call would fail to proxy because left expression
2921 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2922 // FIXME: The async check is another hack but will probably fail with mutators
2923 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2924 InstanceExpression = new This (loc).Resolve (rc);
2928 method = method.MakeGenericMethod (rc, targs);
2932 // Only base will allow this invocation to happen.
2934 if (method.IsAbstract) {
2935 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2941 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2943 if (InstanceExpression == null)
2946 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2947 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2948 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2953 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2955 if (InstanceExpression == null)
2958 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2961 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2963 var ct = rc.CurrentType;
2964 if (ct == qualifier)
2967 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2970 qualifier = qualifier.GetDefinition ();
2971 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2978 public override bool ContainsEmitWithAwait ()
2980 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2983 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2986 type = type.GetDefinition ();
2988 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2991 type = type.DeclaringType;
2992 } while (type != null);
2997 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
2999 if (InstanceExpression != null) {
3000 InstanceExpression = InstanceExpression.Resolve (rc);
3001 CheckProtectedMemberAccess (rc, member);
3004 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3005 UnsafeError (rc, loc);
3008 var dep = member.GetMissingDependencies ();
3010 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3013 if (!rc.IsObsolete) {
3014 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3016 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3019 if (!(member is FieldSpec))
3020 member.MemberDefinition.SetIsUsed ();
3023 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3025 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3028 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3030 rc.Report.SymbolRelatedToPreviousError (member);
3031 rc.Report.Error (1540, loc,
3032 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3033 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3036 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3038 if (!ResolveInstanceExpressionCore (rc, rhs))
3042 // Check intermediate value modification which won't have any effect
3044 if (rhs != null && InstanceExpression.Type.IsStruct &&
3045 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3047 if (rc.CurrentInitializerVariable != null) {
3048 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3049 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3051 rc.Report.Error (1612, loc,
3052 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3053 InstanceExpression.GetSignatureForError ());
3060 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3063 if (InstanceExpression != null) {
3064 if (InstanceExpression is TypeExpr) {
3065 var t = InstanceExpression.Type;
3067 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3068 if (oa != null && !rc.IsObsolete) {
3069 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3072 t = t.DeclaringType;
3073 } while (t != null);
3075 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3076 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3077 rc.Report.Error (176, loc,
3078 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3079 GetSignatureForError ());
3083 InstanceExpression = null;
3089 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3090 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3091 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3092 rc.Report.Error (236, loc,
3093 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3094 GetSignatureForError ());
3096 rc.Report.Error (120, loc,
3097 "An object reference is required to access non-static member `{0}'",
3098 GetSignatureForError ());
3100 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3104 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3105 rc.Report.Error (38, loc,
3106 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3107 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3110 InstanceExpression = new This (loc);
3111 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3112 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3113 InstanceExpression = InstanceExpression.Resolve (rc);
3116 InstanceExpression = InstanceExpression.Resolve (rc);
3122 var me = InstanceExpression as MemberExpr;
3124 me.ResolveInstanceExpressionCore (rc, rhs);
3126 // Using this check to detect probing instance expression resolve
3127 if (!rc.OmitStructFlowAnalysis) {
3128 var fe = me as FieldExpr;
3129 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3130 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3131 rc.Report.Warning (1690, 1, loc,
3132 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3133 me.GetSignatureForError ());
3141 // Run member-access postponed check once we know that
3142 // the expression is not field expression which is the only
3143 // expression which can use uninitialized this
3145 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3146 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3150 // Additional checks for l-value member access
3153 if (InstanceExpression is UnboxCast) {
3154 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3161 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3163 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3164 ec.Report.Warning (1720, 1, left.Location,
3165 "Expression will always cause a `{0}'", "System.NullReferenceException");
3168 InstanceExpression = left;
3172 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3174 TypeSpec instance_type = InstanceExpression.Type;
3175 if (TypeSpec.IsValueType (instance_type)) {
3176 if (InstanceExpression is IMemoryLocation) {
3177 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3179 // Cannot release the temporary variable when its address
3180 // is required to be on stack for any parent
3181 LocalTemporary t = new LocalTemporary (instance_type);
3182 InstanceExpression.Emit (ec);
3184 t.AddressOf (ec, AddressOp.Store);
3187 InstanceExpression.Emit (ec);
3189 // Only to make verifier happy
3190 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3191 ec.Emit (OpCodes.Box, instance_type);
3194 if (prepare_for_load)
3195 ec.Emit (OpCodes.Dup);
3198 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3201 public class ExtensionMethodCandidates
3203 readonly NamespaceContainer container;
3204 readonly IList<MethodSpec> methods;
3206 readonly IMemberContext context;
3208 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3210 this.context = context;
3211 this.methods = methods;
3212 this.container = nsContainer;
3213 this.index = lookupIndex;
3216 public NamespaceContainer Container {
3222 public IMemberContext Context {
3228 public int LookupIndex {
3234 public IList<MethodSpec> Methods {
3242 // Represents a group of extension method candidates for whole namespace
3244 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3246 ExtensionMethodCandidates candidates;
3247 public readonly Expression ExtensionExpression;
3249 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3250 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3252 this.candidates = candidates;
3253 this.ExtensionExpression = extensionExpr;
3256 public override bool IsStatic {
3257 get { return true; }
3261 // For extension methodgroup we are not looking for base members but parent
3262 // namespace extension methods
3264 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3266 // TODO: candidates are null only when doing error reporting, that's
3267 // incorrect. We have to discover same extension methods in error mode
3268 if (candidates == null)
3271 int arity = type_arguments == null ? 0 : type_arguments.Count;
3273 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3274 if (candidates == null)
3277 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3280 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3282 // We are already here
3286 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3288 if (arguments == null)
3289 arguments = new Arguments (1);
3291 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3292 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3294 // Store resolved argument and restore original arguments
3296 // Clean-up modified arguments for error reporting
3297 arguments.RemoveAt (0);
3301 var me = ExtensionExpression as MemberExpr;
3303 me.ResolveInstanceExpression (ec, null);
3304 var fe = me as FieldExpr;
3306 fe.Spec.MemberDefinition.SetIsUsed ();
3309 InstanceExpression = null;
3313 #region IErrorHandler Members
3315 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3320 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3322 rc.Report.SymbolRelatedToPreviousError (best);
3323 rc.Report.Error (1928, loc,
3324 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3325 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3328 rc.Report.Error (1929, loc,
3329 "Extension method instance type `{0}' cannot be converted to `{1}'",
3330 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3336 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3341 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3350 /// MethodGroupExpr represents a group of method candidates which
3351 /// can be resolved to the best method overload
3353 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3355 protected IList<MemberSpec> Methods;
3356 MethodSpec best_candidate;
3357 TypeSpec best_candidate_return;
3358 protected TypeArguments type_arguments;
3360 SimpleName simple_name;
3361 protected TypeSpec queried_type;
3363 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3367 this.type = InternalType.MethodGroup;
3369 eclass = ExprClass.MethodGroup;
3370 queried_type = type;
3373 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3374 : this (new MemberSpec[] { m }, type, loc)
3380 public MethodSpec BestCandidate {
3382 return best_candidate;
3386 public TypeSpec BestCandidateReturnType {
3388 return best_candidate_return;
3392 public IList<MemberSpec> Candidates {
3398 protected override TypeSpec DeclaringType {
3400 return queried_type;
3404 public override bool IsInstance {
3406 if (best_candidate != null)
3407 return !best_candidate.IsStatic;
3413 public override bool IsStatic {
3415 if (best_candidate != null)
3416 return best_candidate.IsStatic;
3422 public override string KindName {
3423 get { return "method"; }
3426 public override string Name {
3428 if (best_candidate != null)
3429 return best_candidate.Name;
3432 return Methods.First ().Name;
3439 // When best candidate is already know this factory can be used
3440 // to avoid expensive overload resolution to be called
3442 // NOTE: InstanceExpression has to be set manually
3444 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3446 return new MethodGroupExpr (best, queriedType, loc) {
3447 best_candidate = best,
3448 best_candidate_return = best.ReturnType
3452 public override string GetSignatureForError ()
3454 if (best_candidate != null)
3455 return best_candidate.GetSignatureForError ();
3457 return Methods.First ().GetSignatureForError ();
3460 public override Expression CreateExpressionTree (ResolveContext ec)
3462 if (best_candidate == null) {
3463 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3467 if (best_candidate.IsConditionallyExcluded (ec, loc))
3468 ec.Report.Error (765, loc,
3469 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3471 return new TypeOfMethod (best_candidate, loc);
3474 protected override Expression DoResolve (ResolveContext ec)
3476 this.eclass = ExprClass.MethodGroup;
3478 if (InstanceExpression != null) {
3479 InstanceExpression = InstanceExpression.Resolve (ec);
3480 if (InstanceExpression == null)
3487 public override void Emit (EmitContext ec)
3489 throw new NotSupportedException ();
3492 public void EmitCall (EmitContext ec, Arguments arguments)
3494 var call = new CallEmitter ();
3495 call.InstanceExpression = InstanceExpression;
3496 call.Emit (ec, best_candidate, arguments, loc);
3499 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3501 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3502 Name, TypeManager.CSharpName (target));
3505 public static bool IsExtensionMethodArgument (Expression expr)
3508 // LAMESPEC: No details about which expressions are not allowed
3510 return !(expr is TypeExpr) && !(expr is BaseThis);
3514 /// Find the Applicable Function Members (7.4.2.1)
3516 /// me: Method Group expression with the members to select.
3517 /// it might contain constructors or methods (or anything
3518 /// that maps to a method).
3520 /// Arguments: ArrayList containing resolved Argument objects.
3522 /// loc: The location if we want an error to be reported, or a Null
3523 /// location for "probing" purposes.
3525 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3526 /// that is the best match of me on Arguments.
3529 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3531 // TODO: causes issues with probing mode, remove explicit Kind check
3532 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3535 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3536 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3537 r.BaseMembersProvider = this;
3538 r.InstanceQualifier = this;
3541 if (cerrors != null)
3542 r.CustomErrors = cerrors;
3544 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3545 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3546 if (best_candidate == null)
3547 return r.BestCandidateIsDynamic ? this : null;
3549 // Overload resolver had to create a new method group, all checks bellow have already been executed
3550 if (r.BestCandidateNewMethodGroup != null)
3551 return r.BestCandidateNewMethodGroup;
3553 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3554 if (InstanceExpression != null) {
3555 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3556 InstanceExpression = null;
3558 if (best_candidate.IsStatic && simple_name != null) {
3559 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3562 InstanceExpression.Resolve (ec);
3566 ResolveInstanceExpression (ec, null);
3569 var base_override = CandidateToBaseOverride (ec, best_candidate);
3570 if (base_override == best_candidate) {
3571 best_candidate_return = r.BestCandidateReturnType;
3573 best_candidate = base_override;
3574 best_candidate_return = best_candidate.ReturnType;
3577 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3578 ConstraintChecker cc = new ConstraintChecker (ec);
3579 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3583 // Additional check for possible imported base override method which
3584 // could not be done during IsOverrideMethodBaseTypeAccessible
3586 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3587 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3588 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3589 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3595 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3597 var fe = left as FieldExpr;
3600 // Using method-group on struct fields makes the struct assigned. I am not sure
3601 // why but that's what .net does
3603 fe.Spec.MemberDefinition.SetIsAssigned ();
3606 simple_name = original;
3607 return base.ResolveMemberAccess (ec, left, original);
3610 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3612 type_arguments = ta;
3615 #region IBaseMembersProvider Members
3617 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3619 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3622 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3624 if (queried_type == member.DeclaringType)
3627 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3628 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3632 // Extension methods lookup after ordinary methods candidates failed to apply
3634 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3636 if (InstanceExpression == null)
3639 InstanceExpression = InstanceExpression.Resolve (rc);
3640 if (!IsExtensionMethodArgument (InstanceExpression))
3643 int arity = type_arguments == null ? 0 : type_arguments.Count;
3644 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3645 if (methods == null)
3648 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3649 emg.SetTypeArguments (rc, type_arguments);
3656 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3658 public ConstructorInstanceQualifier (TypeSpec type)
3661 InstanceType = type;
3664 public TypeSpec InstanceType { get; private set; }
3666 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3668 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3672 public struct OverloadResolver
3675 public enum Restrictions
3679 ProbingOnly = 1 << 1,
3680 CovariantDelegate = 1 << 2,
3681 NoBaseMembers = 1 << 3,
3682 BaseMembersIncluded = 1 << 4
3685 public interface IBaseMembersProvider
3687 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3688 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3689 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3692 public interface IErrorHandler
3694 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3695 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3696 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3697 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3700 public interface IInstanceQualifier
3702 TypeSpec InstanceType { get; }
3703 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3706 sealed class NoBaseMembers : IBaseMembersProvider
3708 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3710 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3715 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3720 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3726 struct AmbiguousCandidate
3728 public readonly MemberSpec Member;
3729 public readonly bool Expanded;
3730 public readonly AParametersCollection Parameters;
3732 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3735 Parameters = parameters;
3736 Expanded = expanded;
3741 IList<MemberSpec> members;
3742 TypeArguments type_arguments;
3743 IBaseMembersProvider base_provider;
3744 IErrorHandler custom_errors;
3745 IInstanceQualifier instance_qualifier;
3746 Restrictions restrictions;
3747 MethodGroupExpr best_candidate_extension_group;
3748 TypeSpec best_candidate_return_type;
3750 SessionReportPrinter lambda_conv_msgs;
3752 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3753 : this (members, null, restrictions, loc)
3757 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3760 if (members == null || members.Count == 0)
3761 throw new ArgumentException ("empty members set");
3763 this.members = members;
3765 type_arguments = targs;
3766 this.restrictions = restrictions;
3767 if (IsDelegateInvoke)
3768 this.restrictions |= Restrictions.NoBaseMembers;
3770 base_provider = NoBaseMembers.Instance;
3775 public IBaseMembersProvider BaseMembersProvider {
3777 return base_provider;
3780 base_provider = value;
3784 public bool BestCandidateIsDynamic { get; set; }
3787 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3789 public MethodGroupExpr BestCandidateNewMethodGroup {
3791 return best_candidate_extension_group;
3796 // Return type can be different between best candidate and closest override
3798 public TypeSpec BestCandidateReturnType {
3800 return best_candidate_return_type;
3804 public IErrorHandler CustomErrors {
3806 return custom_errors;
3809 custom_errors = value;
3813 TypeSpec DelegateType {
3815 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3816 throw new InternalErrorException ("Not running in delegate mode", loc);
3818 return members [0].DeclaringType;
3822 public IInstanceQualifier InstanceQualifier {
3824 return instance_qualifier;
3827 instance_qualifier = value;
3831 bool IsProbingOnly {
3833 return (restrictions & Restrictions.ProbingOnly) != 0;
3837 bool IsDelegateInvoke {
3839 return (restrictions & Restrictions.DelegateInvoke) != 0;
3846 // 7.4.3.3 Better conversion from expression
3847 // Returns : 1 if a->p is better,
3848 // 2 if a->q is better,
3849 // 0 if neither is better
3851 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3853 TypeSpec argument_type = a.Type;
3856 // If argument is an anonymous function
3858 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3860 // p and q are delegate types or expression tree types
3862 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3863 if (q.MemberDefinition != p.MemberDefinition) {
3868 // Uwrap delegate from Expression<T>
3870 q = TypeManager.GetTypeArguments (q)[0];
3871 p = TypeManager.GetTypeArguments (p)[0];
3874 var p_m = Delegate.GetInvokeMethod (p);
3875 var q_m = Delegate.GetInvokeMethod (q);
3878 // With identical parameter lists
3880 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3889 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3891 if (p.Kind == MemberKind.Void) {
3892 return q.Kind != MemberKind.Void ? 2 : 0;
3896 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3898 if (q.Kind == MemberKind.Void) {
3899 return p.Kind != MemberKind.Void ? 1: 0;
3902 var am = (AnonymousMethodExpression) a.Expr;
3905 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3906 // better conversion is performed between underlying types Y1 and Y2
3908 if (p.IsGenericTask || q.IsGenericTask) {
3909 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3910 q = q.TypeArguments[0];
3911 p = p.TypeArguments[0];
3913 } else if (q != p) {
3915 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3917 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3918 var am_rt = am.InferReturnType (ec, null, orig_q);
3919 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3921 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3922 var am_rt = am.InferReturnType (ec, null, orig_p);
3923 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3929 // The parameters are identicial and return type is not void, use better type conversion
3930 // on return type to determine better one
3933 if (argument_type == p)
3936 if (argument_type == q)
3940 return BetterTypeConversion (ec, p, q);
3944 // 7.4.3.4 Better conversion from type
3946 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3948 if (p == null || q == null)
3949 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3951 switch (p.BuiltinType) {
3952 case BuiltinTypeSpec.Type.Int:
3953 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3956 case BuiltinTypeSpec.Type.Long:
3957 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3960 case BuiltinTypeSpec.Type.SByte:
3961 switch (q.BuiltinType) {
3962 case BuiltinTypeSpec.Type.Byte:
3963 case BuiltinTypeSpec.Type.UShort:
3964 case BuiltinTypeSpec.Type.UInt:
3965 case BuiltinTypeSpec.Type.ULong:
3969 case BuiltinTypeSpec.Type.Short:
3970 switch (q.BuiltinType) {
3971 case BuiltinTypeSpec.Type.UShort:
3972 case BuiltinTypeSpec.Type.UInt:
3973 case BuiltinTypeSpec.Type.ULong:
3977 case BuiltinTypeSpec.Type.Dynamic:
3978 // Dynamic is never better
3982 switch (q.BuiltinType) {
3983 case BuiltinTypeSpec.Type.Int:
3984 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3987 case BuiltinTypeSpec.Type.Long:
3988 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3991 case BuiltinTypeSpec.Type.SByte:
3992 switch (p.BuiltinType) {
3993 case BuiltinTypeSpec.Type.Byte:
3994 case BuiltinTypeSpec.Type.UShort:
3995 case BuiltinTypeSpec.Type.UInt:
3996 case BuiltinTypeSpec.Type.ULong:
4000 case BuiltinTypeSpec.Type.Short:
4001 switch (p.BuiltinType) {
4002 case BuiltinTypeSpec.Type.UShort:
4003 case BuiltinTypeSpec.Type.UInt:
4004 case BuiltinTypeSpec.Type.ULong:
4008 case BuiltinTypeSpec.Type.Dynamic:
4009 // Dynamic is never better
4013 // FIXME: handle lifted operators
4015 // TODO: this is expensive
4016 Expression p_tmp = new EmptyExpression (p);
4017 Expression q_tmp = new EmptyExpression (q);
4019 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4020 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4022 if (p_to_q && !q_to_p)
4025 if (q_to_p && !p_to_q)
4032 /// Determines "Better function" between candidate
4033 /// and the current best match
4036 /// Returns a boolean indicating :
4037 /// false if candidate ain't better
4038 /// true if candidate is better than the current best match
4040 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4041 MemberSpec best, AParametersCollection bparam, bool best_params)
4043 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4044 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4046 bool better_at_least_one = false;
4048 int args_count = args == null ? 0 : args.Count;
4052 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4055 // Default arguments are ignored for better decision
4056 if (a.IsDefaultArgument)
4060 // When comparing named argument the parameter type index has to be looked up
4061 // in original parameter set (override version for virtual members)
4063 NamedArgument na = a as NamedArgument;
4065 int idx = cparam.GetParameterIndexByName (na.Name);
4066 ct = candidate_pd.Types[idx];
4067 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4068 ct = TypeManager.GetElementType (ct);
4070 idx = bparam.GetParameterIndexByName (na.Name);
4071 bt = best_pd.Types[idx];
4072 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4073 bt = TypeManager.GetElementType (bt);
4075 ct = candidate_pd.Types[c_idx];
4076 bt = best_pd.Types[b_idx];
4078 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4079 ct = TypeManager.GetElementType (ct);
4083 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4084 bt = TypeManager.GetElementType (bt);
4089 if (TypeSpecComparer.IsEqual (ct, bt))
4093 int result = BetterExpressionConversion (ec, a, ct, bt);
4095 // for each argument, the conversion to 'ct' should be no worse than
4096 // the conversion to 'bt'.
4100 // for at least one argument, the conversion to 'ct' should be better than
4101 // the conversion to 'bt'.
4103 better_at_least_one = true;
4106 if (better_at_least_one)
4110 // This handles the case
4112 // Add (float f1, float f2, float f3);
4113 // Add (params decimal [] foo);
4115 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4116 // first candidate would've chosen as better.
4118 if (!same && !a.IsDefaultArgument)
4122 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4126 // This handles the following cases:
4128 // Foo (int i) is better than Foo (int i, long l = 0)
4129 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4130 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4132 // Prefer non-optional version
4134 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4136 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4137 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4140 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4143 return candidate_pd.Count >= best_pd.Count;
4147 // One is a non-generic method and second is a generic method, then non-generic is better
4149 if (best.IsGeneric != candidate.IsGeneric)
4150 return best.IsGeneric;
4153 // This handles the following cases:
4155 // Trim () is better than Trim (params char[] chars)
4156 // Concat (string s1, string s2, string s3) is better than
4157 // Concat (string s1, params string [] srest)
4158 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4160 // Prefer non-expanded version
4162 if (candidate_params != best_params)
4165 int candidate_param_count = candidate_pd.Count;
4166 int best_param_count = best_pd.Count;
4168 if (candidate_param_count != best_param_count)
4169 // can only happen if (candidate_params && best_params)
4170 return candidate_param_count > best_param_count && best_pd.HasParams;
4173 // Both methods have the same number of parameters, and the parameters have equal types
4174 // Pick the "more specific" signature using rules over original (non-inflated) types
4176 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4177 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4179 bool specific_at_least_once = false;
4180 for (j = 0; j < args_count; ++j) {
4181 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4183 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4184 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4186 ct = candidate_def_pd.Types[j];
4187 bt = best_def_pd.Types[j];
4192 TypeSpec specific = MoreSpecific (ct, bt);
4196 specific_at_least_once = true;
4199 if (specific_at_least_once)
4205 static bool CheckInflatedArguments (MethodSpec ms)
4207 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4210 // Setup constraint checker for probing only
4211 ConstraintChecker cc = new ConstraintChecker (null);
4213 var mp = ms.Parameters.Types;
4214 for (int i = 0; i < mp.Length; ++i) {
4215 var type = mp[i] as InflatedTypeSpec;
4219 var targs = type.TypeArguments;
4220 if (targs.Length == 0)
4223 // TODO: Checking inflated MVAR arguments should be enough
4224 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4231 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4233 rc.Report.Error (1729, loc,
4234 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4235 type.GetSignatureForError (), argCount.ToString ());
4239 // Determines if the candidate method is applicable to the given set of arguments
4240 // There could be two different set of parameters for same candidate where one
4241 // is the closest override for default values and named arguments checks and second
4242 // one being the virtual base for the parameter types and modifiers.
4244 // A return value rates candidate method compatibility,
4245 // 0 = the best, int.MaxValue = the worst
4248 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)
4250 // Parameters of most-derived type used mainly for named and optional parameters
4251 var pd = pm.Parameters;
4253 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4254 // params modifier instead of most-derived type
4255 var cpd = ((IParametersMember) candidate).Parameters;
4256 int param_count = pd.Count;
4257 int optional_count = 0;
4259 Arguments orig_args = arguments;
4261 if (arg_count != param_count) {
4263 // No arguments expansion when doing exact match for delegates
4265 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4266 for (int i = 0; i < pd.Count; ++i) {
4267 if (pd.FixedParameters[i].HasDefaultValue) {
4268 optional_count = pd.Count - i;
4274 if (optional_count != 0) {
4275 // Readjust expected number when params used
4276 if (cpd.HasParams) {
4278 if (arg_count < param_count)
4280 } else if (arg_count > param_count) {
4281 int args_gap = System.Math.Abs (arg_count - param_count);
4282 return int.MaxValue - 10000 + args_gap;
4283 } else if (arg_count < param_count - optional_count) {
4284 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4285 return int.MaxValue - 10000 + args_gap;
4287 } else if (arg_count != param_count) {
4288 int args_gap = System.Math.Abs (arg_count - param_count);
4290 return int.MaxValue - 10000 + args_gap;
4291 if (arg_count < param_count - 1)
4292 return int.MaxValue - 10000 + args_gap;
4295 // Resize to fit optional arguments
4296 if (optional_count != 0) {
4297 if (arguments == null) {
4298 arguments = new Arguments (optional_count);
4300 // Have to create a new container, so the next run can do same
4301 var resized = new Arguments (param_count);
4302 resized.AddRange (arguments);
4303 arguments = resized;
4306 for (int i = arg_count; i < param_count; ++i)
4307 arguments.Add (null);
4311 if (arg_count > 0) {
4313 // Shuffle named arguments to the right positions if there are any
4315 if (arguments[arg_count - 1] is NamedArgument) {
4316 arg_count = arguments.Count;
4318 for (int i = 0; i < arg_count; ++i) {
4319 bool arg_moved = false;
4321 NamedArgument na = arguments[i] as NamedArgument;
4325 int index = pd.GetParameterIndexByName (na.Name);
4327 // Named parameter not found
4331 // already reordered
4336 if (index >= param_count) {
4337 // When using parameters which should not be available to the user
4338 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4341 arguments.Add (null);
4345 temp = arguments[index];
4347 // The slot has been taken by positional argument
4348 if (temp != null && !(temp is NamedArgument))
4353 arguments = arguments.MarkOrderedArgument (na);
4357 arguments[index] = arguments[i];
4358 arguments[i] = temp;
4365 arg_count = arguments.Count;
4367 } else if (arguments != null) {
4368 arg_count = arguments.Count;
4372 // Don't do any expensive checks when the candidate cannot succeed
4374 if (arg_count != param_count && !cpd.HasParams)
4375 return (param_count - arg_count) * 2 + 1;
4377 var dep = candidate.GetMissingDependencies ();
4379 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4384 // 1. Handle generic method using type arguments when specified or type inference
4387 var ms = candidate as MethodSpec;
4388 if (ms != null && ms.IsGeneric) {
4389 if (type_arguments != null) {
4390 var g_args_count = ms.Arity;
4391 if (g_args_count != type_arguments.Count)
4392 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4394 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4397 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4398 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4399 // candidate was found use the set to report more details about what was wrong with lambda body.
4400 // The general idea is to distinguish between code errors and errors caused by
4401 // trial-and-error type inference
4403 if (lambda_conv_msgs == null) {
4404 for (int i = 0; i < arg_count; i++) {
4405 Argument a = arguments[i];
4409 var am = a.Expr as AnonymousMethodExpression;
4411 if (lambda_conv_msgs == null)
4412 lambda_conv_msgs = new SessionReportPrinter ();
4414 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4419 var ti = new TypeInference (arguments);
4420 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4423 return ti.InferenceScore - 20000;
4426 // Clear any error messages when the result was success
4428 if (lambda_conv_msgs != null)
4429 lambda_conv_msgs.ClearSession ();
4431 if (i_args.Length != 0) {
4432 ms = ms.MakeGenericMethod (ec, i_args);
4437 // Type arguments constraints have to match for the method to be applicable
4439 if (!CheckInflatedArguments (ms)) {
4441 return int.MaxValue - 25000;
4445 // We have a generic return type and at same time the method is override which
4446 // means we have to also inflate override return type in case the candidate is
4447 // best candidate and override return type is different to base return type.
4449 // virtual Foo<T, object> with override Foo<T, dynamic>
4451 if (candidate != pm) {
4452 MethodSpec override_ms = (MethodSpec) pm;
4453 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4454 returnType = inflator.Inflate (returnType);
4456 returnType = ms.ReturnType;
4463 if (type_arguments != null)
4464 return int.MaxValue - 15000;
4470 // 2. Each argument has to be implicitly convertible to method parameter
4472 Parameter.Modifier p_mod = 0;
4475 for (int i = 0; i < arg_count; i++) {
4476 Argument a = arguments[i];
4478 var fp = pd.FixedParameters[i];
4479 if (!fp.HasDefaultValue) {
4480 arguments = orig_args;
4481 return arg_count * 2 + 2;
4485 // Get the default value expression, we can use the same expression
4486 // if the type matches
4488 Expression e = fp.DefaultValue;
4490 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4492 // Restore for possible error reporting
4493 for (int ii = i; ii < arg_count; ++ii)
4494 arguments.RemoveAt (i);
4496 return (arg_count - i) * 2 + 1;
4500 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4502 // LAMESPEC: Attributes can be mixed together with build-in priority
4504 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4505 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4506 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4507 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4508 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4509 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4513 arguments[i] = new Argument (e, Argument.AType.Default);
4517 if (p_mod != Parameter.Modifier.PARAMS) {
4518 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4520 } else if (!params_expanded_form) {
4521 params_expanded_form = true;
4522 pt = ((ElementTypeSpec) pt).Element;
4528 if (!params_expanded_form) {
4529 if (a.ArgType == Argument.AType.ExtensionType) {
4531 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4533 // LAMESPEC: or implicit type parameter conversion
4536 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4537 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4538 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4543 score = IsArgumentCompatible (ec, a, p_mod, pt);
4546 dynamicArgument = true;
4551 // It can be applicable in expanded form (when not doing exact match like for delegates)
4553 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4554 if (!params_expanded_form)
4555 pt = ((ElementTypeSpec) pt).Element;
4558 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4561 params_expanded_form = true;
4562 } else if (score < 0) {
4563 params_expanded_form = true;
4564 dynamicArgument = true;
4569 if (params_expanded_form)
4571 return (arg_count - i) * 2 + score;
4576 // When params parameter has no argument it will be provided later if the method is the best candidate
4578 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4579 params_expanded_form = true;
4582 // Restore original arguments for dynamic binder to keep the intention of original source code
4584 if (dynamicArgument)
4585 arguments = orig_args;
4590 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4592 if (e is Constant && e.Type == ptype)
4596 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4598 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4599 e = new MemberAccess (new MemberAccess (new MemberAccess (
4600 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4601 } else if (e is Constant) {
4603 // Handles int to int? conversions, DefaultParameterValue check
4605 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4609 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4612 return e.Resolve (ec);
4616 // Tests argument compatibility with the parameter
4617 // The possible return values are
4619 // 1 - modifier mismatch
4620 // 2 - type mismatch
4621 // -1 - dynamic binding required
4623 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4626 // Types have to be identical when ref or out modifer
4627 // is used and argument is not of dynamic type
4629 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4630 if (argument.Type != parameter) {
4632 // Do full equality check after quick path
4634 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4636 // Using dynamic for ref/out parameter can still succeed at runtime
4638 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4645 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4647 // Using dynamic for ref/out parameter can still succeed at runtime
4649 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4656 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4660 // Use implicit conversion in all modes to return same candidates when the expression
4661 // is used as argument or delegate conversion
4663 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4671 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4673 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4675 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4678 var ac_p = p as ArrayContainer;
4680 var ac_q = q as ArrayContainer;
4684 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4685 if (specific == ac_p.Element)
4687 if (specific == ac_q.Element)
4689 } else if (p.IsGeneric && q.IsGeneric) {
4690 var pargs = TypeManager.GetTypeArguments (p);
4691 var qargs = TypeManager.GetTypeArguments (q);
4693 bool p_specific_at_least_once = false;
4694 bool q_specific_at_least_once = false;
4696 for (int i = 0; i < pargs.Length; i++) {
4697 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4698 if (specific == pargs[i])
4699 p_specific_at_least_once = true;
4700 if (specific == qargs[i])
4701 q_specific_at_least_once = true;
4704 if (p_specific_at_least_once && !q_specific_at_least_once)
4706 if (!p_specific_at_least_once && q_specific_at_least_once)
4714 // Find the best method from candidate list
4716 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4718 List<AmbiguousCandidate> ambiguous_candidates = null;
4720 MemberSpec best_candidate;
4721 Arguments best_candidate_args = null;
4722 bool best_candidate_params = false;
4723 bool best_candidate_dynamic = false;
4724 int best_candidate_rate;
4725 IParametersMember best_parameter_member = null;
4727 int args_count = args != null ? args.Count : 0;
4729 Arguments candidate_args = args;
4730 bool error_mode = false;
4731 MemberSpec invocable_member = null;
4734 best_candidate = null;
4735 best_candidate_rate = int.MaxValue;
4737 var type_members = members;
4739 for (int i = 0; i < type_members.Count; ++i) {
4740 var member = type_members[i];
4743 // Methods in a base class are not candidates if any method in a derived
4744 // class is applicable
4746 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4750 if (!member.IsAccessible (rc))
4753 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4756 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4757 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4762 IParametersMember pm = member as IParametersMember;
4765 // Will use it later to report ambiguity between best method and invocable member
4767 if (Invocation.IsMemberInvocable (member))
4768 invocable_member = member;
4774 // Overload resolution is looking for base member but using parameter names
4775 // and default values from the closest member. That means to do expensive lookup
4776 // for the closest override for virtual or abstract members
4778 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4779 var override_params = base_provider.GetOverrideMemberParameters (member);
4780 if (override_params != null)
4781 pm = override_params;
4785 // Check if the member candidate is applicable
4787 bool params_expanded_form = false;
4788 bool dynamic_argument = false;
4789 TypeSpec rt = pm.MemberType;
4790 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4792 if (lambda_conv_msgs != null)
4793 lambda_conv_msgs.EndSession ();
4796 // How does it score compare to others
4798 if (candidate_rate < best_candidate_rate) {
4800 // Fatal error (missing dependency), cannot continue
4801 if (candidate_rate < 0)
4804 best_candidate_rate = candidate_rate;
4805 best_candidate = member;
4806 best_candidate_args = candidate_args;
4807 best_candidate_params = params_expanded_form;
4808 best_candidate_dynamic = dynamic_argument;
4809 best_parameter_member = pm;
4810 best_candidate_return_type = rt;
4811 } else if (candidate_rate == 0) {
4813 // The member look is done per type for most operations but sometimes
4814 // it's not possible like for binary operators overload because they
4815 // are unioned between 2 sides
4817 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4818 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4823 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4825 // We pack all interface members into top level type which makes the overload resolution
4826 // more complicated for interfaces. We compensate it by removing methods with same
4827 // signature when building the cache hence this path should not really be hit often
4830 // interface IA { void Foo (int arg); }
4831 // interface IB : IA { void Foo (params int[] args); }
4833 // IB::Foo is the best overload when calling IB.Foo (1)
4836 if (ambiguous_candidates != null) {
4837 foreach (var amb_cand in ambiguous_candidates) {
4838 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4847 ambiguous_candidates = null;
4850 // Is the new candidate better
4851 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4855 best_candidate = member;
4856 best_candidate_args = candidate_args;
4857 best_candidate_params = params_expanded_form;
4858 best_candidate_dynamic = dynamic_argument;
4859 best_parameter_member = pm;
4860 best_candidate_return_type = rt;
4862 // It's not better but any other found later could be but we are not sure yet
4863 if (ambiguous_candidates == null)
4864 ambiguous_candidates = new List<AmbiguousCandidate> ();
4866 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4870 // Restore expanded arguments
4871 if (candidate_args != args)
4872 candidate_args = args;
4874 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4877 // We've found exact match
4879 if (best_candidate_rate == 0)
4883 // Try extension methods lookup when no ordinary method match was found and provider enables it
4886 var emg = base_provider.LookupExtensionMethod (rc);
4888 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4890 best_candidate_extension_group = emg;
4891 return (T) (MemberSpec) emg.BestCandidate;
4896 // Don't run expensive error reporting mode for probing
4903 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4906 lambda_conv_msgs = null;
4911 // No best member match found, report an error
4913 if (best_candidate_rate != 0 || error_mode) {
4914 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4918 if (best_candidate_dynamic) {
4919 if (args[0].ArgType == Argument.AType.ExtensionType) {
4920 rc.Report.Error (1973, loc,
4921 "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",
4922 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4926 // Check type constraints only when explicit type arguments are used
4928 if (best_candidate.IsGeneric && type_arguments != null) {
4929 MethodSpec bc = best_candidate as MethodSpec;
4930 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4931 ConstraintChecker cc = new ConstraintChecker (rc);
4932 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4936 BestCandidateIsDynamic = true;
4941 // These flags indicates we are running delegate probing conversion. No need to
4942 // do more expensive checks
4944 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4945 return (T) best_candidate;
4947 if (ambiguous_candidates != null) {
4949 // Now check that there are no ambiguities i.e the selected method
4950 // should be better than all the others
4952 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4953 var candidate = ambiguous_candidates [ix];
4955 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4956 var ambiguous = candidate.Member;
4957 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4958 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4959 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4960 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4961 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4964 return (T) best_candidate;
4969 if (invocable_member != null && !IsProbingOnly) {
4970 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4971 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4972 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4973 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4977 // And now check if the arguments are all
4978 // compatible, perform conversions if
4979 // necessary etc. and return if everything is
4982 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4985 if (best_candidate == null)
4989 // Don't run possibly expensive checks in probing mode
4991 if (!IsProbingOnly && !rc.IsInProbingMode) {
4993 // Check ObsoleteAttribute on the best method
4995 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
4996 if (oa != null && !rc.IsObsolete)
4997 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
4999 best_candidate.MemberDefinition.SetIsUsed ();
5002 args = best_candidate_args;
5003 return (T) best_candidate;
5006 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5008 return ResolveMember<MethodSpec> (rc, ref args);
5011 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5012 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5014 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5017 if (a.Type == InternalType.ErrorType)
5020 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5021 ec.Report.SymbolRelatedToPreviousError (method);
5022 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5023 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5024 TypeManager.CSharpSignature (method));
5027 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5028 TypeManager.CSharpSignature (method));
5029 } else if (IsDelegateInvoke) {
5030 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5031 DelegateType.GetSignatureForError ());
5033 ec.Report.SymbolRelatedToPreviousError (method);
5034 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5035 method.GetSignatureForError ());
5038 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5040 string index = (idx + 1).ToString ();
5041 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5042 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5043 ec.Report.Error (1615, loc, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5044 index, Parameter.GetModifierSignature (a.Modifier));
5046 ec.Report.Error (1620, loc, "Argument `#{0}' is missing `{1}' modifier",
5047 index, Parameter.GetModifierSignature (mod));
5049 string p1 = a.GetSignatureForError ();
5050 string p2 = TypeManager.CSharpName (paramType);
5053 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5054 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5057 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5058 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5059 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5062 ec.Report.Error (1503, a.Expr.Location,
5063 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5068 // We have failed to find exact match so we return error info about the closest match
5070 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5072 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5073 int arg_count = args == null ? 0 : args.Count;
5075 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5076 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5077 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5081 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5086 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5087 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5088 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5092 // For candidates which match on parameters count report more details about incorrect arguments
5095 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5096 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5097 // Reject any inaccessible member
5098 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5099 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5100 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5104 var ms = best_candidate as MethodSpec;
5105 if (ms != null && ms.IsGeneric) {
5106 bool constr_ok = true;
5107 if (ms.TypeArguments != null)
5108 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5110 if (ta_count == 0) {
5111 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5115 rc.Report.Error (411, loc,
5116 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5117 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5124 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5130 // We failed to find any method with correct argument count, report best candidate
5132 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5135 if (best_candidate.Kind == MemberKind.Constructor) {
5136 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5137 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5138 } else if (IsDelegateInvoke) {
5139 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5140 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5141 DelegateType.GetSignatureForError (), arg_count.ToString ());
5143 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5144 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5145 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5146 name, arg_count.ToString ());
5150 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5152 var pd = pm.Parameters;
5153 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5155 Parameter.Modifier p_mod = 0;
5157 int a_idx = 0, a_pos = 0;
5159 ArrayInitializer params_initializers = null;
5160 bool has_unsafe_arg = pm.MemberType.IsPointer;
5161 int arg_count = args == null ? 0 : args.Count;
5163 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5165 if (p_mod != Parameter.Modifier.PARAMS) {
5166 p_mod = pd.FixedParameters[a_idx].ModFlags;
5168 has_unsafe_arg |= pt.IsPointer;
5170 if (p_mod == Parameter.Modifier.PARAMS) {
5171 if (chose_params_expanded) {
5172 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5173 pt = TypeManager.GetElementType (pt);
5179 // Types have to be identical when ref or out modifer is used
5181 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5182 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5185 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5191 NamedArgument na = a as NamedArgument;
5193 int name_index = pd.GetParameterIndexByName (na.Name);
5194 if (name_index < 0 || name_index >= pd.Count) {
5195 if (IsDelegateInvoke) {
5196 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5197 ec.Report.Error (1746, na.Location,
5198 "The delegate `{0}' does not contain a parameter named `{1}'",
5199 DelegateType.GetSignatureForError (), na.Name);
5201 ec.Report.SymbolRelatedToPreviousError (member);
5202 ec.Report.Error (1739, na.Location,
5203 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5204 TypeManager.CSharpSignature (member), na.Name);
5206 } else if (args[name_index] != a) {
5207 if (IsDelegateInvoke)
5208 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5210 ec.Report.SymbolRelatedToPreviousError (member);
5212 ec.Report.Error (1744, na.Location,
5213 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5218 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5221 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5222 custom_errors.NoArgumentMatch (ec, member);
5226 Expression conv = null;
5227 if (a.ArgType == Argument.AType.ExtensionType) {
5228 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5231 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5233 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5236 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5243 // Convert params arguments to an array initializer
5245 if (params_initializers != null) {
5246 // we choose to use 'a.Expr' rather than 'conv' so that
5247 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5248 params_initializers.Add (a.Expr);
5249 args.RemoveAt (a_idx--);
5254 // Update the argument with the implicit conversion
5258 if (a_idx != arg_count) {
5259 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5264 // Fill not provided arguments required by params modifier
5266 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5268 args = new Arguments (1);
5270 pt = ptypes[pd.Count - 1];
5271 pt = TypeManager.GetElementType (pt);
5272 has_unsafe_arg |= pt.IsPointer;
5273 params_initializers = new ArrayInitializer (0, loc);
5277 // Append an array argument with all params arguments
5279 if (params_initializers != null) {
5280 args.Add (new Argument (
5281 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5285 if (has_unsafe_arg && !ec.IsUnsafe) {
5286 Expression.UnsafeError (ec, loc);
5290 // We could infer inaccesible type arguments
5292 if (type_arguments == null && member.IsGeneric) {
5293 var ms = (MethodSpec) member;
5294 foreach (var ta in ms.TypeArguments) {
5295 if (!ta.IsAccessible (ec)) {
5296 ec.Report.SymbolRelatedToPreviousError (ta);
5297 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5307 public class ConstantExpr : MemberExpr
5309 readonly ConstSpec constant;
5311 public ConstantExpr (ConstSpec constant, Location loc)
5313 this.constant = constant;
5317 public override string Name {
5318 get { throw new NotImplementedException (); }
5321 public override string KindName {
5322 get { return "constant"; }
5325 public override bool IsInstance {
5326 get { return !IsStatic; }
5329 public override bool IsStatic {
5330 get { return true; }
5333 protected override TypeSpec DeclaringType {
5334 get { return constant.DeclaringType; }
5337 public override Expression CreateExpressionTree (ResolveContext ec)
5339 throw new NotSupportedException ("ET");
5342 protected override Expression DoResolve (ResolveContext rc)
5344 ResolveInstanceExpression (rc, null);
5345 DoBestMemberChecks (rc, constant);
5347 var c = constant.GetConstant (rc);
5349 // Creates reference expression to the constant value
5350 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5353 public override void Emit (EmitContext ec)
5355 throw new NotSupportedException ();
5358 public override string GetSignatureForError ()
5360 return constant.GetSignatureForError ();
5363 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5365 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5370 // Fully resolved expression that references a Field
5372 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5374 protected FieldSpec spec;
5375 VariableInfo variable_info;
5377 LocalTemporary temp;
5380 protected FieldExpr (Location l)
5385 public FieldExpr (FieldSpec spec, Location loc)
5390 type = spec.MemberType;
5393 public FieldExpr (FieldBase fi, Location l)
5400 public override string Name {
5406 public bool IsHoisted {
5408 IVariableReference hv = InstanceExpression as IVariableReference;
5409 return hv != null && hv.IsHoisted;
5413 public override bool IsInstance {
5415 return !spec.IsStatic;
5419 public override bool IsStatic {
5421 return spec.IsStatic;
5425 public override string KindName {
5426 get { return "field"; }
5429 public FieldSpec Spec {
5435 protected override TypeSpec DeclaringType {
5437 return spec.DeclaringType;
5441 public VariableInfo VariableInfo {
5443 return variable_info;
5449 public override string GetSignatureForError ()
5451 return spec.GetSignatureForError ();
5454 public bool IsMarshalByRefAccess (ResolveContext rc)
5456 // Checks possible ldflda of field access expression
5457 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5458 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5459 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5462 public void SetHasAddressTaken ()
5464 IVariableReference vr = InstanceExpression as IVariableReference;
5466 vr.SetHasAddressTaken ();
5470 public override Expression CreateExpressionTree (ResolveContext ec)
5472 return CreateExpressionTree (ec, true);
5475 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5478 Expression instance;
5480 if (InstanceExpression == null) {
5481 instance = new NullLiteral (loc);
5482 } else if (convertInstance) {
5483 instance = InstanceExpression.CreateExpressionTree (ec);
5485 args = new Arguments (1);
5486 args.Add (new Argument (InstanceExpression));
5487 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5490 args = Arguments.CreateForExpressionTree (ec, null,
5492 CreateTypeOfExpression ());
5494 return CreateExpressionFactoryCall (ec, "Field", args);
5497 public Expression CreateTypeOfExpression ()
5499 return new TypeOfField (spec, loc);
5502 protected override Expression DoResolve (ResolveContext ec)
5504 spec.MemberDefinition.SetIsUsed ();
5506 return DoResolve (ec, null);
5509 Expression DoResolve (ResolveContext ec, Expression rhs)
5511 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5514 if (ResolveInstanceExpression (ec, rhs)) {
5515 // Resolve the field's instance expression while flow analysis is turned
5516 // off: when accessing a field "a.b", we must check whether the field
5517 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5519 if (lvalue_instance) {
5520 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5521 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5523 Expression right_side =
5524 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5526 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5529 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5530 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5534 if (InstanceExpression == null)
5538 DoBestMemberChecks (ec, spec);
5541 var fb = spec as FixedFieldSpec;
5542 IVariableReference var = InstanceExpression as IVariableReference;
5544 if (lvalue_instance && var != null && var.VariableInfo != null) {
5545 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5549 IFixedExpression fe = InstanceExpression as IFixedExpression;
5550 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5551 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5554 if (InstanceExpression.eclass != ExprClass.Variable) {
5555 ec.Report.SymbolRelatedToPreviousError (spec);
5556 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5557 TypeManager.GetFullNameSignature (spec));
5558 } else if (var != null && var.IsHoisted) {
5559 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5562 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5566 // Set flow-analysis variable info for struct member access. It will be check later
5567 // for precise error reporting
5569 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5570 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5571 if (rhs != null && variable_info != null)
5572 variable_info.SetStructFieldAssigned (ec, Name);
5575 eclass = ExprClass.Variable;
5579 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5584 var var = fe.InstanceExpression as IVariableReference;
5586 var vi = var.VariableInfo;
5588 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5590 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5592 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5599 fe = fe.InstanceExpression as FieldExpr;
5601 } while (fe != null);
5604 static readonly int [] codes = {
5605 191, // instance, write access
5606 192, // instance, out access
5607 198, // static, write access
5608 199, // static, out access
5609 1648, // member of value instance, write access
5610 1649, // member of value instance, out access
5611 1650, // member of value static, write access
5612 1651 // member of value static, out access
5615 static readonly string [] msgs = {
5616 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5617 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5618 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5619 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5620 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5621 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5622 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5623 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5626 // The return value is always null. Returning a value simplifies calling code.
5627 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5630 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5634 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5636 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5641 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5643 if (spec is FixedFieldSpec) {
5644 // It could be much better error message but we want to be error compatible
5645 Error_ValueAssignment (ec, right_side);
5648 Expression e = DoResolve (ec, right_side);
5653 spec.MemberDefinition.SetIsAssigned ();
5655 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5656 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5657 ec.Report.Warning (420, 1, loc,
5658 "`{0}': A volatile field references will not be treated as volatile",
5659 spec.GetSignatureForError ());
5662 if (spec.IsReadOnly) {
5663 // InitOnly fields can only be assigned in constructors or initializers
5664 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5665 return Report_AssignToReadonly (ec, right_side);
5667 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5669 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5670 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5671 return Report_AssignToReadonly (ec, right_side);
5672 // static InitOnly fields cannot be assigned-to in an instance constructor
5673 if (IsStatic && !ec.IsStatic)
5674 return Report_AssignToReadonly (ec, right_side);
5675 // instance constructors can't modify InitOnly fields of other instances of the same type
5676 if (!IsStatic && !(InstanceExpression is This))
5677 return Report_AssignToReadonly (ec, right_side);
5681 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5682 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5683 ec.Report.Warning (197, 1, loc,
5684 "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",
5685 GetSignatureForError ());
5688 eclass = ExprClass.Variable;
5692 public override int GetHashCode ()
5694 return spec.GetHashCode ();
5697 public bool IsFixed {
5700 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5702 IVariableReference variable = InstanceExpression as IVariableReference;
5703 if (variable != null)
5704 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5706 IFixedExpression fe = InstanceExpression as IFixedExpression;
5707 return fe != null && fe.IsFixed;
5711 public override bool Equals (object obj)
5713 FieldExpr fe = obj as FieldExpr;
5717 if (spec != fe.spec)
5720 if (InstanceExpression == null || fe.InstanceExpression == null)
5723 return InstanceExpression.Equals (fe.InstanceExpression);
5726 public void Emit (EmitContext ec, bool leave_copy)
5728 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5732 ec.Emit (OpCodes.Volatile);
5734 ec.Emit (OpCodes.Ldsfld, spec);
5737 EmitInstance (ec, false);
5739 // Optimization for build-in types
5740 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5741 ec.EmitLoadFromPtr (type);
5743 var ff = spec as FixedFieldSpec;
5745 ec.Emit (OpCodes.Ldflda, spec);
5746 ec.Emit (OpCodes.Ldflda, ff.Element);
5749 ec.Emit (OpCodes.Volatile);
5751 ec.Emit (OpCodes.Ldfld, spec);
5757 ec.Emit (OpCodes.Dup);
5759 temp = new LocalTemporary (this.Type);
5765 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5767 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5768 if (isCompound && !(source is DynamicExpressionStatement)) {
5769 if (has_await_source) {
5771 InstanceExpression = InstanceExpression.EmitToField (ec);
5778 if (has_await_source)
5779 source = source.EmitToField (ec);
5781 EmitInstance (ec, prepared);
5787 ec.Emit (OpCodes.Dup);
5789 temp = new LocalTemporary (this.Type);
5794 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5795 ec.Emit (OpCodes.Volatile);
5797 spec.MemberDefinition.SetIsAssigned ();
5800 ec.Emit (OpCodes.Stsfld, spec);
5802 ec.Emit (OpCodes.Stfld, spec);
5812 // Emits store to field with prepared values on stack
5814 public void EmitAssignFromStack (EmitContext ec)
5817 ec.Emit (OpCodes.Stsfld, spec);
5819 ec.Emit (OpCodes.Stfld, spec);
5823 public override void Emit (EmitContext ec)
5828 public override void EmitSideEffect (EmitContext ec)
5830 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5832 if (is_volatile) // || is_marshal_by_ref ())
5833 base.EmitSideEffect (ec);
5836 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5838 if ((mode & AddressOp.Store) != 0)
5839 spec.MemberDefinition.SetIsAssigned ();
5840 if ((mode & AddressOp.Load) != 0)
5841 spec.MemberDefinition.SetIsUsed ();
5844 // Handle initonly fields specially: make a copy and then
5845 // get the address of the copy.
5848 if (spec.IsReadOnly){
5850 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5862 var temp = ec.GetTemporaryLocal (type);
5863 ec.Emit (OpCodes.Stloc, temp);
5864 ec.Emit (OpCodes.Ldloca, temp);
5865 ec.FreeTemporaryLocal (temp, type);
5871 ec.Emit (OpCodes.Ldsflda, spec);
5874 EmitInstance (ec, false);
5875 ec.Emit (OpCodes.Ldflda, spec);
5879 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5881 return MakeExpression (ctx);
5884 public override SLE.Expression MakeExpression (BuilderContext ctx)
5887 return base.MakeExpression (ctx);
5889 return SLE.Expression.Field (
5890 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5891 spec.GetMetaInfo ());
5895 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5897 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5903 // Expression that evaluates to a Property.
5905 // This is not an LValue because we need to re-write the expression. We
5906 // can not take data from the stack and store it.
5908 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5910 Arguments arguments;
5912 public PropertyExpr (PropertySpec spec, Location l)
5915 best_candidate = spec;
5916 type = spec.MemberType;
5921 protected override Arguments Arguments {
5930 protected override TypeSpec DeclaringType {
5932 return best_candidate.DeclaringType;
5936 public override string Name {
5938 return best_candidate.Name;
5942 public override bool IsInstance {
5948 public override bool IsStatic {
5950 return best_candidate.IsStatic;
5954 public override string KindName {
5955 get { return "property"; }
5958 public PropertySpec PropertyInfo {
5960 return best_candidate;
5966 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5968 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
5971 var args_count = arguments == null ? 0 : arguments.Count;
5972 if (args_count != body.Parameters.Count && args_count == 0)
5975 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
5976 mg.InstanceExpression = InstanceExpression;
5981 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5983 return new PropertyExpr (spec, loc) {
5989 public override Expression CreateExpressionTree (ResolveContext ec)
5992 if (IsSingleDimensionalArrayLength ()) {
5993 args = new Arguments (1);
5994 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
5995 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
5998 args = new Arguments (2);
5999 if (InstanceExpression == null)
6000 args.Add (new Argument (new NullLiteral (loc)));
6002 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6003 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6004 return CreateExpressionFactoryCall (ec, "Property", args);
6007 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6009 DoResolveLValue (rc, null);
6010 return new TypeOfMethod (Setter, loc);
6013 public override string GetSignatureForError ()
6015 return best_candidate.GetSignatureForError ();
6018 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6021 return base.MakeExpression (ctx);
6023 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6027 public override SLE.Expression MakeExpression (BuilderContext ctx)
6030 return base.MakeExpression (ctx);
6032 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6036 void Error_PropertyNotValid (ResolveContext ec)
6038 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6039 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6040 GetSignatureForError ());
6043 bool IsSingleDimensionalArrayLength ()
6045 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6048 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6049 return ac != null && ac.Rank == 1;
6052 public override void Emit (EmitContext ec, bool leave_copy)
6055 // Special case: length of single dimension array property is turned into ldlen
6057 if (IsSingleDimensionalArrayLength ()) {
6058 EmitInstance (ec, false);
6059 ec.Emit (OpCodes.Ldlen);
6060 ec.Emit (OpCodes.Conv_I4);
6064 base.Emit (ec, leave_copy);
6067 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6070 LocalTemporary await_source_arg = null;
6072 if (isCompound && !(source is DynamicExpressionStatement)) {
6073 emitting_compound_assignment = true;
6076 if (has_await_arguments) {
6077 await_source_arg = new LocalTemporary (Type);
6078 await_source_arg.Store (ec);
6080 args = new Arguments (1);
6081 args.Add (new Argument (await_source_arg));
6084 temp = await_source_arg;
6087 has_await_arguments = false;
6092 ec.Emit (OpCodes.Dup);
6093 temp = new LocalTemporary (this.Type);
6098 args = arguments == null ? new Arguments (1) : arguments;
6102 temp = new LocalTemporary (this.Type);
6104 args.Add (new Argument (temp));
6106 args.Add (new Argument (source));
6110 emitting_compound_assignment = false;
6112 var call = new CallEmitter ();
6113 call.InstanceExpression = InstanceExpression;
6115 call.InstanceExpressionOnStack = true;
6117 call.Emit (ec, Setter, args, loc);
6124 if (await_source_arg != null) {
6125 await_source_arg.Release (ec);
6129 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6131 eclass = ExprClass.PropertyAccess;
6133 if (best_candidate.IsNotCSharpCompatible) {
6134 Error_PropertyNotValid (rc);
6137 ResolveInstanceExpression (rc, right_side);
6139 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6140 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6141 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6143 type = p.MemberType;
6147 DoBestMemberChecks (rc, best_candidate);
6149 // Handling of com-imported properties with any number of default property parameters
6150 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6151 var p = best_candidate.Get.Parameters;
6152 arguments = new Arguments (p.Count);
6153 for (int i = 0; i < p.Count; ++i) {
6154 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6156 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6157 var p = best_candidate.Set.Parameters;
6158 arguments = new Arguments (p.Count - 1);
6159 for (int i = 0; i < p.Count - 1; ++i) {
6160 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6167 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6169 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6173 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6175 // getter and setter can be different for base calls
6176 MethodSpec getter, setter;
6177 protected T best_candidate;
6179 protected LocalTemporary temp;
6180 protected bool emitting_compound_assignment;
6181 protected bool has_await_arguments;
6183 protected PropertyOrIndexerExpr (Location l)
6190 protected abstract Arguments Arguments { get; set; }
6192 public MethodSpec Getter {
6201 public MethodSpec Setter {
6212 protected override Expression DoResolve (ResolveContext ec)
6214 if (eclass == ExprClass.Unresolved) {
6215 var expr = OverloadResolve (ec, null);
6220 return expr.Resolve (ec);
6223 if (!ResolveGetter (ec))
6229 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6231 if (right_side == EmptyExpression.OutAccess) {
6232 // TODO: best_candidate can be null at this point
6233 INamedBlockVariable variable = null;
6234 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6235 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6236 best_candidate.Name);
6238 right_side.DoResolveLValue (ec, this);
6243 if (eclass == ExprClass.Unresolved) {
6244 var expr = OverloadResolve (ec, right_side);
6249 return expr.ResolveLValue (ec, right_side);
6252 if (!ResolveSetter (ec))
6259 // Implements the IAssignMethod interface for assignments
6261 public virtual void Emit (EmitContext ec, bool leave_copy)
6263 var call = new CallEmitter ();
6264 call.InstanceExpression = InstanceExpression;
6265 if (has_await_arguments)
6266 call.HasAwaitArguments = true;
6268 call.DuplicateArguments = emitting_compound_assignment;
6270 call.Emit (ec, Getter, Arguments, loc);
6272 if (call.HasAwaitArguments) {
6273 InstanceExpression = call.InstanceExpression;
6274 Arguments = call.EmittedArguments;
6275 has_await_arguments = true;
6279 ec.Emit (OpCodes.Dup);
6280 temp = new LocalTemporary (Type);
6285 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6287 public override void Emit (EmitContext ec)
6292 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6294 has_await_arguments = true;
6299 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6301 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6303 bool ResolveGetter (ResolveContext rc)
6305 if (!best_candidate.HasGet) {
6306 if (InstanceExpression != EmptyExpression.Null) {
6307 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6308 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6309 best_candidate.GetSignatureForError ());
6312 } else if (!best_candidate.Get.IsAccessible (rc)) {
6313 if (best_candidate.HasDifferentAccessibility) {
6314 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6315 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6316 TypeManager.CSharpSignature (best_candidate));
6318 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6319 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6323 if (best_candidate.HasDifferentAccessibility) {
6324 CheckProtectedMemberAccess (rc, best_candidate.Get);
6327 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6331 bool ResolveSetter (ResolveContext rc)
6333 if (!best_candidate.HasSet) {
6334 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6335 GetSignatureForError ());
6339 if (!best_candidate.Set.IsAccessible (rc)) {
6340 if (best_candidate.HasDifferentAccessibility) {
6341 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6342 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6343 GetSignatureForError ());
6345 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6346 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6350 if (best_candidate.HasDifferentAccessibility)
6351 CheckProtectedMemberAccess (rc, best_candidate.Set);
6353 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6359 /// Fully resolved expression that evaluates to an Event
6361 public class EventExpr : MemberExpr, IAssignMethod
6363 readonly EventSpec spec;
6366 public EventExpr (EventSpec spec, Location loc)
6374 protected override TypeSpec DeclaringType {
6376 return spec.DeclaringType;
6380 public override string Name {
6386 public override bool IsInstance {
6388 return !spec.IsStatic;
6392 public override bool IsStatic {
6394 return spec.IsStatic;
6398 public override string KindName {
6399 get { return "event"; }
6402 public MethodSpec Operator {
6410 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6413 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6415 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6416 if (spec.BackingField != null &&
6417 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6419 spec.MemberDefinition.SetIsUsed ();
6421 if (!ec.IsObsolete) {
6422 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6424 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6427 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6428 Error_AssignmentEventOnly (ec);
6430 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6432 InstanceExpression = null;
6434 return ml.ResolveMemberAccess (ec, left, original);
6438 return base.ResolveMemberAccess (ec, left, original);
6441 public override Expression CreateExpressionTree (ResolveContext ec)
6443 throw new NotSupportedException ("ET");
6446 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6448 if (right_side == EmptyExpression.EventAddition) {
6449 op = spec.AccessorAdd;
6450 } else if (right_side == EmptyExpression.EventSubtraction) {
6451 op = spec.AccessorRemove;
6455 Error_AssignmentEventOnly (ec);
6459 op = CandidateToBaseOverride (ec, op);
6463 protected override Expression DoResolve (ResolveContext ec)
6465 eclass = ExprClass.EventAccess;
6466 type = spec.MemberType;
6468 ResolveInstanceExpression (ec, null);
6470 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6471 Error_AssignmentEventOnly (ec);
6474 DoBestMemberChecks (ec, spec);
6478 public override void Emit (EmitContext ec)
6480 throw new NotSupportedException ();
6481 //Error_CannotAssign ();
6484 #region IAssignMethod Members
6486 public void Emit (EmitContext ec, bool leave_copy)
6488 throw new NotImplementedException ();
6491 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6493 if (leave_copy || !isCompound)
6494 throw new NotImplementedException ("EventExpr::EmitAssign");
6496 Arguments args = new Arguments (1);
6497 args.Add (new Argument (source));
6499 var call = new CallEmitter ();
6500 call.InstanceExpression = InstanceExpression;
6501 call.Emit (ec, op, args, loc);
6506 void Error_AssignmentEventOnly (ResolveContext ec)
6508 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6509 ec.Report.Error (79, loc,
6510 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6511 GetSignatureForError ());
6513 ec.Report.Error (70, loc,
6514 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6515 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6519 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6521 name = name.Substring (0, name.LastIndexOf ('.'));
6522 base.Error_CannotCallAbstractBase (rc, name);
6525 public override string GetSignatureForError ()
6527 return TypeManager.CSharpSignature (spec);
6530 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6532 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6536 public class TemporaryVariableReference : VariableReference
6538 public class Declarator : Statement
6540 TemporaryVariableReference variable;
6542 public Declarator (TemporaryVariableReference variable)
6544 this.variable = variable;
6548 protected override void DoEmit (EmitContext ec)
6550 variable.li.CreateBuilder (ec);
6553 public override void Emit (EmitContext ec)
6555 // Don't create sequence point
6559 protected override void CloneTo (CloneContext clonectx, Statement target)
6567 public TemporaryVariableReference (LocalVariable li, Location loc)
6570 this.type = li.Type;
6574 public override bool IsLockedByStatement {
6582 public LocalVariable LocalInfo {
6588 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6590 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6591 return new TemporaryVariableReference (li, loc);
6594 protected override Expression DoResolve (ResolveContext ec)
6596 eclass = ExprClass.Variable;
6599 // Don't capture temporary variables except when using
6600 // state machine redirection and block yields
6602 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6603 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6604 ec.IsVariableCapturingRequired) {
6605 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6606 storey.CaptureLocalVariable (ec, li);
6612 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6614 return Resolve (ec);
6617 public override void Emit (EmitContext ec)
6619 li.CreateBuilder (ec);
6624 public void EmitAssign (EmitContext ec, Expression source)
6626 li.CreateBuilder (ec);
6628 EmitAssign (ec, source, false, false);
6631 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6633 return li.HoistedVariant;
6636 public override bool IsFixed {
6637 get { return true; }
6640 public override bool IsRef {
6641 get { return false; }
6644 public override string Name {
6645 get { throw new NotImplementedException (); }
6648 public override void SetHasAddressTaken ()
6650 throw new NotImplementedException ();
6653 protected override ILocalVariable Variable {
6657 public override VariableInfo VariableInfo {
6658 get { return null; }
6661 public override void VerifyAssigned (ResolveContext rc)
6667 /// Handles `var' contextual keyword; var becomes a keyword only
6668 /// if no type called var exists in a variable scope
6670 class VarExpr : SimpleName
6672 public VarExpr (Location loc)
6677 public bool InferType (ResolveContext ec, Expression right_side)
6680 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6682 type = right_side.Type;
6683 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6684 ec.Report.Error (815, loc,
6685 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6686 type.GetSignatureForError ());
6690 eclass = ExprClass.Variable;
6694 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6696 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6697 base.Error_TypeOrNamespaceNotFound (ec);
6699 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");