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 virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
516 rc.Module.Compiler.Report.Error (182, loc,
517 "An attribute argument must be a constant expression, typeof expression or array creation expression");
521 /// Emits the code for the expression
525 /// The Emit method is invoked to generate the code
526 /// for the expression.
528 public abstract void Emit (EmitContext ec);
531 // Emit code to branch to @target if this expression is equivalent to @on_true.
532 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
533 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
534 // including the use of conditional branches. Note also that a branch MUST be emitted
535 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
538 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
541 // Emit this expression for its side effects, not for its value.
542 // The default implementation is to emit the value, and then throw it away.
543 // Subclasses can provide more efficient implementations, but those MUST be equivalent
544 public virtual void EmitSideEffect (EmitContext ec)
547 ec.Emit (OpCodes.Pop);
551 // Emits the expression into temporary field variable. The method
552 // should be used for await expressions only
554 public virtual Expression EmitToField (EmitContext ec)
557 // This is the await prepare Emit method. When emitting code like
558 // a + b we emit code like
564 // For await a + await b we have to interfere the flow to keep the
565 // stack clean because await yields from the expression. The emit
568 // a = a.EmitToField () // a is changed to temporary field access
569 // b = b.EmitToField ()
575 // The idea is to emit expression and leave the stack empty with
576 // result value still available.
578 // Expressions should override this default implementation when
579 // optimized version can be provided (e.g. FieldExpr)
582 // We can optimize for side-effect free expressions, they can be
583 // emitted out of order
585 if (IsSideEffectFree)
588 bool needs_temporary = ContainsEmitWithAwait ();
589 if (!needs_temporary)
592 // Emit original code
593 var field = EmitToFieldSource (ec);
596 // Store the result to temporary field when we
597 // cannot load `this' directly
599 field = ec.GetTemporaryField (type);
600 if (needs_temporary) {
602 // Create temporary local (we cannot load `this' before Emit)
604 var temp = ec.GetTemporaryLocal (type);
605 ec.Emit (OpCodes.Stloc, temp);
608 ec.Emit (OpCodes.Ldloc, temp);
609 field.EmitAssignFromStack (ec);
611 ec.FreeTemporaryLocal (temp, type);
613 field.EmitAssignFromStack (ec);
620 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
623 // Default implementation calls Emit method
629 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
631 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
632 bool contains_await = false;
634 for (int i = 1; i < expressions.Count; ++i) {
635 if (expressions[i].ContainsEmitWithAwait ()) {
636 contains_await = true;
641 if (contains_await) {
642 for (int i = 0; i < expressions.Count; ++i) {
643 expressions[i] = expressions[i].EmitToField (ec);
648 for (int i = 0; i < expressions.Count; ++i) {
649 expressions[i].Emit (ec);
654 /// Protected constructor. Only derivate types should
655 /// be able to be created
658 protected Expression ()
663 /// Returns a fully formed expression after a MemberLookup
666 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
668 if (spec is EventSpec)
669 return new EventExpr ((EventSpec) spec, loc);
670 if (spec is ConstSpec)
671 return new ConstantExpr ((ConstSpec) spec, loc);
672 if (spec is FieldSpec)
673 return new FieldExpr ((FieldSpec) spec, loc);
674 if (spec is PropertySpec)
675 return new PropertyExpr ((PropertySpec) spec, loc);
676 if (spec is TypeSpec)
677 return new TypeExpression (((TypeSpec) spec), loc);
682 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
684 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
686 rc.Report.SymbolRelatedToPreviousError (type);
688 // Report meaningful error for struct as they always have default ctor in C# context
689 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
691 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
692 type.GetSignatureForError ());
698 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
699 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
700 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
703 return r.ResolveMember<MethodSpec> (rc, ref args);
707 public enum MemberLookupRestrictions
716 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
717 // `qualifier_type' or null to lookup members in the current class.
719 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
721 var members = MemberCache.FindMembers (queried_type, name, false);
725 MemberSpec non_method = null;
726 MemberSpec ambig_non_method = null;
728 for (int i = 0; i < members.Count; ++i) {
729 var member = members[i];
731 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
732 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
735 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
738 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
742 if (!member.IsAccessible (rc))
746 // With runtime binder we can have a situation where queried type is inaccessible
747 // because it came via dynamic object, the check about inconsisted accessibility
748 // had no effect as the type was unknown during compilation
751 // private class N { }
753 // public dynamic Foo ()
759 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
763 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
764 if (member is MethodSpec)
765 return new MethodGroupExpr (members, queried_type, loc);
767 if (!Invocation.IsMemberInvocable (member))
771 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
773 } else if (!errorMode && !member.IsNotCSharpCompatible) {
775 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
776 // T has both an effective base class other than object and a non-empty effective interface set.
778 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
780 var tps = queried_type as TypeParameterSpec;
781 if (tps != null && tps.HasTypeConstraint) {
782 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
785 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
791 ambig_non_method = member;
795 if (non_method != null) {
796 if (ambig_non_method != null && rc != null) {
797 var report = rc.Module.Compiler.Report;
798 report.SymbolRelatedToPreviousError (non_method);
799 report.SymbolRelatedToPreviousError (ambig_non_method);
800 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
801 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
804 if (non_method is MethodSpec)
805 return new MethodGroupExpr (members, queried_type, loc);
807 return ExprClassFromMemberInfo (non_method, loc);
810 if (members[0].DeclaringType.BaseType == null)
813 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
815 } while (members != null);
820 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
822 throw new NotImplementedException ();
825 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
827 if (t == InternalType.ErrorType)
830 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
831 oper, t.GetSignatureForError ());
834 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
836 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
840 /// Returns an expression that can be used to invoke operator true
841 /// on the expression if it exists.
843 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
845 return GetOperatorTrueOrFalse (ec, e, true, loc);
849 /// Returns an expression that can be used to invoke operator false
850 /// on the expression if it exists.
852 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
854 return GetOperatorTrueOrFalse (ec, e, false, loc);
857 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
859 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
860 var methods = MemberCache.GetUserOperator (e.type, op, false);
864 Arguments arguments = new Arguments (1);
865 arguments.Add (new Argument (e));
867 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
868 var oper = res.ResolveOperator (ec, ref arguments);
873 return new UserOperatorCall (oper, arguments, null, loc);
876 public virtual string ExprClassName
880 case ExprClass.Unresolved:
882 case ExprClass.Value:
884 case ExprClass.Variable:
886 case ExprClass.Namespace:
890 case ExprClass.MethodGroup:
891 return "method group";
892 case ExprClass.PropertyAccess:
893 return "property access";
894 case ExprClass.EventAccess:
895 return "event access";
896 case ExprClass.IndexerAccess:
897 return "indexer access";
898 case ExprClass.Nothing:
900 case ExprClass.TypeParameter:
901 return "type parameter";
903 throw new Exception ("Should not happen");
908 /// Reports that we were expecting `expr' to be of class `expected'
910 public void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
912 var name = memberExpr.GetSignatureForError ();
914 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
917 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
919 string [] valid = new string [4];
922 if ((flags & ResolveFlags.VariableOrValue) != 0) {
923 valid [count++] = "variable";
924 valid [count++] = "value";
927 if ((flags & ResolveFlags.Type) != 0)
928 valid [count++] = "type";
930 if ((flags & ResolveFlags.MethodGroup) != 0)
931 valid [count++] = "method group";
934 valid [count++] = "unknown";
936 StringBuilder sb = new StringBuilder (valid [0]);
937 for (int i = 1; i < count - 1; i++) {
939 sb.Append (valid [i]);
942 sb.Append ("' or `");
943 sb.Append (valid [count - 1]);
946 ec.Report.Error (119, loc,
947 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
950 public static void UnsafeError (ResolveContext ec, Location loc)
952 UnsafeError (ec.Report, loc);
955 public static void UnsafeError (Report Report, Location loc)
957 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
961 // Converts `source' to an int, uint, long or ulong.
963 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source)
965 var btypes = ec.BuiltinTypes;
967 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
968 Arguments args = new Arguments (1);
969 args.Add (new Argument (source));
970 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
973 Expression converted;
975 using (ec.Set (ResolveContext.Options.CheckedScope)) {
976 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
977 if (converted == null)
978 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
979 if (converted == null)
980 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
981 if (converted == null)
982 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
984 if (converted == null) {
985 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
991 // Only positive constants are allowed at compile time
993 Constant c = converted as Constant;
994 if (c != null && c.IsNegative)
995 Error_NegativeArrayIndex (ec, source.loc);
997 // No conversion needed to array index
998 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1001 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1005 // Derived classes implement this method by cloning the fields that
1006 // could become altered during the Resolve stage
1008 // Only expressions that are created for the parser need to implement
1011 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1013 throw new NotImplementedException (
1015 "CloneTo not implemented for expression {0}", this.GetType ()));
1019 // Clones an expression created by the parser.
1021 // We only support expressions created by the parser so far, not
1022 // expressions that have been resolved (many more classes would need
1023 // to implement CloneTo).
1025 // This infrastructure is here merely for Lambda expressions which
1026 // compile the same code using different type values for the same
1027 // arguments to find the correct overload
1029 public virtual Expression Clone (CloneContext clonectx)
1031 Expression cloned = (Expression) MemberwiseClone ();
1032 CloneTo (clonectx, cloned);
1038 // Implementation of expression to expression tree conversion
1040 public abstract Expression CreateExpressionTree (ResolveContext ec);
1042 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1044 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1047 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1049 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1052 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1054 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1057 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1059 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1063 return new TypeExpression (t, loc);
1067 // Implemented by all expressions which support conversion from
1068 // compiler expression to invokable runtime expression. Used by
1069 // dynamic C# binder.
1071 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1073 throw new NotImplementedException ("MakeExpression for " + GetType ());
1076 public virtual object Accept (StructuralVisitor visitor)
1078 return visitor.Visit (this);
1083 /// This is just a base class for expressions that can
1084 /// appear on statements (invocations, object creation,
1085 /// assignments, post/pre increment and decrement). The idea
1086 /// being that they would support an extra Emition interface that
1087 /// does not leave a result on the stack.
1089 public abstract class ExpressionStatement : Expression
1091 public ExpressionStatement ResolveStatement (BlockContext ec)
1093 Expression e = Resolve (ec);
1097 ExpressionStatement es = e as ExpressionStatement;
1099 Error_InvalidExpressionStatement (ec);
1102 // This is quite expensive warning, try to limit the damage
1104 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1105 WarningAsyncWithoutWait (ec, e);
1111 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1113 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1114 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1119 // Need to do full resolve because GetAwaiter can be extension method
1120 // available only in this context
1122 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1126 var arguments = new Arguments (0);
1127 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1132 // Use same check rules as for real await
1134 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1135 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1138 bc.Report.Warning (4014, 1, e.Location,
1139 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1143 var inv = e as Invocation;
1144 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1145 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1146 bc.Report.Warning (4014, 1, e.Location,
1147 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1153 /// Requests the expression to be emitted in a `statement'
1154 /// context. This means that no new value is left on the
1155 /// stack after invoking this method (constrasted with
1156 /// Emit that will always leave a value on the stack).
1158 public abstract void EmitStatement (EmitContext ec);
1160 public override void EmitSideEffect (EmitContext ec)
1167 /// This kind of cast is used to encapsulate the child
1168 /// whose type is child.Type into an expression that is
1169 /// reported to return "return_type". This is used to encapsulate
1170 /// expressions which have compatible types, but need to be dealt
1171 /// at higher levels with.
1173 /// For example, a "byte" expression could be encapsulated in one
1174 /// of these as an "unsigned int". The type for the expression
1175 /// would be "unsigned int".
1178 public abstract class TypeCast : Expression
1180 protected readonly Expression child;
1182 protected TypeCast (Expression child, TypeSpec return_type)
1184 eclass = child.eclass;
1185 loc = child.Location;
1190 public Expression Child {
1196 public override bool ContainsEmitWithAwait ()
1198 return child.ContainsEmitWithAwait ();
1201 public override Expression CreateExpressionTree (ResolveContext ec)
1203 Arguments args = new Arguments (2);
1204 args.Add (new Argument (child.CreateExpressionTree (ec)));
1205 args.Add (new Argument (new TypeOf (type, loc)));
1207 if (type.IsPointer || child.Type.IsPointer)
1208 Error_PointerInsideExpressionTree (ec);
1210 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1213 protected override Expression DoResolve (ResolveContext ec)
1215 // This should never be invoked, we are born in fully
1216 // initialized state.
1221 public override void Emit (EmitContext ec)
1226 public override SLE.Expression MakeExpression (BuilderContext ctx)
1229 return base.MakeExpression (ctx);
1231 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1232 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1233 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1237 protected override void CloneTo (CloneContext clonectx, Expression t)
1242 public override bool IsNull {
1243 get { return child.IsNull; }
1247 public class EmptyCast : TypeCast {
1248 EmptyCast (Expression child, TypeSpec target_type)
1249 : base (child, target_type)
1253 public static Expression Create (Expression child, TypeSpec type)
1255 Constant c = child as Constant;
1257 return new EmptyConstantCast (c, type);
1259 EmptyCast e = child as EmptyCast;
1261 return new EmptyCast (e.child, type);
1263 return new EmptyCast (child, type);
1266 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1268 child.EmitBranchable (ec, label, on_true);
1271 public override void EmitSideEffect (EmitContext ec)
1273 child.EmitSideEffect (ec);
1278 // Used for predefined type user operator (no obsolete check, etc.)
1280 public class OperatorCast : TypeCast
1282 readonly MethodSpec conversion_operator;
1284 public OperatorCast (Expression expr, TypeSpec target_type)
1285 : this (expr, target_type, target_type, false)
1289 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1290 : this (expr, target_type, target_type, find_explicit)
1294 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1295 : base (expr, returnType)
1297 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1298 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1301 foreach (MethodSpec oper in mi) {
1302 if (oper.ReturnType != returnType)
1305 if (oper.Parameters.Types[0] == expr.Type) {
1306 conversion_operator = oper;
1312 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1313 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1316 public override void Emit (EmitContext ec)
1319 ec.Emit (OpCodes.Call, conversion_operator);
1324 // Constant specialization of EmptyCast.
1325 // We need to special case this since an empty cast of
1326 // a constant is still a constant.
1328 public class EmptyConstantCast : Constant
1330 public readonly Constant child;
1332 public EmptyConstantCast (Constant child, TypeSpec type)
1333 : base (child.Location)
1336 throw new ArgumentNullException ("child");
1339 this.eclass = child.eclass;
1343 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1345 if (child.Type == target_type)
1348 // FIXME: check that 'type' can be converted to 'target_type' first
1349 return child.ConvertExplicitly (in_checked_context, target_type);
1352 public override Expression CreateExpressionTree (ResolveContext ec)
1354 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1355 child.CreateExpressionTree (ec),
1356 new TypeOf (type, loc));
1359 Error_PointerInsideExpressionTree (ec);
1361 return CreateExpressionFactoryCall (ec, "Convert", args);
1364 public override bool IsDefaultValue {
1365 get { return child.IsDefaultValue; }
1368 public override bool IsNegative {
1369 get { return child.IsNegative; }
1372 public override bool IsNull {
1373 get { return child.IsNull; }
1376 public override bool IsOneInteger {
1377 get { return child.IsOneInteger; }
1380 public override bool IsSideEffectFree {
1382 return child.IsSideEffectFree;
1386 public override bool IsZeroInteger {
1387 get { return child.IsZeroInteger; }
1390 public override void Emit (EmitContext ec)
1395 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1397 child.EmitBranchable (ec, label, on_true);
1399 // Only to make verifier happy
1400 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1401 ec.Emit (OpCodes.Unbox_Any, type);
1404 public override void EmitSideEffect (EmitContext ec)
1406 child.EmitSideEffect (ec);
1409 public override object GetValue ()
1411 return child.GetValue ();
1414 public override string GetValueAsLiteral ()
1416 return child.GetValueAsLiteral ();
1419 public override long GetValueAsLong ()
1421 return child.GetValueAsLong ();
1424 public override Constant ConvertImplicitly (TypeSpec target_type)
1426 if (type == target_type)
1429 // FIXME: Do we need to check user conversions?
1430 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1433 return child.ConvertImplicitly (target_type);
1438 /// This class is used to wrap literals which belong inside Enums
1440 public class EnumConstant : Constant
1442 public Constant Child;
1444 public EnumConstant (Constant child, TypeSpec enum_type)
1445 : base (child.Location)
1449 this.eclass = ExprClass.Value;
1450 this.type = enum_type;
1453 protected EnumConstant (Location loc)
1458 public override void Emit (EmitContext ec)
1463 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1465 Child.EncodeAttributeValue (rc, enc, Child.Type);
1468 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1470 Child.EmitBranchable (ec, label, on_true);
1473 public override void EmitSideEffect (EmitContext ec)
1475 Child.EmitSideEffect (ec);
1478 public override string GetSignatureForError()
1480 return Type.GetSignatureForError ();
1483 public override object GetValue ()
1485 return Child.GetValue ();
1489 public override object GetTypedValue ()
1492 // The method can be used in dynamic context only (on closed types)
1494 // System.Enum.ToObject cannot be called on dynamic types
1495 // EnumBuilder has to be used, but we cannot use EnumBuilder
1496 // because it does not properly support generics
1498 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1502 public override string GetValueAsLiteral ()
1504 return Child.GetValueAsLiteral ();
1507 public override long GetValueAsLong ()
1509 return Child.GetValueAsLong ();
1512 public EnumConstant Increment()
1514 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1517 public override bool IsDefaultValue {
1519 return Child.IsDefaultValue;
1523 public override bool IsSideEffectFree {
1525 return Child.IsSideEffectFree;
1529 public override bool IsZeroInteger {
1530 get { return Child.IsZeroInteger; }
1533 public override bool IsNegative {
1535 return Child.IsNegative;
1539 public override Constant ConvertExplicitly(bool in_checked_context, TypeSpec target_type)
1541 if (Child.Type == target_type)
1544 return Child.ConvertExplicitly (in_checked_context, target_type);
1547 public override Constant ConvertImplicitly (TypeSpec type)
1549 if (this.type == type) {
1553 if (!Convert.ImplicitStandardConversionExists (this, type)){
1557 return Child.ConvertImplicitly (type);
1562 /// This kind of cast is used to encapsulate Value Types in objects.
1564 /// The effect of it is to box the value type emitted by the previous
1567 public class BoxedCast : TypeCast {
1569 public BoxedCast (Expression expr, TypeSpec target_type)
1570 : base (expr, target_type)
1572 eclass = ExprClass.Value;
1575 protected override Expression DoResolve (ResolveContext ec)
1577 // This should never be invoked, we are born in fully
1578 // initialized state.
1583 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1585 // Only boxing to object type is supported
1586 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1587 base.EncodeAttributeValue (rc, enc, targetType);
1591 enc.Encode (child.Type);
1592 child.EncodeAttributeValue (rc, enc, child.Type);
1595 public override void Emit (EmitContext ec)
1599 ec.Emit (OpCodes.Box, child.Type);
1602 public override void EmitSideEffect (EmitContext ec)
1604 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1605 // so, we need to emit the box+pop instructions in most cases
1606 if (child.Type.IsStruct &&
1607 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1608 child.EmitSideEffect (ec);
1610 base.EmitSideEffect (ec);
1614 public class UnboxCast : TypeCast {
1615 public UnboxCast (Expression expr, TypeSpec return_type)
1616 : base (expr, return_type)
1620 protected override Expression DoResolve (ResolveContext ec)
1622 // This should never be invoked, we are born in fully
1623 // initialized state.
1628 public override void Emit (EmitContext ec)
1632 ec.Emit (OpCodes.Unbox_Any, type);
1637 /// This is used to perform explicit numeric conversions.
1639 /// Explicit numeric conversions might trigger exceptions in a checked
1640 /// context, so they should generate the conv.ovf opcodes instead of
1643 public class ConvCast : TypeCast {
1644 public enum Mode : byte {
1645 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1647 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1648 U2_I1, U2_U1, U2_I2, U2_CH,
1649 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1650 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1651 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1652 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1653 CH_I1, CH_U1, CH_I2,
1654 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1655 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1661 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1662 : base (child, return_type)
1667 protected override Expression DoResolve (ResolveContext ec)
1669 // This should never be invoked, we are born in fully
1670 // initialized state.
1675 public override string ToString ()
1677 return String.Format ("ConvCast ({0}, {1})", mode, child);
1680 public override void Emit (EmitContext ec)
1684 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1686 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1687 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1688 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1689 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1690 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1692 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1693 case Mode.U1_CH: /* nothing */ break;
1695 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1696 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1697 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1698 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1699 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1700 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1702 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1703 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1704 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1705 case Mode.U2_CH: /* nothing */ break;
1707 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1708 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1709 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1710 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1711 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1712 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1713 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1715 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1716 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1717 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1718 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1719 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1720 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1722 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1723 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1724 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1725 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1726 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1727 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1728 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1729 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1730 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1732 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1733 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1734 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1735 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1736 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1737 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1738 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1739 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1740 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1742 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1743 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1744 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1746 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1747 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1748 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1749 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1750 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1751 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1752 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1753 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1754 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1756 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1757 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1758 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1759 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1760 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1761 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1762 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1763 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1764 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1765 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1767 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1771 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1772 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1773 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1774 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1775 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1777 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1778 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1780 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1781 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1782 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1783 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1784 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1785 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1787 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1788 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1789 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1790 case Mode.U2_CH: /* nothing */ break;
1792 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1793 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1794 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1795 case Mode.I4_U4: /* nothing */ break;
1796 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1797 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1798 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1800 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1801 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1802 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
1803 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
1804 case Mode.U4_I4: /* nothing */ break;
1805 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
1807 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
1808 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
1809 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
1810 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
1811 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
1812 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
1813 case Mode.I8_U8: /* nothing */ break;
1814 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
1815 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
1817 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
1818 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
1819 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
1820 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
1821 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
1822 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
1823 case Mode.U8_I8: /* nothing */ break;
1824 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
1825 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
1827 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
1828 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
1829 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
1831 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
1832 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
1833 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
1834 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
1835 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
1836 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
1837 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
1838 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
1839 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
1841 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
1842 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
1843 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
1844 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
1845 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
1846 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
1847 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
1848 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
1849 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
1850 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1852 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
1858 class OpcodeCast : TypeCast
1862 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
1863 : base (child, return_type)
1868 protected override Expression DoResolve (ResolveContext ec)
1870 // This should never be invoked, we are born in fully
1871 // initialized state.
1876 public override void Emit (EmitContext ec)
1882 public TypeSpec UnderlyingType {
1883 get { return child.Type; }
1888 // Opcode casts expression with 2 opcodes but only
1889 // single expression tree node
1891 class OpcodeCastDuplex : OpcodeCast
1893 readonly OpCode second;
1895 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
1896 : base (child, returnType, first)
1898 this.second = second;
1901 public override void Emit (EmitContext ec)
1909 /// This kind of cast is used to encapsulate a child and cast it
1910 /// to the class requested
1912 public sealed class ClassCast : TypeCast {
1913 readonly bool forced;
1915 public ClassCast (Expression child, TypeSpec return_type)
1916 : base (child, return_type)
1920 public ClassCast (Expression child, TypeSpec return_type, bool forced)
1921 : base (child, return_type)
1923 this.forced = forced;
1926 public override void Emit (EmitContext ec)
1930 bool gen = TypeManager.IsGenericParameter (child.Type);
1932 ec.Emit (OpCodes.Box, child.Type);
1934 if (type.IsGenericParameter) {
1935 ec.Emit (OpCodes.Unbox_Any, type);
1942 ec.Emit (OpCodes.Castclass, type);
1947 // Created during resolving pahse when an expression is wrapped or constantified
1948 // and original expression can be used later (e.g. for expression trees)
1950 public class ReducedExpression : Expression
1952 sealed class ReducedConstantExpression : EmptyConstantCast
1954 readonly Expression orig_expr;
1956 public ReducedConstantExpression (Constant expr, Expression orig_expr)
1957 : base (expr, expr.Type)
1959 this.orig_expr = orig_expr;
1962 public override Constant ConvertImplicitly (TypeSpec target_type)
1964 Constant c = base.ConvertImplicitly (target_type);
1966 c = new ReducedConstantExpression (c, orig_expr);
1971 public override Expression CreateExpressionTree (ResolveContext ec)
1973 return orig_expr.CreateExpressionTree (ec);
1976 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1978 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
1980 c = new ReducedConstantExpression (c, orig_expr);
1984 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
1987 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
1989 if (orig_expr is Conditional)
1990 child.EncodeAttributeValue (rc, enc, targetType);
1992 base.EncodeAttributeValue (rc, enc, targetType);
1996 sealed class ReducedExpressionStatement : ExpressionStatement
1998 readonly Expression orig_expr;
1999 readonly ExpressionStatement stm;
2001 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2003 this.orig_expr = orig;
2005 this.eclass = stm.eclass;
2006 this.type = stm.Type;
2008 this.loc = orig.Location;
2011 public override bool ContainsEmitWithAwait ()
2013 return stm.ContainsEmitWithAwait ();
2016 public override Expression CreateExpressionTree (ResolveContext ec)
2018 return orig_expr.CreateExpressionTree (ec);
2021 protected override Expression DoResolve (ResolveContext ec)
2026 public override void Emit (EmitContext ec)
2031 public override void EmitStatement (EmitContext ec)
2033 stm.EmitStatement (ec);
2037 readonly Expression expr, orig_expr;
2039 private ReducedExpression (Expression expr, Expression orig_expr)
2042 this.eclass = expr.eclass;
2043 this.type = expr.Type;
2044 this.orig_expr = orig_expr;
2045 this.loc = orig_expr.Location;
2050 public override bool IsSideEffectFree {
2052 return expr.IsSideEffectFree;
2056 public Expression OriginalExpression {
2064 public override bool ContainsEmitWithAwait ()
2066 return expr.ContainsEmitWithAwait ();
2070 // Creates fully resolved expression switcher
2072 public static Constant Create (Constant expr, Expression original_expr)
2074 if (expr.eclass == ExprClass.Unresolved)
2075 throw new ArgumentException ("Unresolved expression");
2077 return new ReducedConstantExpression (expr, original_expr);
2080 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2082 return new ReducedExpressionStatement (s, orig);
2085 public static Expression Create (Expression expr, Expression original_expr)
2087 return Create (expr, original_expr, true);
2091 // Creates unresolved reduce expression. The original expression has to be
2092 // already resolved. Created expression is constant based based on `expr'
2093 // value unless canBeConstant is used
2095 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2097 if (canBeConstant) {
2098 Constant c = expr as Constant;
2100 return Create (c, original_expr);
2103 ExpressionStatement s = expr as ExpressionStatement;
2105 return Create (s, original_expr);
2107 if (expr.eclass == ExprClass.Unresolved)
2108 throw new ArgumentException ("Unresolved expression");
2110 return new ReducedExpression (expr, original_expr);
2113 public override Expression CreateExpressionTree (ResolveContext ec)
2115 return orig_expr.CreateExpressionTree (ec);
2118 protected override Expression DoResolve (ResolveContext ec)
2123 public override void Emit (EmitContext ec)
2128 public override Expression EmitToField (EmitContext ec)
2130 return expr.EmitToField(ec);
2133 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2135 expr.EmitBranchable (ec, target, on_true);
2138 public override SLE.Expression MakeExpression (BuilderContext ctx)
2140 return orig_expr.MakeExpression (ctx);
2145 // Standard composite pattern
2147 public abstract class CompositeExpression : Expression
2149 protected Expression expr;
2151 protected CompositeExpression (Expression expr)
2154 this.loc = expr.Location;
2157 public override bool ContainsEmitWithAwait ()
2159 return expr.ContainsEmitWithAwait ();
2162 public override Expression CreateExpressionTree (ResolveContext rc)
2164 return expr.CreateExpressionTree (rc);
2167 public Expression Child {
2168 get { return expr; }
2171 protected override Expression DoResolve (ResolveContext rc)
2173 expr = expr.Resolve (rc);
2176 eclass = expr.eclass;
2182 public override void Emit (EmitContext ec)
2187 public override bool IsNull {
2188 get { return expr.IsNull; }
2193 // Base of expressions used only to narrow resolve flow
2195 public abstract class ShimExpression : Expression
2197 protected Expression expr;
2199 protected ShimExpression (Expression expr)
2204 public Expression Expr {
2210 protected override void CloneTo (CloneContext clonectx, Expression t)
2215 ShimExpression target = (ShimExpression) t;
2216 target.expr = expr.Clone (clonectx);
2219 public override bool ContainsEmitWithAwait ()
2221 return expr.ContainsEmitWithAwait ();
2224 public override Expression CreateExpressionTree (ResolveContext ec)
2226 throw new NotSupportedException ("ET");
2229 public override void Emit (EmitContext ec)
2231 throw new InternalErrorException ("Missing Resolve call");
2237 // Unresolved type name expressions
2239 public abstract class ATypeNameExpression : FullNamedExpression
2242 protected TypeArguments targs;
2244 protected ATypeNameExpression (string name, Location l)
2250 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2257 protected ATypeNameExpression (string name, int arity, Location l)
2258 : this (name, new UnboundTypeArguments (arity), l)
2264 protected int Arity {
2266 return targs == null ? 0 : targs.Count;
2270 public bool HasTypeArguments {
2272 return targs != null && !targs.IsEmpty;
2276 public string Name {
2285 public TypeArguments TypeArguments {
2293 public override bool Equals (object obj)
2295 ATypeNameExpression atne = obj as ATypeNameExpression;
2296 return atne != null && atne.Name == Name &&
2297 (targs == null || targs.Equals (atne.targs));
2300 public override int GetHashCode ()
2302 return Name.GetHashCode ();
2305 // TODO: Move it to MemberCore
2306 public static string GetMemberType (MemberCore mc)
2312 if (mc is FieldBase)
2314 if (mc is MethodCore)
2316 if (mc is EnumMember)
2324 public override string GetSignatureForError ()
2326 if (targs != null) {
2327 return Name + "<" + targs.GetSignatureForError () + ">";
2333 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2337 /// SimpleName expressions are formed of a single word and only happen at the beginning
2338 /// of a dotted-name.
2340 public class SimpleName : ATypeNameExpression
2342 public SimpleName (string name, Location l)
2347 public SimpleName (string name, TypeArguments args, Location l)
2348 : base (name, args, l)
2352 public SimpleName (string name, int arity, Location l)
2353 : base (name, arity, l)
2357 public SimpleName GetMethodGroup ()
2359 return new SimpleName (Name, targs, loc);
2362 protected override Expression DoResolve (ResolveContext rc)
2364 var e = SimpleNameResolve (rc, null, false);
2366 var fe = e as FieldExpr;
2368 fe.VerifyAssignedStructField (rc, null);
2374 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2376 return SimpleNameResolve (ec, right_side, false);
2379 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2381 if (ctx.CurrentType != null) {
2382 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2383 if (member != null) {
2384 member.Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2389 var report = ctx.Module.Compiler.Report;
2391 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2392 if (retval != null) {
2393 report.SymbolRelatedToPreviousError (retval.Type);
2394 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2398 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2399 if (retval != null) {
2400 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, Arity, loc);
2404 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2405 if (ns_candidates != null) {
2406 if (ctx is UsingAliasNamespace.AliasContext) {
2407 report.Error (246, loc,
2408 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2409 ns_candidates[0], Name);
2411 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2412 report.Error (246, loc,
2413 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2417 report.Error (246, loc,
2418 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2423 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
2425 FullNamedExpression fne = ec.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2428 if (fne.Type != null && Arity > 0) {
2429 if (HasTypeArguments) {
2430 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2431 if (ct.ResolveAsType (ec) == null)
2437 return new GenericOpenTypeExpr (fne.Type, loc);
2441 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2443 if (!(fne is Namespace))
2447 if (Arity == 0 && Name == "dynamic" && ec.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2448 if (!ec.Module.PredefinedAttributes.Dynamic.IsDefined) {
2449 ec.Module.Compiler.Report.Error (1980, Location,
2450 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2451 ec.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2454 fne = new DynamicTypeExpr (loc);
2455 fne.ResolveAsType (ec);
2461 Error_TypeOrNamespaceNotFound (ec);
2465 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2467 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2470 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2472 int lookup_arity = Arity;
2473 bool errorMode = false;
2475 Block current_block = rc.CurrentBlock;
2476 INamedBlockVariable variable = null;
2477 bool variable_found = false;
2481 // Stage 1: binding to local variables or parameters
2483 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2485 if (current_block != null && lookup_arity == 0) {
2486 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2487 if (!variable.IsDeclared) {
2488 // We found local name in accessible block but it's not
2489 // initialized yet, maybe the user wanted to bind to something else
2491 variable_found = true;
2493 e = variable.CreateReferenceExpression (rc, loc);
2496 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2505 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2507 TypeSpec member_type = rc.CurrentType;
2508 for (; member_type != null; member_type = member_type.DeclaringType) {
2509 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2513 var me = e as MemberExpr;
2515 // The name matches a type, defer to ResolveAsTypeStep
2523 if (variable != null) {
2524 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2525 rc.Report.Error (844, loc,
2526 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2527 Name, me.GetSignatureForError ());
2531 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2532 // Leave it to overload resolution to report correct error
2534 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2535 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2538 // LAMESPEC: again, ignores InvocableOnly
2539 if (variable != null) {
2540 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2541 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2545 // MemberLookup does not check accessors availability, this is actually needed for properties only
2547 var pe = me as PropertyExpr;
2550 // Break as there is no other overload available anyway
2551 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2552 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2555 pe.Getter = pe.PropertyInfo.Get;
2557 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2560 pe.Setter = pe.PropertyInfo.Set;
2565 // TODO: It's used by EventExpr -> FieldExpr transformation only
2566 // TODO: Should go to MemberAccess
2567 me = me.ResolveMemberAccess (rc, null, null);
2571 me.SetTypeArguments (rc, targs);
2578 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2580 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2581 if (IsPossibleTypeOrNamespace (rc)) {
2582 if (variable != null) {
2583 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2584 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2587 return ResolveAsTypeOrNamespace (rc);
2592 if (variable_found) {
2593 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2596 var tparams = rc.CurrentTypeParameters;
2597 if (tparams != null) {
2598 if (tparams.Find (Name) != null) {
2599 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2604 var ct = rc.CurrentType;
2606 if (ct.MemberDefinition.TypeParametersCount > 0) {
2607 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2608 if (ctp.Name == Name) {
2609 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2615 ct = ct.DeclaringType;
2616 } while (ct != null);
2619 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2620 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2622 rc.Report.SymbolRelatedToPreviousError (e.Type);
2623 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2627 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2629 me.Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2630 return ErrorExpression.Instance;
2634 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2636 if (e.Type.Arity != Arity) {
2637 Error_TypeArgumentsCannotBeUsed (rc, e.Type, Arity, loc);
2641 if (e is TypeExpr) {
2642 e.Error_UnexpectedKind (rc, e, "variable", e.ExprClassName, loc);
2647 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2650 return ErrorExpression.Instance;
2653 if (rc.Module.Evaluator != null) {
2654 var fi = rc.Module.Evaluator.LookupField (Name);
2656 return new FieldExpr (fi.Item1, loc);
2664 Expression SimpleNameResolve (ResolveContext ec, Expression right_side, bool intermediate)
2666 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2671 if (right_side != null) {
2672 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2673 e.Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2677 e = e.ResolveLValue (ec, right_side);
2685 public override object Accept (StructuralVisitor visitor)
2687 return visitor.Visit (this);
2692 /// Represents a namespace or a type. The name of the class was inspired by
2693 /// section 10.8.1 (Fully Qualified Names).
2695 public abstract class FullNamedExpression : Expression
2697 protected override void CloneTo (CloneContext clonectx, Expression target)
2699 // Do nothing, most unresolved type expressions cannot be
2700 // resolved to different type
2703 public override bool ContainsEmitWithAwait ()
2708 public override Expression CreateExpressionTree (ResolveContext ec)
2710 throw new NotSupportedException ("ET");
2713 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc);
2716 // This is used to resolve the expression as a type, a null
2717 // value will be returned if the expression is not a type
2720 public override TypeSpec ResolveAsType (IMemberContext mc)
2722 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc);
2727 TypeExpr te = fne as TypeExpr;
2729 fne.Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
2737 var dep = type.GetMissingDependencies ();
2739 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
2742 if (type.Kind == MemberKind.Void) {
2743 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
2747 // Obsolete checks cannot be done when resolving base context as they
2748 // require type dependencies to be set but we are in process of resolving them
2750 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
2751 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
2752 if (obsolete_attr != null && !mc.IsObsolete) {
2753 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
2761 public override void Emit (EmitContext ec)
2763 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
2764 GetSignatureForError ());
2769 /// Expression that evaluates to a type
2771 public abstract class TypeExpr : FullNamedExpression
2773 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
2779 protected sealed override Expression DoResolve (ResolveContext ec)
2785 public override bool Equals (object obj)
2787 TypeExpr tobj = obj as TypeExpr;
2791 return Type == tobj.Type;
2794 public override int GetHashCode ()
2796 return Type.GetHashCode ();
2801 /// Fully resolved Expression that already evaluated to a type
2803 public class TypeExpression : TypeExpr
2805 public TypeExpression (TypeSpec t, Location l)
2808 eclass = ExprClass.Type;
2812 public sealed override TypeSpec ResolveAsType (IMemberContext ec)
2819 /// This class denotes an expression which evaluates to a member
2820 /// of a struct or a class.
2822 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
2825 // An instance expression associated with this member, if it's a
2826 // non-static member
2828 public Expression InstanceExpression;
2831 /// The name of this member.
2833 public abstract string Name {
2838 // When base.member is used
2840 public bool IsBase {
2841 get { return InstanceExpression is BaseThis; }
2845 /// Whether this is an instance member.
2847 public abstract bool IsInstance {
2852 /// Whether this is a static member.
2854 public abstract bool IsStatic {
2858 public abstract string KindName {
2862 protected abstract TypeSpec DeclaringType {
2866 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
2868 return InstanceExpression.Type;
2873 // Converts best base candidate for virtual method starting from QueriedBaseType
2875 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
2878 // Only when base.member is used and method is virtual
2884 // Overload resulution works on virtual or non-virtual members only (no overrides). That
2885 // means for base.member access we have to find the closest match after we found best candidate
2887 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
2889 // The method could already be what we are looking for
2891 TypeSpec[] targs = null;
2892 if (method.DeclaringType != InstanceExpression.Type) {
2893 var base_override = MemberCache.FindMember (InstanceExpression.Type, new MemberFilter (method), BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
2894 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
2895 if (base_override.IsGeneric)
2896 targs = method.TypeArguments;
2898 method = base_override;
2903 // When base access is used inside anonymous method/iterator/etc we need to
2904 // get back to the context of original type. We do it by emiting proxy
2905 // method in original class and rewriting base call to this compiler
2906 // generated method call which does the actual base invocation. This may
2907 // introduce redundant storey but with `this' only but it's tricky to avoid
2908 // at this stage as we don't know what expressions follow base
2910 if (rc.CurrentAnonymousMethod != null) {
2911 if (targs == null && method.IsGeneric) {
2912 targs = method.TypeArguments;
2913 method = method.GetGenericMethodDefinition ();
2916 if (method.Parameters.HasArglist)
2917 throw new NotImplementedException ("__arglist base call proxy");
2919 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
2921 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
2922 // get/set member expressions second call would fail to proxy because left expression
2923 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
2924 // FIXME: The async check is another hack but will probably fail with mutators
2925 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
2926 InstanceExpression = new This (loc).Resolve (rc);
2930 method = method.MakeGenericMethod (rc, targs);
2934 // Only base will allow this invocation to happen.
2936 if (method.IsAbstract) {
2937 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
2943 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2945 if (InstanceExpression == null)
2948 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
2949 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
2950 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
2955 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
2957 if (InstanceExpression == null)
2960 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
2963 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
2965 var ct = rc.CurrentType;
2966 if (ct == qualifier)
2969 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
2972 qualifier = qualifier.GetDefinition ();
2973 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
2980 public override bool ContainsEmitWithAwait ()
2982 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
2985 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
2988 type = type.GetDefinition ();
2990 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
2993 type = type.DeclaringType;
2994 } while (type != null);
2999 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3001 if (InstanceExpression != null) {
3002 InstanceExpression = InstanceExpression.Resolve (rc);
3003 CheckProtectedMemberAccess (rc, member);
3006 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3007 UnsafeError (rc, loc);
3010 var dep = member.GetMissingDependencies ();
3012 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3015 if (!rc.IsObsolete) {
3016 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3018 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3021 if (!(member is FieldSpec))
3022 member.MemberDefinition.SetIsUsed ();
3025 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3027 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3030 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3032 rc.Report.SymbolRelatedToPreviousError (member);
3033 rc.Report.Error (1540, loc,
3034 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3035 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3038 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3040 if (!ResolveInstanceExpressionCore (rc, rhs))
3044 // Check intermediate value modification which won't have any effect
3046 if (rhs != null && InstanceExpression.Type.IsStruct &&
3047 (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation)) {
3049 if (rc.CurrentInitializerVariable != null) {
3050 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3051 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3053 rc.Report.Error (1612, loc,
3054 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3055 InstanceExpression.GetSignatureForError ());
3062 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3065 if (InstanceExpression != null) {
3066 if (InstanceExpression is TypeExpr) {
3067 var t = InstanceExpression.Type;
3069 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3070 if (oa != null && !rc.IsObsolete) {
3071 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3074 t = t.DeclaringType;
3075 } while (t != null);
3077 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3078 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3079 rc.Report.Error (176, loc,
3080 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3081 GetSignatureForError ());
3085 InstanceExpression = null;
3091 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3092 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3093 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
3094 rc.Report.Error (236, loc,
3095 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3096 GetSignatureForError ());
3098 rc.Report.Error (120, loc,
3099 "An object reference is required to access non-static member `{0}'",
3100 GetSignatureForError ());
3102 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3106 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3107 rc.Report.Error (38, loc,
3108 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3109 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3112 InstanceExpression = new This (loc);
3113 if (this is FieldExpr && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3114 using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
3115 InstanceExpression = InstanceExpression.Resolve (rc);
3118 InstanceExpression = InstanceExpression.Resolve (rc);
3124 var me = InstanceExpression as MemberExpr;
3126 me.ResolveInstanceExpressionCore (rc, rhs);
3128 // Using this check to detect probing instance expression resolve
3129 if (!rc.OmitStructFlowAnalysis) {
3130 var fe = me as FieldExpr;
3131 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3132 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3133 rc.Report.Warning (1690, 1, loc,
3134 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3135 me.GetSignatureForError ());
3143 // Run member-access postponed check once we know that
3144 // the expression is not field expression which is the only
3145 // expression which can use uninitialized this
3147 if (InstanceExpression is This && !(this is FieldExpr) && rc.CurrentBlock.ParametersBlock.TopBlock.ThisVariable != null) {
3148 ((This)InstanceExpression).CheckStructThisDefiniteAssignment (rc);
3152 // Additional checks for l-value member access
3155 if (InstanceExpression is UnboxCast) {
3156 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3163 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3165 if (left != null && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3166 ec.Report.Warning (1720, 1, left.Location,
3167 "Expression will always cause a `{0}'", "System.NullReferenceException");
3170 InstanceExpression = left;
3174 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3176 TypeSpec instance_type = InstanceExpression.Type;
3177 if (TypeSpec.IsValueType (instance_type)) {
3178 if (InstanceExpression is IMemoryLocation) {
3179 ((IMemoryLocation) InstanceExpression).AddressOf (ec, AddressOp.Load);
3181 // Cannot release the temporary variable when its address
3182 // is required to be on stack for any parent
3183 LocalTemporary t = new LocalTemporary (instance_type);
3184 InstanceExpression.Emit (ec);
3186 t.AddressOf (ec, AddressOp.Store);
3189 InstanceExpression.Emit (ec);
3191 // Only to make verifier happy
3192 if (instance_type.IsGenericParameter && !(InstanceExpression is This) && TypeSpec.IsReferenceType (instance_type))
3193 ec.Emit (OpCodes.Box, instance_type);
3196 if (prepare_for_load)
3197 ec.Emit (OpCodes.Dup);
3200 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3203 public class ExtensionMethodCandidates
3205 readonly NamespaceContainer container;
3206 readonly IList<MethodSpec> methods;
3208 readonly IMemberContext context;
3210 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3212 this.context = context;
3213 this.methods = methods;
3214 this.container = nsContainer;
3215 this.index = lookupIndex;
3218 public NamespaceContainer Container {
3224 public IMemberContext Context {
3230 public int LookupIndex {
3236 public IList<MethodSpec> Methods {
3244 // Represents a group of extension method candidates for whole namespace
3246 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3248 ExtensionMethodCandidates candidates;
3249 public Expression ExtensionExpression;
3251 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3252 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3254 this.candidates = candidates;
3255 this.ExtensionExpression = extensionExpr;
3258 public override bool IsStatic {
3259 get { return true; }
3263 // For extension methodgroup we are not looking for base members but parent
3264 // namespace extension methods
3266 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3268 // TODO: candidates are null only when doing error reporting, that's
3269 // incorrect. We have to discover same extension methods in error mode
3270 if (candidates == null)
3273 int arity = type_arguments == null ? 0 : type_arguments.Count;
3275 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3276 if (candidates == null)
3279 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3282 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3284 // We are already here
3288 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3290 if (arguments == null)
3291 arguments = new Arguments (1);
3293 ExtensionExpression = ExtensionExpression.Resolve (ec);
3294 if (ExtensionExpression == null)
3297 arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
3298 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3300 // Store resolved argument and restore original arguments
3302 // Clean-up modified arguments for error reporting
3303 arguments.RemoveAt (0);
3307 var me = ExtensionExpression as MemberExpr;
3309 me.ResolveInstanceExpression (ec, null);
3310 var fe = me as FieldExpr;
3312 fe.Spec.MemberDefinition.SetIsUsed ();
3315 InstanceExpression = null;
3319 #region IErrorHandler Members
3321 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3326 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3328 rc.Report.SymbolRelatedToPreviousError (best);
3329 rc.Report.Error (1928, loc,
3330 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3331 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3334 rc.Report.Error (1929, loc,
3335 "Extension method instance type `{0}' cannot be converted to `{1}'",
3336 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3342 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3347 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3356 /// MethodGroupExpr represents a group of method candidates which
3357 /// can be resolved to the best method overload
3359 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3361 protected IList<MemberSpec> Methods;
3362 MethodSpec best_candidate;
3363 TypeSpec best_candidate_return;
3364 protected TypeArguments type_arguments;
3366 SimpleName simple_name;
3367 protected TypeSpec queried_type;
3369 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3373 this.type = InternalType.MethodGroup;
3375 eclass = ExprClass.MethodGroup;
3376 queried_type = type;
3379 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3380 : this (new MemberSpec[] { m }, type, loc)
3386 public MethodSpec BestCandidate {
3388 return best_candidate;
3392 public TypeSpec BestCandidateReturnType {
3394 return best_candidate_return;
3398 public IList<MemberSpec> Candidates {
3404 protected override TypeSpec DeclaringType {
3406 return queried_type;
3410 public override bool IsInstance {
3412 if (best_candidate != null)
3413 return !best_candidate.IsStatic;
3419 public override bool IsStatic {
3421 if (best_candidate != null)
3422 return best_candidate.IsStatic;
3428 public override string KindName {
3429 get { return "method"; }
3432 public override string Name {
3434 if (best_candidate != null)
3435 return best_candidate.Name;
3438 return Methods.First ().Name;
3445 // When best candidate is already know this factory can be used
3446 // to avoid expensive overload resolution to be called
3448 // NOTE: InstanceExpression has to be set manually
3450 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3452 return new MethodGroupExpr (best, queriedType, loc) {
3453 best_candidate = best,
3454 best_candidate_return = best.ReturnType
3458 public override string GetSignatureForError ()
3460 if (best_candidate != null)
3461 return best_candidate.GetSignatureForError ();
3463 return Methods.First ().GetSignatureForError ();
3466 public override Expression CreateExpressionTree (ResolveContext ec)
3468 if (best_candidate == null) {
3469 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3473 if (best_candidate.IsConditionallyExcluded (ec, loc))
3474 ec.Report.Error (765, loc,
3475 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3477 return new TypeOfMethod (best_candidate, loc);
3480 protected override Expression DoResolve (ResolveContext ec)
3482 this.eclass = ExprClass.MethodGroup;
3484 if (InstanceExpression != null) {
3485 InstanceExpression = InstanceExpression.Resolve (ec);
3486 if (InstanceExpression == null)
3493 public override void Emit (EmitContext ec)
3495 throw new NotSupportedException ();
3498 public void EmitCall (EmitContext ec, Arguments arguments)
3500 var call = new CallEmitter ();
3501 call.InstanceExpression = InstanceExpression;
3502 call.Emit (ec, best_candidate, arguments, loc);
3505 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3507 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3508 Name, target.GetSignatureForError ());
3511 public static bool IsExtensionMethodArgument (Expression expr)
3514 // LAMESPEC: No details about which expressions are not allowed
3516 return !(expr is TypeExpr) && !(expr is BaseThis);
3520 /// Find the Applicable Function Members (7.4.2.1)
3522 /// me: Method Group expression with the members to select.
3523 /// it might contain constructors or methods (or anything
3524 /// that maps to a method).
3526 /// Arguments: ArrayList containing resolved Argument objects.
3528 /// loc: The location if we want an error to be reported, or a Null
3529 /// location for "probing" purposes.
3531 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3532 /// that is the best match of me on Arguments.
3535 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
3537 // TODO: causes issues with probing mode, remove explicit Kind check
3538 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
3541 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
3542 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
3543 r.BaseMembersProvider = this;
3544 r.InstanceQualifier = this;
3547 if (cerrors != null)
3548 r.CustomErrors = cerrors;
3550 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
3551 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
3552 if (best_candidate == null)
3553 return r.BestCandidateIsDynamic ? this : null;
3555 // Overload resolver had to create a new method group, all checks bellow have already been executed
3556 if (r.BestCandidateNewMethodGroup != null)
3557 return r.BestCandidateNewMethodGroup;
3559 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
3560 if (InstanceExpression != null) {
3561 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
3562 InstanceExpression = null;
3564 if (best_candidate.IsStatic && simple_name != null) {
3565 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
3568 InstanceExpression.Resolve (ec);
3572 ResolveInstanceExpression (ec, null);
3575 var base_override = CandidateToBaseOverride (ec, best_candidate);
3576 if (base_override == best_candidate) {
3577 best_candidate_return = r.BestCandidateReturnType;
3579 best_candidate = base_override;
3580 best_candidate_return = best_candidate.ReturnType;
3583 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
3584 ConstraintChecker cc = new ConstraintChecker (ec);
3585 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
3589 // Additional check for possible imported base override method which
3590 // could not be done during IsOverrideMethodBaseTypeAccessible
3592 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
3593 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
3594 ec.Report.SymbolRelatedToPreviousError (best_candidate);
3595 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
3601 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3603 var fe = left as FieldExpr;
3606 // Using method-group on struct fields makes the struct assigned. I am not sure
3607 // why but that's what .net does
3609 fe.Spec.MemberDefinition.SetIsAssigned ();
3612 simple_name = original;
3613 return base.ResolveMemberAccess (ec, left, original);
3616 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
3618 type_arguments = ta;
3621 #region IBaseMembersProvider Members
3623 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3625 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
3628 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3630 if (queried_type == member.DeclaringType)
3633 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
3634 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
3638 // Extension methods lookup after ordinary methods candidates failed to apply
3640 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3642 if (InstanceExpression == null)
3645 InstanceExpression = InstanceExpression.Resolve (rc);
3646 if (!IsExtensionMethodArgument (InstanceExpression))
3649 int arity = type_arguments == null ? 0 : type_arguments.Count;
3650 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
3651 if (methods == null)
3654 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
3655 emg.SetTypeArguments (rc, type_arguments);
3662 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
3664 public ConstructorInstanceQualifier (TypeSpec type)
3667 InstanceType = type;
3670 public TypeSpec InstanceType { get; private set; }
3672 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3674 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
3678 public struct OverloadResolver
3681 public enum Restrictions
3685 ProbingOnly = 1 << 1,
3686 CovariantDelegate = 1 << 2,
3687 NoBaseMembers = 1 << 3,
3688 BaseMembersIncluded = 1 << 4
3691 public interface IBaseMembersProvider
3693 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
3694 IParametersMember GetOverrideMemberParameters (MemberSpec member);
3695 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
3698 public interface IErrorHandler
3700 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
3701 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
3702 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
3703 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
3706 public interface IInstanceQualifier
3708 TypeSpec InstanceType { get; }
3709 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
3712 sealed class NoBaseMembers : IBaseMembersProvider
3714 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
3716 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3721 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
3726 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3732 struct AmbiguousCandidate
3734 public readonly MemberSpec Member;
3735 public readonly bool Expanded;
3736 public readonly AParametersCollection Parameters;
3738 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
3741 Parameters = parameters;
3742 Expanded = expanded;
3747 IList<MemberSpec> members;
3748 TypeArguments type_arguments;
3749 IBaseMembersProvider base_provider;
3750 IErrorHandler custom_errors;
3751 IInstanceQualifier instance_qualifier;
3752 Restrictions restrictions;
3753 MethodGroupExpr best_candidate_extension_group;
3754 TypeSpec best_candidate_return_type;
3756 SessionReportPrinter lambda_conv_msgs;
3758 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
3759 : this (members, null, restrictions, loc)
3763 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
3766 if (members == null || members.Count == 0)
3767 throw new ArgumentException ("empty members set");
3769 this.members = members;
3771 type_arguments = targs;
3772 this.restrictions = restrictions;
3773 if (IsDelegateInvoke)
3774 this.restrictions |= Restrictions.NoBaseMembers;
3776 base_provider = NoBaseMembers.Instance;
3781 public IBaseMembersProvider BaseMembersProvider {
3783 return base_provider;
3786 base_provider = value;
3790 public bool BestCandidateIsDynamic { get; set; }
3793 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
3795 public MethodGroupExpr BestCandidateNewMethodGroup {
3797 return best_candidate_extension_group;
3802 // Return type can be different between best candidate and closest override
3804 public TypeSpec BestCandidateReturnType {
3806 return best_candidate_return_type;
3810 public IErrorHandler CustomErrors {
3812 return custom_errors;
3815 custom_errors = value;
3819 TypeSpec DelegateType {
3821 if ((restrictions & Restrictions.DelegateInvoke) == 0)
3822 throw new InternalErrorException ("Not running in delegate mode", loc);
3824 return members [0].DeclaringType;
3828 public IInstanceQualifier InstanceQualifier {
3830 return instance_qualifier;
3833 instance_qualifier = value;
3837 bool IsProbingOnly {
3839 return (restrictions & Restrictions.ProbingOnly) != 0;
3843 bool IsDelegateInvoke {
3845 return (restrictions & Restrictions.DelegateInvoke) != 0;
3852 // 7.4.3.3 Better conversion from expression
3853 // Returns : 1 if a->p is better,
3854 // 2 if a->q is better,
3855 // 0 if neither is better
3857 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
3859 TypeSpec argument_type = a.Type;
3862 // If argument is an anonymous function
3864 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
3866 // p and q are delegate types or expression tree types
3868 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
3869 if (q.MemberDefinition != p.MemberDefinition) {
3874 // Uwrap delegate from Expression<T>
3876 q = TypeManager.GetTypeArguments (q)[0];
3877 p = TypeManager.GetTypeArguments (p)[0];
3880 var p_m = Delegate.GetInvokeMethod (p);
3881 var q_m = Delegate.GetInvokeMethod (q);
3884 // With identical parameter lists
3886 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
3895 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
3897 if (p.Kind == MemberKind.Void) {
3898 return q.Kind != MemberKind.Void ? 2 : 0;
3902 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
3904 if (q.Kind == MemberKind.Void) {
3905 return p.Kind != MemberKind.Void ? 1: 0;
3908 var am = (AnonymousMethodExpression) a.Expr;
3911 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
3912 // better conversion is performed between underlying types Y1 and Y2
3914 if (p.IsGenericTask || q.IsGenericTask) {
3915 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
3916 q = q.TypeArguments[0];
3917 p = p.TypeArguments[0];
3919 } else if (q != p) {
3921 // LAMESPEC: Lambda expression returning dynamic type has identity (better) conversion to delegate returning object type
3923 if (q.BuiltinType == BuiltinTypeSpec.Type.Object) {
3924 var am_rt = am.InferReturnType (ec, null, orig_q);
3925 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3927 } else if (p.BuiltinType == BuiltinTypeSpec.Type.Object) {
3928 var am_rt = am.InferReturnType (ec, null, orig_p);
3929 if (am_rt != null && am_rt.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
3935 // The parameters are identicial and return type is not void, use better type conversion
3936 // on return type to determine better one
3939 if (argument_type == p)
3942 if (argument_type == q)
3946 return BetterTypeConversion (ec, p, q);
3950 // 7.4.3.4 Better conversion from type
3952 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
3954 if (p == null || q == null)
3955 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
3957 switch (p.BuiltinType) {
3958 case BuiltinTypeSpec.Type.Int:
3959 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3962 case BuiltinTypeSpec.Type.Long:
3963 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
3966 case BuiltinTypeSpec.Type.SByte:
3967 switch (q.BuiltinType) {
3968 case BuiltinTypeSpec.Type.Byte:
3969 case BuiltinTypeSpec.Type.UShort:
3970 case BuiltinTypeSpec.Type.UInt:
3971 case BuiltinTypeSpec.Type.ULong:
3975 case BuiltinTypeSpec.Type.Short:
3976 switch (q.BuiltinType) {
3977 case BuiltinTypeSpec.Type.UShort:
3978 case BuiltinTypeSpec.Type.UInt:
3979 case BuiltinTypeSpec.Type.ULong:
3983 case BuiltinTypeSpec.Type.Dynamic:
3984 // Dynamic is never better
3988 switch (q.BuiltinType) {
3989 case BuiltinTypeSpec.Type.Int:
3990 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3993 case BuiltinTypeSpec.Type.Long:
3994 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
3997 case BuiltinTypeSpec.Type.SByte:
3998 switch (p.BuiltinType) {
3999 case BuiltinTypeSpec.Type.Byte:
4000 case BuiltinTypeSpec.Type.UShort:
4001 case BuiltinTypeSpec.Type.UInt:
4002 case BuiltinTypeSpec.Type.ULong:
4006 case BuiltinTypeSpec.Type.Short:
4007 switch (p.BuiltinType) {
4008 case BuiltinTypeSpec.Type.UShort:
4009 case BuiltinTypeSpec.Type.UInt:
4010 case BuiltinTypeSpec.Type.ULong:
4014 case BuiltinTypeSpec.Type.Dynamic:
4015 // Dynamic is never better
4019 // FIXME: handle lifted operators
4021 // TODO: this is expensive
4022 Expression p_tmp = new EmptyExpression (p);
4023 Expression q_tmp = new EmptyExpression (q);
4025 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4026 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4028 if (p_to_q && !q_to_p)
4031 if (q_to_p && !p_to_q)
4038 /// Determines "Better function" between candidate
4039 /// and the current best match
4042 /// Returns a boolean indicating :
4043 /// false if candidate ain't better
4044 /// true if candidate is better than the current best match
4046 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4047 MemberSpec best, AParametersCollection bparam, bool best_params)
4049 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4050 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4052 bool better_at_least_one = false;
4054 int args_count = args == null ? 0 : args.Count;
4058 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4061 // Default arguments are ignored for better decision
4062 if (a.IsDefaultArgument)
4066 // When comparing named argument the parameter type index has to be looked up
4067 // in original parameter set (override version for virtual members)
4069 NamedArgument na = a as NamedArgument;
4071 int idx = cparam.GetParameterIndexByName (na.Name);
4072 ct = candidate_pd.Types[idx];
4073 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4074 ct = TypeManager.GetElementType (ct);
4076 idx = bparam.GetParameterIndexByName (na.Name);
4077 bt = best_pd.Types[idx];
4078 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4079 bt = TypeManager.GetElementType (bt);
4081 ct = candidate_pd.Types[c_idx];
4082 bt = best_pd.Types[b_idx];
4084 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4085 ct = TypeManager.GetElementType (ct);
4089 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4090 bt = TypeManager.GetElementType (bt);
4095 if (TypeSpecComparer.IsEqual (ct, bt))
4099 int result = BetterExpressionConversion (ec, a, ct, bt);
4101 // for each argument, the conversion to 'ct' should be no worse than
4102 // the conversion to 'bt'.
4106 // for at least one argument, the conversion to 'ct' should be better than
4107 // the conversion to 'bt'.
4109 better_at_least_one = true;
4112 if (better_at_least_one)
4116 // This handles the case
4118 // Add (float f1, float f2, float f3);
4119 // Add (params decimal [] foo);
4121 // The call Add (3, 4, 5) should be ambiguous. Without this check, the
4122 // first candidate would've chosen as better.
4124 if (!same && !a.IsDefaultArgument)
4128 // The two methods have equal non-optional parameter types, apply tie-breaking rules
4132 // This handles the following cases:
4134 // Foo (int i) is better than Foo (int i, long l = 0)
4135 // Foo (params int[] args) is better than Foo (int i = 0, params int[] args)
4136 // Foo (string s, params string[] args) is better than Foo (params string[] args)
4138 // Prefer non-optional version
4140 // LAMESPEC: Specification claims this should be done at last but the opposite is true
4142 if (candidate_params == best_params && candidate_pd.Count != best_pd.Count) {
4143 if (j < candidate_pd.Count && candidate_pd.FixedParameters[j].HasDefaultValue)
4146 if (j < best_pd.Count && best_pd.FixedParameters[j].HasDefaultValue)
4149 return candidate_pd.Count >= best_pd.Count;
4153 // One is a non-generic method and second is a generic method, then non-generic is better
4155 if (best.IsGeneric != candidate.IsGeneric)
4156 return best.IsGeneric;
4159 // This handles the following cases:
4161 // Trim () is better than Trim (params char[] chars)
4162 // Concat (string s1, string s2, string s3) is better than
4163 // Concat (string s1, params string [] srest)
4164 // Foo (int, params int [] rest) is better than Foo (params int [] rest)
4166 // Prefer non-expanded version
4168 if (candidate_params != best_params)
4171 int candidate_param_count = candidate_pd.Count;
4172 int best_param_count = best_pd.Count;
4174 if (candidate_param_count != best_param_count)
4175 // can only happen if (candidate_params && best_params)
4176 return candidate_param_count > best_param_count && best_pd.HasParams;
4179 // Both methods have the same number of parameters, and the parameters have equal types
4180 // Pick the "more specific" signature using rules over original (non-inflated) types
4182 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4183 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4185 bool specific_at_least_once = false;
4186 for (j = 0; j < args_count; ++j) {
4187 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4189 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4190 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4192 ct = candidate_def_pd.Types[j];
4193 bt = best_def_pd.Types[j];
4198 TypeSpec specific = MoreSpecific (ct, bt);
4202 specific_at_least_once = true;
4205 if (specific_at_least_once)
4211 static bool CheckInflatedArguments (MethodSpec ms)
4213 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4216 // Setup constraint checker for probing only
4217 ConstraintChecker cc = new ConstraintChecker (null);
4219 var mp = ms.Parameters.Types;
4220 for (int i = 0; i < mp.Length; ++i) {
4221 var type = mp[i] as InflatedTypeSpec;
4225 var targs = type.TypeArguments;
4226 if (targs.Length == 0)
4229 // TODO: Checking inflated MVAR arguments should be enough
4230 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4237 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4239 rc.Report.Error (1729, loc,
4240 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4241 type.GetSignatureForError (), argCount.ToString ());
4245 // Determines if the candidate method is applicable to the given set of arguments
4246 // There could be two different set of parameters for same candidate where one
4247 // is the closest override for default values and named arguments checks and second
4248 // one being the virtual base for the parameter types and modifiers.
4250 // A return value rates candidate method compatibility,
4251 // 0 = the best, int.MaxValue = the worst
4254 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)
4256 // Parameters of most-derived type used mainly for named and optional parameters
4257 var pd = pm.Parameters;
4259 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4260 // params modifier instead of most-derived type
4261 var cpd = ((IParametersMember) candidate).Parameters;
4262 int param_count = pd.Count;
4263 int optional_count = 0;
4265 Arguments orig_args = arguments;
4267 if (arg_count != param_count) {
4269 // No arguments expansion when doing exact match for delegates
4271 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4272 for (int i = 0; i < pd.Count; ++i) {
4273 if (pd.FixedParameters[i].HasDefaultValue) {
4274 optional_count = pd.Count - i;
4280 if (optional_count != 0) {
4281 // Readjust expected number when params used
4282 if (cpd.HasParams) {
4284 if (arg_count < param_count)
4286 } else if (arg_count > param_count) {
4287 int args_gap = System.Math.Abs (arg_count - param_count);
4288 return int.MaxValue - 10000 + args_gap;
4289 } else if (arg_count < param_count - optional_count) {
4290 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4291 return int.MaxValue - 10000 + args_gap;
4293 } else if (arg_count != param_count) {
4294 int args_gap = System.Math.Abs (arg_count - param_count);
4296 return int.MaxValue - 10000 + args_gap;
4297 if (arg_count < param_count - 1)
4298 return int.MaxValue - 10000 + args_gap;
4301 // Resize to fit optional arguments
4302 if (optional_count != 0) {
4303 if (arguments == null) {
4304 arguments = new Arguments (optional_count);
4306 // Have to create a new container, so the next run can do same
4307 var resized = new Arguments (param_count);
4308 resized.AddRange (arguments);
4309 arguments = resized;
4312 for (int i = arg_count; i < param_count; ++i)
4313 arguments.Add (null);
4317 if (arg_count > 0) {
4319 // Shuffle named arguments to the right positions if there are any
4321 if (arguments[arg_count - 1] is NamedArgument) {
4322 arg_count = arguments.Count;
4324 for (int i = 0; i < arg_count; ++i) {
4325 bool arg_moved = false;
4327 NamedArgument na = arguments[i] as NamedArgument;
4331 int index = pd.GetParameterIndexByName (na.Name);
4333 // Named parameter not found
4337 // already reordered
4342 if (index >= param_count) {
4343 // When using parameters which should not be available to the user
4344 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4347 arguments.Add (null);
4351 temp = arguments[index];
4353 // The slot has been taken by positional argument
4354 if (temp != null && !(temp is NamedArgument))
4359 arguments = arguments.MarkOrderedArgument (na);
4363 arguments[index] = arguments[i];
4364 arguments[i] = temp;
4371 arg_count = arguments.Count;
4373 } else if (arguments != null) {
4374 arg_count = arguments.Count;
4378 // Don't do any expensive checks when the candidate cannot succeed
4380 if (arg_count != param_count && !cpd.HasParams)
4381 return (param_count - arg_count) * 2 + 1;
4383 var dep = candidate.GetMissingDependencies ();
4385 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4390 // 1. Handle generic method using type arguments when specified or type inference
4393 var ms = candidate as MethodSpec;
4394 if (ms != null && ms.IsGeneric) {
4395 if (type_arguments != null) {
4396 var g_args_count = ms.Arity;
4397 if (g_args_count != type_arguments.Count)
4398 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4400 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4403 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4404 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4405 // candidate was found use the set to report more details about what was wrong with lambda body.
4406 // The general idea is to distinguish between code errors and errors caused by
4407 // trial-and-error type inference
4409 if (lambda_conv_msgs == null) {
4410 for (int i = 0; i < arg_count; i++) {
4411 Argument a = arguments[i];
4415 var am = a.Expr as AnonymousMethodExpression;
4417 if (lambda_conv_msgs == null)
4418 lambda_conv_msgs = new SessionReportPrinter ();
4420 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4425 var ti = new TypeInference (arguments);
4426 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4429 return ti.InferenceScore - 20000;
4432 // Clear any error messages when the result was success
4434 if (lambda_conv_msgs != null)
4435 lambda_conv_msgs.ClearSession ();
4437 if (i_args.Length != 0) {
4438 ms = ms.MakeGenericMethod (ec, i_args);
4443 // Type arguments constraints have to match for the method to be applicable
4445 if (!CheckInflatedArguments (ms)) {
4447 return int.MaxValue - 25000;
4451 // We have a generic return type and at same time the method is override which
4452 // means we have to also inflate override return type in case the candidate is
4453 // best candidate and override return type is different to base return type.
4455 // virtual Foo<T, object> with override Foo<T, dynamic>
4457 if (candidate != pm) {
4458 MethodSpec override_ms = (MethodSpec) pm;
4459 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4460 returnType = inflator.Inflate (returnType);
4462 returnType = ms.ReturnType;
4469 if (type_arguments != null)
4470 return int.MaxValue - 15000;
4476 // 2. Each argument has to be implicitly convertible to method parameter
4478 Parameter.Modifier p_mod = 0;
4481 for (int i = 0; i < arg_count; i++) {
4482 Argument a = arguments[i];
4484 var fp = pd.FixedParameters[i];
4485 if (!fp.HasDefaultValue) {
4486 arguments = orig_args;
4487 return arg_count * 2 + 2;
4491 // Get the default value expression, we can use the same expression
4492 // if the type matches
4494 Expression e = fp.DefaultValue;
4496 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4498 // Restore for possible error reporting
4499 for (int ii = i; ii < arg_count; ++ii)
4500 arguments.RemoveAt (i);
4502 return (arg_count - i) * 2 + 1;
4506 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4508 // LAMESPEC: Attributes can be mixed together with build-in priority
4510 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4511 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4512 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
4513 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
4514 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
4515 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
4519 arguments[i] = new Argument (e, Argument.AType.Default);
4523 if (p_mod != Parameter.Modifier.PARAMS) {
4524 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
4526 } else if (!params_expanded_form) {
4527 params_expanded_form = true;
4528 pt = ((ElementTypeSpec) pt).Element;
4534 if (!params_expanded_form) {
4535 if (a.ArgType == Argument.AType.ExtensionType) {
4537 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
4539 // LAMESPEC: or implicit type parameter conversion
4542 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
4543 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
4544 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
4549 score = IsArgumentCompatible (ec, a, p_mod, pt);
4552 dynamicArgument = true;
4557 // It can be applicable in expanded form (when not doing exact match like for delegates)
4559 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
4560 if (!params_expanded_form) {
4561 pt = ((ElementTypeSpec) pt).Element;
4565 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
4568 params_expanded_form = true;
4569 dynamicArgument = true;
4570 } else if (score == 0 || arg_count > pd.Count) {
4571 params_expanded_form = true;
4576 if (params_expanded_form)
4578 return (arg_count - i) * 2 + score;
4583 // When params parameter has no argument it will be provided later if the method is the best candidate
4585 if (arg_count + 1 == pd.Count && (cpd.FixedParameters [arg_count].ModFlags & Parameter.Modifier.PARAMS) != 0)
4586 params_expanded_form = true;
4589 // Restore original arguments for dynamic binder to keep the intention of original source code
4591 if (dynamicArgument)
4592 arguments = orig_args;
4597 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
4599 if (e is Constant && e.Type == ptype)
4603 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
4605 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
4606 e = new MemberAccess (new MemberAccess (new MemberAccess (
4607 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
4608 } else if (e is Constant) {
4610 // Handles int to int? conversions, DefaultParameterValue check
4612 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
4616 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
4619 return e.Resolve (ec);
4623 // Tests argument compatibility with the parameter
4624 // The possible return values are
4626 // 1 - modifier mismatch
4627 // 2 - type mismatch
4628 // -1 - dynamic binding required
4630 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
4633 // Types have to be identical when ref or out modifer
4634 // is used and argument is not of dynamic type
4636 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
4637 if (argument.Type != parameter) {
4639 // Do full equality check after quick path
4641 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
4643 // Using dynamic for ref/out parameter can still succeed at runtime
4645 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4652 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
4654 // Using dynamic for ref/out parameter can still succeed at runtime
4656 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
4663 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
4667 // Use implicit conversion in all modes to return same candidates when the expression
4668 // is used as argument or delegate conversion
4670 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
4678 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
4680 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4682 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4685 var ac_p = p as ArrayContainer;
4687 var ac_q = q as ArrayContainer;
4691 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
4692 if (specific == ac_p.Element)
4694 if (specific == ac_q.Element)
4696 } else if (p.IsGeneric && q.IsGeneric) {
4697 var pargs = TypeManager.GetTypeArguments (p);
4698 var qargs = TypeManager.GetTypeArguments (q);
4700 bool p_specific_at_least_once = false;
4701 bool q_specific_at_least_once = false;
4703 for (int i = 0; i < pargs.Length; i++) {
4704 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
4705 if (specific == pargs[i])
4706 p_specific_at_least_once = true;
4707 if (specific == qargs[i])
4708 q_specific_at_least_once = true;
4711 if (p_specific_at_least_once && !q_specific_at_least_once)
4713 if (!p_specific_at_least_once && q_specific_at_least_once)
4721 // Find the best method from candidate list
4723 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
4725 List<AmbiguousCandidate> ambiguous_candidates = null;
4727 MemberSpec best_candidate;
4728 Arguments best_candidate_args = null;
4729 bool best_candidate_params = false;
4730 bool best_candidate_dynamic = false;
4731 int best_candidate_rate;
4732 IParametersMember best_parameter_member = null;
4734 int args_count = args != null ? args.Count : 0;
4736 Arguments candidate_args = args;
4737 bool error_mode = false;
4738 MemberSpec invocable_member = null;
4741 best_candidate = null;
4742 best_candidate_rate = int.MaxValue;
4744 var type_members = members;
4746 for (int i = 0; i < type_members.Count; ++i) {
4747 var member = type_members[i];
4750 // Methods in a base class are not candidates if any method in a derived
4751 // class is applicable
4753 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
4757 if (!member.IsAccessible (rc))
4760 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
4763 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
4764 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
4769 IParametersMember pm = member as IParametersMember;
4772 // Will use it later to report ambiguity between best method and invocable member
4774 if (Invocation.IsMemberInvocable (member))
4775 invocable_member = member;
4781 // Overload resolution is looking for base member but using parameter names
4782 // and default values from the closest member. That means to do expensive lookup
4783 // for the closest override for virtual or abstract members
4785 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
4786 var override_params = base_provider.GetOverrideMemberParameters (member);
4787 if (override_params != null)
4788 pm = override_params;
4792 // Check if the member candidate is applicable
4794 bool params_expanded_form = false;
4795 bool dynamic_argument = false;
4796 TypeSpec rt = pm.MemberType;
4797 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt);
4799 if (lambda_conv_msgs != null)
4800 lambda_conv_msgs.EndSession ();
4803 // How does it score compare to others
4805 if (candidate_rate < best_candidate_rate) {
4807 // Fatal error (missing dependency), cannot continue
4808 if (candidate_rate < 0)
4811 best_candidate_rate = candidate_rate;
4812 best_candidate = member;
4813 best_candidate_args = candidate_args;
4814 best_candidate_params = params_expanded_form;
4815 best_candidate_dynamic = dynamic_argument;
4816 best_parameter_member = pm;
4817 best_candidate_return_type = rt;
4818 } else if (candidate_rate == 0) {
4820 // The member look is done per type for most operations but sometimes
4821 // it's not possible like for binary operators overload because they
4822 // are unioned between 2 sides
4824 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
4825 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
4830 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4832 // We pack all interface members into top level type which makes the overload resolution
4833 // more complicated for interfaces. We compensate it by removing methods with same
4834 // signature when building the cache hence this path should not really be hit often
4837 // interface IA { void Foo (int arg); }
4838 // interface IB : IA { void Foo (params int[] args); }
4840 // IB::Foo is the best overload when calling IB.Foo (1)
4843 if (ambiguous_candidates != null) {
4844 foreach (var amb_cand in ambiguous_candidates) {
4845 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
4854 ambiguous_candidates = null;
4857 // Is the new candidate better
4858 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
4862 best_candidate = member;
4863 best_candidate_args = candidate_args;
4864 best_candidate_params = params_expanded_form;
4865 best_candidate_dynamic = dynamic_argument;
4866 best_parameter_member = pm;
4867 best_candidate_return_type = rt;
4869 // It's not better but any other found later could be but we are not sure yet
4870 if (ambiguous_candidates == null)
4871 ambiguous_candidates = new List<AmbiguousCandidate> ();
4873 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
4877 // Restore expanded arguments
4878 if (candidate_args != args)
4879 candidate_args = args;
4881 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
4884 // We've found exact match
4886 if (best_candidate_rate == 0)
4890 // Try extension methods lookup when no ordinary method match was found and provider enables it
4893 var emg = base_provider.LookupExtensionMethod (rc);
4895 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
4897 best_candidate_extension_group = emg;
4898 return (T) (MemberSpec) emg.BestCandidate;
4903 // Don't run expensive error reporting mode for probing
4910 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
4913 lambda_conv_msgs = null;
4918 // No best member match found, report an error
4920 if (best_candidate_rate != 0 || error_mode) {
4921 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
4925 if (best_candidate_dynamic) {
4926 if (args[0].ArgType == Argument.AType.ExtensionType) {
4927 rc.Report.Error (1973, loc,
4928 "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",
4929 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
4933 // Check type constraints only when explicit type arguments are used
4935 if (best_candidate.IsGeneric && type_arguments != null) {
4936 MethodSpec bc = best_candidate as MethodSpec;
4937 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
4938 ConstraintChecker cc = new ConstraintChecker (rc);
4939 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
4943 BestCandidateIsDynamic = true;
4948 // These flags indicates we are running delegate probing conversion. No need to
4949 // do more expensive checks
4951 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
4952 return (T) best_candidate;
4954 if (ambiguous_candidates != null) {
4956 // Now check that there are no ambiguities i.e the selected method
4957 // should be better than all the others
4959 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
4960 var candidate = ambiguous_candidates [ix];
4962 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
4963 var ambiguous = candidate.Member;
4964 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
4965 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4966 rc.Report.SymbolRelatedToPreviousError (ambiguous);
4967 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4968 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
4971 return (T) best_candidate;
4976 if (invocable_member != null && !IsProbingOnly) {
4977 rc.Report.SymbolRelatedToPreviousError (best_candidate);
4978 rc.Report.SymbolRelatedToPreviousError (invocable_member);
4979 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
4980 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
4984 // And now check if the arguments are all
4985 // compatible, perform conversions if
4986 // necessary etc. and return if everything is
4989 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
4992 if (best_candidate == null)
4996 // Don't run possibly expensive checks in probing mode
4998 if (!IsProbingOnly && !rc.IsInProbingMode) {
5000 // Check ObsoleteAttribute on the best method
5002 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5003 if (oa != null && !rc.IsObsolete)
5004 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5006 best_candidate.MemberDefinition.SetIsUsed ();
5009 args = best_candidate_args;
5010 return (T) best_candidate;
5013 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5015 return ResolveMember<MethodSpec> (rc, ref args);
5018 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5019 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5021 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5024 if (a.Type == InternalType.ErrorType)
5027 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5028 ec.Report.SymbolRelatedToPreviousError (method);
5029 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5030 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5031 TypeManager.CSharpSignature (method));
5034 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5035 TypeManager.CSharpSignature (method));
5036 } else if (IsDelegateInvoke) {
5037 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5038 DelegateType.GetSignatureForError ());
5040 ec.Report.SymbolRelatedToPreviousError (method);
5041 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5042 method.GetSignatureForError ());
5045 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5047 string index = (idx + 1).ToString ();
5048 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5049 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5050 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5051 index, Parameter.GetModifierSignature (a.Modifier));
5053 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5054 index, Parameter.GetModifierSignature (mod));
5056 string p1 = a.GetSignatureForError ();
5057 string p2 = paramType.GetSignatureForError ();
5060 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5061 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5064 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5065 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5066 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5069 ec.Report.Error (1503, a.Expr.Location,
5070 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5075 // We have failed to find exact match so we return error info about the closest match
5077 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5079 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5080 int arg_count = args == null ? 0 : args.Count;
5082 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5083 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5084 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, ta_count, loc);
5088 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5093 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5094 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5095 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5099 // For candidates which match on parameters count report more details about incorrect arguments
5102 int unexpanded_count = ((IParametersMember) best_candidate).Parameters.HasParams ? pm.Parameters.Count - 1 : pm.Parameters.Count;
5103 if (pm.Parameters.Count == arg_count || params_expanded || unexpanded_count == arg_count) {
5104 // Reject any inaccessible member
5105 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5106 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5107 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5111 var ms = best_candidate as MethodSpec;
5112 if (ms != null && ms.IsGeneric) {
5113 bool constr_ok = true;
5114 if (ms.TypeArguments != null)
5115 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5117 if (ta_count == 0) {
5118 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5122 rc.Report.Error (411, loc,
5123 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5124 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5131 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5137 // We failed to find any method with correct argument count, report best candidate
5139 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5142 if (best_candidate.Kind == MemberKind.Constructor) {
5143 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5144 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5145 } else if (IsDelegateInvoke) {
5146 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5147 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5148 DelegateType.GetSignatureForError (), arg_count.ToString ());
5150 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5151 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5152 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5153 name, arg_count.ToString ());
5157 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5159 var pd = pm.Parameters;
5160 TypeSpec[] ptypes = ((IParametersMember) member).Parameters.Types;
5162 Parameter.Modifier p_mod = 0;
5164 int a_idx = 0, a_pos = 0;
5166 ArrayInitializer params_initializers = null;
5167 bool has_unsafe_arg = pm.MemberType.IsPointer;
5168 int arg_count = args == null ? 0 : args.Count;
5170 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5172 if (p_mod != Parameter.Modifier.PARAMS) {
5173 p_mod = pd.FixedParameters[a_idx].ModFlags;
5175 has_unsafe_arg |= pt.IsPointer;
5177 if (p_mod == Parameter.Modifier.PARAMS) {
5178 if (chose_params_expanded) {
5179 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5180 pt = TypeManager.GetElementType (pt);
5186 // Types have to be identical when ref or out modifer is used
5188 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5189 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5192 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5198 NamedArgument na = a as NamedArgument;
5200 int name_index = pd.GetParameterIndexByName (na.Name);
5201 if (name_index < 0 || name_index >= pd.Count) {
5202 if (IsDelegateInvoke) {
5203 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5204 ec.Report.Error (1746, na.Location,
5205 "The delegate `{0}' does not contain a parameter named `{1}'",
5206 DelegateType.GetSignatureForError (), na.Name);
5208 ec.Report.SymbolRelatedToPreviousError (member);
5209 ec.Report.Error (1739, na.Location,
5210 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5211 TypeManager.CSharpSignature (member), na.Name);
5213 } else if (args[name_index] != a) {
5214 if (IsDelegateInvoke)
5215 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5217 ec.Report.SymbolRelatedToPreviousError (member);
5219 ec.Report.Error (1744, na.Location,
5220 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5225 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5228 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5229 custom_errors.NoArgumentMatch (ec, member);
5233 Expression conv = null;
5234 if (a.ArgType == Argument.AType.ExtensionType) {
5235 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5238 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5240 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5243 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5250 // Convert params arguments to an array initializer
5252 if (params_initializers != null) {
5253 // we choose to use 'a.Expr' rather than 'conv' so that
5254 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5255 params_initializers.Add (a.Expr);
5256 args.RemoveAt (a_idx--);
5261 // Update the argument with the implicit conversion
5265 if (a_idx != arg_count) {
5266 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5271 // Fill not provided arguments required by params modifier
5273 if (params_initializers == null && pd.HasParams && arg_count + 1 == pd.Count) {
5275 args = new Arguments (1);
5277 pt = ptypes[pd.Count - 1];
5278 pt = TypeManager.GetElementType (pt);
5279 has_unsafe_arg |= pt.IsPointer;
5280 params_initializers = new ArrayInitializer (0, loc);
5284 // Append an array argument with all params arguments
5286 if (params_initializers != null) {
5287 args.Add (new Argument (
5288 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5292 if (has_unsafe_arg && !ec.IsUnsafe) {
5293 Expression.UnsafeError (ec, loc);
5297 // We could infer inaccesible type arguments
5299 if (type_arguments == null && member.IsGeneric) {
5300 var ms = (MethodSpec) member;
5301 foreach (var ta in ms.TypeArguments) {
5302 if (!ta.IsAccessible (ec)) {
5303 ec.Report.SymbolRelatedToPreviousError (ta);
5304 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5314 public class ConstantExpr : MemberExpr
5316 readonly ConstSpec constant;
5318 public ConstantExpr (ConstSpec constant, Location loc)
5320 this.constant = constant;
5324 public override string Name {
5325 get { throw new NotImplementedException (); }
5328 public override string KindName {
5329 get { return "constant"; }
5332 public override bool IsInstance {
5333 get { return !IsStatic; }
5336 public override bool IsStatic {
5337 get { return true; }
5340 protected override TypeSpec DeclaringType {
5341 get { return constant.DeclaringType; }
5344 public override Expression CreateExpressionTree (ResolveContext ec)
5346 throw new NotSupportedException ("ET");
5349 protected override Expression DoResolve (ResolveContext rc)
5351 ResolveInstanceExpression (rc, null);
5352 DoBestMemberChecks (rc, constant);
5354 var c = constant.GetConstant (rc);
5356 // Creates reference expression to the constant value
5357 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5360 public override void Emit (EmitContext ec)
5362 throw new NotSupportedException ();
5365 public override string GetSignatureForError ()
5367 return constant.GetSignatureForError ();
5370 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5372 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5377 // Fully resolved expression that references a Field
5379 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5381 protected FieldSpec spec;
5382 VariableInfo variable_info;
5384 LocalTemporary temp;
5387 protected FieldExpr (Location l)
5392 public FieldExpr (FieldSpec spec, Location loc)
5397 type = spec.MemberType;
5400 public FieldExpr (FieldBase fi, Location l)
5407 public override string Name {
5413 public bool IsHoisted {
5415 IVariableReference hv = InstanceExpression as IVariableReference;
5416 return hv != null && hv.IsHoisted;
5420 public override bool IsInstance {
5422 return !spec.IsStatic;
5426 public override bool IsStatic {
5428 return spec.IsStatic;
5432 public override string KindName {
5433 get { return "field"; }
5436 public FieldSpec Spec {
5442 protected override TypeSpec DeclaringType {
5444 return spec.DeclaringType;
5448 public VariableInfo VariableInfo {
5450 return variable_info;
5456 public override string GetSignatureForError ()
5458 return spec.GetSignatureForError ();
5461 public bool IsMarshalByRefAccess (ResolveContext rc)
5463 // Checks possible ldflda of field access expression
5464 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5465 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5466 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5469 public void SetHasAddressTaken ()
5471 IVariableReference vr = InstanceExpression as IVariableReference;
5473 vr.SetHasAddressTaken ();
5477 public override Expression CreateExpressionTree (ResolveContext ec)
5479 return CreateExpressionTree (ec, true);
5482 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
5485 Expression instance;
5487 if (InstanceExpression == null) {
5488 instance = new NullLiteral (loc);
5489 } else if (convertInstance) {
5490 instance = InstanceExpression.CreateExpressionTree (ec);
5492 args = new Arguments (1);
5493 args.Add (new Argument (InstanceExpression));
5494 instance = CreateExpressionFactoryCall (ec, "Constant", args);
5497 args = Arguments.CreateForExpressionTree (ec, null,
5499 CreateTypeOfExpression ());
5501 return CreateExpressionFactoryCall (ec, "Field", args);
5504 public Expression CreateTypeOfExpression ()
5506 return new TypeOfField (spec, loc);
5509 protected override Expression DoResolve (ResolveContext ec)
5511 spec.MemberDefinition.SetIsUsed ();
5513 return DoResolve (ec, null);
5516 Expression DoResolve (ResolveContext ec, Expression rhs)
5518 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
5521 if (ResolveInstanceExpression (ec, rhs)) {
5522 // Resolve the field's instance expression while flow analysis is turned
5523 // off: when accessing a field "a.b", we must check whether the field
5524 // "a.b" is initialized, not whether the whole struct "a" is initialized.
5526 if (lvalue_instance) {
5527 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5528 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
5530 Expression right_side =
5531 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
5533 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
5536 using (ec.With (ResolveContext.Options.DoFlowAnalysis, false)) {
5537 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
5541 if (InstanceExpression == null)
5545 DoBestMemberChecks (ec, spec);
5548 var fb = spec as FixedFieldSpec;
5549 IVariableReference var = InstanceExpression as IVariableReference;
5551 if (lvalue_instance && var != null && var.VariableInfo != null) {
5552 var.VariableInfo.SetStructFieldAssigned (ec, Name);
5556 IFixedExpression fe = InstanceExpression as IFixedExpression;
5557 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
5558 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
5561 if (InstanceExpression.eclass != ExprClass.Variable) {
5562 ec.Report.SymbolRelatedToPreviousError (spec);
5563 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
5564 TypeManager.GetFullNameSignature (spec));
5565 } else if (var != null && var.IsHoisted) {
5566 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
5569 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
5573 // Set flow-analysis variable info for struct member access. It will be check later
5574 // for precise error reporting
5576 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
5577 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
5578 if (rhs != null && variable_info != null)
5579 variable_info.SetStructFieldAssigned (ec, Name);
5582 eclass = ExprClass.Variable;
5586 public void VerifyAssignedStructField (ResolveContext rc, Expression rhs)
5591 var var = fe.InstanceExpression as IVariableReference;
5593 var vi = var.VariableInfo;
5595 if (vi != null && !vi.IsStructFieldAssigned (rc, fe.Name) && (rhs == null || !fe.type.IsStruct)) {
5597 rc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5599 rc.Report.Error (170, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
5606 fe = fe.InstanceExpression as FieldExpr;
5608 } while (fe != null);
5611 static readonly int [] codes = {
5612 191, // instance, write access
5613 192, // instance, out access
5614 198, // static, write access
5615 199, // static, out access
5616 1648, // member of value instance, write access
5617 1649, // member of value instance, out access
5618 1650, // member of value static, write access
5619 1651 // member of value static, out access
5622 static readonly string [] msgs = {
5623 /*0191*/ "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
5624 /*0192*/ "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5625 /*0198*/ "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5626 /*0199*/ "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
5627 /*1648*/ "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
5628 /*1649*/ "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
5629 /*1650*/ "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
5630 /*1651*/ "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)"
5633 // The return value is always null. Returning a value simplifies calling code.
5634 Expression Report_AssignToReadonly (ResolveContext ec, Expression right_side)
5637 if (right_side == EmptyExpression.OutAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5641 if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess)
5643 ec.Report.Error (codes [i], loc, msgs [i], GetSignatureForError ());
5648 override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
5650 if (spec is FixedFieldSpec) {
5651 // It could be much better error message but we want to be error compatible
5652 Error_ValueAssignment (ec, right_side);
5655 Expression e = DoResolve (ec, right_side);
5660 spec.MemberDefinition.SetIsAssigned ();
5662 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
5663 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
5664 ec.Report.Warning (420, 1, loc,
5665 "`{0}': A volatile field references will not be treated as volatile",
5666 spec.GetSignatureForError ());
5669 if (spec.IsReadOnly) {
5670 // InitOnly fields can only be assigned in constructors or initializers
5671 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
5672 return Report_AssignToReadonly (ec, right_side);
5674 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
5676 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
5677 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
5678 return Report_AssignToReadonly (ec, right_side);
5679 // static InitOnly fields cannot be assigned-to in an instance constructor
5680 if (IsStatic && !ec.IsStatic)
5681 return Report_AssignToReadonly (ec, right_side);
5682 // instance constructors can't modify InitOnly fields of other instances of the same type
5683 if (!IsStatic && !(InstanceExpression is This))
5684 return Report_AssignToReadonly (ec, right_side);
5688 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
5689 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
5690 ec.Report.Warning (197, 1, loc,
5691 "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",
5692 GetSignatureForError ());
5695 eclass = ExprClass.Variable;
5699 public override int GetHashCode ()
5701 return spec.GetHashCode ();
5704 public bool IsFixed {
5707 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
5709 IVariableReference variable = InstanceExpression as IVariableReference;
5710 if (variable != null)
5711 return InstanceExpression.Type.IsStruct && variable.IsFixed;
5713 IFixedExpression fe = InstanceExpression as IFixedExpression;
5714 return fe != null && fe.IsFixed;
5718 public override bool Equals (object obj)
5720 FieldExpr fe = obj as FieldExpr;
5724 if (spec != fe.spec)
5727 if (InstanceExpression == null || fe.InstanceExpression == null)
5730 return InstanceExpression.Equals (fe.InstanceExpression);
5733 public void Emit (EmitContext ec, bool leave_copy)
5735 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5739 ec.Emit (OpCodes.Volatile);
5741 ec.Emit (OpCodes.Ldsfld, spec);
5744 EmitInstance (ec, false);
5746 // Optimization for build-in types
5747 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
5748 ec.EmitLoadFromPtr (type);
5750 var ff = spec as FixedFieldSpec;
5752 ec.Emit (OpCodes.Ldflda, spec);
5753 ec.Emit (OpCodes.Ldflda, ff.Element);
5756 ec.Emit (OpCodes.Volatile);
5758 ec.Emit (OpCodes.Ldfld, spec);
5764 ec.Emit (OpCodes.Dup);
5766 temp = new LocalTemporary (this.Type);
5772 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
5774 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
5775 if (isCompound && !(source is DynamicExpressionStatement)) {
5776 if (has_await_source) {
5778 InstanceExpression = InstanceExpression.EmitToField (ec);
5785 if (has_await_source)
5786 source = source.EmitToField (ec);
5788 EmitInstance (ec, prepared);
5794 ec.Emit (OpCodes.Dup);
5796 temp = new LocalTemporary (this.Type);
5801 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
5802 ec.Emit (OpCodes.Volatile);
5804 spec.MemberDefinition.SetIsAssigned ();
5807 ec.Emit (OpCodes.Stsfld, spec);
5809 ec.Emit (OpCodes.Stfld, spec);
5819 // Emits store to field with prepared values on stack
5821 public void EmitAssignFromStack (EmitContext ec)
5824 ec.Emit (OpCodes.Stsfld, spec);
5826 ec.Emit (OpCodes.Stfld, spec);
5830 public override void Emit (EmitContext ec)
5835 public override void EmitSideEffect (EmitContext ec)
5837 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
5839 if (is_volatile) // || is_marshal_by_ref ())
5840 base.EmitSideEffect (ec);
5843 public virtual void AddressOf (EmitContext ec, AddressOp mode)
5845 if ((mode & AddressOp.Store) != 0)
5846 spec.MemberDefinition.SetIsAssigned ();
5847 if ((mode & AddressOp.Load) != 0)
5848 spec.MemberDefinition.SetIsUsed ();
5851 // Handle initonly fields specially: make a copy and then
5852 // get the address of the copy.
5855 if (spec.IsReadOnly){
5857 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
5869 var temp = ec.GetTemporaryLocal (type);
5870 ec.Emit (OpCodes.Stloc, temp);
5871 ec.Emit (OpCodes.Ldloca, temp);
5872 ec.FreeTemporaryLocal (temp, type);
5878 ec.Emit (OpCodes.Ldsflda, spec);
5881 EmitInstance (ec, false);
5882 ec.Emit (OpCodes.Ldflda, spec);
5886 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
5888 return MakeExpression (ctx);
5891 public override SLE.Expression MakeExpression (BuilderContext ctx)
5894 return base.MakeExpression (ctx);
5896 return SLE.Expression.Field (
5897 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
5898 spec.GetMetaInfo ());
5902 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5904 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
5910 // Expression that evaluates to a Property.
5912 // This is not an LValue because we need to re-write the expression. We
5913 // can not take data from the stack and store it.
5915 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
5917 Arguments arguments;
5919 public PropertyExpr (PropertySpec spec, Location l)
5922 best_candidate = spec;
5923 type = spec.MemberType;
5928 protected override Arguments Arguments {
5937 protected override TypeSpec DeclaringType {
5939 return best_candidate.DeclaringType;
5943 public override string Name {
5945 return best_candidate.Name;
5949 public override bool IsInstance {
5955 public override bool IsStatic {
5957 return best_candidate.IsStatic;
5961 public override string KindName {
5962 get { return "property"; }
5965 public PropertySpec PropertyInfo {
5967 return best_candidate;
5973 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
5975 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
5978 var args_count = arguments == null ? 0 : arguments.Count;
5979 if (args_count != body.Parameters.Count && args_count == 0)
5982 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
5983 mg.InstanceExpression = InstanceExpression;
5988 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
5990 return new PropertyExpr (spec, loc) {
5996 public override Expression CreateExpressionTree (ResolveContext ec)
5999 if (IsSingleDimensionalArrayLength ()) {
6000 args = new Arguments (1);
6001 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6002 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6005 args = new Arguments (2);
6006 if (InstanceExpression == null)
6007 args.Add (new Argument (new NullLiteral (loc)));
6009 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6010 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6011 return CreateExpressionFactoryCall (ec, "Property", args);
6014 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6016 DoResolveLValue (rc, null);
6017 return new TypeOfMethod (Setter, loc);
6020 public override string GetSignatureForError ()
6022 return best_candidate.GetSignatureForError ();
6025 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6028 return base.MakeExpression (ctx);
6030 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6034 public override SLE.Expression MakeExpression (BuilderContext ctx)
6037 return base.MakeExpression (ctx);
6039 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6043 void Error_PropertyNotValid (ResolveContext ec)
6045 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6046 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6047 GetSignatureForError ());
6050 bool IsSingleDimensionalArrayLength ()
6052 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6055 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6056 return ac != null && ac.Rank == 1;
6059 public override void Emit (EmitContext ec, bool leave_copy)
6062 // Special case: length of single dimension array property is turned into ldlen
6064 if (IsSingleDimensionalArrayLength ()) {
6065 EmitInstance (ec, false);
6066 ec.Emit (OpCodes.Ldlen);
6067 ec.Emit (OpCodes.Conv_I4);
6071 base.Emit (ec, leave_copy);
6074 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6077 LocalTemporary await_source_arg = null;
6079 if (isCompound && !(source is DynamicExpressionStatement)) {
6080 emitting_compound_assignment = true;
6083 if (has_await_arguments) {
6084 await_source_arg = new LocalTemporary (Type);
6085 await_source_arg.Store (ec);
6087 args = new Arguments (1);
6088 args.Add (new Argument (await_source_arg));
6091 temp = await_source_arg;
6094 has_await_arguments = false;
6099 ec.Emit (OpCodes.Dup);
6100 temp = new LocalTemporary (this.Type);
6105 args = arguments == null ? new Arguments (1) : arguments;
6109 temp = new LocalTemporary (this.Type);
6111 args.Add (new Argument (temp));
6113 args.Add (new Argument (source));
6117 emitting_compound_assignment = false;
6119 var call = new CallEmitter ();
6120 call.InstanceExpression = InstanceExpression;
6122 call.InstanceExpressionOnStack = true;
6124 call.Emit (ec, Setter, args, loc);
6131 if (await_source_arg != null) {
6132 await_source_arg.Release (ec);
6136 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6138 eclass = ExprClass.PropertyAccess;
6140 if (best_candidate.IsNotCSharpCompatible) {
6141 Error_PropertyNotValid (rc);
6144 ResolveInstanceExpression (rc, right_side);
6146 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6147 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6148 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6150 type = p.MemberType;
6154 DoBestMemberChecks (rc, best_candidate);
6156 // Handling of com-imported properties with any number of default property parameters
6157 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6158 var p = best_candidate.Get.Parameters;
6159 arguments = new Arguments (p.Count);
6160 for (int i = 0; i < p.Count; ++i) {
6161 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6163 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6164 var p = best_candidate.Set.Parameters;
6165 arguments = new Arguments (p.Count - 1);
6166 for (int i = 0; i < p.Count - 1; ++i) {
6167 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6174 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6176 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6180 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6182 // getter and setter can be different for base calls
6183 MethodSpec getter, setter;
6184 protected T best_candidate;
6186 protected LocalTemporary temp;
6187 protected bool emitting_compound_assignment;
6188 protected bool has_await_arguments;
6190 protected PropertyOrIndexerExpr (Location l)
6197 protected abstract Arguments Arguments { get; set; }
6199 public MethodSpec Getter {
6208 public MethodSpec Setter {
6219 protected override Expression DoResolve (ResolveContext ec)
6221 if (eclass == ExprClass.Unresolved) {
6222 var expr = OverloadResolve (ec, null);
6227 return expr.Resolve (ec);
6230 if (!ResolveGetter (ec))
6236 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6238 if (right_side == EmptyExpression.OutAccess) {
6239 // TODO: best_candidate can be null at this point
6240 INamedBlockVariable variable = null;
6241 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6242 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6243 best_candidate.Name);
6245 right_side.DoResolveLValue (ec, this);
6250 if (eclass == ExprClass.Unresolved) {
6251 var expr = OverloadResolve (ec, right_side);
6256 return expr.ResolveLValue (ec, right_side);
6259 if (!ResolveSetter (ec))
6266 // Implements the IAssignMethod interface for assignments
6268 public virtual void Emit (EmitContext ec, bool leave_copy)
6270 var call = new CallEmitter ();
6271 call.InstanceExpression = InstanceExpression;
6272 if (has_await_arguments)
6273 call.HasAwaitArguments = true;
6275 call.DuplicateArguments = emitting_compound_assignment;
6277 call.Emit (ec, Getter, Arguments, loc);
6279 if (call.HasAwaitArguments) {
6280 InstanceExpression = call.InstanceExpression;
6281 Arguments = call.EmittedArguments;
6282 has_await_arguments = true;
6286 ec.Emit (OpCodes.Dup);
6287 temp = new LocalTemporary (Type);
6292 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6294 public override void Emit (EmitContext ec)
6299 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6301 has_await_arguments = true;
6306 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6308 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6310 bool ResolveGetter (ResolveContext rc)
6312 if (!best_candidate.HasGet) {
6313 if (InstanceExpression != EmptyExpression.Null) {
6314 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6315 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6316 best_candidate.GetSignatureForError ());
6319 } else if (!best_candidate.Get.IsAccessible (rc)) {
6320 if (best_candidate.HasDifferentAccessibility) {
6321 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6322 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6323 TypeManager.CSharpSignature (best_candidate));
6325 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6326 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6330 if (best_candidate.HasDifferentAccessibility) {
6331 CheckProtectedMemberAccess (rc, best_candidate.Get);
6334 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6338 bool ResolveSetter (ResolveContext rc)
6340 if (!best_candidate.HasSet) {
6341 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
6342 GetSignatureForError ());
6346 if (!best_candidate.Set.IsAccessible (rc)) {
6347 if (best_candidate.HasDifferentAccessibility) {
6348 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6349 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
6350 GetSignatureForError ());
6352 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
6353 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
6357 if (best_candidate.HasDifferentAccessibility)
6358 CheckProtectedMemberAccess (rc, best_candidate.Set);
6360 setter = CandidateToBaseOverride (rc, best_candidate.Set);
6366 /// Fully resolved expression that evaluates to an Event
6368 public class EventExpr : MemberExpr, IAssignMethod
6370 readonly EventSpec spec;
6373 public EventExpr (EventSpec spec, Location loc)
6381 protected override TypeSpec DeclaringType {
6383 return spec.DeclaringType;
6387 public override string Name {
6393 public override bool IsInstance {
6395 return !spec.IsStatic;
6399 public override bool IsStatic {
6401 return spec.IsStatic;
6405 public override string KindName {
6406 get { return "event"; }
6409 public MethodSpec Operator {
6417 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
6420 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
6422 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6423 if (spec.BackingField != null &&
6424 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
6426 spec.MemberDefinition.SetIsUsed ();
6428 if (!ec.IsObsolete) {
6429 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
6431 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
6434 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
6435 Error_AssignmentEventOnly (ec);
6437 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
6439 InstanceExpression = null;
6441 return ml.ResolveMemberAccess (ec, left, original);
6445 return base.ResolveMemberAccess (ec, left, original);
6448 public override Expression CreateExpressionTree (ResolveContext ec)
6450 throw new NotSupportedException ("ET");
6453 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6455 if (right_side == EmptyExpression.EventAddition) {
6456 op = spec.AccessorAdd;
6457 } else if (right_side == EmptyExpression.EventSubtraction) {
6458 op = spec.AccessorRemove;
6462 Error_AssignmentEventOnly (ec);
6466 op = CandidateToBaseOverride (ec, op);
6470 protected override Expression DoResolve (ResolveContext ec)
6472 eclass = ExprClass.EventAccess;
6473 type = spec.MemberType;
6475 ResolveInstanceExpression (ec, null);
6477 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
6478 Error_AssignmentEventOnly (ec);
6481 DoBestMemberChecks (ec, spec);
6485 public override void Emit (EmitContext ec)
6487 throw new NotSupportedException ();
6488 //Error_CannotAssign ();
6491 #region IAssignMethod Members
6493 public void Emit (EmitContext ec, bool leave_copy)
6495 throw new NotImplementedException ();
6498 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6500 if (leave_copy || !isCompound)
6501 throw new NotImplementedException ("EventExpr::EmitAssign");
6503 Arguments args = new Arguments (1);
6504 args.Add (new Argument (source));
6506 var call = new CallEmitter ();
6507 call.InstanceExpression = InstanceExpression;
6508 call.Emit (ec, op, args, loc);
6513 void Error_AssignmentEventOnly (ResolveContext ec)
6515 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
6516 ec.Report.Error (79, loc,
6517 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
6518 GetSignatureForError ());
6520 ec.Report.Error (70, loc,
6521 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
6522 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
6526 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
6528 name = name.Substring (0, name.LastIndexOf ('.'));
6529 base.Error_CannotCallAbstractBase (rc, name);
6532 public override string GetSignatureForError ()
6534 return TypeManager.CSharpSignature (spec);
6537 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6539 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
6543 public class TemporaryVariableReference : VariableReference
6545 public class Declarator : Statement
6547 TemporaryVariableReference variable;
6549 public Declarator (TemporaryVariableReference variable)
6551 this.variable = variable;
6555 protected override void DoEmit (EmitContext ec)
6557 variable.li.CreateBuilder (ec);
6560 public override void Emit (EmitContext ec)
6562 // Don't create sequence point
6566 protected override void CloneTo (CloneContext clonectx, Statement target)
6574 public TemporaryVariableReference (LocalVariable li, Location loc)
6577 this.type = li.Type;
6581 public override bool IsLockedByStatement {
6589 public LocalVariable LocalInfo {
6595 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
6597 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
6598 return new TemporaryVariableReference (li, loc);
6601 protected override Expression DoResolve (ResolveContext ec)
6603 eclass = ExprClass.Variable;
6606 // Don't capture temporary variables except when using
6607 // state machine redirection and block yields
6609 if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer &&
6610 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
6611 ec.IsVariableCapturingRequired) {
6612 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
6613 storey.CaptureLocalVariable (ec, li);
6619 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6621 return Resolve (ec);
6624 public override void Emit (EmitContext ec)
6626 li.CreateBuilder (ec);
6631 public void EmitAssign (EmitContext ec, Expression source)
6633 li.CreateBuilder (ec);
6635 EmitAssign (ec, source, false, false);
6638 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
6640 return li.HoistedVariant;
6643 public override bool IsFixed {
6644 get { return true; }
6647 public override bool IsRef {
6648 get { return false; }
6651 public override string Name {
6652 get { throw new NotImplementedException (); }
6655 public override void SetHasAddressTaken ()
6657 throw new NotImplementedException ();
6660 protected override ILocalVariable Variable {
6664 public override VariableInfo VariableInfo {
6665 get { return null; }
6668 public override void VerifyAssigned (ResolveContext rc)
6674 /// Handles `var' contextual keyword; var becomes a keyword only
6675 /// if no type called var exists in a variable scope
6677 class VarExpr : SimpleName
6679 public VarExpr (Location loc)
6684 public bool InferType (ResolveContext ec, Expression right_side)
6687 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
6689 type = right_side.Type;
6690 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
6691 ec.Report.Error (815, loc,
6692 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
6693 type.GetSignatureForError ());
6697 eclass = ExprClass.Variable;
6701 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
6703 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
6704 base.Error_TypeOrNamespaceNotFound (ec);
6706 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");