2 // ecore.cs: Core of the Expression representation for the intermediate tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Copyright 2001, 2002, 2003 Ximian, Inc.
9 // Copyright 2003-2008 Novell, Inc.
10 // Copyright 2011-2012 Xamarin Inc.
15 using System.Collections.Generic;
17 using SLE = System.Linq.Expressions;
21 using IKVM.Reflection;
22 using IKVM.Reflection.Emit;
24 using System.Reflection;
25 using System.Reflection.Emit;
28 namespace Mono.CSharp {
31 /// The ExprClass class contains the is used to pass the
32 /// classification of an expression (value, variable, namespace,
33 /// type, method group, property access, event access, indexer access,
36 public enum ExprClass : byte {
52 /// This is used to tell Resolve in which types of expressions we're
56 public enum ResolveFlags {
57 // Returns Value, Variable, PropertyAccess, EventAccess or IndexerAccess.
60 // Returns a type expression.
63 // Returns a method group.
66 TypeParameter = 1 << 3,
68 // Mask of all the expression class flags.
69 MaskExprClass = VariableOrValue | Type | MethodGroup | TypeParameter,
73 // This is just as a hint to AddressOf of what will be done with the
76 public enum AddressOp {
83 /// This interface is implemented by variables
85 public interface IMemoryLocation {
87 /// The AddressOf method should generate code that loads
88 /// the address of the object and leaves it on the stack.
90 /// The `mode' argument is used to notify the expression
91 /// of whether this will be used to read from the address or
92 /// write to the address.
94 /// This is just a hint that can be used to provide good error
95 /// reporting, and should have no other side effects.
97 void AddressOf (EmitContext ec, AddressOp mode);
101 // An expressions resolved as a direct variable reference
103 public interface IVariableReference : IFixedExpression
105 bool IsHoisted { get; }
107 VariableInfo VariableInfo { get; }
109 void SetHasAddressTaken ();
113 // Implemented by an expression which could be or is always
116 public interface IFixedExpression
118 bool IsFixed { get; }
121 public interface IExpressionCleanup
123 void EmitCleanup (EmitContext ec);
127 /// Base class for expressions
129 public abstract class Expression {
130 public ExprClass eclass;
131 protected TypeSpec type;
132 protected Location loc;
134 public TypeSpec Type {
136 set { type = value; }
139 public virtual bool IsSideEffectFree {
145 public Location Location {
149 public virtual bool IsNull {
156 // Used to workaround parser limitation where we cannot get
157 // start of statement expression location
159 public virtual Location StartLocation {
165 public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
168 // Return method-group expression when the expression can be used as
169 // lambda replacement. A good example is array sorting where instead of
172 // Array.Sort (s, (a, b) => String.Compare (a, b));
174 // we can use method group directly
176 // Array.Sort (s, String.Compare);
178 // Correct overload will be used because we do the reduction after
179 // best candidate was found.
185 // Returns true when the expression during Emit phase breaks stack
186 // by using await expression
188 public virtual bool ContainsEmitWithAwait ()
194 /// Performs semantic analysis on the Expression
198 /// The Resolve method is invoked to perform the semantic analysis
201 /// The return value is an expression (it can be the
202 /// same expression in some cases) or a new
203 /// expression that better represents this node.
205 /// For example, optimizations of Unary (LiteralInt)
206 /// would return a new LiteralInt with a negated
209 /// If there is an error during semantic analysis,
210 /// then an error should be reported (using Report)
211 /// and a null value should be returned.
213 /// There are two side effects expected from calling
214 /// Resolve(): the the field variable "eclass" should
215 /// be set to any value of the enumeration
216 /// `ExprClass' and the type variable should be set
217 /// to a valid type (this is the type of the
220 protected abstract Expression DoResolve (ResolveContext rc);
222 public virtual Expression DoResolveLValue (ResolveContext rc, Expression right_side)
228 // This is used if the expression should be resolved as a type or namespace name.
229 // the default implementation fails.
231 public virtual TypeSpec ResolveAsType (IMemberContext mc)
233 ResolveContext ec = new ResolveContext (mc);
234 Expression e = Resolve (ec);
236 e.Error_UnexpectedKind (ec, ResolveFlags.Type, loc);
241 public static void ErrorIsInaccesible (IMemberContext rc, string member, Location loc)
243 rc.Module.Compiler.Report.Error (122, loc, "`{0}' is inaccessible due to its protection level", member);
246 public void Error_ExpressionMustBeConstant (ResolveContext rc, Location loc, string e_name)
248 rc.Report.Error (133, loc, "The expression being assigned to `{0}' must be constant", e_name);
251 public void Error_ConstantCanBeInitializedWithNullOnly (ResolveContext rc, TypeSpec type, Location loc, string name)
253 rc.Report.Error (134, loc, "A constant `{0}' of reference type `{1}' can only be initialized with null",
254 name, type.GetSignatureForError ());
257 protected virtual void Error_InvalidExpressionStatement (Report report, Location loc)
259 report.Error (201, loc, "Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement");
262 public void Error_InvalidExpressionStatement (BlockContext bc)
264 Error_InvalidExpressionStatement (bc.Report, loc);
267 public void Error_InvalidExpressionStatement (Report report)
269 Error_InvalidExpressionStatement (report, loc);
272 public static void Error_VoidInvalidInTheContext (Location loc, Report Report)
274 Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
277 public virtual void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
279 Error_ValueCannotBeConvertedCore (ec, loc, target, expl);
282 protected void Error_ValueCannotBeConvertedCore (ResolveContext ec, Location loc, TypeSpec target, bool expl)
284 // The error was already reported as CS1660
285 if (type == InternalType.AnonymousMethod)
288 if (type == InternalType.ErrorType || target == InternalType.ErrorType)
291 string from_type = type.GetSignatureForError ();
292 string to_type = target.GetSignatureForError ();
293 if (from_type == to_type) {
294 from_type = type.GetSignatureForErrorIncludingAssemblyName ();
295 to_type = target.GetSignatureForErrorIncludingAssemblyName ();
299 ec.Report.Error (30, loc, "Cannot convert type `{0}' to `{1}'",
304 ec.Report.DisableReporting ();
305 bool expl_exists = Convert.ExplicitConversion (ec, this, target, Location.Null) != null;
306 ec.Report.EnableReporting ();
309 ec.Report.Error (266, loc,
310 "Cannot implicitly convert type `{0}' to `{1}'. An explicit conversion exists (are you missing a cast?)",
313 ec.Report.Error (29, loc, "Cannot implicitly convert type `{0}' to `{1}'",
318 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, MemberSpec member, int arity, Location loc)
320 // Better message for possible generic expressions
321 if (member != null && (member.Kind & MemberKind.GenericMask) != 0) {
322 var report = context.Module.Compiler.Report;
323 report.SymbolRelatedToPreviousError (member);
324 if (member is TypeSpec)
325 member = ((TypeSpec) member).GetDefinition ();
327 member = ((MethodSpec) member).GetGenericMethodDefinition ();
329 string name = member.Kind == MemberKind.Method ? "method" : "type";
330 if (member.IsGeneric) {
331 report.Error (305, loc, "Using the generic {0} `{1}' requires `{2}' type argument(s)",
332 name, member.GetSignatureForError (), member.Arity.ToString ());
334 report.Error (308, loc, "The non-generic {0} `{1}' cannot be used with the type arguments",
335 name, member.GetSignatureForError ());
338 Error_TypeArgumentsCannotBeUsed (context, ExprClassName, GetSignatureForError (), loc);
342 public void Error_TypeArgumentsCannotBeUsed (IMemberContext context, string exprType, string name, Location loc)
344 context.Module.Compiler.Report.Error (307, loc, "The {0} `{1}' cannot be used with type arguments",
348 protected virtual void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
350 Error_TypeDoesNotContainDefinition (ec, loc, type, name);
353 public static void Error_TypeDoesNotContainDefinition (ResolveContext ec, Location loc, TypeSpec type, string name)
355 ec.Report.SymbolRelatedToPreviousError (type);
356 ec.Report.Error (117, loc, "`{0}' does not contain a definition for `{1}'",
357 type.GetSignatureForError (), name);
360 public virtual void Error_ValueAssignment (ResolveContext rc, Expression rhs)
362 if (rhs == EmptyExpression.LValueMemberAccess || rhs == EmptyExpression.LValueMemberOutAccess) {
363 // Already reported as CS1612
364 } else if (rhs == EmptyExpression.OutAccess) {
365 rc.Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
367 rc.Report.Error (131, loc, "The left-hand side of an assignment must be a variable, a property or an indexer");
371 protected void Error_VoidPointerOperation (ResolveContext rc)
373 rc.Report.Error (242, loc, "The operation in question is undefined on void pointers");
376 public ResolveFlags ExprClassToResolveFlags {
380 case ExprClass.Namespace:
381 return ResolveFlags.Type;
383 case ExprClass.MethodGroup:
384 return ResolveFlags.MethodGroup;
386 case ExprClass.TypeParameter:
387 return ResolveFlags.TypeParameter;
389 case ExprClass.Value:
390 case ExprClass.Variable:
391 case ExprClass.PropertyAccess:
392 case ExprClass.EventAccess:
393 case ExprClass.IndexerAccess:
394 return ResolveFlags.VariableOrValue;
397 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
403 // Implements identical simple name and type-name resolution
405 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
408 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
411 // 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
412 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
414 if (left is MemberExpr || left is VariableReference) {
415 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
416 if (identical_type != null && identical_type.Type == left.Type)
417 return identical_type;
423 public virtual string GetSignatureForError ()
425 return type.GetDefinition ().GetSignatureForError ();
429 /// Resolves an expression and performs semantic analysis on it.
433 /// Currently Resolve wraps DoResolve to perform sanity
434 /// checking and assertion checking on what we expect from Resolve.
436 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
438 if (eclass != ExprClass.Unresolved)
448 if ((flags & e.ExprClassToResolveFlags) == 0) {
449 e.Error_UnexpectedKind (ec, flags, loc);
454 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
457 } catch (Exception ex) {
458 if (loc.IsNull || ec.Module.Compiler.Settings.DebugFlags > 0 || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException)
461 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
462 return ErrorExpression.Instance; // TODO: Add location
467 /// Resolves an expression and performs semantic analysis on it.
469 public Expression Resolve (ResolveContext rc)
471 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
475 /// Resolves an expression for LValue assignment
479 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
480 /// checking and assertion checking on what we expect from Resolve
482 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
484 int errors = ec.Report.Errors;
485 bool out_access = right_side == EmptyExpression.OutAccess;
487 Expression e = DoResolveLValue (ec, right_side);
489 if (e != null && out_access && !(e is IMemoryLocation)) {
490 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
491 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
493 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
494 // e.GetType () + " " + e.GetSignatureForError ());
499 if (errors == ec.Report.Errors) {
500 Error_ValueAssignment (ec, right_side);
505 if (e.eclass == ExprClass.Unresolved)
506 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
508 if ((e.type == null) && !(e is GenericTypeExpr))
509 throw new Exception ("Expression " + e + " did not set its type after Resolve");
514 public Constant ResolveLabelConstant (ResolveContext rc)
516 var expr = Resolve (rc);
520 Constant c = expr as Constant;
522 if (c.type != InternalType.ErrorType)
523 rc.Report.Error (150, StartLocation, "A constant value is expected");
531 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
533 rc.Module.Compiler.Report.Error (182, loc,
534 "An attribute argument must be a constant expression, typeof expression or array creation expression");
538 /// Emits the code for the expression
542 /// The Emit method is invoked to generate the code
543 /// for the expression.
545 public abstract void Emit (EmitContext ec);
548 // Emit code to branch to @target if this expression is equivalent to @on_true.
549 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
550 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
551 // including the use of conditional branches. Note also that a branch MUST be emitted
552 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
555 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
558 // Emit this expression for its side effects, not for its value.
559 // The default implementation is to emit the value, and then throw it away.
560 // Subclasses can provide more efficient implementations, but those MUST be equivalent
561 public virtual void EmitSideEffect (EmitContext ec)
564 ec.Emit (OpCodes.Pop);
568 // Emits the expression into temporary field variable. The method
569 // should be used for await expressions only
571 public virtual Expression EmitToField (EmitContext ec)
574 // This is the await prepare Emit method. When emitting code like
575 // a + b we emit code like
581 // For await a + await b we have to interfere the flow to keep the
582 // stack clean because await yields from the expression. The emit
585 // a = a.EmitToField () // a is changed to temporary field access
586 // b = b.EmitToField ()
592 // The idea is to emit expression and leave the stack empty with
593 // result value still available.
595 // Expressions should override this default implementation when
596 // optimized version can be provided (e.g. FieldExpr)
599 // We can optimize for side-effect free expressions, they can be
600 // emitted out of order
602 if (IsSideEffectFree)
605 bool needs_temporary = ContainsEmitWithAwait ();
606 if (!needs_temporary)
609 // Emit original code
610 var field = EmitToFieldSource (ec);
613 // Store the result to temporary field when we
614 // cannot load `this' directly
616 field = ec.GetTemporaryField (type);
617 if (needs_temporary) {
619 // Create temporary local (we cannot load `this' before Emit)
621 var temp = ec.GetTemporaryLocal (type);
622 ec.Emit (OpCodes.Stloc, temp);
625 ec.Emit (OpCodes.Ldloc, temp);
626 field.EmitAssignFromStack (ec);
628 ec.FreeTemporaryLocal (temp, type);
630 field.EmitAssignFromStack (ec);
637 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
640 // Default implementation calls Emit method
646 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
648 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
649 bool contains_await = false;
651 for (int i = 1; i < expressions.Count; ++i) {
652 if (expressions[i].ContainsEmitWithAwait ()) {
653 contains_await = true;
658 if (contains_await) {
659 for (int i = 0; i < expressions.Count; ++i) {
660 expressions[i] = expressions[i].EmitToField (ec);
665 for (int i = 0; i < expressions.Count; ++i) {
666 expressions[i].Emit (ec);
671 /// Protected constructor. Only derivate types should
672 /// be able to be created
675 protected Expression ()
680 /// Returns a fully formed expression after a MemberLookup
683 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
685 if (spec is EventSpec)
686 return new EventExpr ((EventSpec) spec, loc);
687 if (spec is ConstSpec)
688 return new ConstantExpr ((ConstSpec) spec, loc);
689 if (spec is FieldSpec)
690 return new FieldExpr ((FieldSpec) spec, loc);
691 if (spec is PropertySpec)
692 return new PropertyExpr ((PropertySpec) spec, loc);
693 if (spec is TypeSpec)
694 return new TypeExpression (((TypeSpec) spec), loc);
699 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
701 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
703 rc.Report.SymbolRelatedToPreviousError (type);
705 // Report meaningful error for struct as they always have default ctor in C# context
706 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
708 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
709 type.GetSignatureForError ());
715 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
716 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
717 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
720 return r.ResolveMember<MethodSpec> (rc, ref args);
724 public enum MemberLookupRestrictions
733 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
734 // `qualifier_type' or null to lookup members in the current class.
736 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
738 var members = MemberCache.FindMembers (queried_type, name, false);
742 MemberSpec non_method = null;
743 MemberSpec ambig_non_method = null;
745 for (int i = 0; i < members.Count; ++i) {
746 var member = members[i];
748 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
749 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
752 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
755 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
759 if (!member.IsAccessible (rc))
763 // With runtime binder we can have a situation where queried type is inaccessible
764 // because it came via dynamic object, the check about inconsisted accessibility
765 // had no effect as the type was unknown during compilation
768 // private class N { }
770 // public dynamic Foo ()
776 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
780 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
781 if (member is MethodSpec)
782 return new MethodGroupExpr (members, queried_type, loc);
784 if (!Invocation.IsMemberInvocable (member))
788 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
790 } else if (!errorMode && !member.IsNotCSharpCompatible) {
792 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
793 // T has both an effective base class other than object and a non-empty effective interface set.
795 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
797 var tps = queried_type as TypeParameterSpec;
798 if (tps != null && tps.HasTypeConstraint) {
799 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
802 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
808 ambig_non_method = member;
812 if (non_method != null) {
813 if (ambig_non_method != null && rc != null) {
814 var report = rc.Module.Compiler.Report;
815 report.SymbolRelatedToPreviousError (non_method);
816 report.SymbolRelatedToPreviousError (ambig_non_method);
817 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
818 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
821 if (non_method is MethodSpec)
822 return new MethodGroupExpr (members, queried_type, loc);
824 return ExprClassFromMemberInfo (non_method, loc);
827 if (members[0].DeclaringType.BaseType == null)
830 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
832 } while (members != null);
837 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
839 throw new NotImplementedException ();
842 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
844 if (t == InternalType.ErrorType)
847 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
848 oper, t.GetSignatureForError ());
851 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
853 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
857 /// Returns an expression that can be used to invoke operator true
858 /// on the expression if it exists.
860 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
862 return GetOperatorTrueOrFalse (ec, e, true, loc);
866 /// Returns an expression that can be used to invoke operator false
867 /// on the expression if it exists.
869 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
871 return GetOperatorTrueOrFalse (ec, e, false, loc);
874 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
876 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
877 var methods = MemberCache.GetUserOperator (e.type, op, false);
881 Arguments arguments = new Arguments (1);
882 arguments.Add (new Argument (e));
884 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
885 var oper = res.ResolveOperator (ec, ref arguments);
890 return new UserOperatorCall (oper, arguments, null, loc);
893 public virtual string ExprClassName
897 case ExprClass.Unresolved:
899 case ExprClass.Value:
901 case ExprClass.Variable:
903 case ExprClass.Namespace:
907 case ExprClass.MethodGroup:
908 return "method group";
909 case ExprClass.PropertyAccess:
910 return "property access";
911 case ExprClass.EventAccess:
912 return "event access";
913 case ExprClass.IndexerAccess:
914 return "indexer access";
915 case ExprClass.Nothing:
917 case ExprClass.TypeParameter:
918 return "type parameter";
920 throw new Exception ("Should not happen");
925 /// Reports that we were expecting `expr' to be of class `expected'
927 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
929 var name = memberExpr.GetSignatureForError ();
931 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
934 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
936 string [] valid = new string [4];
939 if ((flags & ResolveFlags.VariableOrValue) != 0) {
940 valid [count++] = "variable";
941 valid [count++] = "value";
944 if ((flags & ResolveFlags.Type) != 0)
945 valid [count++] = "type";
947 if ((flags & ResolveFlags.MethodGroup) != 0)
948 valid [count++] = "method group";
951 valid [count++] = "unknown";
953 StringBuilder sb = new StringBuilder (valid [0]);
954 for (int i = 1; i < count - 1; i++) {
956 sb.Append (valid [i]);
959 sb.Append ("' or `");
960 sb.Append (valid [count - 1]);
963 ec.Report.Error (119, loc,
964 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
967 public static void UnsafeError (ResolveContext ec, Location loc)
969 UnsafeError (ec.Report, loc);
972 public static void UnsafeError (Report Report, Location loc)
974 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
978 // Converts `source' to an int, uint, long or ulong.
980 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
982 var btypes = ec.BuiltinTypes;
984 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
985 Arguments args = new Arguments (1);
986 args.Add (new Argument (source));
987 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
990 Expression converted;
992 using (ec.Set (ResolveContext.Options.CheckedScope)) {
993 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
994 if (converted == null)
995 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
996 if (converted == null)
997 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
998 if (converted == null)
999 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1001 if (converted == null) {
1002 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1008 // Only positive constants are allowed at compile time
1010 Constant c = converted as Constant;
1011 if (c != null && c.IsNegative)
1012 Error_NegativeArrayIndex (ec, source.loc);
1014 // No conversion needed to array index
1015 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1018 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1022 // Derived classes implement this method by cloning the fields that
1023 // could become altered during the Resolve stage
1025 // Only expressions that are created for the parser need to implement
1028 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1030 throw new NotImplementedException (
1032 "CloneTo not implemented for expression {0}", this.GetType ()));
1036 // Clones an expression created by the parser.
1038 // We only support expressions created by the parser so far, not
1039 // expressions that have been resolved (many more classes would need
1040 // to implement CloneTo).
1042 // This infrastructure is here merely for Lambda expressions which
1043 // compile the same code using different type values for the same
1044 // arguments to find the correct overload
1046 public virtual Expression Clone (CloneContext clonectx)
1048 Expression cloned = (Expression) MemberwiseClone ();
1049 CloneTo (clonectx, cloned);
1055 // Implementation of expression to expression tree conversion
1057 public abstract Expression CreateExpressionTree (ResolveContext ec);
1059 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1061 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1064 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1066 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1069 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1071 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1074 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1076 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1080 return new TypeExpression (t, loc);
1084 // Implemented by all expressions which support conversion from
1085 // compiler expression to invokable runtime expression. Used by
1086 // dynamic C# binder.
1088 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1090 throw new NotImplementedException ("MakeExpression for " + GetType ());
1093 public virtual object Accept (StructuralVisitor visitor)
1095 return visitor.Visit (this);
1100 /// This is just a base class for expressions that can
1101 /// appear on statements (invocations, object creation,
1102 /// assignments, post/pre increment and decrement). The idea
1103 /// being that they would support an extra Emition interface that
1104 /// does not leave a result on the stack.
1106 public abstract class ExpressionStatement : Expression
1108 public ExpressionStatement ResolveStatement (BlockContext ec)
1110 Expression e = Resolve (ec);
1114 ExpressionStatement es = e as ExpressionStatement;
1116 Error_InvalidExpressionStatement (ec);
1119 // This is quite expensive warning, try to limit the damage
1121 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1122 WarningAsyncWithoutWait (ec, e);
1128 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1130 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1131 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1136 // Need to do full resolve because GetAwaiter can be extension method
1137 // available only in this context
1139 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1143 var arguments = new Arguments (0);
1144 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1149 // Use same check rules as for real await
1151 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1152 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1155 bc.Report.Warning (4014, 1, e.Location,
1156 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1160 var inv = e as Invocation;
1161 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1162 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1163 bc.Report.Warning (4014, 1, e.Location,
1164 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1170 /// Requests the expression to be emitted in a `statement'
1171 /// context. This means that no new value is left on the
1172 /// stack after invoking this method (constrasted with
1173 /// Emit that will always leave a value on the stack).
1175 public abstract void EmitStatement (EmitContext ec);
1177 public override void EmitSideEffect (EmitContext ec)
1184 /// This kind of cast is used to encapsulate the child
1185 /// whose type is child.Type into an expression that is
1186 /// reported to return "return_type". This is used to encapsulate
1187 /// expressions which have compatible types, but need to be dealt
1188 /// at higher levels with.
1190 /// For example, a "byte" expression could be encapsulated in one
1191 /// of these as an "unsigned int". The type for the expression
1192 /// would be "unsigned int".
1195 public abstract class TypeCast : Expression
1197 protected readonly Expression child;
1199 protected TypeCast (Expression child, TypeSpec return_type)
1201 eclass = child.eclass;
1202 loc = child.Location;
1207 public Expression Child {
1213 public override bool ContainsEmitWithAwait ()
1215 return child.ContainsEmitWithAwait ();
1218 public override Expression CreateExpressionTree (ResolveContext ec)
1220 Arguments args = new Arguments (2);
1221 args.Add (new Argument (child.CreateExpressionTree (ec)));
1222 args.Add (new Argument (new TypeOf (type, loc)));
1224 if (type.IsPointer || child.Type.IsPointer)
1225 Error_PointerInsideExpressionTree (ec);
1227 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1230 protected override Expression DoResolve (ResolveContext ec)
1232 // This should never be invoked, we are born in fully
1233 // initialized state.
1238 public override void Emit (EmitContext ec)
1243 public override SLE.Expression MakeExpression (BuilderContext ctx)
1246 return base.MakeExpression (ctx);
1248 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1249 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1250 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1254 protected override void CloneTo (CloneContext clonectx, Expression t)
1259 public override bool IsNull {
1260 get { return child.IsNull; }
1264 public class EmptyCast : TypeCast {
1265 EmptyCast (Expression child, TypeSpec target_type)
1266 : base (child, target_type)
1270 public static Expression Create (Expression child, TypeSpec type)
1272 Constant c = child as Constant;
1274 var enum_constant = c as EnumConstant;
1275 if (enum_constant != null)
1276 c = enum_constant.Child;
1278 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1282 var res = c.ConvertImplicitly (type);
1288 EmptyCast e = child as EmptyCast;
1290 return new EmptyCast (e.child, type);
1292 return new EmptyCast (child, type);
1295 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1297 child.EmitBranchable (ec, label, on_true);
1300 public override void EmitSideEffect (EmitContext ec)
1302 child.EmitSideEffect (ec);
1307 // Used for predefined type user operator (no obsolete check, etc.)
1309 public class OperatorCast : TypeCast
1311 readonly MethodSpec conversion_operator;
1313 public OperatorCast (Expression expr, TypeSpec target_type)
1314 : this (expr, target_type, target_type, false)
1318 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1319 : this (expr, target_type, target_type, find_explicit)
1323 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1324 : base (expr, returnType)
1326 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1327 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1330 foreach (MethodSpec oper in mi) {
1331 if (oper.ReturnType != returnType)
1334 if (oper.Parameters.Types[0] == expr.Type) {
1335 conversion_operator = oper;
1341 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1342 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1345 public override void Emit (EmitContext ec)
1348 ec.Emit (OpCodes.Call, conversion_operator);
1353 // Constant specialization of EmptyCast.
1354 // We need to special case this since an empty cast of
1355 // a constant is still a constant.
1357 public class EmptyConstantCast : Constant
1359 public readonly Constant child;
1361 public EmptyConstantCast (Constant child, TypeSpec type)
1362 : base (child.Location)
1365 throw new ArgumentNullException ("child");
1368 this.eclass = child.eclass;
1372 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1374 if (child.Type == target_type)
1377 // FIXME: check that 'type' can be converted to 'target_type' first
1378 return child.ConvertExplicitly (in_checked_context, target_type);
1381 public override Expression CreateExpressionTree (ResolveContext ec)
1383 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1384 child.CreateExpressionTree (ec),
1385 new TypeOf (type, loc));
1388 Error_PointerInsideExpressionTree (ec);
1390 return CreateExpressionFactoryCall (ec, "Convert", args);
1393 public override bool IsDefaultValue {
1394 get { return child.IsDefaultValue; }
1397 public override bool IsNegative {
1398 get { return child.IsNegative; }
1401 public override bool IsNull {
1402 get { return child.IsNull; }
1405 public override bool IsOneInteger {
1406 get { return child.IsOneInteger; }
1409 public override bool IsSideEffectFree {
1411 return child.IsSideEffectFree;
1415 public override bool IsZeroInteger {
1416 get { return child.IsZeroInteger; }
1419 public override void Emit (EmitContext ec)
1424 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1426 child.EmitBranchable (ec, label, on_true);
1428 // Only to make verifier happy
1429 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1430 ec.Emit (OpCodes.Unbox_Any, type);
1433 public override void EmitSideEffect (EmitContext ec)
1435 child.EmitSideEffect (ec);
1438 public override object GetValue ()
1440 return child.GetValue ();
1443 public override string GetValueAsLiteral ()
1445 return child.GetValueAsLiteral ();
1448 public override long GetValueAsLong ()
1450 return child.GetValueAsLong ();
1453 public override Constant ConvertImplicitly (TypeSpec target_type)
1455 if (type == target_type)
1458 // FIXME: Do we need to check user conversions?
1459 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1462 return child.ConvertImplicitly (target_type);
1467 /// This class is used to wrap literals which belong inside Enums
1469 public class EnumConstant : Constant
1471 public Constant Child;
1473 public EnumConstant (Constant child, TypeSpec enum_type)
1474 : base (child.Location)
1478 this.eclass = ExprClass.Value;
1479 this.type = enum_type;
1482 protected EnumConstant (Location loc)
1487 public override void Emit (EmitContext ec)
1492 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1494 Child.EncodeAttributeValue (rc, enc, Child.Type);
1497 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1499 Child.EmitBranchable (ec, label, on_true);
1502 public override void EmitSideEffect (EmitContext ec)
1504 Child.EmitSideEffect (ec);
1507 public override string GetSignatureForError()
1509 return Type.GetSignatureForError ();
1512 public override object GetValue ()
1514 return Child.GetValue ();
1518 public override object GetTypedValue ()
1521 // The method can be used in dynamic context only (on closed types)
1523 // System.Enum.ToObject cannot be called on dynamic types
1524 // EnumBuilder has to be used, but we cannot use EnumBuilder
1525 // because it does not properly support generics
1527 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1531 public override string GetValueAsLiteral ()
1533 return Child.GetValueAsLiteral ();
1536 public override long GetValueAsLong ()
1538 return Child.GetValueAsLong ();
1541 public EnumConstant Increment()
1543 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1546 public override bool IsDefaultValue {
1548 return Child.IsDefaultValue;
1552 public override bool IsSideEffectFree {
1554 return Child.IsSideEffectFree;
1558 public override bool IsZeroInteger {
1559 get { return Child.IsZeroInteger; }
1562 public override bool IsNegative {
1564 return Child.IsNegative;
1568 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1570 if (Child.Type == target_type)
1573 return Child.ConvertExplicitly (in_checked_context, target_type);
1576 public override Constant ConvertImplicitly (TypeSpec type)
1578 if (this.type == type) {
1582 if (!Convert.ImplicitStandardConversionExists (this, type)){
1586 return Child.ConvertImplicitly (type);
1591 /// This kind of cast is used to encapsulate Value Types in objects.
1593 /// The effect of it is to box the value type emitted by the previous
1596 public class BoxedCast : TypeCast {
1598 public BoxedCast (Expression expr, TypeSpec target_type)
1599 : base (expr, target_type)
1601 eclass = ExprClass.Value;
1604 protected override Expression DoResolve (ResolveContext ec)
1606 // This should never be invoked, we are born in fully
1607 // initialized state.
1612 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1614 // Only boxing to object type is supported
1615 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1616 base.EncodeAttributeValue (rc, enc, targetType);
1620 enc.Encode (child.Type);
1621 child.EncodeAttributeValue (rc, enc, child.Type);
1624 public override void Emit (EmitContext ec)
1628 ec.Emit (OpCodes.Box, child.Type);
1631 public override void EmitSideEffect (EmitContext ec)
1633 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1634 // so, we need to emit the box+pop instructions in most cases
1635 if (child.Type.IsStruct &&
1636 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1637 child.EmitSideEffect (ec);
1639 base.EmitSideEffect (ec);
1643 public class UnboxCast : TypeCast {
1644 public UnboxCast (Expression expr, TypeSpec return_type)
1645 : base (expr, return_type)
1649 protected override Expression DoResolve (ResolveContext ec)
1651 // This should never be invoked, we are born in fully
1652 // initialized state.
1657 public override void Emit (EmitContext ec)
1661 ec.Emit (OpCodes.Unbox_Any, type);
1666 /// This is used to perform explicit numeric conversions.
1668 /// Explicit numeric conversions might trigger exceptions in a checked
1669 /// context, so they should generate the conv.ovf opcodes instead of
1672 public class ConvCast : TypeCast {
1673 public enum Mode : byte {
1674 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1676 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1677 U2_I1, U2_U1, U2_I2, U2_CH,
1678 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1679 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1680 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1681 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1682 CH_I1, CH_U1, CH_I2,
1683 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1684 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1690 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1691 : base (child, return_type)
1696 protected override Expression DoResolve (ResolveContext ec)
1698 // This should never be invoked, we are born in fully
1699 // initialized state.
1704 public override string ToString ()
1706 return String.Format ("ConvCast ({0}, {1})", mode, child);
1709 public override void Emit (EmitContext ec)
1715 public static void Emit (EmitContext ec, Mode mode)
1717 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1719 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1720 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1721 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1722 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1723 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1725 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1726 case Mode.U1_CH: /* nothing */ break;
1728 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1729 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1730 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1731 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1732 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1733 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1735 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1736 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1737 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1738 case Mode.U2_CH: /* nothing */ break;
1740 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1741 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1742 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1743 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1744 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1745 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1746 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1748 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1749 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1750 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1751 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1752 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1753 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1755 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1756 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1757 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1758 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1759 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1760 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1761 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1762 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1763 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1765 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1766 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1767 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1768 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1769 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1770 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1771 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1772 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1773 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1775 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1776 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1777 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1779 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1780 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1781 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1782 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1783 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1784 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1785 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1786 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1787 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1789 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1790 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1791 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1792 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1793 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1794 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1795 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1796 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1797 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1798 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1800 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1804 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1805 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1806 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1807 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1808 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1810 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1811 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1813 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1814 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1815 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1816 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1817 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1818 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1820 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1821 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1822 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1823 case Mode.U2_CH: /* nothing */ break;
1825 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1826 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1827 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1828 case Mode.I4_U4: /* nothing */ break;
1829 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1830 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1831 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1833 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1834 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1835 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1836 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1837 case Mode.U4_I4: /* nothing */ break;
1838 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1840 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1841 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1842 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1843 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1844 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1845 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1846 case Mode.I8_U8: /* nothing */ break;
1847 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1848 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1850 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1851 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1852 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1853 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1854 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1855 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1856 case Mode.U8_I8: /* nothing */ break;
1857 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1858 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1860 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1861 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1862 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1864 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1865 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1866 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1867 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1868 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1869 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1870 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1871 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1872 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1874 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1875 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1876 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1877 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1878 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1879 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1880 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1881 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1882 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1883 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1885 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1891 class OpcodeCast : TypeCast
1895 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1896 : base (child, return_type)
1901 protected override Expression DoResolve (ResolveContext ec)
1903 // This should never be invoked, we are born in fully
1904 // initialized state.
1909 public override void Emit (EmitContext ec)
1915 public TypeSpec UnderlyingType {
1916 get { return child.Type; }
1921 // Opcode casts expression with 2 opcodes but only
1922 // single expression tree node
1924 class OpcodeCastDuplex : OpcodeCast
1926 readonly OpCode second;
1928 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1929 : base (child, returnType, first)
1931 this.second = second;
1934 public override void Emit (EmitContext ec)
1942 /// This kind of cast is used to encapsulate a child and cast it
1943 /// to the class requested
1945 public sealed class ClassCast : TypeCast {
1946 readonly bool forced;
1948 public ClassCast (Expression child, TypeSpec return_type)
1949 : base (child, return_type)
1953 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1954 : base (child, return_type)
1956 this.forced = forced;
1959 public override void Emit (EmitContext ec)
1963 bool gen = TypeManager.IsGenericParameter (child.Type);
1965 ec.Emit (OpCodes.Box, child.Type);
1967 if (type.IsGenericParameter) {
1968 ec.Emit (OpCodes.Unbox_Any, type);
1975 ec.Emit (OpCodes.Castclass, type);
1980 // Created during resolving pahse when an expression is wrapped or constantified
1981 // and original expression can be used later (e.g. for expression trees)
1983 public class ReducedExpression : Expression
1985 public sealed class ReducedConstantExpression : EmptyConstantCast
1987 readonly Expression orig_expr;
1989 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1990 : base (expr, expr.Type)
1992 this.orig_expr = orig_expr;
1995 public override Constant ConvertImplicitly (TypeSpec target_type)
1997 Constant c = base.ConvertImplicitly (target_type);
1999 c = new ReducedConstantExpression (c, orig_expr);
2004 public override Expression CreateExpressionTree (ResolveContext ec)
2006 return orig_expr.CreateExpressionTree (ec);
2009 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2011 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2013 c = new ReducedConstantExpression (c, orig_expr);
2017 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
2020 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2022 if (orig_expr is Conditional)
2023 child.EncodeAttributeValue (rc, enc, targetType);
2025 base.EncodeAttributeValue (rc, enc, targetType);
2029 sealed class ReducedExpressionStatement : ExpressionStatement
2031 readonly Expression orig_expr;
2032 readonly ExpressionStatement stm;
2034 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2036 this.orig_expr = orig;
2038 this.eclass = stm.eclass;
2039 this.type = stm.Type;
2041 this.loc = orig.Location;
2044 public override bool ContainsEmitWithAwait ()
2046 return stm.ContainsEmitWithAwait ();
2049 public override Expression CreateExpressionTree (ResolveContext ec)
2051 return orig_expr.CreateExpressionTree (ec);
2054 protected override Expression DoResolve (ResolveContext ec)
2059 public override void Emit (EmitContext ec)
2064 public override void EmitStatement (EmitContext ec)
2066 stm.EmitStatement (ec);
2070 readonly Expression expr, orig_expr;
2072 private ReducedExpression (Expression expr, Expression orig_expr)
2075 this.eclass = expr.eclass;
2076 this.type = expr.Type;
2077 this.orig_expr = orig_expr;
2078 this.loc = orig_expr.Location;
2083 public override bool IsSideEffectFree {
2085 return expr.IsSideEffectFree;
2089 public Expression OriginalExpression {
2097 public override bool ContainsEmitWithAwait ()
2099 return expr.ContainsEmitWithAwait ();
2103 // Creates fully resolved expression switcher
2105 public static Constant Create (Constant expr, Expression original_expr)
2107 if (expr.eclass == ExprClass.Unresolved)
2108 throw new ArgumentException ("Unresolved expression");
2110 return new ReducedConstantExpression (expr, original_expr);
2113 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2115 return new ReducedExpressionStatement (s, orig);
2118 public static Expression Create (Expression expr, Expression original_expr)
2120 return Create (expr, original_expr, true);
2124 // Creates unresolved reduce expression. The original expression has to be
2125 // already resolved. Created expression is constant based based on `expr'
2126 // value unless canBeConstant is used
2128 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2130 if (canBeConstant) {
2131 Constant c = expr as Constant;
2133 return Create (c, original_expr);
2136 ExpressionStatement s = expr as ExpressionStatement;
2138 return Create (s, original_expr);
2140 if (expr.eclass == ExprClass.Unresolved)
2141 throw new ArgumentException ("Unresolved expression");
2143 return new ReducedExpression (expr, original_expr);
2146 public override Expression CreateExpressionTree (ResolveContext ec)
2148 return orig_expr.CreateExpressionTree (ec);
2151 protected override Expression DoResolve (ResolveContext ec)
2156 public override void Emit (EmitContext ec)
2161 public override Expression EmitToField (EmitContext ec)
2163 return expr.EmitToField(ec);
2166 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2168 expr.EmitBranchable (ec, target, on_true);
2171 public override SLE.Expression MakeExpression (BuilderContext ctx)
2173 return orig_expr.MakeExpression (ctx);
2178 // Standard composite pattern
2180 public abstract class CompositeExpression : Expression
2182 protected Expression expr;
2184 protected CompositeExpression (Expression expr)
2187 this.loc = expr.Location;
2190 public override bool ContainsEmitWithAwait ()
2192 return expr.ContainsEmitWithAwait ();
2195 public override Expression CreateExpressionTree (ResolveContext rc)
2197 return expr.CreateExpressionTree (rc);
2200 public Expression Child {
2201 get { return expr; }
2204 protected override Expression DoResolve (ResolveContext rc)
2206 expr = expr.Resolve (rc);
2209 eclass = expr.eclass;
2215 public override void Emit (EmitContext ec)
2220 public override bool IsNull {
2221 get { return expr.IsNull; }
2226 // Base of expressions used only to narrow resolve flow
2228 public abstract class ShimExpression : Expression
2230 protected Expression expr;
2232 protected ShimExpression (Expression expr)
2237 public Expression Expr {
2243 protected override void CloneTo (CloneContext clonectx, Expression t)
2248 ShimExpression target = (ShimExpression) t;
2249 target.expr = expr.Clone (clonectx);
2252 public override bool ContainsEmitWithAwait ()
2254 return expr.ContainsEmitWithAwait ();
2257 public override Expression CreateExpressionTree (ResolveContext ec)
2259 throw new NotSupportedException ("ET");
2262 public override void Emit (EmitContext ec)
2264 throw new InternalErrorException ("Missing Resolve call");
2270 // Unresolved type name expressions
2272 public abstract class ATypeNameExpression : FullNamedExpression
2275 protected TypeArguments targs;
2277 protected ATypeNameExpression (string name, Location l)
2283 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2290 protected ATypeNameExpression (string name, int arity, Location l)
2291 : this (name, new UnboundTypeArguments (arity), l)
2297 protected int Arity {
2299 return targs == null ? 0 : targs.Count;
2303 public bool HasTypeArguments {
2305 return targs != null && !targs.IsEmpty;
2309 public string Name {
2318 public TypeArguments TypeArguments {
2326 public override bool Equals (object obj)
2328 ATypeNameExpression atne = obj as ATypeNameExpression;
2329 return atne != null && atne.Name == Name &&
2330 (targs == null || targs.Equals (atne.targs));
2333 public override int GetHashCode ()
2335 return Name.GetHashCode ();
2338 // TODO: Move it to MemberCore
2339 public static string GetMemberType (MemberCore mc)
2345 if (mc is FieldBase)
2347 if (mc is MethodCore)
2349 if (mc is EnumMember)
2357 public override string GetSignatureForError ()
2359 if (targs != null) {
2360 return Name + "<" + targs.GetSignatureForError () + ">";
2366 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2370 /// SimpleName expressions are formed of a single word and only happen at the beginning
2371 /// of a dotted-name.
2373 public class SimpleName : ATypeNameExpression
2375 public SimpleName (string name, Location l)
2380 public SimpleName (string name, TypeArguments args, Location l)
2381 : base (name, args, l)
2385 public SimpleName (string name, int arity, Location l)
2386 : base (name, arity, l)
2390 public SimpleName GetMethodGroup ()
2392 return new SimpleName (Name, targs, loc);
2395 protected override Expression DoResolve (ResolveContext rc)
2397 var e = SimpleNameResolve (rc, null, false);
2399 var fe = e as FieldExpr;
2401 fe.VerifyAssignedStructField (rc, null);
2407 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2409 return SimpleNameResolve (ec, right_side, false);
2412 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2414 if (ctx.CurrentType != null) {
2415 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2416 if (member != null) {
2417 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2422 var report = ctx.Module.Compiler.Report;
2424 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2425 if (retval != null) {
2426 report.SymbolRelatedToPreviousError (retval.Type);
2427 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2431 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2432 if (retval != null) {
2433 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2437 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2438 if (ns_candidates != null) {
2439 if (ctx is UsingAliasNamespace.AliasContext) {
2440 report.Error (246, loc,
2441 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2442 ns_candidates[0], Name);
2444 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2445 report.Error (246, loc,
2446 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2450 report.Error (246, loc,
2451 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2456 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2458 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2461 if (fne.Type != null && Arity > 0) {
2462 if (HasTypeArguments) {
2463 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2464 if (ct.ResolveAsType (mc) == null)
2470 return new GenericOpenTypeExpr (fne.Type, loc);
2474 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2476 if (!(fne is Namespace))
2480 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2481 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2482 mc.Module.Compiler.Report.Error (1980, Location,
2483 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2484 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2487 fne = new DynamicTypeExpr (loc);
2488 fne.ResolveAsType (mc);
2494 Error_TypeOrNamespaceNotFound (mc);
2498 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2500 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2503 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2505 int lookup_arity = Arity;
2506 bool errorMode = false;
2508 Block current_block = rc.CurrentBlock;
2509 INamedBlockVariable variable = null;
2510 bool variable_found = false;
2514 // Stage 1: binding to local variables or parameters
2516 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2518 if (current_block != null && lookup_arity == 0) {
2519 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2520 if (!variable.IsDeclared) {
2521 // We found local name in accessible block but it's not
2522 // initialized yet, maybe the user wanted to bind to something else
2524 variable_found = true;
2526 e = variable.CreateReferenceExpression (rc, loc);
2529 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2538 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2540 TypeSpec member_type = rc.CurrentType;
2541 for (; member_type != null; member_type = member_type.DeclaringType) {
2542 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2546 var me = e as MemberExpr;
2548 // The name matches a type, defer to ResolveAsTypeStep
2556 if (variable != null) {
2557 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2558 rc.Report.Error (844, loc,
2559 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2560 Name, me.GetSignatureForError ());
2564 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2565 // Leave it to overload resolution to report correct error
2567 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2568 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2571 // LAMESPEC: again, ignores InvocableOnly
2572 if (variable != null) {
2573 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2574 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2578 // MemberLookup does not check accessors availability, this is actually needed for properties only
2580 var pe = me as PropertyExpr;
2583 // Break as there is no other overload available anyway
2584 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2585 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2588 pe.Getter = pe.PropertyInfo.Get;
2590 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2593 pe.Setter = pe.PropertyInfo.Set;
2598 // TODO: It's used by EventExpr -> FieldExpr transformation only
2599 // TODO: Should go to MemberAccess
2600 me = me.ResolveMemberAccess (rc, null, null);
2604 me.SetTypeArguments (rc, targs);
2611 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2613 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2614 if (IsPossibleTypeOrNamespace (rc)) {
2615 if (variable != null) {
2616 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2617 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2620 return ResolveAsTypeOrNamespace (rc);
2625 if (variable_found) {
2626 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2629 var tparams = rc.CurrentTypeParameters;
2630 if (tparams != null) {
2631 if (tparams.Find (Name) != null) {
2632 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2637 var ct = rc.CurrentType;
2639 if (ct.MemberDefinition.TypeParametersCount > 0) {
2640 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2641 if (ctp.Name == Name) {
2642 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2648 ct = ct.DeclaringType;
2649 } while (ct != null);
2652 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2653 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2655 rc.Report.SymbolRelatedToPreviousError (e.Type);
2656 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2660 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2662 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2663 return ErrorExpression.Instance;
2667 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2669 if (e.Type.Arity != Arity) {
2670 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2674 if (e is TypeExpr) {
2675 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2680 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2683 return ErrorExpression.Instance;
2686 if (rc.Module.Evaluator != null) {
2687 var fi = rc.Module.Evaluator.LookupField (Name);
2689 return new FieldExpr (fi.Item1, loc);
2697 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2699 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2704 if (right_side != null) {
2705 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2706 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2710 e = e.ResolveLValue (ec, right_side);
2718 public override object Accept (StructuralVisitor visitor)
2720 return visitor.Visit (this);
2725 /// Represents a namespace or a type. The name of the class was inspired by
2726 /// section 10.8.1 (Fully Qualified Names).
2728 public abstract class FullNamedExpression : Expression
2730 protected override void CloneTo (CloneContext clonectx, Expression target)
2732 // Do nothing, most unresolved type expressions cannot be
2733 // resolved to different type
2736 public override bool ContainsEmitWithAwait ()
2741 public override Expression CreateExpressionTree (ResolveContext ec)
2743 throw new NotSupportedException ("ET");
2746 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2749 // This is used to resolve the expression as a type, a null
2750 // value will be returned if the expression is not a type
2753 public override TypeSpec ResolveAsType (IMemberContext mc)
2755 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2760 TypeExpr te = fne as TypeExpr;
2762 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2770 var dep = type.GetMissingDependencies ();
2772 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2775 if (type.Kind == MemberKind.Void) {
2776 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2780 // Obsolete checks cannot be done when resolving base context as they
2781 // require type dependencies to be set but we are in process of resolving them
2783 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2784 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2785 if (obsolete_attr != null && !mc.IsObsolete) {
2786 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2794 public override void Emit (EmitContext ec)
2796 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2797 GetSignatureForError ());
2802 /// Expression that evaluates to a type
2804 public abstract class TypeExpr : FullNamedExpression
2806 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2812 protected sealed override Expression DoResolve (ResolveContext ec)
2818 public override bool Equals (object obj)
2820 TypeExpr tobj = obj as TypeExpr;
2824 return Type == tobj.Type;
2827 public override int GetHashCode ()
2829 return Type.GetHashCode ();
2834 /// Fully resolved Expression that already evaluated to a type
2836 public class TypeExpression : TypeExpr
2838 public TypeExpression (TypeSpec t, Location l)
2841 eclass = ExprClass.Type;
2845 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2852 /// This class denotes an expression which evaluates to a member
2853 /// of a struct or a class.
2855 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2858 // An instance expression associated with this member, if it's a
2859 // non-static member
2861 public Expression InstanceExpression;
2864 /// The name of this member.
2866 public abstract string Name {
2871 // When base.member is used
2873 public bool IsBase {
2874 get { return InstanceExpression is BaseThis; }
2878 /// Whether this is an instance member.
2880 public abstract bool IsInstance {
2885 /// Whether this is a static member.
2887 public abstract bool IsStatic {
2891 public abstract string KindName {
2895 protected abstract TypeSpec DeclaringType {
2899 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2901 return InstanceExpression.Type;
2906 // Converts best base candidate for virtual method starting from QueriedBaseType
2908 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2911 // Only when base.member is used and method is virtual
2917 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2918 // means for base.member access we have to find the closest match after we found best candidate
2920 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2922 // The method could already be what we are looking for
2924 TypeSpec[] targs = null;
2925 if (method.DeclaringType != InstanceExpression.Type) {
2926 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2927 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2928 if (base_override.IsGeneric)
2929 targs = method.TypeArguments;
2931 method = base_override;
2936 // When base access is used inside anonymous method/iterator/etc we need to
2937 // get back to the context of original type. We do it by emiting proxy
2938 // method in original class and rewriting base call to this compiler
2939 // generated method call which does the actual base invocation. This may
2940 // introduce redundant storey but with `this' only but it's tricky to avoid
2941 // at this stage as we don't know what expressions follow base
2943 if (rc.CurrentAnonymousMethod != null) {
2944 if (targs == null && method.IsGeneric) {
2945 targs = method.TypeArguments;
2946 method = method.GetGenericMethodDefinition ();
2949 if (method.Parameters.HasArglist)
2950 throw new NotImplementedException ("__arglist base call proxy");
2952 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2954 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2955 // get/set member expressions second call would fail to proxy because left expression
2956 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2957 // FIXME: The async check is another hack but will probably fail with mutators
2958 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2959 InstanceExpression = new This (loc).Resolve (rc);
2963 method = method.MakeGenericMethod (rc, targs);
2967 // Only base will allow this invocation to happen.
2969 if (method.IsAbstract) {
2970 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2976 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2978 if (InstanceExpression == null)
2981 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2982 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2983 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2988 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2990 if (InstanceExpression == null)
2993 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2996 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2998 var ct = rc.CurrentType;
2999 if (ct == qualifier)
3002 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3005 qualifier = qualifier.GetDefinition ();
3006 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3013 public override bool ContainsEmitWithAwait ()
3015 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3018 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3021 type = type.GetDefinition ();
3023 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3026 type = type.DeclaringType;
3027 } while (type != null);
3032 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3034 if (InstanceExpression != null) {
3035 InstanceExpression = InstanceExpression.Resolve (rc);
3036 CheckProtectedMemberAccess (rc, member);
3039 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3040 UnsafeError (rc, loc);
3043 var dep = member.GetMissingDependencies ();
3045 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3048 if (!rc.IsObsolete) {
3049 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3051 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3054 if (!(member is FieldSpec))
3055 member.MemberDefinition.SetIsUsed ();
3058 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3060 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3063 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3065 rc.Report.SymbolRelatedToPreviousError (member);
3066 rc.Report.Error (1540, loc,
3067 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3068 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3071 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3073 if (!ResolveInstanceExpressionCore (rc, rhs))
3077 // Check intermediate value modification which won't have any effect
3079 if (rhs != null && InstanceExpression.Type.IsStruct &&
3080 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3082 if (rc.CurrentInitializerVariable != null) {
3083 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3084 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3086 rc.Report.Error (1612, loc,
3087 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3088 InstanceExpression.GetSignatureForError ());
3095 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3098 if (InstanceExpression != null) {
3099 if (InstanceExpression is TypeExpr) {
3100 var t = InstanceExpression.Type;
3102 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3103 if (oa != null && !rc.IsObsolete) {
3104 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3107 t = t.DeclaringType;
3108 } while (t != null);
3110 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3111 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3112 rc.Report.Error (176, loc,
3113 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3114 GetSignatureForError ());
3118 InstanceExpression = null;
3124 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3125 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3126 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3127 rc.Report.Error (236, loc,
3128 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3129 GetSignatureForError ());
3131 rc.Report.Error (120, loc,
3132 "An object reference is required to access non-static member `{0}'",
3133 GetSignatureForError ());
3135 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3139 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3140 rc.Report.Error (38, loc,
3141 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3142 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3145 InstanceExpression = new This (loc);
3146 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3147 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3148 InstanceExpression = InstanceExpression.Resolve (rc);
3151 InstanceExpression = InstanceExpression.Resolve (rc);
3157 var me = InstanceExpression as MemberExpr;
3159 me.ResolveInstanceExpressionCore (rc, rhs);
3161 // Using this check to detect probing instance expression resolve
3162 if (!rc.OmitStructFlowAnalysis) {
3163 var fe = me as FieldExpr;
3164 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3165 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3166 rc.Report.Warning (1690, 1, loc,
3167 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3168 me.GetSignatureForError ());
3176 // Run member-access postponed check once we know that
3177 // the expression is not field expression which is the only
3178 // expression which can use uninitialized this
3180 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3181 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3185 // Additional checks for l-value member access
3188 if (InstanceExpression is UnboxCast) {
3189 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3196 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3198 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3199 ec.Report.Warning (1720, 1, left.Location,
3200 "Expression will always cause a `{0}'", "System.NullReferenceException");
3203 InstanceExpression = left;
3207 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3209 TypeSpec instance_type = InstanceExpression.Type;
3210 if (TypeSpec.IsValueType (instance_type)) {
3211 if (InstanceExpression is IMemoryLocation) {
3212 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3214 // Cannot release the temporary variable when its address
3215 // is required to be on stack for any parent
3216 LocalTemporary t = new LocalTemporary (instance_type);
3217 InstanceExpression.Emit (ec);
3219 t.AddressOf (ec, AddressOp.Store);
3222 InstanceExpression.Emit (ec);
3224 // Only to make verifier happy
3225 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3226 ec.Emit (OpCodes.Box, instance_type);
3229 if (prepare_for_load)
3230 ec.Emit (OpCodes.Dup);
3233 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3236 public class ExtensionMethodCandidates
3238 readonly NamespaceContainer container;
3239 readonly IList<MethodSpec> methods;
3241 readonly IMemberContext context;
3243 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3245 this.context = context;
3246 this.methods = methods;
3247 this.container = nsContainer;
3248 this.index = lookupIndex;
3251 public NamespaceContainer Container {
3257 public IMemberContext Context {
3263 public int LookupIndex {
3269 public IList<MethodSpec> Methods {
3277 // Represents a group of extension method candidates for whole namespace
3279 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3281 ExtensionMethodCandidates candidates;
3282 public Expression ExtensionExpression;
3284 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3285 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3287 this.candidates = candidates;
3288 this.ExtensionExpression = extensionExpr;
3291 public override bool IsStatic {
3292 get { return true; }
3296 // For extension methodgroup we are not looking for base members but parent
3297 // namespace extension methods
3299 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3301 // TODO: candidates are null only when doing error reporting, that's
3302 // incorrect. We have to discover same extension methods in error mode
3303 if (candidates == null)
3306 int arity = type_arguments == null ? 0 : type_arguments.Count;
3308 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3309 if (candidates == null)
3312 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3315 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3317 // We are already here
3321 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3323 if (arguments == null)
3324 arguments = new Arguments (1);
3326 ExtensionExpression = ExtensionExpression.Resolve (ec);
3327 if (ExtensionExpression == null)
3330 var cand = candidates;
3331 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3332 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3334 // Restore candidates in case we are running in probing mode
3337 // Store resolved argument and restore original arguments
3339 // Clean-up modified arguments for error reporting
3340 arguments.RemoveAt (0);
3344 var me = ExtensionExpression as MemberExpr;
3346 me.ResolveInstanceExpression (ec, null);
3347 var fe = me as FieldExpr;
3349 fe.Spec.MemberDefinition.SetIsUsed ();
3352 InstanceExpression = null;
3356 #region IErrorHandler Members
3358 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3363 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3365 rc.Report.SymbolRelatedToPreviousError (best);
3366 rc.Report.Error (1928, loc,
3367 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3368 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3371 rc.Report.Error (1929, loc,
3372 "Extension method instance type `{0}' cannot be converted to `{1}'",
3373 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3379 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3384 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3393 /// MethodGroupExpr represents a group of method candidates which
3394 /// can be resolved to the best method overload
3396 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3398 protected IList<MemberSpec> Methods;
3399 MethodSpec best_candidate;
3400 TypeSpec best_candidate_return;
3401 protected TypeArguments type_arguments;
3403 SimpleName simple_name;
3404 protected TypeSpec queried_type;
3406 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3410 this.type = InternalType.MethodGroup;
3412 eclass = ExprClass.MethodGroup;
3413 queried_type = type;
3416 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3417 : this (new MemberSpec[] { m }, type, loc)
3423 public MethodSpec BestCandidate {
3425 return best_candidate;
3429 public TypeSpec BestCandidateReturnType {
3431 return best_candidate_return;
3435 public IList<MemberSpec> Candidates {
3441 protected override TypeSpec DeclaringType {
3443 return queried_type;
3447 public override bool IsInstance {
3449 if (best_candidate != null)
3450 return !best_candidate.IsStatic;
3456 public override bool IsStatic {
3458 if (best_candidate != null)
3459 return best_candidate.IsStatic;
3465 public override string KindName {
3466 get { return "method"; }
3469 public override string Name {
3471 if (best_candidate != null)
3472 return best_candidate.Name;
3475 return Methods.First ().Name;
3482 // When best candidate is already know this factory can be used
3483 // to avoid expensive overload resolution to be called
3485 // NOTE: InstanceExpression has to be set manually
3487 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3489 return new MethodGroupExpr (best, queriedType, loc) {
3490 best_candidate = best,
3491 best_candidate_return = best.ReturnType
3495 public override string GetSignatureForError ()
3497 if (best_candidate != null)
3498 return best_candidate.GetSignatureForError ();
3500 return Methods.First ().GetSignatureForError ();
3503 public override Expression CreateExpressionTree (ResolveContext ec)
3505 if (best_candidate == null) {
3506 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3510 if (best_candidate.IsConditionallyExcluded (ec, loc))
3511 ec.Report.Error (765, loc,
3512 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3514 return new TypeOfMethod (best_candidate, loc);
3517 protected override Expression DoResolve (ResolveContext ec)
3519 this.eclass = ExprClass.MethodGroup;
3521 if (InstanceExpression != null) {
3522 InstanceExpression = InstanceExpression.Resolve (ec);
3523 if (InstanceExpression == null)
3530 public override void Emit (EmitContext ec)
3532 throw new NotSupportedException ();
3535 public void EmitCall (EmitContext ec, Arguments arguments)
3537 var call = new CallEmitter ();
3538 call.InstanceExpression = InstanceExpression;
3539 call.Emit (ec, best_candidate, arguments, loc);
3542 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3544 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3545 Name, target.GetSignatureForError ());
3548 public static bool IsExtensionMethodArgument (Expression expr)
3551 // LAMESPEC: No details about which expressions are not allowed
3553 return !(expr is TypeExpr) && !(expr is BaseThis);
3557 /// Find the Applicable Function Members (7.4.2.1)
3559 /// me: Method Group expression with the members to select.
3560 /// it might contain constructors or methods (or anything
3561 /// that maps to a method).
3563 /// Arguments: ArrayList containing resolved Argument objects.
3565 /// loc: The location if we want an error to be reported, or a Null
3566 /// location for "probing" purposes.
3568 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3569 /// that is the best match of me on Arguments.
3572 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3574 // TODO: causes issues with probing mode, remove explicit Kind check
3575 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3578 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3579 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3580 r.BaseMembersProvider = this;
3581 r.InstanceQualifier = this;
3584 if (cerrors != null)
3585 r.CustomErrors = cerrors;
3587 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3588 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3589 if (best_candidate == null)
3590 return r.BestCandidateIsDynamic ? this : null;
3592 // Overload resolver had to create a new method group, all checks bellow have already been executed
3593 if (r.BestCandidateNewMethodGroup != null)
3594 return r.BestCandidateNewMethodGroup;
3596 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3597 if (InstanceExpression != null) {
3598 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3599 InstanceExpression = null;
3601 if (best_candidate.IsStatic && simple_name != null) {
3602 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3605 InstanceExpression.Resolve (ec);
3609 ResolveInstanceExpression (ec, null);
3612 var base_override = CandidateToBaseOverride (ec, best_candidate);
3613 if (base_override == best_candidate) {
3614 best_candidate_return = r.BestCandidateReturnType;
3616 best_candidate = base_override;
3617 best_candidate_return = best_candidate.ReturnType;
3620 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3621 ConstraintChecker cc = new ConstraintChecker (ec);
3622 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3626 // Additional check for possible imported base override method which
3627 // could not be done during IsOverrideMethodBaseTypeAccessible
3629 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3630 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3631 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3632 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3638 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3640 var fe = left as FieldExpr;
3643 // Using method-group on struct fields makes the struct assigned. I am not sure
3644 // why but that's what .net does
3646 fe.Spec.MemberDefinition.SetIsAssigned ();
3649 simple_name = original;
3650 return base.ResolveMemberAccess (ec, left, original);
3653 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3655 type_arguments = ta;
3658 #region IBaseMembersProvider Members
3660 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3662 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3665 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3667 if (queried_type == member.DeclaringType)
3670 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3671 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3675 // Extension methods lookup after ordinary methods candidates failed to apply
3677 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3679 if (InstanceExpression == null)
3682 InstanceExpression = InstanceExpression.Resolve (rc);
3683 if (!IsExtensionMethodArgument (InstanceExpression))
3686 int arity = type_arguments == null ? 0 : type_arguments.Count;
3687 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3688 if (methods == null)
3691 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3692 emg.SetTypeArguments (rc, type_arguments);
3699 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3701 public ConstructorInstanceQualifier (TypeSpec type)
3704 InstanceType = type;
3707 public TypeSpec InstanceType { get; private set; }
3709 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3711 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3715 public struct OverloadResolver
3718 public enum Restrictions
3722 ProbingOnly = 1 << 1,
3723 CovariantDelegate = 1 << 2,
3724 NoBaseMembers = 1 << 3,
3725 BaseMembersIncluded = 1 << 4
3728 public interface IBaseMembersProvider
3730 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3731 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3732 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3735 public interface IErrorHandler
3737 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3738 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3739 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3740 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3743 public interface IInstanceQualifier
3745 TypeSpec InstanceType { get; }
3746 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3749 sealed class NoBaseMembers : IBaseMembersProvider
3751 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3753 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3758 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3763 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3769 struct AmbiguousCandidate
3771 public readonly MemberSpec Member;
3772 public readonly bool Expanded;
3773 public readonly AParametersCollection Parameters;
3775 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3778 Parameters = parameters;
3779 Expanded = expanded;
3784 IList<MemberSpec> members;
3785 TypeArguments type_arguments;
3786 IBaseMembersProvider base_provider;
3787 IErrorHandler custom_errors;
3788 IInstanceQualifier instance_qualifier;
3789 Restrictions restrictions;
3790 MethodGroupExpr best_candidate_extension_group;
3791 TypeSpec best_candidate_return_type;
3793 SessionReportPrinter lambda_conv_msgs;
3795 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3796 : this (members, null, restrictions, loc)
3800 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3803 if (members == null || members.Count == 0)
3804 throw new ArgumentException ("empty members set");
3806 this.members = members;
3808 type_arguments = targs;
3809 this.restrictions = restrictions;
3810 if (IsDelegateInvoke)
3811 this.restrictions |= Restrictions.NoBaseMembers;
3813 base_provider = NoBaseMembers.Instance;
3818 public IBaseMembersProvider BaseMembersProvider {
3820 return base_provider;
3823 base_provider = value;
3827 public bool BestCandidateIsDynamic { get; set; }
3830 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3832 public MethodGroupExpr BestCandidateNewMethodGroup {
3834 return best_candidate_extension_group;
3839 // Return type can be different between best candidate and closest override
3841 public TypeSpec BestCandidateReturnType {
3843 return best_candidate_return_type;
3847 public IErrorHandler CustomErrors {
3849 return custom_errors;
3852 custom_errors = value;
3856 TypeSpec DelegateType {
3858 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3859 throw new InternalErrorException ("Not running in delegate mode", loc);
3861 return members [0].DeclaringType;
3865 public IInstanceQualifier InstanceQualifier {
3867 return instance_qualifier;
3870 instance_qualifier = value;
3874 bool IsProbingOnly {
3876 return (restrictions & Restrictions.ProbingOnly) != 0;
3880 bool IsDelegateInvoke {
3882 return (restrictions & Restrictions.DelegateInvoke) != 0;
3889 // 7.4.3.3 Better conversion from expression
3890 // Returns : 1 if a->p is better,
3891 // 2 if a->q is better,
3892 // 0 if neither is better
3894 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3896 TypeSpec argument_type = a.Type;
3899 // If argument is an anonymous function
3901 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3903 // p and q are delegate types or expression tree types
3905 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3906 if (q.MemberDefinition != p.MemberDefinition) {
3911 // Uwrap delegate from Expression<T>
3913 q = TypeManager.GetTypeArguments (q)[0];
3914 p = TypeManager.GetTypeArguments (p)[0];
3917 var p_m = Delegate.GetInvokeMethod (p);
3918 var q_m = Delegate.GetInvokeMethod (q);
3921 // With identical parameter lists
3923 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3932 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3934 if (p.Kind == MemberKind.Void) {
3935 return q.Kind != MemberKind.Void ? 2 : 0;
3939 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3941 if (q.Kind == MemberKind.Void) {
3942 return p.Kind != MemberKind.Void ? 1: 0;
3945 var am = (AnonymousMethodExpression) a.Expr;
3948 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3949 // better conversion is performed between underlying types Y1 and Y2
3951 if (p.IsGenericTask || q.IsGenericTask) {
3952 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3953 q = q.TypeArguments[0];
3954 p = p.TypeArguments[0];
3956 } else if (q != p) {
3958 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3960 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3961 var am_rt = am.InferReturnType (ec, null, orig_q);
3962 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3964 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3965 var am_rt = am.InferReturnType (ec, null, orig_p);
3966 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3972 // The parameters are identicial and return type is not void, use better type conversion
3973 // on return type to determine better one
3976 if (argument_type == p)
3979 if (argument_type == q)
3983 return BetterTypeConversion (ec, p, q);
3987 // 7.4.3.4 Better conversion from type
3989 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3991 if (p == null || q == null)
3992 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3994 switch (p.BuiltinType) {
3995 case BuiltinTypeSpec.Type.Int:
3996 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3999 case BuiltinTypeSpec.Type.Long:
4000 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4003 case BuiltinTypeSpec.Type.SByte:
4004 switch (q.BuiltinType) {
4005 case BuiltinTypeSpec.Type.Byte:
4006 case BuiltinTypeSpec.Type.UShort:
4007 case BuiltinTypeSpec.Type.UInt:
4008 case BuiltinTypeSpec.Type.ULong:
4012 case BuiltinTypeSpec.Type.Short:
4013 switch (q.BuiltinType) {
4014 case BuiltinTypeSpec.Type.UShort:
4015 case BuiltinTypeSpec.Type.UInt:
4016 case BuiltinTypeSpec.Type.ULong:
4020 case BuiltinTypeSpec.Type.Dynamic:
4021 // Dynamic is never better
4025 switch (q.BuiltinType) {
4026 case BuiltinTypeSpec.Type.Int:
4027 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4030 case BuiltinTypeSpec.Type.Long:
4031 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4034 case BuiltinTypeSpec.Type.SByte:
4035 switch (p.BuiltinType) {
4036 case BuiltinTypeSpec.Type.Byte:
4037 case BuiltinTypeSpec.Type.UShort:
4038 case BuiltinTypeSpec.Type.UInt:
4039 case BuiltinTypeSpec.Type.ULong:
4043 case BuiltinTypeSpec.Type.Short:
4044 switch (p.BuiltinType) {
4045 case BuiltinTypeSpec.Type.UShort:
4046 case BuiltinTypeSpec.Type.UInt:
4047 case BuiltinTypeSpec.Type.ULong:
4051 case BuiltinTypeSpec.Type.Dynamic:
4052 // Dynamic is never better
4056 // FIXME: handle lifted operators
4058 // TODO: this is expensive
4059 Expression p_tmp = new EmptyExpression (p);
4060 Expression q_tmp = new EmptyExpression (q);
4062 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4063 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4065 if (p_to_q && !q_to_p)
4068 if (q_to_p && !p_to_q)
4075 /// Determines "Better function" between candidate
4076 /// and the current best match
4079 /// Returns a boolean indicating :
4080 /// false if candidate ain't better
4081 /// true if candidate is better than the current best match
4083 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4084 MemberSpec best, AParametersCollection bparam, bool best_params)
4086 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4087 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4089 bool better_at_least_one = false;
4091 int args_count = args == null ? 0 : args.Count;
4095 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4098 // Default arguments are ignored for better decision
4099 if (a.IsDefaultArgument)
4103 // When comparing named argument the parameter type index has to be looked up
4104 // in original parameter set (override version for virtual members)
4106 NamedArgument na = a as NamedArgument;
4108 int idx = cparam.GetParameterIndexByName (na.Name);
4109 ct = candidate_pd.Types[idx];
4110 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4111 ct = TypeManager.GetElementType (ct);
4113 idx = bparam.GetParameterIndexByName (na.Name);
4114 bt = best_pd.Types[idx];
4115 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4116 bt = TypeManager.GetElementType (bt);
4118 ct = candidate_pd.Types[c_idx];
4119 bt = best_pd.Types[b_idx];
4121 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4122 ct = TypeManager.GetElementType (ct);
4126 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4127 bt = TypeManager.GetElementType (bt);
4132 if (TypeSpecComparer.IsEqual (ct, bt))
4136 int result = BetterExpressionConversion (ec, a, ct, bt);
4138 // for each argument, the conversion to 'ct' should be no worse than
4139 // the conversion to 'bt'.
4143 // for at least one argument, the conversion to 'ct' should be better than
4144 // the conversion to 'bt'.
4146 better_at_least_one = true;
4149 if (better_at_least_one)
4153 // This handles the case
4155 // Add (float f1, float f2, float f3);
4156 // Add (params decimal [] foo);
4158 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4159 // first candidate would've chosen as better.
4161 if (!same && !a.IsDefaultArgument)
4165 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4169 // This handles the following cases:
4171 // Foo (int i) is better than Foo (int i, long l = 0)
4172 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4173 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4175 // Prefer non-optional version
4177 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4179 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4180 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4183 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4186 return candidate_pd.Count >= best_pd.Count;
4190 // One is a non-generic method and second is a generic method, then non-generic is better
4192 if (best.IsGeneric != candidate.IsGeneric)
4193 return best.IsGeneric;
4196 // This handles the following cases:
4198 // Trim () is better than Trim (params char[] chars)
4199 // Concat (string s1, string s2, string s3) is better than
4200 // Concat (string s1, params string [] srest)
4201 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4203 // Prefer non-expanded version
4205 if (candidate_params != best_params)
4208 int candidate_param_count = candidate_pd.Count;
4209 int best_param_count = best_pd.Count;
4211 if (candidate_param_count != best_param_count)
4212 // can only happen if (candidate_params && best_params)
4213 return candidate_param_count > best_param_count && best_pd.HasParams;
4216 // Both methods have the same number of parameters, and the parameters have equal types
4217 // Pick the "more specific" signature using rules over original (non-inflated) types
4219 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4220 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4222 bool specific_at_least_once = false;
4223 for (j = 0; j < args_count; ++j) {
4224 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4226 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4227 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4229 ct = candidate_def_pd.Types[j];
4230 bt = best_def_pd.Types[j];
4235 TypeSpec specific = MoreSpecific (ct, bt);
4239 specific_at_least_once = true;
4242 if (specific_at_least_once)
4248 static bool CheckInflatedArguments (MethodSpec ms)
4250 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4253 // Setup constraint checker for probing only
4254 ConstraintChecker cc = new ConstraintChecker (null);
4256 var mp = ms.Parameters.Types;
4257 for (int i = 0; i < mp.Length; ++i) {
4258 var type = mp[i] as InflatedTypeSpec;
4262 var targs = type.TypeArguments;
4263 if (targs.Length == 0)
4266 // TODO: Checking inflated MVAR arguments should be enough
4267 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4274 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4276 rc.Report.Error (1729, loc,
4277 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4278 type.GetSignatureForError (), argCount.ToString ());
4282 // Determines if the candidate method is applicable to the given set of arguments
4283 // There could be two different set of parameters for same candidate where one
4284 // is the closest override for default values and named arguments checks and second
4285 // one being the virtual base for the parameter types and modifiers.
4287 // A return value rates candidate method compatibility,
4288 // 0 = the best, int.MaxValue = the worst
4291 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)
4293 // Parameters of most-derived type used mainly for named and optional parameters
4294 var pd = pm.Parameters;
4296 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4297 // params modifier instead of most-derived type
4298 var cpd = ((IParametersMember) candidate).Parameters;
4299 int param_count = pd.Count;
4300 int optional_count = 0;
4302 Arguments orig_args = arguments;
4304 if (arg_count != param_count) {
4306 // No arguments expansion when doing exact match for delegates
4308 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4309 for (int i = 0; i < pd.Count; ++i) {
4310 if (pd.FixedParameters[i].HasDefaultValue) {
4311 optional_count = pd.Count - i;
4317 if (optional_count != 0) {
4318 // Readjust expected number when params used
4319 if (cpd.HasParams) {
4321 if (arg_count < param_count)
4323 } else if (arg_count > param_count) {
4324 int args_gap = System.Math.Abs (arg_count - param_count);
4325 return int.MaxValue - 10000 + args_gap;
4326 } else if (arg_count < param_count - optional_count) {
4327 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4328 return int.MaxValue - 10000 + args_gap;
4330 } else if (arg_count != param_count) {
4331 int args_gap = System.Math.Abs (arg_count - param_count);
4333 return int.MaxValue - 10000 + args_gap;
4334 if (arg_count < param_count - 1)
4335 return int.MaxValue - 10000 + args_gap;
4338 // Resize to fit optional arguments
4339 if (optional_count != 0) {
4340 if (arguments == null) {
4341 arguments = new Arguments (optional_count);
4343 // Have to create a new container, so the next run can do same
4344 var resized = new Arguments (param_count);
4345 resized.AddRange (arguments);
4346 arguments = resized;
4349 for (int i = arg_count; i < param_count; ++i)
4350 arguments.Add (null);
4354 if (arg_count > 0) {
4356 // Shuffle named arguments to the right positions if there are any
4358 if (arguments[arg_count - 1] is NamedArgument) {
4359 arg_count = arguments.Count;
4361 for (int i = 0; i < arg_count; ++i) {
4362 bool arg_moved = false;
4364 NamedArgument na = arguments[i] as NamedArgument;
4368 int index = pd.GetParameterIndexByName (na.Name);
4370 // Named parameter not found
4374 // already reordered
4379 if (index >= param_count) {
4380 // When using parameters which should not be available to the user
4381 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4384 arguments.Add (null);
4388 temp = arguments[index];
4390 // The slot has been taken by positional argument
4391 if (temp != null && !(temp is NamedArgument))
4396 arguments = arguments.MarkOrderedArgument (na);
4400 arguments[index] = arguments[i];
4401 arguments[i] = temp;
4408 arg_count = arguments.Count;
4410 } else if (arguments != null) {
4411 arg_count = arguments.Count;
4415 // Don't do any expensive checks when the candidate cannot succeed
4417 if (arg_count != param_count && !cpd.HasParams)
4418 return (param_count - arg_count) * 2 + 1;
4420 var dep = candidate.GetMissingDependencies ();
4422 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4427 // 1. Handle generic method using type arguments when specified or type inference
4430 var ms = candidate as MethodSpec;
4431 if (ms != null && ms.IsGeneric) {
4432 if (type_arguments != null) {
4433 var g_args_count = ms.Arity;
4434 if (g_args_count != type_arguments.Count)
4435 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4437 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4440 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4441 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4442 // candidate was found use the set to report more details about what was wrong with lambda body.
4443 // The general idea is to distinguish between code errors and errors caused by
4444 // trial-and-error type inference
4446 if (lambda_conv_msgs == null) {
4447 for (int i = 0; i < arg_count; i++) {
4448 Argument a = arguments[i];
4452 var am = a.Expr as AnonymousMethodExpression;
4454 if (lambda_conv_msgs == null)
4455 lambda_conv_msgs = new SessionReportPrinter ();
4457 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4462 var ti = new TypeInference (arguments);
4463 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4466 return ti.InferenceScore - 20000;
4469 // Clear any error messages when the result was success
4471 if (lambda_conv_msgs != null)
4472 lambda_conv_msgs.ClearSession ();
4474 if (i_args.Length != 0) {
4475 ms = ms.MakeGenericMethod (ec, i_args);
4480 // Type arguments constraints have to match for the method to be applicable
4482 if (!CheckInflatedArguments (ms)) {
4484 return int.MaxValue - 25000;
4488 // We have a generic return type and at same time the method is override which
4489 // means we have to also inflate override return type in case the candidate is
4490 // best candidate and override return type is different to base return type.
4492 // virtual Foo<T, object> with override Foo<T, dynamic>
4494 if (candidate != pm) {
4495 MethodSpec override_ms = (MethodSpec) pm;
4496 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4497 returnType = inflator.Inflate (returnType);
4499 returnType = ms.ReturnType;
4506 if (type_arguments != null)
4507 return int.MaxValue - 15000;
4513 // 2. Each argument has to be implicitly convertible to method parameter
4515 Parameter.Modifier p_mod = 0;
4518 for (int i = 0; i < arg_count; i++) {
4519 Argument a = arguments[i];
4521 var fp = pd.FixedParameters[i];
4522 if (!fp.HasDefaultValue) {
4523 arguments = orig_args;
4524 return arg_count * 2 + 2;
4528 // Get the default value expression, we can use the same expression
4529 // if the type matches
4531 Expression e = fp.DefaultValue;
4533 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4535 // Restore for possible error reporting
4536 for (int ii = i; ii < arg_count; ++ii)
4537 arguments.RemoveAt (i);
4539 return (arg_count - i) * 2 + 1;
4543 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4545 // LAMESPEC: Attributes can be mixed together with build-in priority
4547 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4548 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4549 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4550 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4551 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4552 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4556 arguments[i] = new Argument (e, Argument.AType.Default);
4560 if (p_mod != Parameter.Modifier.PARAMS) {
4561 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4563 } else if (!params_expanded_form) {
4564 params_expanded_form = true;
4565 pt = ((ElementTypeSpec) pt).Element;
4571 if (!params_expanded_form) {
4572 if (a.ArgType == Argument.AType.ExtensionType) {
4574 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4576 // LAMESPEC: or implicit type parameter conversion
4579 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4580 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4581 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4586 score = IsArgumentCompatible (ec, a, p_mod, pt);
4589 dynamicArgument = true;
4594 // It can be applicable in expanded form (when not doing exact match like for delegates)
4596 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4597 if (!params_expanded_form) {
4598 pt = ((ElementTypeSpec) pt).Element;
4602 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4605 params_expanded_form = true;
4606 dynamicArgument = true;
4607 } else if (score == 0 || arg_count > pd.Count) {
4608 params_expanded_form = true;
4613 if (params_expanded_form)
4615 return (arg_count - i) * 2 + score;
4620 // When params parameter has no argument it will be provided later if the method is the best candidate
4622 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4623 params_expanded_form = true;
4626 // Restore original arguments for dynamic binder to keep the intention of original source code
4628 if (dynamicArgument)
4629 arguments = orig_args;
4634 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4636 if (e is Constant && e.Type == ptype)
4640 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4642 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4643 e = new MemberAccess (new MemberAccess (new MemberAccess (
4644 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4645 } else if (e is Constant) {
4647 // Handles int to int? conversions, DefaultParameterValue check
4649 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4653 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4656 return e.Resolve (ec);
4660 // Tests argument compatibility with the parameter
4661 // The possible return values are
4663 // 1 - modifier mismatch
4664 // 2 - type mismatch
4665 // -1 - dynamic binding required
4667 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4670 // Types have to be identical when ref or out modifer
4671 // is used and argument is not of dynamic type
4673 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4674 if (argument.Type != parameter) {
4676 // Do full equality check after quick path
4678 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4680 // Using dynamic for ref/out parameter can still succeed at runtime
4682 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4689 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4691 // Using dynamic for ref/out parameter can still succeed at runtime
4693 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4700 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4704 // Use implicit conversion in all modes to return same candidates when the expression
4705 // is used as argument or delegate conversion
4707 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4715 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4717 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4719 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4722 var ac_p = p as ArrayContainer;
4724 var ac_q = q as ArrayContainer;
4728 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4729 if (specific == ac_p.Element)
4731 if (specific == ac_q.Element)
4733 } else if (p.IsGeneric && q.IsGeneric) {
4734 var pargs = TypeManager.GetTypeArguments (p);
4735 var qargs = TypeManager.GetTypeArguments (q);
4737 bool p_specific_at_least_once = false;
4738 bool q_specific_at_least_once = false;
4740 for (int i = 0; i < pargs.Length; i++) {
4741 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4742 if (specific == pargs[i])
4743 p_specific_at_least_once = true;
4744 if (specific == qargs[i])
4745 q_specific_at_least_once = true;
4748 if (p_specific_at_least_once && !q_specific_at_least_once)
4750 if (!p_specific_at_least_once && q_specific_at_least_once)
4758 // Find the best method from candidate list
4760 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4762 List<AmbiguousCandidate> ambiguous_candidates = null;
4764 MemberSpec best_candidate;
4765 Arguments best_candidate_args = null;
4766 bool best_candidate_params = false;
4767 bool best_candidate_dynamic = false;
4768 int best_candidate_rate;
4769 IParametersMember best_parameter_member = null;
4771 int args_count = args != null ? args.Count : 0;
4773 Arguments candidate_args = args;
4774 bool error_mode = false;
4775 MemberSpec invocable_member = null;
4778 best_candidate = null;
4779 best_candidate_rate = int.MaxValue;
4781 var type_members = members;
4783 for (int i = 0; i < type_members.Count; ++i) {
4784 var member = type_members[i];
4787 // Methods in a base class are not candidates if any method in a derived
4788 // class is applicable
4790 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4794 if (!member.IsAccessible (rc))
4797 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4800 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4801 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4806 IParametersMember pm = member as IParametersMember;
4809 // Will use it later to report ambiguity between best method and invocable member
4811 if (Invocation.IsMemberInvocable (member))
4812 invocable_member = member;
4818 // Overload resolution is looking for base member but using parameter names
4819 // and default values from the closest member. That means to do expensive lookup
4820 // for the closest override for virtual or abstract members
4822 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4823 var override_params = base_provider.GetOverrideMemberParameters (member);
4824 if (override_params != null)
4825 pm = override_params;
4829 // Check if the member candidate is applicable
4831 bool params_expanded_form = false;
4832 bool dynamic_argument = false;
4833 TypeSpec rt = pm.MemberType;
4834 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4836 if (lambda_conv_msgs != null)
4837 lambda_conv_msgs.EndSession ();
4840 // How does it score compare to others
4842 if (candidate_rate < best_candidate_rate) {
4844 // Fatal error (missing dependency), cannot continue
4845 if (candidate_rate < 0)
4848 best_candidate_rate = candidate_rate;
4849 best_candidate = member;
4850 best_candidate_args = candidate_args;
4851 best_candidate_params = params_expanded_form;
4852 best_candidate_dynamic = dynamic_argument;
4853 best_parameter_member = pm;
4854 best_candidate_return_type = rt;
4855 } else if (candidate_rate == 0) {
4857 // The member look is done per type for most operations but sometimes
4858 // it's not possible like for binary operators overload because they
4859 // are unioned between 2 sides
4861 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4862 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4867 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4869 // We pack all interface members into top level type which makes the overload resolution
4870 // more complicated for interfaces. We compensate it by removing methods with same
4871 // signature when building the cache hence this path should not really be hit often
4874 // interface IA { void Foo (int arg); }
4875 // interface IB : IA { void Foo (params int[] args); }
4877 // IB::Foo is the best overload when calling IB.Foo (1)
4880 if (ambiguous_candidates != null) {
4881 foreach (var amb_cand in ambiguous_candidates) {
4882 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4891 ambiguous_candidates = null;
4894 // Is the new candidate better
4895 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4899 best_candidate = member;
4900 best_candidate_args = candidate_args;
4901 best_candidate_params = params_expanded_form;
4902 best_candidate_dynamic = dynamic_argument;
4903 best_parameter_member = pm;
4904 best_candidate_return_type = rt;
4906 // It's not better but any other found later could be but we are not sure yet
4907 if (ambiguous_candidates == null)
4908 ambiguous_candidates = new List<AmbiguousCandidate> ();
4910 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4914 // Restore expanded arguments
4915 if (candidate_args != args)
4916 candidate_args = args;
4918 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4921 // We've found exact match
4923 if (best_candidate_rate == 0)
4927 // Try extension methods lookup when no ordinary method match was found and provider enables it
4930 var emg = base_provider.LookupExtensionMethod (rc);
4932 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4934 best_candidate_extension_group = emg;
4935 return (T) (MemberSpec) emg.BestCandidate;
4940 // Don't run expensive error reporting mode for probing
4947 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4950 lambda_conv_msgs = null;
4955 // No best member match found, report an error
4957 if (best_candidate_rate != 0 || error_mode) {
4958 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4962 if (best_candidate_dynamic) {
4963 if (args[0].ArgType == Argument.AType.ExtensionType) {
4964 rc.Report.Error (1973, loc,
4965 "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",
4966 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4970 // Check type constraints only when explicit type arguments are used
4972 if (best_candidate.IsGeneric && type_arguments != null) {
4973 MethodSpec bc = best_candidate as MethodSpec;
4974 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4975 ConstraintChecker cc = new ConstraintChecker (rc);
4976 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4980 BestCandidateIsDynamic = true;
4985 // These flags indicates we are running delegate probing conversion. No need to
4986 // do more expensive checks
4988 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4989 return (T) best_candidate;
4991 if (ambiguous_candidates != null) {
4993 // Now check that there are no ambiguities i.e the selected method
4994 // should be better than all the others
4996 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4997 var candidate = ambiguous_candidates [ix];
4999 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5000 var ambiguous = candidate.Member;
5001 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5002 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5003 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5004 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5005 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5008 return (T) best_candidate;
5013 if (invocable_member != null && !IsProbingOnly) {
5014 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5015 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5016 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5017 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5021 // And now check if the arguments are all
5022 // compatible, perform conversions if
5023 // necessary etc. and return if everything is
5026 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5029 if (best_candidate == null)
5033 // Don't run possibly expensive checks in probing mode
5035 if (!IsProbingOnly && !rc.IsInProbingMode) {
5037 // Check ObsoleteAttribute on the best method
5039 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5040 if (oa != null && !rc.IsObsolete)
5041 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5043 best_candidate.MemberDefinition.SetIsUsed ();
5046 args = best_candidate_args;
5047 return (T) best_candidate;
5050 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5052 return ResolveMember<MethodSpec> (rc, ref args);
5055 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5056 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5058 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5061 if (a.Type == InternalType.ErrorType)
5064 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5065 ec.Report.SymbolRelatedToPreviousError (method);
5066 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5067 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5068 TypeManager.CSharpSignature (method));
5071 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5072 TypeManager.CSharpSignature (method));
5073 } else if (IsDelegateInvoke) {
5074 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5075 DelegateType.GetSignatureForError ());
5077 ec.Report.SymbolRelatedToPreviousError (method);
5078 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5079 method.GetSignatureForError ());
5082 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5084 string index = (idx + 1).ToString ();
5085 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5086 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5087 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5088 index, Parameter.GetModifierSignature (a.Modifier));
5090 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5091 index, Parameter.GetModifierSignature (mod));
5093 string p1 = a.GetSignatureForError ();
5094 string p2 = paramType.GetSignatureForError ();
5097 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5098 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5101 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5102 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5103 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5106 ec.Report.Error (1503, a.Expr.Location,
5107 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5112 // We have failed to find exact match so we return error info about the closest match
5114 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5116 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5117 int arg_count = args == null ? 0 : args.Count;
5119 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5120 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5121 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5125 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5130 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5131 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5132 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5136 // For candidates which match on parameters count report more details about incorrect arguments
5139 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5140 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5141 // Reject any inaccessible member
5142 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5143 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5144 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5148 var ms = best_candidate as MethodSpec;
5149 if (ms != null && ms.IsGeneric) {
5150 bool constr_ok = true;
5151 if (ms.TypeArguments != null)
5152 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5154 if (ta_count == 0) {
5155 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5159 rc.Report.Error (411, loc,
5160 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5161 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5168 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5174 // We failed to find any method with correct argument count, report best candidate
5176 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5179 if (best_candidate.Kind == MemberKind.Constructor) {
5180 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5181 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5182 } else if (IsDelegateInvoke) {
5183 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5184 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5185 DelegateType.GetSignatureForError (), arg_count.ToString ());
5187 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5188 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5189 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5190 name, arg_count.ToString ());
5194 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5196 var pd = pm.Parameters;
5197 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5199 Parameter.Modifier p_mod = 0;
5201 int a_idx = 0, a_pos = 0;
5203 ArrayInitializer params_initializers = null;
5204 bool has_unsafe_arg = pm.MemberType.IsPointer;
5205 int arg_count = args == null ? 0 : args.Count;
5207 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5209 if (p_mod != Parameter.Modifier.PARAMS) {
5210 p_mod = pd.FixedParameters[a_idx].ModFlags;
5212 has_unsafe_arg |= pt.IsPointer;
5214 if (p_mod == Parameter.Modifier.PARAMS) {
5215 if (chose_params_expanded) {
5216 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5217 pt = TypeManager.GetElementType (pt);
5223 // Types have to be identical when ref or out modifer is used
5225 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5226 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5229 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5235 NamedArgument na = a as NamedArgument;
5237 int name_index = pd.GetParameterIndexByName (na.Name);
5238 if (name_index < 0 || name_index >= pd.Count) {
5239 if (IsDelegateInvoke) {
5240 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5241 ec.Report.Error (1746, na.Location,
5242 "The delegate `{0}' does not contain a parameter named `{1}'",
5243 DelegateType.GetSignatureForError (), na.Name);
5245 ec.Report.SymbolRelatedToPreviousError (member);
5246 ec.Report.Error (1739, na.Location,
5247 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5248 TypeManager.CSharpSignature (member), na.Name);
5250 } else if (args[name_index] != a) {
5251 if (IsDelegateInvoke)
5252 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5254 ec.Report.SymbolRelatedToPreviousError (member);
5256 ec.Report.Error (1744, na.Location,
5257 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5262 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5265 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5266 custom_errors.NoArgumentMatch (ec, member);
5270 Expression conv = null;
5271 if (a.ArgType == Argument.AType.ExtensionType) {
5272 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5275 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5277 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5280 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5287 // Convert params arguments to an array initializer
5289 if (params_initializers != null) {
5290 // we choose to use 'a.Expr' rather than 'conv' so that
5291 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5292 params_initializers.Add (a.Expr);
5293 args.RemoveAt (a_idx--);
5298 // Update the argument with the implicit conversion
5302 if (a_idx != arg_count) {
5303 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5308 // Fill not provided arguments required by params modifier
5310 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5312 args = new Arguments (1);
5314 pt = ptypes[pd.Count - 1];
5315 pt = TypeManager.GetElementType (pt);
5316 has_unsafe_arg |= pt.IsPointer;
5317 params_initializers = new ArrayInitializer (0, loc);
5321 // Append an array argument with all params arguments
5323 if (params_initializers != null) {
5324 args.Add (new Argument (
5325 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5329 if (has_unsafe_arg && !ec.IsUnsafe) {
5330 Expression.UnsafeError (ec, loc);
5334 // We could infer inaccesible type arguments
5336 if (type_arguments == null && member.IsGeneric) {
5337 var ms = (MethodSpec) member;
5338 foreach (var ta in ms.TypeArguments) {
5339 if (!ta.IsAccessible (ec)) {
5340 ec.Report.SymbolRelatedToPreviousError (ta);
5341 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5351 public class ConstantExpr : MemberExpr
5353 readonly ConstSpec constant;
5355 public ConstantExpr (ConstSpec constant, Location loc)
5357 this.constant = constant;
5361 public override string Name {
5362 get { throw new NotImplementedException (); }
5365 public override string KindName {
5366 get { return "constant"; }
5369 public override bool IsInstance {
5370 get { return !IsStatic; }
5373 public override bool IsStatic {
5374 get { return true; }
5377 protected override TypeSpec DeclaringType {
5378 get { return constant.DeclaringType; }
5381 public override Expression CreateExpressionTree (ResolveContext ec)
5383 throw new NotSupportedException ("ET");
5386 protected override Expression DoResolve (ResolveContext rc)
5388 ResolveInstanceExpression (rc, null);
5389 DoBestMemberChecks (rc, constant);
5391 var c = constant.GetConstant (rc);
5393 // Creates reference expression to the constant value
5394 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5397 public override void Emit (EmitContext ec)
5399 throw new NotSupportedException ();
5402 public override string GetSignatureForError ()
5404 return constant.GetSignatureForError ();
5407 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5409 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5414 // Fully resolved expression that references a Field
5416 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5418 protected FieldSpec spec;
5419 VariableInfo variable_info;
5421 LocalTemporary temp;
5424 protected FieldExpr (Location l)
5429 public FieldExpr (FieldSpec spec, Location loc)
5434 type = spec.MemberType;
5437 public FieldExpr (FieldBase fi, Location l)
5444 public override string Name {
5450 public bool IsHoisted {
5452 IVariableReference hv = InstanceExpression as IVariableReference;
5453 return hv != null && hv.IsHoisted;
5457 public override bool IsInstance {
5459 return !spec.IsStatic;
5463 public override bool IsStatic {
5465 return spec.IsStatic;
5469 public override string KindName {
5470 get { return "field"; }
5473 public FieldSpec Spec {
5479 protected override TypeSpec DeclaringType {
5481 return spec.DeclaringType;
5485 public VariableInfo VariableInfo {
5487 return variable_info;
5493 public override string GetSignatureForError ()
5495 return spec.GetSignatureForError ();
5498 public bool IsMarshalByRefAccess (ResolveContext rc)
5500 // Checks possible ldflda of field access expression
5501 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5502 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5503 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5506 public void SetHasAddressTaken ()
5508 IVariableReference vr = InstanceExpression as IVariableReference;
5510 vr.SetHasAddressTaken ();
5514 public override Expression CreateExpressionTree (ResolveContext ec)
5516 return CreateExpressionTree (ec, true);
5519 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5522 Expression instance;
5524 if (InstanceExpression == null) {
5525 instance = new NullLiteral (loc);
5526 } else if (convertInstance) {
5527 instance = InstanceExpression.CreateExpressionTree (ec);
5529 args = new Arguments (1);
5530 args.Add (new Argument (InstanceExpression));
5531 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5534 args = Arguments.CreateForExpressionTree (ec, null,
5536 CreateTypeOfExpression ());
5538 return CreateExpressionFactoryCall (ec, "Field", args);
5541 public Expression CreateTypeOfExpression ()
5543 return new TypeOfField (spec, loc);
5546 protected override Expression DoResolve (ResolveContext ec)
5548 spec.MemberDefinition.SetIsUsed ();
5550 return DoResolve (ec, null);
5553 Expression DoResolve (ResolveContext ec, Expression rhs)
5555 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5558 if (ResolveInstanceExpression (ec, rhs)) {
5559 // Resolve the field's instance expression while flow analysis is turned
5560 // off: when accessing a field "a.b", we must check whether the field
5561 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5563 if (lvalue_instance) {
5564 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5565 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5567 Expression right_side =
5568 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5570 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5573 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5574 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5578 if (InstanceExpression == null)
5582 DoBestMemberChecks (ec, spec);
5585 var fb = spec as FixedFieldSpec;
5586 IVariableReference var = InstanceExpression as IVariableReference;
5588 if (lvalue_instance && var != null && var.VariableInfo != null) {
5589 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5593 IFixedExpression fe = InstanceExpression as IFixedExpression;
5594 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5595 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5598 if (InstanceExpression.eclass != ExprClass.Variable) {
5599 ec.Report.SymbolRelatedToPreviousError (spec);
5600 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5601 TypeManager.GetFullNameSignature (spec));
5602 } else if (var != null && var.IsHoisted) {
5603 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5606 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5610 // Set flow-analysis variable info for struct member access. It will be check later
5611 // for precise error reporting
5613 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5614 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5615 if (rhs != null && variable_info != null)
5616 variable_info.SetStructFieldAssigned (ec, Name);
5619 eclass = ExprClass.Variable;
5623 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5628 var var = fe.InstanceExpression as IVariableReference;
5630 var vi = var.VariableInfo;
5632 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5634 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5636 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5643 fe = fe.InstanceExpression as FieldExpr;
5645 } while (fe != null);
5648 static readonly int [] codes = {
5649 191, // instance, write access
5650 192, // instance, out access
5651 198, // static, write access
5652 199, // static, out access
5653 1648, // member of value instance, write access
5654 1649, // member of value instance, out access
5655 1650, // member of value static, write access
5656 1651 // member of value static, out access
5659 static readonly string [] msgs = {
5660 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5661 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5662 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5663 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5664 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5665 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5666 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5667 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5670 // The return value is always null. Returning a value simplifies calling code.
5671 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5674 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5678 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5680 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5685 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5687 if (spec is FixedFieldSpec) {
5688 // It could be much better error message but we want to be error compatible
5689 Error_ValueAssignment (ec, right_side);
5692 Expression e = DoResolve (ec, right_side);
5697 spec.MemberDefinition.SetIsAssigned ();
5699 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5700 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5701 ec.Report.Warning (420, 1, loc,
5702 "`{0}': A volatile field references will not be treated as volatile",
5703 spec.GetSignatureForError ());
5706 if (spec.IsReadOnly) {
5707 // InitOnly fields can only be assigned in constructors or initializers
5708 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5709 return Report_AssignToReadonly (ec, right_side);
5711 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5713 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5714 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5715 return Report_AssignToReadonly (ec, right_side);
5716 // static InitOnly fields cannot be assigned-to in an instance constructor
5717 if (IsStatic && !ec.IsStatic)
5718 return Report_AssignToReadonly (ec, right_side);
5719 // instance constructors can't modify InitOnly fields of other instances of the same type
5720 if (!IsStatic && !(InstanceExpression is This))
5721 return Report_AssignToReadonly (ec, right_side);
5725 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5726 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5727 ec.Report.Warning (197, 1, loc,
5728 "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",
5729 GetSignatureForError ());
5732 eclass = ExprClass.Variable;
5736 public override int GetHashCode ()
5738 return spec.GetHashCode ();
5741 public bool IsFixed {
5744 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5746 IVariableReference variable = InstanceExpression as IVariableReference;
5747 if (variable != null)
5748 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5750 IFixedExpression fe = InstanceExpression as IFixedExpression;
5751 return fe != null && fe.IsFixed;
5755 public override bool Equals (object obj)
5757 FieldExpr fe = obj as FieldExpr;
5761 if (spec != fe.spec)
5764 if (InstanceExpression == null || fe.InstanceExpression == null)
5767 return InstanceExpression.Equals (fe.InstanceExpression);
5770 public void Emit (EmitContext ec, bool leave_copy)
5772 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5776 ec.Emit (OpCodes.Volatile);
5778 ec.Emit (OpCodes.Ldsfld, spec);
5781 EmitInstance (ec, false);
5783 // Optimization for build-in types
5784 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5785 ec.EmitLoadFromPtr (type);
5787 var ff = spec as FixedFieldSpec;
5789 ec.Emit (OpCodes.Ldflda, spec);
5790 ec.Emit (OpCodes.Ldflda, ff.Element);
5793 ec.Emit (OpCodes.Volatile);
5795 ec.Emit (OpCodes.Ldfld, spec);
5801 ec.Emit (OpCodes.Dup);
5803 temp = new LocalTemporary (this.Type);
5809 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5811 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5812 if (isCompound && !(source is DynamicExpressionStatement)) {
5813 if (has_await_source) {
5815 InstanceExpression = InstanceExpression.EmitToField (ec);
5822 if (has_await_source)
5823 source = source.EmitToField (ec);
5825 EmitInstance (ec, prepared);
5831 ec.Emit (OpCodes.Dup);
5833 temp = new LocalTemporary (this.Type);
5838 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5839 ec.Emit (OpCodes.Volatile);
5841 spec.MemberDefinition.SetIsAssigned ();
5844 ec.Emit (OpCodes.Stsfld, spec);
5846 ec.Emit (OpCodes.Stfld, spec);
5856 // Emits store to field with prepared values on stack
5858 public void EmitAssignFromStack (EmitContext ec)
5861 ec.Emit (OpCodes.Stsfld, spec);
5863 ec.Emit (OpCodes.Stfld, spec);
5867 public override void Emit (EmitContext ec)
5872 public override void EmitSideEffect (EmitContext ec)
5874 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5876 if (is_volatile) // || is_marshal_by_ref ())
5877 base.EmitSideEffect (ec);
5880 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5882 if ((mode & AddressOp.Store) != 0)
5883 spec.MemberDefinition.SetIsAssigned ();
5884 if ((mode & AddressOp.Load) != 0)
5885 spec.MemberDefinition.SetIsUsed ();
5888 // Handle initonly fields specially: make a copy and then
5889 // get the address of the copy.
5892 if (spec.IsReadOnly){
5894 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5906 var temp = ec.GetTemporaryLocal (type);
5907 ec.Emit (OpCodes.Stloc, temp);
5908 ec.Emit (OpCodes.Ldloca, temp);
5909 ec.FreeTemporaryLocal (temp, type);
5915 ec.Emit (OpCodes.Ldsflda, spec);
5918 EmitInstance (ec, false);
5919 ec.Emit (OpCodes.Ldflda, spec);
5923 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5925 return MakeExpression (ctx);
5928 public override SLE.Expression MakeExpression (BuilderContext ctx)
5931 return base.MakeExpression (ctx);
5933 return SLE.Expression.Field (
5934 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5935 spec.GetMetaInfo ());
5939 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5941 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5947 // Expression that evaluates to a Property.
5949 // This is not an LValue because we need to re-write the expression. We
5950 // can not take data from the stack and store it.
5952 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5954 Arguments arguments;
5956 public PropertyExpr (PropertySpec spec, Location l)
5959 best_candidate = spec;
5960 type = spec.MemberType;
5965 protected override Arguments Arguments {
5974 protected override TypeSpec DeclaringType {
5976 return best_candidate.DeclaringType;
5980 public override string Name {
5982 return best_candidate.Name;
5986 public override bool IsInstance {
5992 public override bool IsStatic {
5994 return best_candidate.IsStatic;
5998 public override string KindName {
5999 get { return "property"; }
6002 public PropertySpec PropertyInfo {
6004 return best_candidate;
6010 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6012 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6015 var args_count = arguments == null ? 0 : arguments.Count;
6016 if (args_count != body.Parameters.Count && args_count == 0)
6019 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6020 mg.InstanceExpression = InstanceExpression;
6025 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6027 return new PropertyExpr (spec, loc) {
6033 public override Expression CreateExpressionTree (ResolveContext ec)
6036 if (IsSingleDimensionalArrayLength ()) {
6037 args = new Arguments (1);
6038 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6039 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6042 args = new Arguments (2);
6043 if (InstanceExpression == null)
6044 args.Add (new Argument (new NullLiteral (loc)));
6046 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6047 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6048 return CreateExpressionFactoryCall (ec, "Property", args);
6051 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6053 DoResolveLValue (rc, null);
6054 return new TypeOfMethod (Setter, loc);
6057 public override string GetSignatureForError ()
6059 return best_candidate.GetSignatureForError ();
6062 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6065 return base.MakeExpression (ctx);
6067 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6071 public override SLE.Expression MakeExpression (BuilderContext ctx)
6074 return base.MakeExpression (ctx);
6076 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6080 void Error_PropertyNotValid (ResolveContext ec)
6082 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6083 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6084 GetSignatureForError ());
6087 bool IsSingleDimensionalArrayLength ()
6089 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6092 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6093 return ac != null && ac.Rank == 1;
6096 public override void Emit (EmitContext ec, bool leave_copy)
6099 // Special case: length of single dimension array property is turned into ldlen
6101 if (IsSingleDimensionalArrayLength ()) {
6102 EmitInstance (ec, false);
6103 ec.Emit (OpCodes.Ldlen);
6104 ec.Emit (OpCodes.Conv_I4);
6108 base.Emit (ec, leave_copy);
6111 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6114 LocalTemporary await_source_arg = null;
6116 if (isCompound && !(source is DynamicExpressionStatement)) {
6117 emitting_compound_assignment = true;
6120 if (has_await_arguments) {
6121 await_source_arg = new LocalTemporary (Type);
6122 await_source_arg.Store (ec);
6124 args = new Arguments (1);
6125 args.Add (new Argument (await_source_arg));
6128 temp = await_source_arg;
6131 has_await_arguments = false;
6136 ec.Emit (OpCodes.Dup);
6137 temp = new LocalTemporary (this.Type);
6142 args = arguments == null ? new Arguments (1) : arguments;
6146 temp = new LocalTemporary (this.Type);
6148 args.Add (new Argument (temp));
6150 args.Add (new Argument (source));
6154 emitting_compound_assignment = false;
6156 var call = new CallEmitter ();
6157 call.InstanceExpression = InstanceExpression;
6159 call.InstanceExpressionOnStack = true;
6161 call.Emit (ec, Setter, args, loc);
6168 if (await_source_arg != null) {
6169 await_source_arg.Release (ec);
6173 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6175 eclass = ExprClass.PropertyAccess;
6177 if (best_candidate.IsNotCSharpCompatible) {
6178 Error_PropertyNotValid (rc);
6181 ResolveInstanceExpression (rc, right_side);
6183 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6184 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6185 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6187 type = p.MemberType;
6191 DoBestMemberChecks (rc, best_candidate);
6193 // Handling of com-imported properties with any number of default property parameters
6194 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6195 var p = best_candidate.Get.Parameters;
6196 arguments = new Arguments (p.Count);
6197 for (int i = 0; i < p.Count; ++i) {
6198 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6200 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6201 var p = best_candidate.Set.Parameters;
6202 arguments = new Arguments (p.Count - 1);
6203 for (int i = 0; i < p.Count - 1; ++i) {
6204 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6211 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6213 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6217 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6219 // getter and setter can be different for base calls
6220 MethodSpec getter, setter;
6221 protected T best_candidate;
6223 protected LocalTemporary temp;
6224 protected bool emitting_compound_assignment;
6225 protected bool has_await_arguments;
6227 protected PropertyOrIndexerExpr (Location l)
6234 protected abstract Arguments Arguments { get; set; }
6236 public MethodSpec Getter {
6245 public MethodSpec Setter {
6256 protected override Expression DoResolve (ResolveContext ec)
6258 if (eclass == ExprClass.Unresolved) {
6259 var expr = OverloadResolve (ec, null);
6264 return expr.Resolve (ec);
6267 if (!ResolveGetter (ec))
6273 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6275 if (right_side == EmptyExpression.OutAccess) {
6276 // TODO: best_candidate can be null at this point
6277 INamedBlockVariable variable = null;
6278 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6279 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6280 best_candidate.Name);
6282 right_side.DoResolveLValue (ec, this);
6287 if (eclass == ExprClass.Unresolved) {
6288 var expr = OverloadResolve (ec, right_side);
6293 return expr.ResolveLValue (ec, right_side);
6296 if (!ResolveSetter (ec))
6303 // Implements the IAssignMethod interface for assignments
6305 public virtual void Emit (EmitContext ec, bool leave_copy)
6307 var call = new CallEmitter ();
6308 call.InstanceExpression = InstanceExpression;
6309 if (has_await_arguments)
6310 call.HasAwaitArguments = true;
6312 call.DuplicateArguments = emitting_compound_assignment;
6314 call.Emit (ec, Getter, Arguments, loc);
6316 if (call.HasAwaitArguments) {
6317 InstanceExpression = call.InstanceExpression;
6318 Arguments = call.EmittedArguments;
6319 has_await_arguments = true;
6323 ec.Emit (OpCodes.Dup);
6324 temp = new LocalTemporary (Type);
6329 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6331 public override void Emit (EmitContext ec)
6336 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6338 has_await_arguments = true;
6343 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6345 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6347 bool ResolveGetter (ResolveContext rc)
6349 if (!best_candidate.HasGet) {
6350 if (InstanceExpression != EmptyExpression.Null) {
6351 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6352 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6353 best_candidate.GetSignatureForError ());
6356 } else if (!best_candidate.Get.IsAccessible (rc)) {
6357 if (best_candidate.HasDifferentAccessibility) {
6358 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6359 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6360 TypeManager.CSharpSignature (best_candidate));
6362 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6363 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6367 if (best_candidate.HasDifferentAccessibility) {
6368 CheckProtectedMemberAccess (rc, best_candidate.Get);
6371 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6375 bool ResolveSetter (ResolveContext rc)
6377 if (!best_candidate.HasSet) {
6378 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6379 GetSignatureForError ());
6383 if (!best_candidate.Set.IsAccessible (rc)) {
6384 if (best_candidate.HasDifferentAccessibility) {
6385 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6386 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6387 GetSignatureForError ());
6389 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6390 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6394 if (best_candidate.HasDifferentAccessibility)
6395 CheckProtectedMemberAccess (rc, best_candidate.Set);
6397 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6403 /// Fully resolved expression that evaluates to an Event
6405 public class EventExpr : MemberExpr, IAssignMethod
6407 readonly EventSpec spec;
6410 public EventExpr (EventSpec spec, Location loc)
6418 protected override TypeSpec DeclaringType {
6420 return spec.DeclaringType;
6424 public override string Name {
6430 public override bool IsInstance {
6432 return !spec.IsStatic;
6436 public override bool IsStatic {
6438 return spec.IsStatic;
6442 public override string KindName {
6443 get { return "event"; }
6446 public MethodSpec Operator {
6454 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6457 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6459 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6460 if (spec.BackingField != null &&
6461 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6463 spec.MemberDefinition.SetIsUsed ();
6465 if (!ec.IsObsolete) {
6466 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6468 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6471 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6472 Error_AssignmentEventOnly (ec);
6474 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6476 InstanceExpression = null;
6478 return ml.ResolveMemberAccess (ec, left, original);
6482 return base.ResolveMemberAccess (ec, left, original);
6485 public override Expression CreateExpressionTree (ResolveContext ec)
6487 throw new NotSupportedException ("ET");
6490 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6492 if (right_side == EmptyExpression.EventAddition) {
6493 op = spec.AccessorAdd;
6494 } else if (right_side == EmptyExpression.EventSubtraction) {
6495 op = spec.AccessorRemove;
6499 Error_AssignmentEventOnly (ec);
6503 op = CandidateToBaseOverride (ec, op);
6507 protected override Expression DoResolve (ResolveContext ec)
6509 eclass = ExprClass.EventAccess;
6510 type = spec.MemberType;
6512 ResolveInstanceExpression (ec, null);
6514 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6515 Error_AssignmentEventOnly (ec);
6518 DoBestMemberChecks (ec, spec);
6522 public override void Emit (EmitContext ec)
6524 throw new NotSupportedException ();
6525 //Error_CannotAssign ();
6528 #region IAssignMethod Members
6530 public void Emit (EmitContext ec, bool leave_copy)
6532 throw new NotImplementedException ();
6535 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6537 if (leave_copy || !isCompound)
6538 throw new NotImplementedException ("EventExpr::EmitAssign");
6540 Arguments args = new Arguments (1);
6541 args.Add (new Argument (source));
6543 var call = new CallEmitter ();
6544 call.InstanceExpression = InstanceExpression;
6545 call.Emit (ec, op, args, loc);
6550 void Error_AssignmentEventOnly (ResolveContext ec)
6552 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6553 ec.Report.Error (79, loc,
6554 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6555 GetSignatureForError ());
6557 ec.Report.Error (70, loc,
6558 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6559 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6563 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6565 name = name.Substring (0, name.LastIndexOf ('.'));
6566 base.Error_CannotCallAbstractBase (rc, name);
6569 public override string GetSignatureForError ()
6571 return TypeManager.CSharpSignature (spec);
6574 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6576 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6580 public class TemporaryVariableReference : VariableReference
6582 public class Declarator : Statement
6584 TemporaryVariableReference variable;
6586 public Declarator (TemporaryVariableReference variable)
6588 this.variable = variable;
6592 protected override void DoEmit (EmitContext ec)
6594 variable.li.CreateBuilder (ec);
6597 public override void Emit (EmitContext ec)
6599 // Don't create sequence point
6603 protected override void CloneTo (CloneContext clonectx, Statement target)
6611 public TemporaryVariableReference (LocalVariable li, Location loc)
6614 this.type = li.Type;
6618 public override bool IsLockedByStatement {
6626 public LocalVariable LocalInfo {
6632 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6634 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6635 return new TemporaryVariableReference (li, loc);
6638 protected override Expression DoResolve (ResolveContext ec)
6640 eclass = ExprClass.Variable;
6643 // Don't capture temporary variables except when using
6644 // state machine redirection and block yields
6646 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6647 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6648 ec.IsVariableCapturingRequired) {
6649 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6650 storey.CaptureLocalVariable (ec, li);
6656 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6658 return Resolve (ec);
6661 public override void Emit (EmitContext ec)
6663 li.CreateBuilder (ec);
6668 public void EmitAssign (EmitContext ec, Expression source)
6670 li.CreateBuilder (ec);
6672 EmitAssign (ec, source, false, false);
6675 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6677 return li.HoistedVariant;
6680 public override bool IsFixed {
6681 get { return true; }
6684 public override bool IsRef {
6685 get { return false; }
6688 public override string Name {
6689 get { throw new NotImplementedException (); }
6692 public override void SetHasAddressTaken ()
6694 throw new NotImplementedException ();
6697 protected override ILocalVariable Variable {
6701 public override VariableInfo VariableInfo {
6702 get { return null; }
6705 public override void VerifyAssigned (ResolveContext rc)
6711 /// Handles `var' contextual keyword; var becomes a keyword only
6712 /// if no type called var exists in a variable scope
6714 class VarExpr : SimpleName
6716 public VarExpr (Location loc)
6721 public bool InferType (ResolveContext ec, Expression right_side)
6724 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6726 type = right_side.Type;
6727 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6728 ec.Report.Error (815, loc,
6729 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6730 type.GetSignatureForError ());
6734 eclass = ExprClass.Variable;
6738 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6740 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6741 base.Error_TypeOrNamespaceNotFound (ec);
6743 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");