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, bool allowUnboundTypeArguments = false)
233 var rc = mc as ResolveContext ?? new ResolveContext (mc);
234 Expression e = Resolve (rc);
236 e.Error_UnexpectedKind (rc, 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, 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 static 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 static void Warning_UnreachableExpression (ResolveContext rc, Location loc)
378 rc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
381 public ResolveFlags ExprClassToResolveFlags {
385 case ExprClass.Namespace:
386 return ResolveFlags.Type;
388 case ExprClass.MethodGroup:
389 return ResolveFlags.MethodGroup;
391 case ExprClass.TypeParameter:
392 return ResolveFlags.TypeParameter;
394 case ExprClass.Value:
395 case ExprClass.Variable:
396 case ExprClass.PropertyAccess:
397 case ExprClass.EventAccess:
398 case ExprClass.IndexerAccess:
399 return ResolveFlags.VariableOrValue;
402 throw new InternalErrorException (loc.ToString () + " " + GetType () + " ExprClass is Invalid after resolve");
408 // Implements identical simple name and type-name resolution
410 public Expression ProbeIdenticalTypeName (ResolveContext rc, Expression left, SimpleName name)
413 if (t.Kind == MemberKind.InternalCompilerType || t is ElementTypeSpec || t.Arity > 0)
416 // 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
417 // a constant, field, property, local variable, or parameter with the same type as the meaning of E as a type-name
419 if (left is MemberExpr || left is VariableReference) {
420 var identical_type = rc.LookupNamespaceOrType (name.Name, 0, LookupMode.Probing, loc) as TypeExpr;
421 if (identical_type != null && identical_type.Type == left.Type)
422 return identical_type;
428 public virtual string GetSignatureForError ()
430 return type.GetDefinition ().GetSignatureForError ();
433 public static bool IsNeverNull (Expression expr)
435 if (expr is This || expr is New || expr is ArrayCreation || expr is DelegateCreation || expr is ConditionalMemberAccess)
438 var c = expr as Constant;
442 var tc = expr as TypeCast;
444 return IsNeverNull (tc.Child);
449 protected static bool IsNullPropagatingValid (TypeSpec type)
452 case MemberKind.Struct:
453 return type.IsNullableType;
454 case MemberKind.Enum:
455 case MemberKind.Void:
456 case MemberKind.PointerType:
458 case MemberKind.InternalCompilerType:
459 return type.BuiltinType == BuiltinTypeSpec.Type.Dynamic;
465 public virtual bool HasConditionalAccess ()
470 protected static TypeSpec LiftMemberType (ResolveContext rc, TypeSpec type)
472 return TypeSpec.IsValueType (type) && !type.IsNullableType ?
473 Nullable.NullableInfo.MakeType (rc.Module, type) :
478 /// Resolves an expression and performs semantic analysis on it.
482 /// Currently Resolve wraps DoResolve to perform sanity
483 /// checking and assertion checking on what we expect from Resolve.
485 public Expression Resolve (ResolveContext ec, ResolveFlags flags)
487 if (eclass != ExprClass.Unresolved) {
488 if ((flags & ExprClassToResolveFlags) == 0) {
489 Error_UnexpectedKind (ec, flags, loc);
503 if ((flags & e.ExprClassToResolveFlags) == 0) {
504 e.Error_UnexpectedKind (ec, flags, loc);
509 throw new InternalErrorException ("Expression `{0}' didn't set its type in DoResolve", e.GetType ());
512 } catch (Exception ex) {
513 if (loc.IsNull || ec.Module.Compiler.Settings.BreakOnInternalError || ex is CompletionResult || ec.Report.IsDisabled || ex is FatalException ||
514 ec.Report.Printer is NullReportPrinter)
517 ec.Report.Error (584, loc, "Internal compiler error: {0}", ex.Message);
518 return ErrorExpression.Instance; // TODO: Add location
523 /// Resolves an expression and performs semantic analysis on it.
525 public Expression Resolve (ResolveContext rc)
527 return Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
531 /// Resolves an expression for LValue assignment
535 /// Currently ResolveLValue wraps DoResolveLValue to perform sanity
536 /// checking and assertion checking on what we expect from Resolve
538 public Expression ResolveLValue (ResolveContext ec, Expression right_side)
540 int errors = ec.Report.Errors;
541 bool out_access = right_side == EmptyExpression.OutAccess;
543 Expression e = DoResolveLValue (ec, right_side);
545 if (e != null && out_access && !(e is IMemoryLocation)) {
546 // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
547 // Enabling this 'throw' will "only" result in deleting useless code elsewhere,
549 //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
550 // e.GetType () + " " + e.GetSignatureForError ());
555 if (errors == ec.Report.Errors) {
556 Error_ValueAssignment (ec, right_side);
561 if (e.eclass == ExprClass.Unresolved)
562 throw new Exception ("Expression " + e + " ExprClass is Invalid after resolve");
564 if ((e.type == null) && !(e is GenericTypeExpr))
565 throw new Exception ("Expression " + e + " did not set its type after Resolve");
570 public Constant ResolveLabelConstant (ResolveContext rc)
572 var expr = Resolve (rc);
576 Constant c = expr as Constant;
578 if (expr.type != InternalType.ErrorType)
579 rc.Report.Error (150, expr.StartLocation, "A constant value is expected");
587 public virtual void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
589 if (Attribute.IsValidArgumentType (parameterType)) {
590 rc.Module.Compiler.Report.Error (182, loc,
591 "An attribute argument must be a constant expression, typeof expression or array creation expression");
593 rc.Module.Compiler.Report.Error (181, loc,
594 "Attribute constructor parameter has type `{0}', which is not a valid attribute parameter type",
595 targetType.GetSignatureForError ());
600 /// Emits the code for the expression
604 /// The Emit method is invoked to generate the code
605 /// for the expression.
607 public abstract void Emit (EmitContext ec);
610 // Emit code to branch to @target if this expression is equivalent to @on_true.
611 // The default implementation is to emit the value, and then emit a brtrue or brfalse.
612 // Subclasses can provide more efficient implementations, but those MUST be equivalent,
613 // including the use of conditional branches. Note also that a branch MUST be emitted
614 public virtual void EmitBranchable (EmitContext ec, Label target, bool on_true)
617 ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
620 // Emit this expression for its side effects, not for its value.
621 // The default implementation is to emit the value, and then throw it away.
622 // Subclasses can provide more efficient implementations, but those MUST be equivalent
623 public virtual void EmitSideEffect (EmitContext ec)
626 ec.Emit (OpCodes.Pop);
630 // Emits the expression into temporary field variable. The method
631 // should be used for await expressions only
633 public virtual Expression EmitToField (EmitContext ec)
636 // This is the await prepare Emit method. When emitting code like
637 // a + b we emit code like
643 // For await a + await b we have to interfere the flow to keep the
644 // stack clean because await yields from the expression. The emit
647 // a = a.EmitToField () // a is changed to temporary field access
648 // b = b.EmitToField ()
654 // The idea is to emit expression and leave the stack empty with
655 // result value still available.
657 // Expressions should override this default implementation when
658 // optimized version can be provided (e.g. FieldExpr)
661 // We can optimize for side-effect free expressions, they can be
662 // emitted out of order
664 if (IsSideEffectFree)
667 bool needs_temporary = ContainsEmitWithAwait ();
668 if (!needs_temporary)
671 // Emit original code
672 var field = EmitToFieldSource (ec);
675 // Store the result to temporary field when we
676 // cannot load `this' directly
678 field = ec.GetTemporaryField (type);
679 if (needs_temporary) {
681 // Create temporary local (we cannot load `this' before Emit)
683 var temp = ec.GetTemporaryLocal (type);
684 ec.Emit (OpCodes.Stloc, temp);
687 ec.Emit (OpCodes.Ldloc, temp);
688 field.EmitAssignFromStack (ec);
690 ec.FreeTemporaryLocal (temp, type);
692 field.EmitAssignFromStack (ec);
699 protected virtual FieldExpr EmitToFieldSource (EmitContext ec)
702 // Default implementation calls Emit method
708 protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
710 if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
711 bool contains_await = false;
713 for (int i = 1; i < expressions.Count; ++i) {
714 if (expressions[i].ContainsEmitWithAwait ()) {
715 contains_await = true;
720 if (contains_await) {
721 for (int i = 0; i < expressions.Count; ++i) {
722 expressions[i] = expressions[i].EmitToField (ec);
727 for (int i = 0; i < expressions.Count; ++i) {
728 expressions[i].Emit (ec);
733 /// Protected constructor. Only derivate types should
734 /// be able to be created
737 protected Expression ()
742 /// Returns a fully formed expression after a MemberLookup
745 static Expression ExprClassFromMemberInfo (MemberSpec spec, Location loc)
747 if (spec is EventSpec)
748 return new EventExpr ((EventSpec) spec, loc);
749 if (spec is ConstSpec)
750 return new ConstantExpr ((ConstSpec) spec, loc);
751 if (spec is FieldSpec)
752 return new FieldExpr ((FieldSpec) spec, loc);
753 if (spec is PropertySpec)
754 return new PropertyExpr ((PropertySpec) spec, loc);
755 if (spec is TypeSpec)
756 return new TypeExpression (((TypeSpec) spec), loc);
761 public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
763 var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
766 case MemberKind.Struct:
767 rc.Report.SymbolRelatedToPreviousError (type);
768 // Report meaningful error for struct as they always have default ctor in C# context
769 OverloadResolver.Error_ConstructorMismatch (rc, type, args == null ? 0 : args.Count, loc);
771 case MemberKind.MissingType:
772 case MemberKind.InternalCompilerType:
773 // LAMESPEC: dynamic is not really object
774 // if (type.BuiltinType == BuiltinTypeSpec.Type.Object)
778 rc.Report.SymbolRelatedToPreviousError (type);
779 rc.Report.Error (143, loc, "The class `{0}' has no constructors defined",
780 type.GetSignatureForError ());
787 var r = new OverloadResolver (ctors, OverloadResolver.Restrictions.NoBaseMembers, loc);
788 if (!rc.HasSet (ResolveContext.Options.BaseInitializer)) {
789 r.InstanceQualifier = new ConstructorInstanceQualifier (type);
792 return r.ResolveMember<MethodSpec> (rc, ref args);
796 public enum MemberLookupRestrictions
802 EmptyArguments = 1 << 4,
803 IgnoreArity = 1 << 5,
804 IgnoreAmbiguity = 1 << 6
808 // Lookup type `queried_type' for code in class `container_type' with a qualifier of
809 // `qualifier_type' or null to lookup members in the current class.
811 public static Expression MemberLookup (IMemberContext rc, bool errorMode, TypeSpec queried_type, string name, int arity, MemberLookupRestrictions restrictions, Location loc)
813 var members = MemberCache.FindMembers (queried_type, name, false);
817 MemberSpec non_method = null;
818 MemberSpec ambig_non_method = null;
820 for (int i = 0; i < members.Count; ++i) {
821 var member = members[i];
823 // HACK: for events because +=/-= can appear at same class only, should use OverrideToBase there
824 if ((member.Modifiers & Modifiers.OVERRIDE) != 0 && member.Kind != MemberKind.Event)
827 if ((member.Modifiers & Modifiers.BACKING_FIELD) != 0 || member.Kind == MemberKind.Operator)
830 if ((arity > 0 || (restrictions & MemberLookupRestrictions.ExactArity) != 0) && member.Arity != arity)
834 if (!member.IsAccessible (rc))
838 // With runtime binder we can have a situation where queried type is inaccessible
839 // because it came via dynamic object, the check about inconsisted accessibility
840 // had no effect as the type was unknown during compilation
843 // private class N { }
845 // public dynamic Foo ()
851 if (rc.Module.Compiler.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
855 if ((restrictions & MemberLookupRestrictions.InvocableOnly) != 0) {
856 if (member is MethodSpec) {
858 // Interface members that are hidden by class members are removed from the set. This
859 // step only has an effect if T is a type parameter and T has both an effective base
860 // class other than object and a non-empty effective interface set
862 var tps = queried_type as TypeParameterSpec;
863 if (tps != null && tps.HasTypeConstraint)
864 members = RemoveHiddenTypeParameterMethods (members);
866 return new MethodGroupExpr (members, queried_type, loc);
869 if (!Invocation.IsMemberInvocable (member))
873 if (non_method == null || member is MethodSpec || non_method.IsNotCSharpCompatible) {
875 } else if (!errorMode && !member.IsNotCSharpCompatible) {
877 // Interface members that are hidden by class members are removed from the set when T is a type parameter and
878 // T has both an effective base class other than object and a non-empty effective interface set.
880 // The spec has more complex rules but we simply remove all members declared in an interface declaration.
882 var tps = queried_type as TypeParameterSpec;
883 if (tps != null && tps.HasTypeConstraint) {
884 if (non_method.DeclaringType.IsClass && member.DeclaringType.IsInterface)
887 if (non_method.DeclaringType.IsInterface && member.DeclaringType.IsInterface) {
893 ambig_non_method = member;
897 if (non_method != null) {
898 if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
899 var report = rc.Module.Compiler.Report;
900 report.SymbolRelatedToPreviousError (non_method);
901 report.SymbolRelatedToPreviousError (ambig_non_method);
902 report.Error (229, loc, "Ambiguity between `{0}' and `{1}'",
903 non_method.GetSignatureForError (), ambig_non_method.GetSignatureForError ());
906 if (non_method is MethodSpec)
907 return new MethodGroupExpr (members, queried_type, loc);
909 return ExprClassFromMemberInfo (non_method, loc);
912 if (members[0].DeclaringType.BaseType == null)
915 members = MemberCache.FindMembers (members[0].DeclaringType.BaseType, name, false);
917 } while (members != null);
922 static IList<MemberSpec> RemoveHiddenTypeParameterMethods (IList<MemberSpec> members)
924 if (members.Count < 2)
928 // If M is a method, then all non-method members declared in an interface declaration
929 // are removed from the set, and all methods with the same signature as M declared in
930 // an interface declaration are removed from the set
934 for (int i = 0; i < members.Count; ++i) {
935 var method = members[i] as MethodSpec;
936 if (method == null) {
939 members = new List<MemberSpec> (members);
942 members.RemoveAt (i--);
946 if (!method.DeclaringType.IsInterface)
949 for (int ii = 0; ii < members.Count; ++ii) {
950 var candidate = members[ii] as MethodSpec;
951 if (candidate == null || !candidate.DeclaringType.IsClass)
954 if (!TypeSpecComparer.Override.IsEqual (candidate.Parameters, method.Parameters))
959 members = new List<MemberSpec> (members);
962 members.RemoveAt (i--);
970 protected virtual void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
972 throw new NotImplementedException ();
975 public virtual void Error_OperatorCannotBeApplied (ResolveContext rc, Location loc, string oper, TypeSpec t)
977 if (t == InternalType.ErrorType)
980 rc.Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
981 oper, t.GetSignatureForError ());
984 protected void Error_PointerInsideExpressionTree (ResolveContext ec)
986 ec.Report.Error (1944, loc, "An expression tree cannot contain an unsafe pointer operation");
989 protected void Error_NullShortCircuitInsideExpressionTree (ResolveContext rc)
991 rc.Report.Error (8072, loc, "An expression tree cannot contain a null propagating operator");
994 public virtual void FlowAnalysis (FlowAnalysisContext fc)
999 // Special version of flow analysis for expressions which can return different
1000 // on-true and on-false result. Used by &&, ||, ?: expressions
1002 public virtual void FlowAnalysisConditional (FlowAnalysisContext fc)
1005 fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = fc.DefiniteAssignment;
1009 /// Returns an expression that can be used to invoke operator true
1010 /// on the expression if it exists.
1012 protected static Expression GetOperatorTrue (ResolveContext ec, Expression e, Location loc)
1014 return GetOperatorTrueOrFalse (ec, e, true, loc);
1018 /// Returns an expression that can be used to invoke operator false
1019 /// on the expression if it exists.
1021 protected static Expression GetOperatorFalse (ResolveContext ec, Expression e, Location loc)
1023 return GetOperatorTrueOrFalse (ec, e, false, loc);
1026 static Expression GetOperatorTrueOrFalse (ResolveContext ec, Expression e, bool is_true, Location loc)
1028 var op = is_true ? Operator.OpType.True : Operator.OpType.False;
1029 var methods = MemberCache.GetUserOperator (e.type, op, false);
1030 if (methods == null)
1033 Arguments arguments = new Arguments (1);
1034 arguments.Add (new Argument (e));
1036 var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
1037 var oper = res.ResolveOperator (ec, ref arguments);
1042 return new UserOperatorCall (oper, arguments, null, loc);
1045 public virtual string ExprClassName
1049 case ExprClass.Unresolved:
1050 return "Unresolved";
1051 case ExprClass.Value:
1053 case ExprClass.Variable:
1055 case ExprClass.Namespace:
1057 case ExprClass.Type:
1059 case ExprClass.MethodGroup:
1060 return "method group";
1061 case ExprClass.PropertyAccess:
1062 return "property access";
1063 case ExprClass.EventAccess:
1064 return "event access";
1065 case ExprClass.IndexerAccess:
1066 return "indexer access";
1067 case ExprClass.Nothing:
1069 case ExprClass.TypeParameter:
1070 return "type parameter";
1072 throw new Exception ("Should not happen");
1077 /// Reports that we were expecting `expr' to be of class `expected'
1079 public static void Error_UnexpectedKind (IMemberContext ctx, Expression memberExpr, string expected, string was, Location loc)
1081 var name = memberExpr.GetSignatureForError ();
1083 ctx.Module.Compiler.Report.Error (118, loc, "`{0}' is a `{1}' but a `{2}' was expected", name, was, expected);
1086 public virtual void Error_UnexpectedKind (ResolveContext ec, ResolveFlags flags, Location loc)
1088 string [] valid = new string [4];
1091 if ((flags & ResolveFlags.VariableOrValue) != 0) {
1092 valid [count++] = "variable";
1093 valid [count++] = "value";
1096 if ((flags & ResolveFlags.Type) != 0)
1097 valid [count++] = "type";
1099 if ((flags & ResolveFlags.MethodGroup) != 0)
1100 valid [count++] = "method group";
1103 valid [count++] = "unknown";
1105 StringBuilder sb = new StringBuilder (valid [0]);
1106 for (int i = 1; i < count - 1; i++) {
1108 sb.Append (valid [i]);
1111 sb.Append ("' or `");
1112 sb.Append (valid [count - 1]);
1115 ec.Report.Error (119, loc,
1116 "Expression denotes a `{0}', where a `{1}' was expected", ExprClassName, sb.ToString ());
1119 public static void UnsafeError (ResolveContext ec, Location loc)
1121 UnsafeError (ec.Report, loc);
1124 public static void UnsafeError (Report Report, Location loc)
1126 Report.Error (214, loc, "Pointers and fixed size buffers may only be used in an unsafe context");
1130 // Converts `source' to an int, uint, long or ulong.
1132 protected Expression ConvertExpressionToArrayIndex (ResolveContext ec, Expression source, bool pointerArray = false)
1134 var btypes = ec.BuiltinTypes;
1136 if (source.type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1137 Arguments args = new Arguments (1);
1138 args.Add (new Argument (source));
1139 return new DynamicConversion (btypes.Int, CSharpBinderFlags.ConvertArrayIndex, args, loc).Resolve (ec);
1142 Expression converted;
1144 using (ec.Set (ResolveContext.Options.CheckedScope)) {
1145 converted = Convert.ImplicitConversion (ec, source, btypes.Int, source.loc);
1146 if (converted == null)
1147 converted = Convert.ImplicitConversion (ec, source, btypes.UInt, source.loc);
1148 if (converted == null)
1149 converted = Convert.ImplicitConversion (ec, source, btypes.Long, source.loc);
1150 if (converted == null)
1151 converted = Convert.ImplicitConversion (ec, source, btypes.ULong, source.loc);
1153 if (converted == null) {
1154 source.Error_ValueCannotBeConverted (ec, btypes.Int, false);
1163 // Only positive constants are allowed at compile time
1165 Constant c = converted as Constant;
1166 if (c != null && c.IsNegative)
1167 Error_NegativeArrayIndex (ec, source.loc);
1169 // No conversion needed to array index
1170 if (converted.Type.BuiltinType == BuiltinTypeSpec.Type.Int)
1173 return new ArrayIndexCast (converted, btypes.Int).Resolve (ec);
1177 // Derived classes implement this method by cloning the fields that
1178 // could become altered during the Resolve stage
1180 // Only expressions that are created for the parser need to implement
1183 protected virtual void CloneTo (CloneContext clonectx, Expression target)
1185 throw new NotImplementedException (
1187 "CloneTo not implemented for expression {0}", this.GetType ()));
1191 // Clones an expression created by the parser.
1193 // We only support expressions created by the parser so far, not
1194 // expressions that have been resolved (many more classes would need
1195 // to implement CloneTo).
1197 // This infrastructure is here merely for Lambda expressions which
1198 // compile the same code using different type values for the same
1199 // arguments to find the correct overload
1201 public virtual Expression Clone (CloneContext clonectx)
1203 Expression cloned = (Expression) MemberwiseClone ();
1204 CloneTo (clonectx, cloned);
1210 // Implementation of expression to expression tree conversion
1212 public abstract Expression CreateExpressionTree (ResolveContext ec);
1214 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, Arguments args)
1216 return CreateExpressionFactoryCall (ec, name, null, args, loc);
1219 protected Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args)
1221 return CreateExpressionFactoryCall (ec, name, typeArguments, args, loc);
1224 public static Expression CreateExpressionFactoryCall (ResolveContext ec, string name, TypeArguments typeArguments, Arguments args, Location loc)
1226 return new Invocation (new MemberAccess (CreateExpressionTypeExpression (ec, loc), name, typeArguments, loc), args);
1229 protected static TypeExpr CreateExpressionTypeExpression (ResolveContext ec, Location loc)
1231 var t = ec.Module.PredefinedTypes.Expression.Resolve ();
1235 return new TypeExpression (t, loc);
1239 // Implemented by all expressions which support conversion from
1240 // compiler expression to invokable runtime expression. Used by
1241 // dynamic C# binder.
1243 public virtual SLE.Expression MakeExpression (BuilderContext ctx)
1245 throw new NotImplementedException ("MakeExpression for " + GetType ());
1248 public virtual object Accept (StructuralVisitor visitor)
1250 return visitor.Visit (this);
1255 /// This is just a base class for expressions that can
1256 /// appear on statements (invocations, object creation,
1257 /// assignments, post/pre increment and decrement). The idea
1258 /// being that they would support an extra Emition interface that
1259 /// does not leave a result on the stack.
1261 public abstract class ExpressionStatement : Expression
1263 public virtual void MarkReachable (Reachability rc)
1267 public ExpressionStatement ResolveStatement (BlockContext ec)
1269 Expression e = Resolve (ec);
1273 ExpressionStatement es = e as ExpressionStatement;
1274 if (es == null || e is AnonymousMethodBody)
1275 Error_InvalidExpressionStatement (ec);
1278 // This is quite expensive warning, try to limit the damage
1280 if (MemberAccess.IsValidDotExpression (e.Type) && !(e is Assign || e is Await)) {
1281 WarningAsyncWithoutWait (ec, e);
1287 static void WarningAsyncWithoutWait (BlockContext bc, Expression e)
1289 if (bc.CurrentAnonymousMethod is AsyncInitializer) {
1290 var awaiter = new AwaitStatement.AwaitableMemberAccess (e) {
1295 // Need to do full resolve because GetAwaiter can be extension method
1296 // available only in this context
1298 var mg = awaiter.Resolve (bc) as MethodGroupExpr;
1302 var arguments = new Arguments (0);
1303 mg = mg.OverloadResolve (bc, ref arguments, null, OverloadResolver.Restrictions.ProbingOnly);
1308 // Use same check rules as for real await
1310 var awaiter_definition = bc.Module.GetAwaiter (mg.BestCandidateReturnType);
1311 if (!awaiter_definition.IsValidPattern || !awaiter_definition.INotifyCompletion)
1314 bc.Report.Warning (4014, 1, e.Location,
1315 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator");
1319 var inv = e as Invocation;
1320 if (inv != null && inv.MethodGroup != null && inv.MethodGroup.BestCandidate.IsAsync) {
1321 // The warning won't be reported for imported methods to maintain warning compatiblity with csc
1322 bc.Report.Warning (4014, 1, e.Location,
1323 "The statement is not awaited and execution of current method continues before the call is completed. Consider using `await' operator or calling `Wait' method");
1329 /// Requests the expression to be emitted in a `statement'
1330 /// context. This means that no new value is left on the
1331 /// stack after invoking this method (constrasted with
1332 /// Emit that will always leave a value on the stack).
1334 public abstract void EmitStatement (EmitContext ec);
1336 public override void EmitSideEffect (EmitContext ec)
1343 /// This kind of cast is used to encapsulate the child
1344 /// whose type is child.Type into an expression that is
1345 /// reported to return "return_type". This is used to encapsulate
1346 /// expressions which have compatible types, but need to be dealt
1347 /// at higher levels with.
1349 /// For example, a "byte" expression could be encapsulated in one
1350 /// of these as an "unsigned int". The type for the expression
1351 /// would be "unsigned int".
1354 public abstract class TypeCast : Expression
1356 protected readonly Expression child;
1358 protected TypeCast (Expression child, TypeSpec return_type)
1360 eclass = child.eclass;
1361 loc = child.Location;
1366 public Expression Child {
1372 public override bool ContainsEmitWithAwait ()
1374 return child.ContainsEmitWithAwait ();
1377 public override Expression CreateExpressionTree (ResolveContext ec)
1379 Arguments args = new Arguments (2);
1380 args.Add (new Argument (child.CreateExpressionTree (ec)));
1381 args.Add (new Argument (new TypeOf (type, loc)));
1383 if (type.IsPointer || child.Type.IsPointer)
1384 Error_PointerInsideExpressionTree (ec);
1386 return CreateExpressionFactoryCall (ec, ec.HasSet (ResolveContext.Options.CheckedScope) ? "ConvertChecked" : "Convert", args);
1389 protected override Expression DoResolve (ResolveContext ec)
1391 // This should never be invoked, we are born in fully
1392 // initialized state.
1397 public override void Emit (EmitContext ec)
1402 public override void FlowAnalysis (FlowAnalysisContext fc)
1404 child.FlowAnalysis (fc);
1407 public override SLE.Expression MakeExpression (BuilderContext ctx)
1410 return base.MakeExpression (ctx);
1412 return ctx.HasSet (BuilderContext.Options.CheckedScope) ?
1413 SLE.Expression.ConvertChecked (child.MakeExpression (ctx), type.GetMetaInfo ()) :
1414 SLE.Expression.Convert (child.MakeExpression (ctx), type.GetMetaInfo ());
1418 protected override void CloneTo (CloneContext clonectx, Expression t)
1423 public override bool IsNull {
1424 get { return child.IsNull; }
1428 public class EmptyCast : TypeCast {
1429 EmptyCast (Expression child, TypeSpec target_type)
1430 : base (child, target_type)
1434 public static Expression Create (Expression child, TypeSpec type)
1436 Constant c = child as Constant;
1438 var enum_constant = c as EnumConstant;
1439 if (enum_constant != null)
1440 c = enum_constant.Child;
1442 if (!(c is ReducedExpression.ReducedConstantExpression)) {
1446 var res = c.ConvertImplicitly (type);
1452 EmptyCast e = child as EmptyCast;
1454 return new EmptyCast (e.child, type);
1456 return new EmptyCast (child, type);
1459 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1461 child.EmitBranchable (ec, label, on_true);
1464 public override void EmitSideEffect (EmitContext ec)
1466 child.EmitSideEffect (ec);
1471 // Used for predefined type user operator (no obsolete check, etc.)
1473 public class OperatorCast : TypeCast
1475 readonly MethodSpec conversion_operator;
1477 public OperatorCast (Expression expr, TypeSpec target_type)
1478 : this (expr, target_type, target_type, false)
1482 public OperatorCast (Expression expr, TypeSpec target_type, bool find_explicit)
1483 : this (expr, target_type, target_type, find_explicit)
1487 public OperatorCast (Expression expr, TypeSpec declaringType, TypeSpec returnType, bool isExplicit)
1488 : base (expr, returnType)
1490 var op = isExplicit ? Operator.OpType.Explicit : Operator.OpType.Implicit;
1491 var mi = MemberCache.GetUserOperator (declaringType, op, true);
1494 foreach (MethodSpec oper in mi) {
1495 if (oper.ReturnType != returnType)
1498 if (oper.Parameters.Types[0] == expr.Type) {
1499 conversion_operator = oper;
1505 throw new InternalErrorException ("Missing predefined user operator between `{0}' and `{1}'",
1506 returnType.GetSignatureForError (), expr.Type.GetSignatureForError ());
1509 public override void Emit (EmitContext ec)
1512 ec.Emit (OpCodes.Call, conversion_operator);
1517 // Constant specialization of EmptyCast.
1518 // We need to special case this since an empty cast of
1519 // a constant is still a constant.
1521 public class EmptyConstantCast : Constant
1523 public readonly Constant child;
1525 public EmptyConstantCast (Constant child, TypeSpec type)
1526 : base (child.Location)
1529 throw new ArgumentNullException ("child");
1532 this.eclass = child.eclass;
1536 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1538 if (child.Type == target_type)
1541 // FIXME: check that 'type' can be converted to 'target_type' first
1542 return child.ConvertExplicitly (in_checked_context, target_type);
1545 public override Expression CreateExpressionTree (ResolveContext ec)
1547 Arguments args = Arguments.CreateForExpressionTree (ec, null,
1548 child.CreateExpressionTree (ec),
1549 new TypeOf (type, loc));
1552 Error_PointerInsideExpressionTree (ec);
1554 return CreateExpressionFactoryCall (ec, "Convert", args);
1557 public override bool IsDefaultValue {
1558 get { return child.IsDefaultValue; }
1561 public override bool IsNegative {
1562 get { return child.IsNegative; }
1565 public override bool IsNull {
1566 get { return child.IsNull; }
1569 public override bool IsOneInteger {
1570 get { return child.IsOneInteger; }
1573 public override bool IsSideEffectFree {
1575 return child.IsSideEffectFree;
1579 public override bool IsZeroInteger {
1580 get { return child.IsZeroInteger; }
1583 public override void Emit (EmitContext ec)
1588 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1590 child.EmitBranchable (ec, label, on_true);
1592 // Only to make verifier happy
1593 if (TypeManager.IsGenericParameter (type) && child.IsNull)
1594 ec.Emit (OpCodes.Unbox_Any, type);
1597 public override void EmitSideEffect (EmitContext ec)
1599 child.EmitSideEffect (ec);
1602 public override object GetValue ()
1604 return child.GetValue ();
1607 public override string GetValueAsLiteral ()
1609 return child.GetValueAsLiteral ();
1612 public override long GetValueAsLong ()
1614 return child.GetValueAsLong ();
1617 public override Constant ConvertImplicitly (TypeSpec target_type)
1619 if (type == target_type)
1622 // FIXME: Do we need to check user conversions?
1623 if (!Convert.ImplicitStandardConversionExists (this, target_type))
1626 return child.ConvertImplicitly (target_type);
1631 /// This class is used to wrap literals which belong inside Enums
1633 public class EnumConstant : Constant
1635 public Constant Child;
1637 public EnumConstant (Constant child, TypeSpec enum_type)
1638 : base (child.Location)
1642 this.eclass = ExprClass.Value;
1643 this.type = enum_type;
1646 protected EnumConstant (Location loc)
1651 public override void Emit (EmitContext ec)
1656 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1658 Child.EncodeAttributeValue (rc, enc, Child.Type, parameterType);
1661 public override void EmitBranchable (EmitContext ec, Label label, bool on_true)
1663 Child.EmitBranchable (ec, label, on_true);
1666 public override void EmitSideEffect (EmitContext ec)
1668 Child.EmitSideEffect (ec);
1671 public override string GetSignatureForError()
1673 return Type.GetSignatureForError ();
1676 public override object GetValue ()
1678 return Child.GetValue ();
1682 public override object GetTypedValue ()
1685 // The method can be used in dynamic context only (on closed types)
1687 // System.Enum.ToObject cannot be called on dynamic types
1688 // EnumBuilder has to be used, but we cannot use EnumBuilder
1689 // because it does not properly support generics
1691 return System.Enum.ToObject (type.GetMetaInfo (), Child.GetValue ());
1695 public override string GetValueAsLiteral ()
1697 return Child.GetValueAsLiteral ();
1700 public override long GetValueAsLong ()
1702 return Child.GetValueAsLong ();
1705 public EnumConstant Increment()
1707 return new EnumConstant (((IntegralConstant) Child).Increment (), type);
1710 public override bool IsDefaultValue {
1712 return Child.IsDefaultValue;
1716 public override bool IsSideEffectFree {
1718 return Child.IsSideEffectFree;
1722 public override bool IsZeroInteger {
1723 get { return Child.IsZeroInteger; }
1726 public override bool IsNegative {
1728 return Child.IsNegative;
1732 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
1734 if (Child.Type == target_type)
1737 return Child.ConvertExplicitly (in_checked_context, target_type);
1740 public override Constant ConvertImplicitly (TypeSpec type)
1742 if (this.type == type) {
1746 if (!Convert.ImplicitStandardConversionExists (this, type)){
1750 return Child.ConvertImplicitly (type);
1755 /// This kind of cast is used to encapsulate Value Types in objects.
1757 /// The effect of it is to box the value type emitted by the previous
1760 public class BoxedCast : TypeCast {
1762 public BoxedCast (Expression expr, TypeSpec target_type)
1763 : base (expr, target_type)
1765 eclass = ExprClass.Value;
1768 protected override Expression DoResolve (ResolveContext ec)
1770 // This should never be invoked, we are born in fully
1771 // initialized state.
1776 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
1778 // Only boxing to object type is supported
1779 if (targetType.BuiltinType != BuiltinTypeSpec.Type.Object) {
1780 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
1784 enc.Encode (child.Type);
1785 child.EncodeAttributeValue (rc, enc, child.Type, parameterType);
1788 public override void Emit (EmitContext ec)
1792 ec.Emit (OpCodes.Box, child.Type);
1795 public override void EmitSideEffect (EmitContext ec)
1797 // boxing is side-effectful, since it involves runtime checks, except when boxing to Object or ValueType
1798 // so, we need to emit the box+pop instructions in most cases
1799 if (child.Type.IsStruct &&
1800 (type.BuiltinType == BuiltinTypeSpec.Type.Object || type.BuiltinType == BuiltinTypeSpec.Type.ValueType))
1801 child.EmitSideEffect (ec);
1803 base.EmitSideEffect (ec);
1807 public class UnboxCast : TypeCast {
1808 public UnboxCast (Expression expr, TypeSpec return_type)
1809 : base (expr, return_type)
1813 protected override Expression DoResolve (ResolveContext ec)
1815 // This should never be invoked, we are born in fully
1816 // initialized state.
1821 public override void Emit (EmitContext ec)
1825 ec.Emit (OpCodes.Unbox_Any, type);
1830 /// This is used to perform explicit numeric conversions.
1832 /// Explicit numeric conversions might trigger exceptions in a checked
1833 /// context, so they should generate the conv.ovf opcodes instead of
1836 public class ConvCast : TypeCast {
1837 public enum Mode : byte {
1838 I1_U1, I1_U2, I1_U4, I1_U8, I1_CH,
1840 I2_I1, I2_U1, I2_U2, I2_U4, I2_U8, I2_CH,
1841 U2_I1, U2_U1, U2_I2, U2_CH,
1842 I4_I1, I4_U1, I4_I2, I4_U2, I4_U4, I4_U8, I4_CH,
1843 U4_I1, U4_U1, U4_I2, U4_U2, U4_I4, U4_CH,
1844 I8_I1, I8_U1, I8_I2, I8_U2, I8_I4, I8_U4, I8_U8, I8_CH, I8_I,
1845 U8_I1, U8_U1, U8_I2, U8_U2, U8_I4, U8_U4, U8_I8, U8_CH, U8_I,
1846 CH_I1, CH_U1, CH_I2,
1847 R4_I1, R4_U1, R4_I2, R4_U2, R4_I4, R4_U4, R4_I8, R4_U8, R4_CH,
1848 R8_I1, R8_U1, R8_I2, R8_U2, R8_I4, R8_U4, R8_I8, R8_U8, R8_CH, R8_R4,
1854 public ConvCast (Expression child, TypeSpec return_type, Mode m)
1855 : base (child, return_type)
1860 protected override Expression DoResolve (ResolveContext ec)
1862 // This should never be invoked, we are born in fully
1863 // initialized state.
1868 public override string ToString ()
1870 return String.Format ("ConvCast ({0}, {1})", mode, child);
1873 public override void Emit (EmitContext ec)
1879 public static void Emit (EmitContext ec, Mode mode)
1881 if (ec.HasSet (EmitContext.Options.CheckedScope)) {
1883 case Mode.I1_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1884 case Mode.I1_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1885 case Mode.I1_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1886 case Mode.I1_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1887 case Mode.I1_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1889 case Mode.U1_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1890 case Mode.U1_CH: /* nothing */ break;
1892 case Mode.I2_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1893 case Mode.I2_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1894 case Mode.I2_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1895 case Mode.I2_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1896 case Mode.I2_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1897 case Mode.I2_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1899 case Mode.U2_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1900 case Mode.U2_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1901 case Mode.U2_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1902 case Mode.U2_CH: /* nothing */ break;
1904 case Mode.I4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1905 case Mode.I4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1906 case Mode.I4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1907 case Mode.I4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1908 case Mode.I4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1909 case Mode.I4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1910 case Mode.I4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1912 case Mode.U4_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1913 case Mode.U4_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1914 case Mode.U4_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1915 case Mode.U4_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1916 case Mode.U4_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1917 case Mode.U4_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1919 case Mode.I8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1920 case Mode.I8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1921 case Mode.I8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1922 case Mode.I8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1923 case Mode.I8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1924 case Mode.I8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1925 case Mode.I8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1926 case Mode.I8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1927 case Mode.I8_I: ec.Emit (OpCodes.Conv_Ovf_U); break;
1929 case Mode.U8_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1930 case Mode.U8_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1931 case Mode.U8_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1932 case Mode.U8_U2: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1933 case Mode.U8_I4: ec.Emit (OpCodes.Conv_Ovf_I4_Un); break;
1934 case Mode.U8_U4: ec.Emit (OpCodes.Conv_Ovf_U4_Un); break;
1935 case Mode.U8_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1936 case Mode.U8_CH: ec.Emit (OpCodes.Conv_Ovf_U2_Un); break;
1937 case Mode.U8_I: ec.Emit (OpCodes.Conv_Ovf_U_Un); break;
1939 case Mode.CH_I1: ec.Emit (OpCodes.Conv_Ovf_I1_Un); break;
1940 case Mode.CH_U1: ec.Emit (OpCodes.Conv_Ovf_U1_Un); break;
1941 case Mode.CH_I2: ec.Emit (OpCodes.Conv_Ovf_I2_Un); break;
1943 case Mode.R4_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1944 case Mode.R4_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1945 case Mode.R4_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1946 case Mode.R4_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1947 case Mode.R4_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1948 case Mode.R4_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1949 case Mode.R4_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1950 case Mode.R4_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1951 case Mode.R4_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1953 case Mode.R8_I1: ec.Emit (OpCodes.Conv_Ovf_I1); break;
1954 case Mode.R8_U1: ec.Emit (OpCodes.Conv_Ovf_U1); break;
1955 case Mode.R8_I2: ec.Emit (OpCodes.Conv_Ovf_I2); break;
1956 case Mode.R8_U2: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1957 case Mode.R8_I4: ec.Emit (OpCodes.Conv_Ovf_I4); break;
1958 case Mode.R8_U4: ec.Emit (OpCodes.Conv_Ovf_U4); break;
1959 case Mode.R8_I8: ec.Emit (OpCodes.Conv_Ovf_I8); break;
1960 case Mode.R8_U8: ec.Emit (OpCodes.Conv_Ovf_U8); break;
1961 case Mode.R8_CH: ec.Emit (OpCodes.Conv_Ovf_U2); break;
1962 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
1964 case Mode.I_I8: ec.Emit (OpCodes.Conv_Ovf_I8_Un); break;
1968 case Mode.I1_U1: ec.Emit (OpCodes.Conv_U1); break;
1969 case Mode.I1_U2: ec.Emit (OpCodes.Conv_U2); break;
1970 case Mode.I1_U4: ec.Emit (OpCodes.Conv_U4); break;
1971 case Mode.I1_U8: ec.Emit (OpCodes.Conv_I8); break;
1972 case Mode.I1_CH: ec.Emit (OpCodes.Conv_U2); break;
1974 case Mode.U1_I1: ec.Emit (OpCodes.Conv_I1); break;
1975 case Mode.U1_CH: ec.Emit (OpCodes.Conv_U2); break;
1977 case Mode.I2_I1: ec.Emit (OpCodes.Conv_I1); break;
1978 case Mode.I2_U1: ec.Emit (OpCodes.Conv_U1); break;
1979 case Mode.I2_U2: ec.Emit (OpCodes.Conv_U2); break;
1980 case Mode.I2_U4: ec.Emit (OpCodes.Conv_U4); break;
1981 case Mode.I2_U8: ec.Emit (OpCodes.Conv_I8); break;
1982 case Mode.I2_CH: ec.Emit (OpCodes.Conv_U2); break;
1984 case Mode.U2_I1: ec.Emit (OpCodes.Conv_I1); break;
1985 case Mode.U2_U1: ec.Emit (OpCodes.Conv_U1); break;
1986 case Mode.U2_I2: ec.Emit (OpCodes.Conv_I2); break;
1987 case Mode.U2_CH: /* nothing */ break;
1989 case Mode.I4_I1: ec.Emit (OpCodes.Conv_I1); break;
1990 case Mode.I4_U1: ec.Emit (OpCodes.Conv_U1); break;
1991 case Mode.I4_I2: ec.Emit (OpCodes.Conv_I2); break;
1992 case Mode.I4_U4: /* nothing */ break;
1993 case Mode.I4_U2: ec.Emit (OpCodes.Conv_U2); break;
1994 case Mode.I4_U8: ec.Emit (OpCodes.Conv_I8); break;
1995 case Mode.I4_CH: ec.Emit (OpCodes.Conv_U2); break;
1997 case Mode.U4_I1: ec.Emit (OpCodes.Conv_I1); break;
1998 case Mode.U4_U1: ec.Emit (OpCodes.Conv_U1); break;
1999 case Mode.U4_I2: ec.Emit (OpCodes.Conv_I2); break;
2000 case Mode.U4_U2: ec.Emit (OpCodes.Conv_U2); break;
2001 case Mode.U4_I4: /* nothing */ break;
2002 case Mode.U4_CH: ec.Emit (OpCodes.Conv_U2); break;
2004 case Mode.I8_I1: ec.Emit (OpCodes.Conv_I1); break;
2005 case Mode.I8_U1: ec.Emit (OpCodes.Conv_U1); break;
2006 case Mode.I8_I2: ec.Emit (OpCodes.Conv_I2); break;
2007 case Mode.I8_U2: ec.Emit (OpCodes.Conv_U2); break;
2008 case Mode.I8_I4: ec.Emit (OpCodes.Conv_I4); break;
2009 case Mode.I8_U4: ec.Emit (OpCodes.Conv_U4); break;
2010 case Mode.I8_U8: /* nothing */ break;
2011 case Mode.I8_CH: ec.Emit (OpCodes.Conv_U2); break;
2012 case Mode.I8_I: ec.Emit (OpCodes.Conv_U); break;
2014 case Mode.U8_I1: ec.Emit (OpCodes.Conv_I1); break;
2015 case Mode.U8_U1: ec.Emit (OpCodes.Conv_U1); break;
2016 case Mode.U8_I2: ec.Emit (OpCodes.Conv_I2); break;
2017 case Mode.U8_U2: ec.Emit (OpCodes.Conv_U2); break;
2018 case Mode.U8_I4: ec.Emit (OpCodes.Conv_I4); break;
2019 case Mode.U8_U4: ec.Emit (OpCodes.Conv_U4); break;
2020 case Mode.U8_I8: /* nothing */ break;
2021 case Mode.U8_CH: ec.Emit (OpCodes.Conv_U2); break;
2022 case Mode.U8_I: ec.Emit (OpCodes.Conv_U); break;
2024 case Mode.CH_I1: ec.Emit (OpCodes.Conv_I1); break;
2025 case Mode.CH_U1: ec.Emit (OpCodes.Conv_U1); break;
2026 case Mode.CH_I2: ec.Emit (OpCodes.Conv_I2); break;
2028 case Mode.R4_I1: ec.Emit (OpCodes.Conv_I1); break;
2029 case Mode.R4_U1: ec.Emit (OpCodes.Conv_U1); break;
2030 case Mode.R4_I2: ec.Emit (OpCodes.Conv_I2); break;
2031 case Mode.R4_U2: ec.Emit (OpCodes.Conv_U2); break;
2032 case Mode.R4_I4: ec.Emit (OpCodes.Conv_I4); break;
2033 case Mode.R4_U4: ec.Emit (OpCodes.Conv_U4); break;
2034 case Mode.R4_I8: ec.Emit (OpCodes.Conv_I8); break;
2035 case Mode.R4_U8: ec.Emit (OpCodes.Conv_U8); break;
2036 case Mode.R4_CH: ec.Emit (OpCodes.Conv_U2); break;
2038 case Mode.R8_I1: ec.Emit (OpCodes.Conv_I1); break;
2039 case Mode.R8_U1: ec.Emit (OpCodes.Conv_U1); break;
2040 case Mode.R8_I2: ec.Emit (OpCodes.Conv_I2); break;
2041 case Mode.R8_U2: ec.Emit (OpCodes.Conv_U2); break;
2042 case Mode.R8_I4: ec.Emit (OpCodes.Conv_I4); break;
2043 case Mode.R8_U4: ec.Emit (OpCodes.Conv_U4); break;
2044 case Mode.R8_I8: ec.Emit (OpCodes.Conv_I8); break;
2045 case Mode.R8_U8: ec.Emit (OpCodes.Conv_U8); break;
2046 case Mode.R8_CH: ec.Emit (OpCodes.Conv_U2); break;
2047 case Mode.R8_R4: ec.Emit (OpCodes.Conv_R4); break;
2049 case Mode.I_I8: ec.Emit (OpCodes.Conv_U8); break;
2055 class OpcodeCast : TypeCast
2059 public OpcodeCast (Expression child, TypeSpec return_type, OpCode op)
2060 : base (child, return_type)
2065 protected override Expression DoResolve (ResolveContext ec)
2067 // This should never be invoked, we are born in fully
2068 // initialized state.
2073 public override void Emit (EmitContext ec)
2079 public TypeSpec UnderlyingType {
2080 get { return child.Type; }
2085 // Opcode casts expression with 2 opcodes but only
2086 // single expression tree node
2088 class OpcodeCastDuplex : OpcodeCast
2090 readonly OpCode second;
2092 public OpcodeCastDuplex (Expression child, TypeSpec returnType, OpCode first, OpCode second)
2093 : base (child, returnType, first)
2095 this.second = second;
2098 public override void Emit (EmitContext ec)
2106 /// This kind of cast is used to encapsulate a child and cast it
2107 /// to the class requested
2109 public sealed class ClassCast : TypeCast {
2110 readonly bool forced;
2112 public ClassCast (Expression child, TypeSpec return_type)
2113 : base (child, return_type)
2117 public ClassCast (Expression child, TypeSpec return_type, bool forced)
2118 : base (child, return_type)
2120 this.forced = forced;
2123 public override void Emit (EmitContext ec)
2127 bool gen = TypeManager.IsGenericParameter (child.Type);
2129 ec.Emit (OpCodes.Box, child.Type);
2131 if (type.IsGenericParameter) {
2132 ec.Emit (OpCodes.Unbox_Any, type);
2139 ec.Emit (OpCodes.Castclass, type);
2144 // Created during resolving pahse when an expression is wrapped or constantified
2145 // and original expression can be used later (e.g. for expression trees)
2147 public class ReducedExpression : Expression
2149 public sealed class ReducedConstantExpression : EmptyConstantCast
2151 readonly Expression orig_expr;
2153 public ReducedConstantExpression (Constant expr, Expression orig_expr)
2154 : base (expr, expr.Type)
2156 this.orig_expr = orig_expr;
2159 public Expression OriginalExpression {
2165 public override Constant ConvertImplicitly (TypeSpec target_type)
2167 Constant c = base.ConvertImplicitly (target_type);
2169 c = new ReducedConstantExpression (c, orig_expr);
2174 public override Expression CreateExpressionTree (ResolveContext ec)
2176 return orig_expr.CreateExpressionTree (ec);
2179 public override Constant ConvertExplicitly (bool in_checked_context, TypeSpec target_type)
2181 Constant c = base.ConvertExplicitly (in_checked_context, target_type);
2183 c = new ReducedConstantExpression (c, orig_expr);
2187 public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType, TypeSpec parameterType)
2190 // LAMESPEC: Reduced conditional expression is allowed as an attribute argument
2192 if (orig_expr is Conditional)
2193 child.EncodeAttributeValue (rc, enc, targetType,parameterType);
2195 base.EncodeAttributeValue (rc, enc, targetType, parameterType);
2199 sealed class ReducedExpressionStatement : ExpressionStatement
2201 readonly Expression orig_expr;
2202 readonly ExpressionStatement stm;
2204 public ReducedExpressionStatement (ExpressionStatement stm, Expression orig)
2206 this.orig_expr = orig;
2208 this.eclass = stm.eclass;
2209 this.type = stm.Type;
2211 this.loc = orig.Location;
2214 public override bool ContainsEmitWithAwait ()
2216 return stm.ContainsEmitWithAwait ();
2219 public override Expression CreateExpressionTree (ResolveContext ec)
2221 return orig_expr.CreateExpressionTree (ec);
2224 protected override Expression DoResolve (ResolveContext ec)
2229 public override void Emit (EmitContext ec)
2234 public override void EmitStatement (EmitContext ec)
2236 stm.EmitStatement (ec);
2239 public override void FlowAnalysis (FlowAnalysisContext fc)
2241 stm.FlowAnalysis (fc);
2245 readonly Expression expr, orig_expr;
2247 private ReducedExpression (Expression expr, Expression orig_expr)
2250 this.eclass = expr.eclass;
2251 this.type = expr.Type;
2252 this.orig_expr = orig_expr;
2253 this.loc = orig_expr.Location;
2258 public override bool IsSideEffectFree {
2260 return expr.IsSideEffectFree;
2264 public Expression OriginalExpression {
2272 public override bool ContainsEmitWithAwait ()
2274 return expr.ContainsEmitWithAwait ();
2278 // Creates fully resolved expression switcher
2280 public static Constant Create (Constant expr, Expression original_expr)
2282 if (expr.eclass == ExprClass.Unresolved)
2283 throw new ArgumentException ("Unresolved expression");
2285 return new ReducedConstantExpression (expr, original_expr);
2288 public static ExpressionStatement Create (ExpressionStatement s, Expression orig)
2290 return new ReducedExpressionStatement (s, orig);
2293 public static Expression Create (Expression expr, Expression original_expr)
2295 return Create (expr, original_expr, true);
2299 // Creates unresolved reduce expression. The original expression has to be
2300 // already resolved. Created expression is constant based based on `expr'
2301 // value unless canBeConstant is used
2303 public static Expression Create (Expression expr, Expression original_expr, bool canBeConstant)
2305 if (canBeConstant) {
2306 Constant c = expr as Constant;
2308 return Create (c, original_expr);
2311 ExpressionStatement s = expr as ExpressionStatement;
2313 return Create (s, original_expr);
2315 if (expr.eclass == ExprClass.Unresolved)
2316 throw new ArgumentException ("Unresolved expression");
2318 return new ReducedExpression (expr, original_expr);
2321 public override Expression CreateExpressionTree (ResolveContext ec)
2323 return orig_expr.CreateExpressionTree (ec);
2326 protected override Expression DoResolve (ResolveContext ec)
2331 public override void Emit (EmitContext ec)
2336 public override Expression EmitToField (EmitContext ec)
2338 return expr.EmitToField(ec);
2341 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2343 expr.EmitBranchable (ec, target, on_true);
2346 public override void FlowAnalysis (FlowAnalysisContext fc)
2348 expr.FlowAnalysis (fc);
2351 public override SLE.Expression MakeExpression (BuilderContext ctx)
2353 return orig_expr.MakeExpression (ctx);
2358 // Standard composite pattern
2360 public abstract class CompositeExpression : Expression
2362 protected Expression expr;
2364 protected CompositeExpression (Expression expr)
2367 this.loc = expr.Location;
2370 public override bool ContainsEmitWithAwait ()
2372 return expr.ContainsEmitWithAwait ();
2375 public override Expression CreateExpressionTree (ResolveContext rc)
2377 return expr.CreateExpressionTree (rc);
2380 public Expression Child {
2381 get { return expr; }
2384 protected override Expression DoResolve (ResolveContext rc)
2386 expr = expr.Resolve (rc);
2391 eclass = expr.eclass;
2395 public override void Emit (EmitContext ec)
2400 public override bool IsNull {
2401 get { return expr.IsNull; }
2406 // Base of expressions used only to narrow resolve flow
2408 public abstract class ShimExpression : Expression
2410 protected Expression expr;
2412 protected ShimExpression (Expression expr)
2417 public Expression Expr {
2423 protected override void CloneTo (CloneContext clonectx, Expression t)
2428 ShimExpression target = (ShimExpression) t;
2429 target.expr = expr.Clone (clonectx);
2432 public override bool ContainsEmitWithAwait ()
2434 return expr.ContainsEmitWithAwait ();
2437 public override Expression CreateExpressionTree (ResolveContext ec)
2439 throw new NotSupportedException ("ET");
2442 public override void Emit (EmitContext ec)
2444 throw new InternalErrorException ("Missing Resolve call");
2448 public class UnreachableExpression : Expression
2450 public UnreachableExpression (Expression expr)
2452 this.loc = expr.Location;
2455 public override Expression CreateExpressionTree (ResolveContext ec)
2458 throw new NotImplementedException ();
2461 protected override Expression DoResolve (ResolveContext rc)
2463 throw new NotSupportedException ();
2466 public override void FlowAnalysis (FlowAnalysisContext fc)
2468 fc.Report.Warning (429, 4, loc, "Unreachable expression code detected");
2471 public override void Emit (EmitContext ec)
2475 public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
2481 // Unresolved type name expressions
2483 public abstract class ATypeNameExpression : FullNamedExpression
2486 protected TypeArguments targs;
2488 protected ATypeNameExpression (string name, Location l)
2494 protected ATypeNameExpression (string name, TypeArguments targs, Location l)
2501 protected ATypeNameExpression (string name, int arity, Location l)
2502 : this (name, new UnboundTypeArguments (arity), l)
2508 protected int Arity {
2510 return targs == null ? 0 : targs.Count;
2514 public bool HasTypeArguments {
2516 return targs != null && !targs.IsEmpty;
2520 public string Name {
2529 public TypeArguments TypeArguments {
2537 public override bool Equals (object obj)
2539 ATypeNameExpression atne = obj as ATypeNameExpression;
2540 return atne != null && atne.Name == Name &&
2541 (targs == null || targs.Equals (atne.targs));
2544 protected void Error_OpenGenericTypeIsNotAllowed (IMemberContext mc)
2546 mc.Module.Compiler.Report.Error (7003, Location, "Unbound generic name is not valid in this context");
2549 public override int GetHashCode ()
2551 return Name.GetHashCode ();
2554 // TODO: Move it to MemberCore
2555 public static string GetMemberType (MemberCore mc)
2561 if (mc is FieldBase)
2563 if (mc is MethodCore)
2565 if (mc is EnumMember)
2573 public override string GetSignatureForError ()
2575 if (targs != null) {
2576 return Name + "<" + targs.GetSignatureForError () + ">";
2582 public abstract Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restriction);
2586 /// SimpleName expressions are formed of a single word and only happen at the beginning
2587 /// of a dotted-name.
2589 public class SimpleName : ATypeNameExpression
2591 public SimpleName (string name, Location l)
2596 public SimpleName (string name, TypeArguments args, Location l)
2597 : base (name, args, l)
2601 public SimpleName (string name, int arity, Location l)
2602 : base (name, arity, l)
2606 public SimpleName GetMethodGroup ()
2608 return new SimpleName (Name, targs, loc);
2611 protected override Expression DoResolve (ResolveContext rc)
2613 return SimpleNameResolve (rc, null);
2616 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
2618 return SimpleNameResolve (ec, right_side);
2621 public void Error_NameDoesNotExist (ResolveContext rc)
2623 rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
2626 protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
2628 if (ctx.CurrentType != null) {
2629 var member = MemberLookup (ctx, false, ctx.CurrentType, Name, 0, MemberLookupRestrictions.ExactArity, loc) as MemberExpr;
2630 if (member != null) {
2631 Error_UnexpectedKind (ctx, member, "type", member.KindName, loc);
2636 var report = ctx.Module.Compiler.Report;
2638 var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2639 if (retval != null) {
2640 report.SymbolRelatedToPreviousError (retval.Type);
2641 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
2645 retval = ctx.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2646 if (retval != null) {
2647 Error_TypeArgumentsCannotBeUsed (ctx, retval.Type, loc);
2651 var ns_candidates = ctx.Module.GlobalRootNamespace.FindTypeNamespaces (ctx, Name, Arity);
2652 if (ns_candidates != null) {
2653 if (ctx is UsingAliasNamespace.AliasContext) {
2654 report.Error (246, loc,
2655 "The type or namespace name `{1}' could not be found. Consider using fully qualified name `{0}.{1}'",
2656 ns_candidates[0], Name);
2658 string usings = string.Join ("' or `", ns_candidates.ToArray ());
2659 report.Error (246, loc,
2660 "The type or namespace name `{0}' could not be found. Are you missing `{1}' using directive?",
2664 report.Error (246, loc,
2665 "The type or namespace name `{0}' could not be found. Are you missing an assembly reference?",
2670 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
2672 FullNamedExpression fne = mc.LookupNamespaceOrType (Name, Arity, LookupMode.Normal, loc);
2675 if (fne.Type != null && Arity > 0) {
2676 if (HasTypeArguments) {
2677 GenericTypeExpr ct = new GenericTypeExpr (fne.Type, targs, loc);
2678 if (ct.ResolveAsType (mc) == null)
2684 if (!allowUnboundTypeArguments)
2685 Error_OpenGenericTypeIsNotAllowed (mc);
2687 return new GenericOpenTypeExpr (fne.Type, loc);
2691 // dynamic namespace is ignored when dynamic is allowed (does not apply to types)
2693 if (!(fne is NamespaceExpression))
2697 if (Arity == 0 && Name == "dynamic" && mc.Module.Compiler.Settings.Version > LanguageVersion.V_3) {
2698 if (!mc.Module.PredefinedAttributes.Dynamic.IsDefined) {
2699 mc.Module.Compiler.Report.Error (1980, Location,
2700 "Dynamic keyword requires `{0}' to be defined. Are you missing System.Core.dll assembly reference?",
2701 mc.Module.PredefinedAttributes.Dynamic.GetSignatureForError ());
2704 fne = new DynamicTypeExpr (loc);
2705 fne.ResolveAsType (mc);
2711 Error_TypeOrNamespaceNotFound (mc);
2715 public bool IsPossibleTypeOrNamespace (IMemberContext mc)
2717 return mc.LookupNamespaceOrType (Name, Arity, LookupMode.Probing, loc) != null;
2720 public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
2722 int lookup_arity = Arity;
2723 bool errorMode = false;
2725 Block current_block = rc.CurrentBlock;
2726 INamedBlockVariable variable = null;
2727 bool variable_found = false;
2731 // Stage 1: binding to local variables or parameters
2733 // LAMESPEC: It should take invocableOnly into account but that would break csc compatibility
2735 if (current_block != null && lookup_arity == 0) {
2736 if (current_block.ParametersBlock.TopBlock.GetLocalName (Name, current_block.Original, ref variable)) {
2737 if (!variable.IsDeclared) {
2738 // We found local name in accessible block but it's not
2739 // initialized yet, maybe the user wanted to bind to something else
2741 variable_found = true;
2743 e = variable.CreateReferenceExpression (rc, loc);
2746 Error_TypeArgumentsCannotBeUsed (rc, "variable", Name, loc);
2755 // Stage 2: Lookup members if we are inside a type up to top level type for nested types
2757 TypeSpec member_type = rc.CurrentType;
2758 for (; member_type != null; member_type = member_type.DeclaringType) {
2759 e = MemberLookup (rc, errorMode, member_type, Name, lookup_arity, restrictions, loc);
2763 var me = e as MemberExpr;
2765 // The name matches a type, defer to ResolveAsTypeStep
2773 if (variable != null) {
2774 if (me is FieldExpr || me is ConstantExpr || me is EventExpr || me is PropertyExpr) {
2775 rc.Report.Error (844, loc,
2776 "A local variable `{0}' cannot be used before it is declared. Consider renaming the local variable when it hides the member `{1}'",
2777 Name, me.GetSignatureForError ());
2781 } else if (me is MethodGroupExpr || me is PropertyExpr || me is IndexerExpr) {
2782 // Leave it to overload resolution to report correct error
2784 // TODO: rc.Report.SymbolRelatedToPreviousError ()
2785 ErrorIsInaccesible (rc, me.GetSignatureForError (), loc);
2788 // LAMESPEC: again, ignores InvocableOnly
2789 if (variable != null) {
2790 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2791 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2795 // MemberLookup does not check accessors availability, this is actually needed for properties only
2797 var pe = me as PropertyExpr;
2800 // Break as there is no other overload available anyway
2801 if ((restrictions & MemberLookupRestrictions.ReadAccess) != 0) {
2802 if (!pe.PropertyInfo.HasGet || !pe.PropertyInfo.Get.IsAccessible (rc))
2805 pe.Getter = pe.PropertyInfo.Get;
2807 if (!pe.PropertyInfo.HasSet || !pe.PropertyInfo.Set.IsAccessible (rc))
2810 pe.Setter = pe.PropertyInfo.Set;
2815 // TODO: It's used by EventExpr -> FieldExpr transformation only
2816 // TODO: Should go to MemberAccess
2817 me = me.ResolveMemberAccess (rc, null, null);
2821 me.SetTypeArguments (rc, targs);
2828 // Stage 3: Lookup nested types, namespaces and type parameters in the context
2830 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0 && !variable_found) {
2831 if (IsPossibleTypeOrNamespace (rc)) {
2832 if (variable != null) {
2833 rc.Report.SymbolRelatedToPreviousError (variable.Location, Name);
2834 rc.Report.Error (135, loc, "`{0}' conflicts with a declaration in a child block", Name);
2837 return ResolveAsTypeOrNamespace (rc, false);
2841 var mg = NamespaceContainer.LookupStaticUsings (rc, Name, Arity, loc);
2845 mg.SetTypeArguments (rc, targs);
2850 if (Name == "nameof")
2851 return new NameOf (this);
2854 if (variable_found) {
2855 rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
2858 var tparams = rc.CurrentTypeParameters;
2859 if (tparams != null) {
2860 if (tparams.Find (Name) != null) {
2861 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2866 var ct = rc.CurrentType;
2868 if (ct.MemberDefinition.TypeParametersCount > 0) {
2869 foreach (var ctp in ct.MemberDefinition.TypeParameters) {
2870 if (ctp.Name == Name) {
2871 Error_TypeArgumentsCannotBeUsed (rc, "type parameter", Name, loc);
2877 ct = ct.DeclaringType;
2878 } while (ct != null);
2881 if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
2882 e = rc.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
2884 rc.Report.SymbolRelatedToPreviousError (e.Type);
2885 ErrorIsInaccesible (rc, e.GetSignatureForError (), loc);
2889 var me = MemberLookup (rc, false, rc.CurrentType, Name, Arity, restrictions & ~MemberLookupRestrictions.InvocableOnly, loc) as MemberExpr;
2891 Error_UnexpectedKind (rc, me, "method group", me.KindName, loc);
2892 return ErrorExpression.Instance;
2896 e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
2898 if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
2899 Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
2903 if (e is TypeExpr) {
2904 // TypeExpression does not have correct location
2905 if (e is TypeExpression)
2906 e = new TypeExpression (e.Type, loc);
2912 Error_NameDoesNotExist (rc);
2915 return ErrorExpression.Instance;
2918 if (rc.Module.Evaluator != null) {
2919 var fi = rc.Module.Evaluator.LookupField (Name);
2921 return new FieldExpr (fi.Item1, loc);
2929 Expression SimpleNameResolve (ResolveContext ec, Expression right_side)
2931 Expression e = LookupNameExpression (ec, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
2936 if (e is FullNamedExpression && e.eclass != ExprClass.Unresolved) {
2937 Error_UnexpectedKind (ec, e, "variable", e.ExprClassName, loc);
2941 if (right_side != null) {
2942 e = e.ResolveLValue (ec, right_side);
2950 public override object Accept (StructuralVisitor visitor)
2952 return visitor.Visit (this);
2957 /// Represents a namespace or a type. The name of the class was inspired by
2958 /// section 10.8.1 (Fully Qualified Names).
2960 public abstract class FullNamedExpression : Expression
2962 protected override void CloneTo (CloneContext clonectx, Expression target)
2964 // Do nothing, most unresolved type expressions cannot be
2965 // resolved to different type
2968 public override bool ContainsEmitWithAwait ()
2973 public override Expression CreateExpressionTree (ResolveContext ec)
2975 throw new NotSupportedException ("ET");
2978 public abstract FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments);
2981 // This is used to resolve the expression as a type, a null
2982 // value will be returned if the expression is not a type
2985 public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
2987 FullNamedExpression fne = ResolveAsTypeOrNamespace (mc, allowUnboundTypeArguments);
2992 TypeExpr te = fne as TypeExpr;
2994 Error_UnexpectedKind (mc, fne, "type", fne.ExprClassName, loc);
3002 var dep = type.GetMissingDependencies ();
3004 ImportedTypeDefinition.Error_MissingDependency (mc, dep, loc);
3007 if (type.Kind == MemberKind.Void) {
3008 mc.Module.Compiler.Report.Error (673, loc, "System.Void cannot be used from C#. Consider using `void'");
3012 // Obsolete checks cannot be done when resolving base context as they
3013 // require type dependencies to be set but we are in process of resolving them
3015 if (!(mc is TypeDefinition.BaseContext) && !(mc is UsingAliasNamespace.AliasContext)) {
3016 ObsoleteAttribute obsolete_attr = type.GetAttributeObsolete ();
3017 if (obsolete_attr != null && !mc.IsObsolete) {
3018 AttributeTester.Report_ObsoleteMessage (obsolete_attr, te.GetSignatureForError (), Location, mc.Module.Compiler.Report);
3026 public override void Emit (EmitContext ec)
3028 throw new InternalErrorException ("FullNamedExpression `{0}' found in resolved tree",
3029 GetSignatureForError ());
3034 /// Expression that evaluates to a type
3036 public abstract class TypeExpr : FullNamedExpression
3038 public sealed override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3044 protected sealed override Expression DoResolve (ResolveContext ec)
3050 public override bool Equals (object obj)
3052 TypeExpr tobj = obj as TypeExpr;
3056 return Type == tobj.Type;
3059 public override int GetHashCode ()
3061 return Type.GetHashCode ();
3066 /// Fully resolved Expression that already evaluated to a type
3068 public class TypeExpression : TypeExpr
3070 public TypeExpression (TypeSpec t, Location l)
3073 eclass = ExprClass.Type;
3077 public sealed override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
3083 public class NamespaceExpression : FullNamedExpression
3085 readonly Namespace ns;
3087 public NamespaceExpression (Namespace ns, Location loc)
3090 this.Type = InternalType.Namespace;
3091 this.eclass = ExprClass.Namespace;
3095 public Namespace Namespace {
3101 protected override Expression DoResolve (ResolveContext rc)
3103 throw new NotImplementedException ();
3106 public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc, bool allowUnboundTypeArguments)
3111 public void Error_NamespaceDoesNotExist (IMemberContext ctx, string name, int arity)
3113 var retval = Namespace.LookupType (ctx, name, arity, LookupMode.IgnoreAccessibility, loc);
3114 if (retval != null) {
3115 // ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.MemberDefinition);
3116 ErrorIsInaccesible (ctx, retval.GetSignatureForError (), loc);
3120 retval = Namespace.LookupType (ctx, name, -System.Math.Max (1, arity), LookupMode.Probing, loc);
3121 if (retval != null) {
3122 Error_TypeArgumentsCannotBeUsed (ctx, retval, loc);
3127 if (arity > 0 && Namespace.TryGetNamespace (name, out ns)) {
3128 Error_TypeArgumentsCannotBeUsed (ctx, ExprClassName, ns.GetSignatureForError (), loc);
3132 string assembly = null;
3133 string possible_name = Namespace.GetSignatureForError () + "." + name;
3135 // Only assembly unique name should be added
3136 switch (possible_name) {
3137 case "System.Drawing":
3138 case "System.Web.Services":
3141 case "System.Configuration":
3142 case "System.Data.Services":
3143 case "System.DirectoryServices":
3145 case "System.Net.Http":
3146 case "System.Numerics":
3147 case "System.Runtime.Caching":
3148 case "System.ServiceModel":
3149 case "System.Transactions":
3150 case "System.Web.Routing":
3151 case "System.Xml.Linq":
3153 assembly = possible_name;
3157 case "System.Linq.Expressions":
3158 assembly = "System.Core";
3161 case "System.Windows.Forms":
3162 case "System.Windows.Forms.Layout":
3163 assembly = "System.Windows.Forms";
3167 assembly = assembly == null ? "an" : "`" + assembly + "'";
3169 if (Namespace is GlobalRootNamespace) {
3170 ctx.Module.Compiler.Report.Error (400, loc,
3171 "The type or namespace name `{0}' could not be found in the global namespace. Are you missing {1} assembly reference?",
3174 ctx.Module.Compiler.Report.Error (234, loc,
3175 "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing {2} assembly reference?",
3176 name, GetSignatureForError (), assembly);
3180 public override string GetSignatureForError ()
3182 return ns.GetSignatureForError ();
3185 public FullNamedExpression LookupTypeOrNamespace (IMemberContext ctx, string name, int arity, LookupMode mode, Location loc)
3187 return ns.LookupTypeOrNamespace (ctx, name, arity, mode, loc);
3192 /// This class denotes an expression which evaluates to a member
3193 /// of a struct or a class.
3195 public abstract class MemberExpr : Expression, OverloadResolver.IInstanceQualifier
3197 protected bool conditional_access_receiver;
3200 // An instance expression associated with this member, if it's a
3201 // non-static member
3203 public Expression InstanceExpression;
3206 /// The name of this member.
3208 public abstract string Name {
3213 // When base.member is used
3215 public bool IsBase {
3216 get { return InstanceExpression is BaseThis; }
3220 /// Whether this is an instance member.
3222 public abstract bool IsInstance {
3227 /// Whether this is a static member.
3229 public abstract bool IsStatic {
3233 public abstract string KindName {
3237 public bool ConditionalAccess { get; set; }
3239 protected abstract TypeSpec DeclaringType {
3243 TypeSpec OverloadResolver.IInstanceQualifier.InstanceType {
3245 return InstanceExpression.Type;
3250 // Converts best base candidate for virtual method starting from QueriedBaseType
3252 protected MethodSpec CandidateToBaseOverride (ResolveContext rc, MethodSpec method)
3255 // Only when base.member is used and method is virtual
3261 // Overload resulution works on virtual or non-virtual members only (no overrides). That
3262 // means for base.member access we have to find the closest match after we found best candidate
3264 if ((method.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
3266 // The method could already be what we are looking for
3268 TypeSpec[] targs = null;
3269 if (method.DeclaringType != InstanceExpression.Type) {
3271 // Candidate can have inflated MVAR parameters and we need to find
3272 // base match for original definition not inflated parameter types
3274 var parameters = method.Parameters;
3275 if (method.Arity > 0) {
3276 parameters = ((IParametersMember) method.MemberDefinition).Parameters;
3277 var inflated = method.DeclaringType as InflatedTypeSpec;
3278 if (inflated != null) {
3279 parameters = parameters.Inflate (inflated.CreateLocalInflator (rc));
3283 var filter = new MemberFilter (method.Name, method.Arity, MemberKind.Method, parameters, null);
3284 var base_override = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as MethodSpec;
3285 if (base_override != null && base_override.DeclaringType != method.DeclaringType) {
3286 if (base_override.IsGeneric)
3287 targs = method.TypeArguments;
3289 method = base_override;
3294 // When base access is used inside anonymous method/iterator/etc we need to
3295 // get back to the context of original type. We do it by emiting proxy
3296 // method in original class and rewriting base call to this compiler
3297 // generated method call which does the actual base invocation. This may
3298 // introduce redundant storey but with `this' only but it's tricky to avoid
3299 // at this stage as we don't know what expressions follow base
3301 if (rc.CurrentAnonymousMethod != null) {
3302 if (targs == null && method.IsGeneric) {
3303 targs = method.TypeArguments;
3304 method = method.GetGenericMethodDefinition ();
3307 if (method.Parameters.HasArglist)
3308 throw new NotImplementedException ("__arglist base call proxy");
3310 method = rc.CurrentMemberDefinition.Parent.PartialContainer.CreateHoistedBaseCallProxy (rc, method);
3312 // Ideally this should apply to any proxy rewrite but in the case of unary mutators on
3313 // get/set member expressions second call would fail to proxy because left expression
3314 // would be of 'this' and not 'base' because we share InstanceExpression for get/set
3315 // FIXME: The async check is another hack but will probably fail with mutators
3316 if (rc.CurrentType.IsStruct || rc.CurrentAnonymousMethod.Storey is AsyncTaskStorey)
3317 InstanceExpression = new This (loc).Resolve (rc);
3321 method = method.MakeGenericMethod (rc, targs);
3325 // Only base will allow this invocation to happen.
3327 if (method.IsAbstract) {
3328 rc.Report.SymbolRelatedToPreviousError (method);
3329 Error_CannotCallAbstractBase (rc, method.GetSignatureForError ());
3335 protected void CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3337 if (InstanceExpression == null)
3340 if ((member.Modifiers & Modifiers.PROTECTED) != 0 && !(InstanceExpression is This)) {
3341 if (!CheckProtectedMemberAccess (rc, member, InstanceExpression.Type)) {
3342 Error_ProtectedMemberAccess (rc, member, InstanceExpression.Type, loc);
3347 bool OverloadResolver.IInstanceQualifier.CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
3349 if (InstanceExpression == null)
3352 return InstanceExpression is This || CheckProtectedMemberAccess (rc, member, InstanceExpression.Type);
3355 public static bool CheckProtectedMemberAccess<T> (ResolveContext rc, T member, TypeSpec qualifier) where T : MemberSpec
3357 var ct = rc.CurrentType;
3358 if (ct == qualifier)
3361 if ((member.Modifiers & Modifiers.INTERNAL) != 0 && member.DeclaringType.MemberDefinition.IsInternalAsPublic (ct.MemberDefinition.DeclaringAssembly))
3364 qualifier = qualifier.GetDefinition ();
3365 if (ct != qualifier && !IsSameOrBaseQualifier (ct, qualifier)) {
3372 public override bool ContainsEmitWithAwait ()
3374 return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
3377 public override bool HasConditionalAccess ()
3379 return ConditionalAccess || (InstanceExpression != null && InstanceExpression.HasConditionalAccess ());
3382 static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
3385 type = type.GetDefinition ();
3387 if (type == qtype || TypeManager.IsFamilyAccessible (qtype, type))
3390 type = type.DeclaringType;
3391 } while (type != null);
3396 protected void DoBestMemberChecks<T> (ResolveContext rc, T member) where T : MemberSpec, IInterfaceMemberSpec
3398 if (InstanceExpression != null) {
3399 InstanceExpression = InstanceExpression.Resolve (rc);
3400 CheckProtectedMemberAccess (rc, member);
3403 if (member.MemberType.IsPointer && !rc.IsUnsafe) {
3404 UnsafeError (rc, loc);
3407 var dep = member.GetMissingDependencies ();
3409 ImportedTypeDefinition.Error_MissingDependency (rc, dep, loc);
3412 if (!rc.IsObsolete) {
3413 ObsoleteAttribute oa = member.GetAttributeObsolete ();
3415 AttributeTester.Report_ObsoleteMessage (oa, member.GetSignatureForError (), loc, rc.Report);
3418 if (!(member is FieldSpec))
3419 member.MemberDefinition.SetIsUsed ();
3422 protected virtual void Error_CannotCallAbstractBase (ResolveContext rc, string name)
3424 rc.Report.Error (205, loc, "Cannot call an abstract base member `{0}'", name);
3427 public static void Error_ProtectedMemberAccess (ResolveContext rc, MemberSpec member, TypeSpec qualifier, Location loc)
3429 rc.Report.SymbolRelatedToPreviousError (member);
3430 rc.Report.Error (1540, loc,
3431 "Cannot access protected member `{0}' via a qualifier of type `{1}'. The qualifier must be of type `{2}' or derived from it",
3432 member.GetSignatureForError (), qualifier.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3435 public override void FlowAnalysis (FlowAnalysisContext fc)
3437 if (InstanceExpression != null) {
3438 InstanceExpression.FlowAnalysis (fc);
3440 if (ConditionalAccess) {
3441 fc.BranchConditionalAccessDefiniteAssignment ();
3446 protected void ResolveConditionalAccessReceiver (ResolveContext rc)
3448 if (!rc.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
3449 if (HasConditionalAccess ()) {
3450 conditional_access_receiver = true;
3451 rc.Set (ResolveContext.Options.ConditionalAccessReceiver);
3456 public bool ResolveInstanceExpression (ResolveContext rc, Expression rhs)
3458 if (!ResolveInstanceExpressionCore (rc, rhs))
3462 // Check intermediate value modification which won't have any effect
3464 if (rhs != null && TypeSpec.IsValueType (InstanceExpression.Type)) {
3465 var fexpr = InstanceExpression as FieldExpr;
3466 if (fexpr != null) {
3467 if (!fexpr.Spec.IsReadOnly || rc.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
3470 if (fexpr.IsStatic) {
3471 rc.Report.Error (1650, loc, "Fields of static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
3472 fexpr.GetSignatureForError ());
3474 rc.Report.Error (1648, loc, "Members of readonly field `{0}' cannot be modified (except in a constructor or a variable initializer)",
3475 fexpr.GetSignatureForError ());
3481 if (InstanceExpression is PropertyExpr || InstanceExpression is IndexerExpr || InstanceExpression is Invocation) {
3482 if (rc.CurrentInitializerVariable != null) {
3483 rc.Report.Error (1918, loc, "Members of value type `{0}' cannot be assigned using a property `{1}' object initializer",
3484 InstanceExpression.Type.GetSignatureForError (), InstanceExpression.GetSignatureForError ());
3486 rc.Report.Error (1612, loc,
3487 "Cannot modify a value type return value of `{0}'. Consider storing the value in a temporary variable",
3488 InstanceExpression.GetSignatureForError ());
3494 var lvr = InstanceExpression as LocalVariableReference;
3497 if (!lvr.local_info.IsReadonly)
3500 rc.Report.Error (1654, loc, "Cannot assign to members of `{0}' because it is a `{1}'",
3501 InstanceExpression.GetSignatureForError (), lvr.local_info.GetReadOnlyContext ());
3508 bool ResolveInstanceExpressionCore (ResolveContext rc, Expression rhs)
3511 if (InstanceExpression != null) {
3512 if (InstanceExpression is TypeExpr) {
3513 var t = InstanceExpression.Type;
3515 ObsoleteAttribute oa = t.GetAttributeObsolete ();
3516 if (oa != null && !rc.IsObsolete) {
3517 AttributeTester.Report_ObsoleteMessage (oa, t.GetSignatureForError (), loc, rc.Report);
3520 t = t.DeclaringType;
3521 } while (t != null);
3523 var runtime_expr = InstanceExpression as RuntimeValueExpression;
3524 if (runtime_expr == null || !runtime_expr.IsSuggestionOnly) {
3525 rc.Report.Error (176, loc,
3526 "Static member `{0}' cannot be accessed with an instance reference, qualify it with a type name instead",
3527 GetSignatureForError ());
3531 InstanceExpression = null;
3537 if (InstanceExpression == null || InstanceExpression is TypeExpr) {
3538 if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
3539 if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
3540 rc.Report.Error (236, loc,
3541 "A field initializer cannot reference the nonstatic field, method, or property `{0}'",
3542 GetSignatureForError ());
3544 var fe = this as FieldExpr;
3545 if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
3546 if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
3547 rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
3549 rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
3553 rc.Report.Error (120, loc,
3554 "An object reference is required to access non-static member `{0}'",
3555 GetSignatureForError ());
3559 InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
3563 if (!TypeManager.IsFamilyAccessible (rc.CurrentType, DeclaringType)) {
3564 rc.Report.Error (38, loc,
3565 "Cannot access a nonstatic member of outer type `{0}' via nested type `{1}'",
3566 DeclaringType.GetSignatureForError (), rc.CurrentType.GetSignatureForError ());
3569 InstanceExpression = new This (loc).Resolve (rc);
3573 var me = InstanceExpression as MemberExpr;
3575 me.ResolveInstanceExpressionCore (rc, rhs);
3577 var fe = me as FieldExpr;
3578 if (fe != null && fe.IsMarshalByRefAccess (rc)) {
3579 rc.Report.SymbolRelatedToPreviousError (me.DeclaringType);
3580 rc.Report.Warning (1690, 1, loc,
3581 "Cannot call methods, properties, or indexers on `{0}' because it is a value type member of a marshal-by-reference class",
3582 me.GetSignatureForError ());
3589 // Additional checks for l-value member access
3592 if (InstanceExpression is UnboxCast) {
3593 rc.Report.Error (445, InstanceExpression.Location, "Cannot modify the result of an unboxing conversion");
3600 public virtual MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
3602 if (left != null && !ConditionalAccess && left.IsNull && TypeSpec.IsReferenceType (left.Type)) {
3603 ec.Report.Warning (1720, 1, left.Location,
3604 "Expression will always cause a `{0}'", "System.NullReferenceException");
3607 InstanceExpression = left;
3611 protected void EmitInstance (EmitContext ec, bool prepare_for_load)
3613 var inst = new InstanceEmitter (InstanceExpression, TypeSpec.IsValueType (InstanceExpression.Type));
3614 inst.Emit (ec, ConditionalAccess);
3616 if (prepare_for_load)
3617 ec.Emit (OpCodes.Dup);
3620 public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
3623 public class ExtensionMethodCandidates
3625 readonly NamespaceContainer container;
3626 readonly IList<MethodSpec> methods;
3628 readonly IMemberContext context;
3630 public ExtensionMethodCandidates (IMemberContext context, IList<MethodSpec> methods, NamespaceContainer nsContainer, int lookupIndex)
3632 this.context = context;
3633 this.methods = methods;
3634 this.container = nsContainer;
3635 this.index = lookupIndex;
3638 public NamespaceContainer Container {
3644 public IMemberContext Context {
3650 public int LookupIndex {
3656 public IList<MethodSpec> Methods {
3664 // Represents a group of extension method candidates for whole namespace
3666 class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
3668 ExtensionMethodCandidates candidates;
3669 public Expression ExtensionExpression;
3671 public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
3672 : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
3674 this.candidates = candidates;
3675 this.ExtensionExpression = extensionExpr;
3678 public override bool IsStatic {
3679 get { return true; }
3682 public override void FlowAnalysis (FlowAnalysisContext fc)
3684 if (ConditionalAccess) {
3685 fc.BranchConditionalAccessDefiniteAssignment ();
3690 // For extension methodgroup we are not looking for base members but parent
3691 // namespace extension methods
3693 public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
3695 // TODO: candidates are null only when doing error reporting, that's
3696 // incorrect. We have to discover same extension methods in error mode
3697 if (candidates == null)
3700 int arity = type_arguments == null ? 0 : type_arguments.Count;
3702 candidates = candidates.Container.LookupExtensionMethod (candidates.Context, ExtensionExpression.Type, Name, arity, candidates.LookupIndex);
3703 if (candidates == null)
3706 return candidates.Methods.Cast<MemberSpec> ().ToList ();
3709 public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
3711 // We are already here
3715 public override MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments arguments, OverloadResolver.IErrorHandler ehandler, OverloadResolver.Restrictions restr)
3717 if (arguments == null)
3718 arguments = new Arguments (1);
3720 ExtensionExpression = ExtensionExpression.Resolve (ec);
3721 if (ExtensionExpression == null)
3724 var cand = candidates;
3725 var atype = ConditionalAccess ? Argument.AType.ExtensionTypeConditionalAccess : Argument.AType.ExtensionType;
3726 arguments.Insert (0, new Argument (ExtensionExpression, atype));
3727 var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
3729 // Restore candidates in case we are running in probing mode
3732 // Store resolved argument and restore original arguments
3734 // Clean-up modified arguments for error reporting
3735 arguments.RemoveAt (0);
3739 var me = ExtensionExpression as MemberExpr;
3741 me.ResolveInstanceExpression (ec, null);
3742 var fe = me as FieldExpr;
3744 fe.Spec.MemberDefinition.SetIsUsed ();
3747 InstanceExpression = null;
3751 #region IErrorHandler Members
3753 bool OverloadResolver.IErrorHandler.AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous)
3758 bool OverloadResolver.IErrorHandler.ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument arg, int index)
3760 rc.Report.SymbolRelatedToPreviousError (best);
3761 rc.Report.Error (1928, loc,
3762 "Type `{0}' does not contain a member `{1}' and the best extension method overload `{2}' has some invalid arguments",
3763 queried_type.GetSignatureForError (), Name, best.GetSignatureForError ());
3766 rc.Report.Error (1929, loc,
3767 "Extension method instance type `{0}' cannot be converted to `{1}'",
3768 arg.Type.GetSignatureForError (), ((MethodSpec)best).Parameters.ExtensionMethodType.GetSignatureForError ());
3774 bool OverloadResolver.IErrorHandler.NoArgumentMatch (ResolveContext rc, MemberSpec best)
3779 bool OverloadResolver.IErrorHandler.TypeInferenceFailed (ResolveContext rc, MemberSpec best)
3788 /// MethodGroupExpr represents a group of method candidates which
3789 /// can be resolved to the best method overload
3791 public class MethodGroupExpr : MemberExpr, OverloadResolver.IBaseMembersProvider
3793 static readonly MemberSpec[] Excluded = new MemberSpec[0];
3795 protected IList<MemberSpec> Methods;
3796 MethodSpec best_candidate;
3797 TypeSpec best_candidate_return;
3798 protected TypeArguments type_arguments;
3800 SimpleName simple_name;
3801 protected TypeSpec queried_type;
3803 public MethodGroupExpr (IList<MemberSpec> mi, TypeSpec type, Location loc)
3807 this.type = InternalType.MethodGroup;
3809 eclass = ExprClass.MethodGroup;
3810 queried_type = type;
3813 public MethodGroupExpr (MethodSpec m, TypeSpec type, Location loc)
3814 : this (new MemberSpec[] { m }, type, loc)
3820 public MethodSpec BestCandidate {
3822 return best_candidate;
3826 public TypeSpec BestCandidateReturnType {
3828 return best_candidate_return;
3832 public IList<MemberSpec> Candidates {
3838 protected override TypeSpec DeclaringType {
3840 return queried_type;
3844 public bool IsConditionallyExcluded {
3846 return Methods == Excluded;
3850 public override bool IsInstance {
3852 if (best_candidate != null)
3853 return !best_candidate.IsStatic;
3859 public override bool IsSideEffectFree {
3861 return InstanceExpression == null || InstanceExpression.IsSideEffectFree;
3865 public override bool IsStatic {
3867 if (best_candidate != null)
3868 return best_candidate.IsStatic;
3874 public override string KindName {
3875 get { return "method"; }
3878 public override string Name {
3880 if (best_candidate != null)
3881 return best_candidate.Name;
3884 return Methods.First ().Name;
3891 // When best candidate is already know this factory can be used
3892 // to avoid expensive overload resolution to be called
3894 // NOTE: InstanceExpression has to be set manually
3896 public static MethodGroupExpr CreatePredefined (MethodSpec best, TypeSpec queriedType, Location loc)
3898 return new MethodGroupExpr (best, queriedType, loc) {
3899 best_candidate = best,
3900 best_candidate_return = best.ReturnType
3904 public override string GetSignatureForError ()
3906 if (best_candidate != null)
3907 return best_candidate.GetSignatureForError ();
3909 return Methods.First ().GetSignatureForError ();
3912 public override Expression CreateExpressionTree (ResolveContext ec)
3914 if (best_candidate == null) {
3915 ec.Report.Error (1953, loc, "An expression tree cannot contain an expression with method group");
3919 if (IsConditionallyExcluded)
3920 ec.Report.Error (765, loc,
3921 "Partial methods with only a defining declaration or removed conditional methods cannot be used in an expression tree");
3923 if (ConditionalAccess)
3924 Error_NullShortCircuitInsideExpressionTree (ec);
3926 return new TypeOfMethod (best_candidate, loc);
3929 protected override Expression DoResolve (ResolveContext ec)
3931 this.eclass = ExprClass.MethodGroup;
3933 if (InstanceExpression != null) {
3934 InstanceExpression = InstanceExpression.Resolve (ec);
3935 if (InstanceExpression == null)
3942 public override void Emit (EmitContext ec)
3944 throw new NotSupportedException ();
3947 public void EmitCall (EmitContext ec, Arguments arguments, bool statement)
3949 var call = new CallEmitter ();
3950 call.InstanceExpression = InstanceExpression;
3951 call.ConditionalAccess = ConditionalAccess;
3954 call.EmitStatement (ec, best_candidate, arguments, loc);
3956 call.Emit (ec, best_candidate, arguments, loc);
3959 public void EmitCall (EmitContext ec, Arguments arguments, TypeSpec conditionalAccessReceiver, bool statement)
3961 ec.ConditionalAccess = new ConditionalAccessContext (conditionalAccessReceiver, ec.DefineLabel ()) {
3962 Statement = statement
3965 EmitCall (ec, arguments, statement);
3967 ec.CloseConditionalAccess (!statement && best_candidate_return != conditionalAccessReceiver && conditionalAccessReceiver.IsNullableType ? conditionalAccessReceiver : null);
3970 public override void Error_ValueCannotBeConverted (ResolveContext ec, TypeSpec target, bool expl)
3972 ec.Report.Error (428, loc, "Cannot convert method group `{0}' to non-delegate type `{1}'. Consider using parentheses to invoke the method",
3973 Name, target.GetSignatureForError ());
3976 public static bool IsExtensionMethodArgument (Expression expr)
3979 // LAMESPEC: No details about which expressions are not allowed
3981 return !(expr is TypeExpr) && !(expr is BaseThis);
3985 /// Find the Applicable Function Members (7.4.2.1)
3987 /// me: Method Group expression with the members to select.
3988 /// it might contain constructors or methods (or anything
3989 /// that maps to a method).
3991 /// Arguments: ArrayList containing resolved Argument objects.
3993 /// loc: The location if we want an error to be reported, or a Null
3994 /// location for "probing" purposes.
3996 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3997 /// that is the best match of me on Arguments.
4000 public virtual MethodGroupExpr OverloadResolve (ResolveContext ec, ref Arguments args, OverloadResolver.IErrorHandler cerrors, OverloadResolver.Restrictions restr)
4002 // TODO: causes issues with probing mode, remove explicit Kind check
4003 if (best_candidate != null && best_candidate.Kind == MemberKind.Destructor)
4006 var r = new OverloadResolver (Methods, type_arguments, restr, loc);
4007 if ((restr & OverloadResolver.Restrictions.NoBaseMembers) == 0) {
4008 r.BaseMembersProvider = this;
4009 r.InstanceQualifier = this;
4012 if (cerrors != null)
4013 r.CustomErrors = cerrors;
4015 // TODO: When in probing mode do IsApplicable only and when called again do VerifyArguments for full error reporting
4016 best_candidate = r.ResolveMember<MethodSpec> (ec, ref args);
4017 if (best_candidate == null) {
4018 if (!r.BestCandidateIsDynamic)
4021 if (simple_name != null && ec.IsStatic)
4022 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4027 // Overload resolver had to create a new method group, all checks bellow have already been executed
4028 if (r.BestCandidateNewMethodGroup != null)
4029 return r.BestCandidateNewMethodGroup;
4031 if (best_candidate.Kind == MemberKind.Method && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0) {
4032 if (InstanceExpression != null) {
4033 if (best_candidate.IsExtensionMethod && args[0].Expr == InstanceExpression) {
4034 InstanceExpression = null;
4036 if (simple_name != null && best_candidate.IsStatic) {
4037 InstanceExpression = ProbeIdenticalTypeName (ec, InstanceExpression, simple_name);
4040 InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
4044 ResolveInstanceExpression (ec, null);
4047 var base_override = CandidateToBaseOverride (ec, best_candidate);
4048 if (base_override == best_candidate) {
4049 best_candidate_return = r.BestCandidateReturnType;
4051 best_candidate = base_override;
4052 best_candidate_return = best_candidate.ReturnType;
4055 if (best_candidate.IsGeneric && (restr & OverloadResolver.Restrictions.ProbingOnly) == 0 && TypeParameterSpec.HasAnyTypeParameterConstrained (best_candidate.GenericDefinition)) {
4056 ConstraintChecker cc = new ConstraintChecker (ec);
4057 cc.CheckAll (best_candidate.GetGenericMethodDefinition (), best_candidate.TypeArguments, best_candidate.Constraints, loc);
4061 // Additional check for possible imported base override method which
4062 // could not be done during IsOverrideMethodBaseTypeAccessible
4064 if (best_candidate.IsVirtual && (best_candidate.DeclaringType.Modifiers & Modifiers.PROTECTED) != 0 &&
4065 best_candidate.MemberDefinition.IsImported && !best_candidate.DeclaringType.IsAccessible (ec)) {
4066 ec.Report.SymbolRelatedToPreviousError (best_candidate);
4067 ErrorIsInaccesible (ec, best_candidate.GetSignatureForError (), loc);
4070 // Speed up the check by not doing it on disallowed targets
4071 if (best_candidate_return.Kind == MemberKind.Void && best_candidate.IsConditionallyExcluded (ec))
4077 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
4079 var fe = left as FieldExpr;
4082 // Using method-group on struct fields makes the struct assigned. I am not sure
4083 // why but that's what .net does
4085 fe.Spec.MemberDefinition.SetIsAssigned ();
4088 simple_name = original;
4089 return base.ResolveMemberAccess (ec, left, original);
4092 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
4094 type_arguments = ta;
4097 #region IBaseMembersProvider Members
4099 public virtual IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4101 return baseType == null ? null : MemberCache.FindMembers (baseType, Methods [0].Name, false);
4104 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4106 if (queried_type == member.DeclaringType)
4109 return MemberCache.FindMember (queried_type, new MemberFilter ((MethodSpec) member),
4110 BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as IParametersMember;
4114 // Extension methods lookup after ordinary methods candidates failed to apply
4116 public virtual MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4118 if (InstanceExpression == null || InstanceExpression.eclass == ExprClass.Type)
4121 if (!IsExtensionMethodArgument (InstanceExpression))
4124 int arity = type_arguments == null ? 0 : type_arguments.Count;
4125 var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
4126 if (methods == null)
4129 var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
4130 emg.SetTypeArguments (rc, type_arguments);
4137 struct ConstructorInstanceQualifier : OverloadResolver.IInstanceQualifier
4139 public ConstructorInstanceQualifier (TypeSpec type)
4142 InstanceType = type;
4145 public TypeSpec InstanceType { get; private set; }
4147 public bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member)
4149 return MemberExpr.CheckProtectedMemberAccess (rc, member, InstanceType);
4153 public struct OverloadResolver
4156 public enum Restrictions
4160 ProbingOnly = 1 << 1,
4161 CovariantDelegate = 1 << 2,
4162 NoBaseMembers = 1 << 3,
4163 BaseMembersIncluded = 1 << 4,
4164 GetEnumeratorLookup = 1 << 5
4167 public interface IBaseMembersProvider
4169 IList<MemberSpec> GetBaseMembers (TypeSpec baseType);
4170 IParametersMember GetOverrideMemberParameters (MemberSpec member);
4171 MethodGroupExpr LookupExtensionMethod (ResolveContext rc);
4174 public interface IErrorHandler
4176 bool AmbiguousCandidates (ResolveContext rc, MemberSpec best, MemberSpec ambiguous);
4177 bool ArgumentMismatch (ResolveContext rc, MemberSpec best, Argument a, int index);
4178 bool NoArgumentMatch (ResolveContext rc, MemberSpec best);
4179 bool TypeInferenceFailed (ResolveContext rc, MemberSpec best);
4182 public interface IInstanceQualifier
4184 TypeSpec InstanceType { get; }
4185 bool CheckProtectedMemberAccess (ResolveContext rc, MemberSpec member);
4188 sealed class NoBaseMembers : IBaseMembersProvider
4190 public static readonly IBaseMembersProvider Instance = new NoBaseMembers ();
4192 public IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
4197 public IParametersMember GetOverrideMemberParameters (MemberSpec member)
4202 public MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
4208 struct AmbiguousCandidate
4210 public readonly MemberSpec Member;
4211 public readonly bool Expanded;
4212 public readonly AParametersCollection Parameters;
4214 public AmbiguousCandidate (MemberSpec member, AParametersCollection parameters, bool expanded)
4217 Parameters = parameters;
4218 Expanded = expanded;
4223 IList<MemberSpec> members;
4224 TypeArguments type_arguments;
4225 IBaseMembersProvider base_provider;
4226 IErrorHandler custom_errors;
4227 IInstanceQualifier instance_qualifier;
4228 Restrictions restrictions;
4229 MethodGroupExpr best_candidate_extension_group;
4230 TypeSpec best_candidate_return_type;
4232 SessionReportPrinter lambda_conv_msgs;
4234 public OverloadResolver (IList<MemberSpec> members, Restrictions restrictions, Location loc)
4235 : this (members, null, restrictions, loc)
4239 public OverloadResolver (IList<MemberSpec> members, TypeArguments targs, Restrictions restrictions, Location loc)
4242 if (members == null || members.Count == 0)
4243 throw new ArgumentException ("empty members set");
4245 this.members = members;
4247 type_arguments = targs;
4248 this.restrictions = restrictions;
4249 if (IsDelegateInvoke)
4250 this.restrictions |= Restrictions.NoBaseMembers;
4252 base_provider = NoBaseMembers.Instance;
4257 public IBaseMembersProvider BaseMembersProvider {
4259 return base_provider;
4262 base_provider = value;
4266 public bool BestCandidateIsDynamic { get; set; }
4269 // Best candidate was found in newly created MethodGroupExpr, used by extension methods
4271 public MethodGroupExpr BestCandidateNewMethodGroup {
4273 return best_candidate_extension_group;
4278 // Return type can be different between best candidate and closest override
4280 public TypeSpec BestCandidateReturnType {
4282 return best_candidate_return_type;
4286 public IErrorHandler CustomErrors {
4288 return custom_errors;
4291 custom_errors = value;
4295 TypeSpec DelegateType {
4297 if ((restrictions & Restrictions.DelegateInvoke) == 0)
4298 throw new InternalErrorException ("Not running in delegate mode", loc);
4300 return members [0].DeclaringType;
4304 public IInstanceQualifier InstanceQualifier {
4306 return instance_qualifier;
4309 instance_qualifier = value;
4313 bool IsProbingOnly {
4315 return (restrictions & Restrictions.ProbingOnly) != 0;
4319 bool IsDelegateInvoke {
4321 return (restrictions & Restrictions.DelegateInvoke) != 0;
4328 // 7.4.3.3 Better conversion from expression
4329 // Returns : 1 if a->p is better,
4330 // 2 if a->q is better,
4331 // 0 if neither is better
4333 static int BetterExpressionConversion (ResolveContext ec, Argument a, TypeSpec p, TypeSpec q)
4335 TypeSpec argument_type = a.Type;
4338 // If argument is an anonymous function
4340 if (argument_type == InternalType.AnonymousMethod && ec.Module.Compiler.Settings.Version > LanguageVersion.ISO_2) {
4342 // p and q are delegate types or expression tree types
4344 if (p.IsExpressionTreeType || q.IsExpressionTreeType) {
4345 if (q.MemberDefinition != p.MemberDefinition) {
4350 // Uwrap delegate from Expression<T>
4352 q = TypeManager.GetTypeArguments (q)[0];
4353 p = TypeManager.GetTypeArguments (p)[0];
4356 var p_m = Delegate.GetInvokeMethod (p);
4357 var q_m = Delegate.GetInvokeMethod (q);
4360 // With identical parameter lists
4362 if (!TypeSpecComparer.Equals (p_m.Parameters.Types, q_m.Parameters.Types))
4370 // if p is void returning, and q has a return type Y, then C2 is the better conversion.
4372 if (p.Kind == MemberKind.Void) {
4373 return q.Kind != MemberKind.Void ? 2 : 0;
4377 // if p has a return type Y, and q is void returning, then C1 is the better conversion.
4379 if (q.Kind == MemberKind.Void) {
4380 return p.Kind != MemberKind.Void ? 1: 0;
4383 var am = (AnonymousMethodExpression) a.Expr;
4386 // When anonymous method is an asynchronous, and P has a return type Task<Y1>, and Q has a return type Task<Y2>
4387 // better conversion is performed between underlying types Y1 and Y2
4389 if (p.IsGenericTask || q.IsGenericTask) {
4390 if (am.Block.IsAsync && p.IsGenericTask && q.IsGenericTask) {
4391 q = q.TypeArguments[0];
4392 p = p.TypeArguments[0];
4398 // An inferred return type X exists for E in the context of that parameter list, and
4399 // the conversion from X to Y1 is better than the conversion from X to Y2
4401 argument_type = am.InferReturnType (ec, null, orig_q);
4402 if (argument_type == null) {
4403 // TODO: Can this be hit?
4407 if (argument_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
4408 argument_type = ec.BuiltinTypes.Object;
4412 if (argument_type == p)
4415 if (argument_type == q)
4419 // The parameters are identicial and return type is not void, use better type conversion
4420 // on return type to determine better one
4422 return BetterTypeConversion (ec, p, q);
4426 // 7.4.3.4 Better conversion from type
4428 public static int BetterTypeConversion (ResolveContext ec, TypeSpec p, TypeSpec q)
4430 if (p == null || q == null)
4431 throw new InternalErrorException ("BetterTypeConversion got a null conversion");
4433 switch (p.BuiltinType) {
4434 case BuiltinTypeSpec.Type.Int:
4435 if (q.BuiltinType == BuiltinTypeSpec.Type.UInt || q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4438 case BuiltinTypeSpec.Type.Long:
4439 if (q.BuiltinType == BuiltinTypeSpec.Type.ULong)
4442 case BuiltinTypeSpec.Type.SByte:
4443 switch (q.BuiltinType) {
4444 case BuiltinTypeSpec.Type.Byte:
4445 case BuiltinTypeSpec.Type.UShort:
4446 case BuiltinTypeSpec.Type.UInt:
4447 case BuiltinTypeSpec.Type.ULong:
4451 case BuiltinTypeSpec.Type.Short:
4452 switch (q.BuiltinType) {
4453 case BuiltinTypeSpec.Type.UShort:
4454 case BuiltinTypeSpec.Type.UInt:
4455 case BuiltinTypeSpec.Type.ULong:
4459 case BuiltinTypeSpec.Type.Dynamic:
4460 // Dynamic is never better
4464 switch (q.BuiltinType) {
4465 case BuiltinTypeSpec.Type.Int:
4466 if (p.BuiltinType == BuiltinTypeSpec.Type.UInt || p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4469 case BuiltinTypeSpec.Type.Long:
4470 if (p.BuiltinType == BuiltinTypeSpec.Type.ULong)
4473 case BuiltinTypeSpec.Type.SByte:
4474 switch (p.BuiltinType) {
4475 case BuiltinTypeSpec.Type.Byte:
4476 case BuiltinTypeSpec.Type.UShort:
4477 case BuiltinTypeSpec.Type.UInt:
4478 case BuiltinTypeSpec.Type.ULong:
4482 case BuiltinTypeSpec.Type.Short:
4483 switch (p.BuiltinType) {
4484 case BuiltinTypeSpec.Type.UShort:
4485 case BuiltinTypeSpec.Type.UInt:
4486 case BuiltinTypeSpec.Type.ULong:
4490 case BuiltinTypeSpec.Type.Dynamic:
4491 // Dynamic is never better
4495 // FIXME: handle lifted operators
4497 // TODO: this is expensive
4498 Expression p_tmp = new EmptyExpression (p);
4499 Expression q_tmp = new EmptyExpression (q);
4501 bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4502 bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4504 if (p_to_q && !q_to_p)
4507 if (q_to_p && !p_to_q)
4514 /// Determines "Better function" between candidate
4515 /// and the current best match
4518 /// Returns a boolean indicating :
4519 /// false if candidate ain't better
4520 /// true if candidate is better than the current best match
4522 static bool BetterFunction (ResolveContext ec, Arguments args, MemberSpec candidate, AParametersCollection cparam, bool candidate_params,
4523 MemberSpec best, AParametersCollection bparam, bool best_params)
4525 AParametersCollection candidate_pd = ((IParametersMember) candidate).Parameters;
4526 AParametersCollection best_pd = ((IParametersMember) best).Parameters;
4528 bool better_at_least_one = false;
4529 bool are_equivalent = true;
4530 int args_count = args == null ? 0 : args.Count;
4534 for (int c_idx = 0, b_idx = 0; j < args_count; ++j, ++c_idx, ++b_idx) {
4537 // Default arguments are ignored for better decision
4538 if (a.IsDefaultArgument)
4542 // When comparing named argument the parameter type index has to be looked up
4543 // in original parameter set (override version for virtual members)
4545 NamedArgument na = a as NamedArgument;
4547 int idx = cparam.GetParameterIndexByName (na.Name);
4548 ct = candidate_pd.Types[idx];
4549 if (candidate_params && candidate_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4550 ct = TypeManager.GetElementType (ct);
4552 idx = bparam.GetParameterIndexByName (na.Name);
4553 bt = best_pd.Types[idx];
4554 if (best_params && best_pd.FixedParameters[idx].ModFlags == Parameter.Modifier.PARAMS)
4555 bt = TypeManager.GetElementType (bt);
4557 ct = candidate_pd.Types[c_idx];
4558 bt = best_pd.Types[b_idx];
4560 if (candidate_params && candidate_pd.FixedParameters[c_idx].ModFlags == Parameter.Modifier.PARAMS) {
4561 ct = TypeManager.GetElementType (ct);
4565 if (best_params && best_pd.FixedParameters[b_idx].ModFlags == Parameter.Modifier.PARAMS) {
4566 bt = TypeManager.GetElementType (bt);
4571 if (TypeSpecComparer.IsEqual (ct, bt))
4574 are_equivalent = false;
4575 int result = BetterExpressionConversion (ec, a, ct, bt);
4577 // for each argument, the conversion to 'ct' should be no worse than
4578 // the conversion to 'bt'.
4582 // for at least one argument, the conversion to 'ct' should be better than
4583 // the conversion to 'bt'.
4585 better_at_least_one = true;
4588 if (better_at_least_one)
4592 // Tie-breaking rules are applied only for equivalent parameter types
4594 if (!are_equivalent)
4598 // If candidate is applicable in its normal form and best has a params array and is applicable
4599 // only in its expanded form, then candidate is better
4601 if (candidate_params != best_params)
4602 return !candidate_params;
4605 // We have not reached end of parameters list due to params or used default parameters
4607 while (j < candidate_pd.Count && j < best_pd.Count) {
4608 var cand_param = candidate_pd.FixedParameters [j];
4609 var best_param = best_pd.FixedParameters [j];
4611 if (candidate_pd.Count == best_pd.Count) {
4615 // void Foo (int i = 0) is better than void Foo (params int[]) for Foo ()
4616 // void Foo (string[] s, string value = null) is better than Foo (string s, params string[]) for Foo (null) or Foo ()
4618 if (cand_param.HasDefaultValue != best_param.HasDefaultValue)
4619 return cand_param.HasDefaultValue;
4621 if (cand_param.HasDefaultValue) {
4627 // Neither is better when not all arguments are provided
4629 // void Foo (string s, int i = 0) <-> Foo (string s, int i = 0, int i2 = 0)
4630 // void Foo (string s, int i = 0) <-> Foo (string s, byte i = 0)
4631 // void Foo (string s, params int[]) <-> Foo (string s, params byte[])
4633 if (cand_param.HasDefaultValue && best_param.HasDefaultValue)
4640 if (candidate_pd.Count != best_pd.Count)
4641 return candidate_pd.Count < best_pd.Count;
4644 // One is a non-generic method and second is a generic method, then non-generic is better
4646 if (best.IsGeneric != candidate.IsGeneric)
4647 return best.IsGeneric;
4650 // Both methods have the same number of parameters, and the parameters have equal types
4651 // Pick the "more specific" signature using rules over original (non-inflated) types
4653 var candidate_def_pd = ((IParametersMember) candidate.MemberDefinition).Parameters;
4654 var best_def_pd = ((IParametersMember) best.MemberDefinition).Parameters;
4656 bool specific_at_least_once = false;
4657 for (j = 0; j < args_count; ++j) {
4658 NamedArgument na = args_count == 0 ? null : args [j] as NamedArgument;
4660 ct = candidate_def_pd.Types[cparam.GetParameterIndexByName (na.Name)];
4661 bt = best_def_pd.Types[bparam.GetParameterIndexByName (na.Name)];
4663 ct = candidate_def_pd.Types[j];
4664 bt = best_def_pd.Types[j];
4669 TypeSpec specific = MoreSpecific (ct, bt);
4673 specific_at_least_once = true;
4676 if (specific_at_least_once)
4682 static bool CheckInflatedArguments (MethodSpec ms)
4684 if (!TypeParameterSpec.HasAnyTypeParameterTypeConstrained (ms.GenericDefinition))
4687 // Setup constraint checker for probing only
4688 ConstraintChecker cc = new ConstraintChecker (null);
4690 var mp = ms.Parameters.Types;
4691 for (int i = 0; i < mp.Length; ++i) {
4692 var type = mp[i] as InflatedTypeSpec;
4696 var targs = type.TypeArguments;
4697 if (targs.Length == 0)
4700 // TODO: Checking inflated MVAR arguments should be enough
4701 if (!cc.CheckAll (type.GetDefinition (), targs, type.Constraints, Location.Null))
4708 public static void Error_ConstructorMismatch (ResolveContext rc, TypeSpec type, int argCount, Location loc)
4710 rc.Report.Error (1729, loc,
4711 "The type `{0}' does not contain a constructor that takes `{1}' arguments",
4712 type.GetSignatureForError (), argCount.ToString ());
4716 // Determines if the candidate method is applicable to the given set of arguments
4717 // There could be two different set of parameters for same candidate where one
4718 // is the closest override for default values and named arguments checks and second
4719 // one being the virtual base for the parameter types and modifiers.
4721 // A return value rates candidate method compatibility,
4722 // 0 = the best, int.MaxValue = the worst
4725 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, bool errorMode)
4727 // Parameters of most-derived type used mainly for named and optional parameters
4728 var pd = pm.Parameters;
4730 // Used for params modifier only, that's legacy of C# 1.0 which uses base type for
4731 // params modifier instead of most-derived type
4732 var cpd = ((IParametersMember) candidate).Parameters;
4733 int param_count = pd.Count;
4734 int optional_count = 0;
4736 Arguments orig_args = arguments;
4738 if (arg_count != param_count) {
4740 // No arguments expansion when doing exact match for delegates
4742 if ((restrictions & Restrictions.CovariantDelegate) == 0) {
4743 for (int i = 0; i < pd.Count; ++i) {
4744 if (pd.FixedParameters[i].HasDefaultValue) {
4745 optional_count = pd.Count - i;
4751 if (optional_count != 0) {
4752 // Readjust expected number when params used
4753 if (cpd.HasParams) {
4755 if (arg_count < param_count)
4757 } else if (arg_count > param_count) {
4758 int args_gap = System.Math.Abs (arg_count - param_count);
4759 return int.MaxValue - 10000 + args_gap;
4760 } else if (arg_count < param_count - optional_count) {
4761 int args_gap = System.Math.Abs (param_count - optional_count - arg_count);
4762 return int.MaxValue - 10000 + args_gap;
4764 } else if (arg_count != param_count) {
4765 int args_gap = System.Math.Abs (arg_count - param_count);
4767 return int.MaxValue - 10000 + args_gap;
4768 if (arg_count < param_count - 1)
4769 return int.MaxValue - 10000 + args_gap;
4772 // Resize to fit optional arguments
4773 if (optional_count != 0) {
4774 if (arguments == null) {
4775 arguments = new Arguments (optional_count);
4777 // Have to create a new container, so the next run can do same
4778 var resized = new Arguments (param_count);
4779 resized.AddRange (arguments);
4780 arguments = resized;
4783 for (int i = arg_count; i < param_count; ++i)
4784 arguments.Add (null);
4788 if (arg_count > 0) {
4790 // Shuffle named arguments to the right positions if there are any
4792 if (arguments[arg_count - 1] is NamedArgument) {
4793 arg_count = arguments.Count;
4795 for (int i = 0; i < arg_count; ++i) {
4796 bool arg_moved = false;
4798 NamedArgument na = arguments[i] as NamedArgument;
4802 int index = pd.GetParameterIndexByName (na.Name);
4804 // Named parameter not found
4808 // already reordered
4813 if (index >= param_count) {
4814 // When using parameters which should not be available to the user
4815 if ((cpd.FixedParameters[index].ModFlags & Parameter.Modifier.PARAMS) == 0)
4818 arguments.Add (null);
4822 if (index == arg_count)
4825 temp = arguments [index];
4827 // The slot has been taken by positional argument
4828 if (temp != null && !(temp is NamedArgument))
4833 arguments = arguments.MarkOrderedArgument (na);
4837 if (arguments == orig_args) {
4838 arguments = new Arguments (orig_args.Count);
4839 arguments.AddRange (orig_args);
4842 arguments[index] = arguments[i];
4843 arguments[i] = temp;
4850 arg_count = arguments.Count;
4852 } else if (arguments != null) {
4853 arg_count = arguments.Count;
4857 // Don't do any expensive checks when the candidate cannot succeed
4859 if (arg_count != param_count && !cpd.HasParams)
4860 return (param_count - arg_count) * 2 + 1;
4862 var dep = candidate.GetMissingDependencies ();
4864 ImportedTypeDefinition.Error_MissingDependency (ec, dep, loc);
4869 // 1. Handle generic method using type arguments when specified or type inference
4872 var ms = candidate as MethodSpec;
4873 if (ms != null && ms.IsGeneric) {
4874 if (type_arguments != null) {
4875 var g_args_count = ms.Arity;
4876 if (g_args_count != type_arguments.Count)
4877 return int.MaxValue - 20000 + System.Math.Abs (type_arguments.Count - g_args_count);
4879 if (type_arguments.Arguments != null)
4880 ms = ms.MakeGenericMethod (ec, type_arguments.Arguments);
4883 // Deploy custom error reporting for infered anonymous expression or lambda methods. When
4884 // probing lambda methods keep all errors reported in separate set and once we are done and no best
4885 // candidate was found use the set to report more details about what was wrong with lambda body.
4886 // The general idea is to distinguish between code errors and errors caused by
4887 // trial-and-error type inference
4889 if (lambda_conv_msgs == null) {
4890 for (int i = 0; i < arg_count; i++) {
4891 Argument a = arguments[i];
4895 var am = a.Expr as AnonymousMethodExpression;
4897 if (lambda_conv_msgs == null)
4898 lambda_conv_msgs = new SessionReportPrinter ();
4900 am.TypeInferenceReportPrinter = lambda_conv_msgs;
4905 var ti = new TypeInference (arguments);
4906 TypeSpec[] i_args = ti.InferMethodArguments (ec, ms);
4909 return ti.InferenceScore - 20000;
4912 // Clear any error messages when the result was success
4914 if (lambda_conv_msgs != null)
4915 lambda_conv_msgs.ClearSession ();
4917 if (i_args.Length != 0) {
4919 foreach (var ta in i_args) {
4920 if (!ta.IsAccessible (ec))
4921 return ti.InferenceScore - 10000;
4925 ms = ms.MakeGenericMethod (ec, i_args);
4930 // Type arguments constraints have to match for the method to be applicable
4932 if (!CheckInflatedArguments (ms)) {
4934 return int.MaxValue - 25000;
4938 // We have a generic return type and at same time the method is override which
4939 // means we have to also inflate override return type in case the candidate is
4940 // best candidate and override return type is different to base return type.
4942 // virtual Foo<T, object> with override Foo<T, dynamic>
4944 if (candidate != pm) {
4945 MethodSpec override_ms = (MethodSpec) pm;
4946 var inflator = new TypeParameterInflator (ec, ms.DeclaringType, override_ms.GenericDefinition.TypeParameters, ms.TypeArguments);
4947 returnType = inflator.Inflate (returnType);
4949 returnType = ms.ReturnType;
4956 if (type_arguments != null)
4957 return int.MaxValue - 15000;
4963 // 2. Each argument has to be implicitly convertible to method parameter
4965 Parameter.Modifier p_mod = 0;
4968 for (int i = 0; i < arg_count; i++) {
4969 Argument a = arguments[i];
4971 var fp = pd.FixedParameters[i];
4972 if (!fp.HasDefaultValue) {
4973 arguments = orig_args;
4974 return arg_count * 2 + 2;
4978 // Get the default value expression, we can use the same expression
4979 // if the type matches
4981 Expression e = fp.DefaultValue;
4983 e = ResolveDefaultValueArgument (ec, ptypes[i], e, loc);
4985 // Restore for possible error reporting
4986 for (int ii = i; ii < arg_count; ++ii)
4987 arguments.RemoveAt (i);
4989 return (arg_count - i) * 2 + 1;
4993 if ((fp.ModFlags & Parameter.Modifier.CallerMask) != 0) {
4995 // LAMESPEC: Attributes can be mixed together with build-in priority
4997 if ((fp.ModFlags & Parameter.Modifier.CallerLineNumber) != 0) {
4998 e = new IntLiteral (ec.BuiltinTypes, loc.Row, loc);
4999 } else if ((fp.ModFlags & Parameter.Modifier.CallerFilePath) != 0) {
5000 e = new StringLiteral (ec.BuiltinTypes, loc.NameFullPath, loc);
5001 } else if (ec.MemberContext.CurrentMemberDefinition != null) {
5002 e = new StringLiteral (ec.BuiltinTypes, ec.MemberContext.CurrentMemberDefinition.GetCallerMemberName (), loc);
5006 arguments[i] = new Argument (e, Argument.AType.Default);
5010 if (p_mod != Parameter.Modifier.PARAMS) {
5011 p_mod = (pd.FixedParameters[i].ModFlags & ~Parameter.Modifier.PARAMS) | (cpd.FixedParameters[i].ModFlags & Parameter.Modifier.PARAMS);
5013 } else if (!params_expanded_form) {
5014 params_expanded_form = true;
5015 pt = ((ElementTypeSpec) pt).Element;
5021 if (!params_expanded_form) {
5022 if (a.IsExtensionType) {
5024 // Indentity, implicit reference or boxing conversion must exist for the extension parameter
5026 // LAMESPEC: or implicit type parameter conversion
5029 if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
5030 Convert.ImplicitReferenceConversionExists (at, pt, false) ||
5031 Convert.ImplicitBoxingConversion (null, at, pt) != null) {
5036 score = IsArgumentCompatible (ec, a, p_mod, pt);
5039 dynamicArgument = true;
5044 // It can be applicable in expanded form (when not doing exact match like for delegates)
5046 if (score != 0 && (p_mod & Parameter.Modifier.PARAMS) != 0 && (restrictions & Restrictions.CovariantDelegate) == 0) {
5047 if (!params_expanded_form) {
5048 pt = ((ElementTypeSpec) pt).Element;
5052 score = IsArgumentCompatible (ec, a, Parameter.Modifier.NONE, pt);
5055 params_expanded_form = true;
5056 dynamicArgument = true;
5057 } else if (score == 0 || arg_count > pd.Count) {
5058 params_expanded_form = true;
5063 if (params_expanded_form)
5065 return (arg_count - i) * 2 + score;
5070 // Restore original arguments for dynamic binder to keep the intention of original source code
5072 if (dynamicArgument)
5073 arguments = orig_args;
5078 public static Expression ResolveDefaultValueArgument (ResolveContext ec, TypeSpec ptype, Expression e, Location loc)
5080 if (e is Constant && e.Type == ptype)
5084 // LAMESPEC: No idea what the exact rules are for System.Reflection.Missing.Value instead of null
5086 if (e == EmptyExpression.MissingValue && ptype.BuiltinType == BuiltinTypeSpec.Type.Object || ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
5087 e = new MemberAccess (new MemberAccess (new MemberAccess (
5088 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Reflection", loc), "Missing", loc), "Value", loc);
5089 } else if (e is Constant) {
5091 // Handles int to int? conversions, DefaultParameterValue check
5093 e = Convert.ImplicitConversionStandard (ec, e, ptype, loc);
5097 e = new DefaultValueExpression (new TypeExpression (ptype, loc), loc);
5100 return e.Resolve (ec);
5104 // Tests argument compatibility with the parameter
5105 // The possible return values are
5107 // 1 - modifier mismatch
5108 // 2 - type mismatch
5109 // -1 - dynamic binding required
5111 int IsArgumentCompatible (ResolveContext ec, Argument argument, Parameter.Modifier param_mod, TypeSpec parameter)
5114 // Types have to be identical when ref or out modifer
5115 // is used and argument is not of dynamic type
5117 if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
5118 if (argument.Type != parameter) {
5120 // Do full equality check after quick path
5122 if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
5124 // Using dynamic for ref/out parameter can still succeed at runtime
5126 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5133 if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
5135 // Using dynamic for ref/out parameter can still succeed at runtime
5137 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
5144 if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
5148 // Use implicit conversion in all modes to return same candidates when the expression
5149 // is used as argument or delegate conversion
5151 if (!Convert.ImplicitConversionExists (ec, argument.Expr, parameter)) {
5152 return parameter.IsDelegate && argument.Expr is AnonymousMethodExpression ? 2 : 3;
5159 static TypeSpec MoreSpecific (TypeSpec p, TypeSpec q)
5161 if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
5163 if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
5166 var ac_p = p as ArrayContainer;
5168 var ac_q = q as ArrayContainer;
5172 TypeSpec specific = MoreSpecific (ac_p.Element, ac_q.Element);
5173 if (specific == ac_p.Element)
5175 if (specific == ac_q.Element)
5177 } else if (p.IsGeneric && q.IsGeneric) {
5178 var pargs = TypeManager.GetTypeArguments (p);
5179 var qargs = TypeManager.GetTypeArguments (q);
5181 bool p_specific_at_least_once = false;
5182 bool q_specific_at_least_once = false;
5184 for (int i = 0; i < pargs.Length; i++) {
5185 TypeSpec specific = MoreSpecific (pargs[i], qargs[i]);
5186 if (specific == pargs[i])
5187 p_specific_at_least_once = true;
5188 if (specific == qargs[i])
5189 q_specific_at_least_once = true;
5192 if (p_specific_at_least_once && !q_specific_at_least_once)
5194 if (!p_specific_at_least_once && q_specific_at_least_once)
5202 // Find the best method from candidate list
5204 public T ResolveMember<T> (ResolveContext rc, ref Arguments args) where T : MemberSpec, IParametersMember
5206 List<AmbiguousCandidate> ambiguous_candidates = null;
5208 MemberSpec best_candidate;
5209 Arguments best_candidate_args = null;
5210 bool best_candidate_params = false;
5211 bool best_candidate_dynamic = false;
5212 int best_candidate_rate;
5213 IParametersMember best_parameter_member = null;
5215 int args_count = args != null ? args.Count : 0;
5217 Arguments candidate_args = args;
5218 bool error_mode = false;
5219 MemberSpec invocable_member = null;
5222 best_candidate = null;
5223 best_candidate_rate = int.MaxValue;
5225 var type_members = members;
5227 for (int i = 0; i < type_members.Count; ++i) {
5228 var member = type_members[i];
5231 // Methods in a base class are not candidates if any method in a derived
5232 // class is applicable
5234 if ((member.Modifiers & Modifiers.OVERRIDE) != 0)
5238 if (!member.IsAccessible (rc))
5241 if (rc.IsRuntimeBinder && !member.DeclaringType.IsAccessible (rc))
5244 if ((member.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5245 instance_qualifier != null && !instance_qualifier.CheckProtectedMemberAccess (rc, member)) {
5250 IParametersMember pm = member as IParametersMember;
5253 // Will use it later to report ambiguity between best method and invocable member
5255 if (Invocation.IsMemberInvocable (member))
5256 invocable_member = member;
5262 // Overload resolution is looking for base member but using parameter names
5263 // and default values from the closest member. That means to do expensive lookup
5264 // for the closest override for virtual or abstract members
5266 if ((member.Modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
5267 var override_params = base_provider.GetOverrideMemberParameters (member);
5268 if (override_params != null)
5269 pm = override_params;
5273 // Check if the member candidate is applicable
5275 bool params_expanded_form = false;
5276 bool dynamic_argument = false;
5277 TypeSpec rt = pm.MemberType;
5278 int candidate_rate = IsApplicable (rc, ref candidate_args, args_count, ref member, pm, ref params_expanded_form, ref dynamic_argument, ref rt, error_mode);
5280 if (lambda_conv_msgs != null)
5281 lambda_conv_msgs.EndSession ();
5284 // How does it score compare to others
5286 if (candidate_rate < best_candidate_rate) {
5288 // Fatal error (missing dependency), cannot continue
5289 if (candidate_rate < 0)
5292 if ((restrictions & Restrictions.GetEnumeratorLookup) != 0 && candidate_args.Count != 0) {
5293 // Only parameterless methods are considered
5295 best_candidate_rate = candidate_rate;
5296 best_candidate = member;
5297 best_candidate_args = candidate_args;
5298 best_candidate_params = params_expanded_form;
5299 best_candidate_dynamic = dynamic_argument;
5300 best_parameter_member = pm;
5301 best_candidate_return_type = rt;
5303 } else if (candidate_rate == 0) {
5305 // The member look is done per type for most operations but sometimes
5306 // it's not possible like for binary operators overload because they
5307 // are unioned between 2 sides
5309 if ((restrictions & Restrictions.BaseMembersIncluded) != 0) {
5310 if (TypeSpec.IsBaseClass (best_candidate.DeclaringType, member.DeclaringType, true))
5315 if (best_candidate.DeclaringType.IsInterface && member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5317 // We pack all interface members into top level type which makes the overload resolution
5318 // more complicated for interfaces. We compensate it by removing methods with same
5319 // signature when building the cache hence this path should not really be hit often
5322 // interface IA { void Foo (int arg); }
5323 // interface IB : IA { void Foo (params int[] args); }
5325 // IB::Foo is the best overload when calling IB.Foo (1)
5328 if (ambiguous_candidates != null) {
5329 foreach (var amb_cand in ambiguous_candidates) {
5330 if (member.DeclaringType.ImplementsInterface (best_candidate.DeclaringType, false)) {
5339 ambiguous_candidates = null;
5342 // Is the new candidate better
5343 is_better = BetterFunction (rc, candidate_args, member, pm.Parameters, params_expanded_form, best_candidate, best_parameter_member.Parameters, best_candidate_params);
5347 best_candidate = member;
5348 best_candidate_args = candidate_args;
5349 best_candidate_params = params_expanded_form;
5350 best_candidate_dynamic = dynamic_argument;
5351 best_parameter_member = pm;
5352 best_candidate_return_type = rt;
5354 // It's not better but any other found later could be but we are not sure yet
5355 if (ambiguous_candidates == null)
5356 ambiguous_candidates = new List<AmbiguousCandidate> ();
5358 ambiguous_candidates.Add (new AmbiguousCandidate (member, pm.Parameters, params_expanded_form));
5362 // Restore expanded arguments
5363 candidate_args = args;
5365 } while (best_candidate_rate != 0 && (type_members = base_provider.GetBaseMembers (type_members[0].DeclaringType.BaseType)) != null);
5368 // We've found exact match
5370 if (best_candidate_rate == 0)
5374 // Try extension methods lookup when no ordinary method match was found and provider enables it
5377 var emg = base_provider.LookupExtensionMethod (rc);
5379 emg = emg.OverloadResolve (rc, ref args, null, restrictions);
5381 best_candidate_extension_group = emg;
5382 return (T) (MemberSpec) emg.BestCandidate;
5387 // Don't run expensive error reporting mode for probing
5394 if (lambda_conv_msgs != null && !lambda_conv_msgs.IsEmpty)
5397 lambda_conv_msgs = null;
5402 // No best member match found, report an error
5404 if (best_candidate_rate != 0 || error_mode) {
5405 ReportOverloadError (rc, best_candidate, best_parameter_member, best_candidate_args, best_candidate_params);
5409 if (best_candidate_dynamic) {
5410 if (args[0].IsExtensionType) {
5411 rc.Report.Error (1973, loc,
5412 "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",
5413 args [0].Type.GetSignatureForError (), best_candidate.Name, best_candidate.GetSignatureForError ());
5417 // Check type constraints only when explicit type arguments are used
5419 if (best_candidate.IsGeneric && type_arguments != null) {
5420 MethodSpec bc = best_candidate as MethodSpec;
5421 if (bc != null && TypeParameterSpec.HasAnyTypeParameterConstrained (bc.GenericDefinition)) {
5422 ConstraintChecker cc = new ConstraintChecker (rc);
5423 cc.CheckAll (bc.GetGenericMethodDefinition (), bc.TypeArguments, bc.Constraints, loc);
5427 BestCandidateIsDynamic = true;
5432 // These flags indicates we are running delegate probing conversion. No need to
5433 // do more expensive checks
5435 if ((restrictions & (Restrictions.ProbingOnly | Restrictions.CovariantDelegate)) == (Restrictions.CovariantDelegate | Restrictions.ProbingOnly))
5436 return (T) best_candidate;
5438 if (ambiguous_candidates != null) {
5440 // Now check that there are no ambiguities i.e the selected method
5441 // should be better than all the others
5443 for (int ix = 0; ix < ambiguous_candidates.Count; ix++) {
5444 var candidate = ambiguous_candidates [ix];
5446 if (!BetterFunction (rc, best_candidate_args, best_candidate, best_parameter_member.Parameters, best_candidate_params, candidate.Member, candidate.Parameters, candidate.Expanded)) {
5447 var ambiguous = candidate.Member;
5448 if (custom_errors == null || !custom_errors.AmbiguousCandidates (rc, best_candidate, ambiguous)) {
5449 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5450 rc.Report.SymbolRelatedToPreviousError (ambiguous);
5451 rc.Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5452 best_candidate.GetSignatureForError (), ambiguous.GetSignatureForError ());
5455 return (T) best_candidate;
5460 if (invocable_member != null && !IsProbingOnly) {
5461 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5462 rc.Report.SymbolRelatedToPreviousError (invocable_member);
5463 rc.Report.Warning (467, 2, loc, "Ambiguity between method `{0}' and invocable non-method `{1}'. Using method group",
5464 best_candidate.GetSignatureForError (), invocable_member.GetSignatureForError ());
5468 // And now check if the arguments are all
5469 // compatible, perform conversions if
5470 // necessary etc. and return if everything is
5473 if (!VerifyArguments (rc, ref best_candidate_args, best_candidate, best_parameter_member, best_candidate_params))
5476 if (best_candidate == null)
5480 // Don't run possibly expensive checks in probing mode
5482 if (!IsProbingOnly && !rc.IsInProbingMode) {
5484 // Check ObsoleteAttribute on the best method
5486 ObsoleteAttribute oa = best_candidate.GetAttributeObsolete ();
5487 if (oa != null && !rc.IsObsolete)
5488 AttributeTester.Report_ObsoleteMessage (oa, best_candidate.GetSignatureForError (), loc, rc.Report);
5490 best_candidate.MemberDefinition.SetIsUsed ();
5493 args = best_candidate_args;
5494 return (T) best_candidate;
5497 public MethodSpec ResolveOperator (ResolveContext rc, ref Arguments args)
5499 return ResolveMember<MethodSpec> (rc, ref args);
5502 void ReportArgumentMismatch (ResolveContext ec, int idx, MemberSpec method,
5503 Argument a, AParametersCollection expected_par, TypeSpec paramType)
5505 if (custom_errors != null && custom_errors.ArgumentMismatch (ec, method, a, idx))
5508 if (a.Type == InternalType.ErrorType)
5511 if (a is CollectionElementInitializer.ElementInitializerArgument) {
5512 ec.Report.SymbolRelatedToPreviousError (method);
5513 if ((expected_par.FixedParameters[idx].ModFlags & Parameter.Modifier.RefOutMask) != 0) {
5514 ec.Report.Error (1954, loc, "The best overloaded collection initalizer method `{0}' cannot have `ref' or `out' modifier",
5515 TypeManager.CSharpSignature (method));
5518 ec.Report.Error (1950, loc, "The best overloaded collection initalizer method `{0}' has some invalid arguments",
5519 TypeManager.CSharpSignature (method));
5520 } else if (IsDelegateInvoke) {
5521 ec.Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5522 DelegateType.GetSignatureForError ());
5524 ec.Report.SymbolRelatedToPreviousError (method);
5525 ec.Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5526 method.GetSignatureForError ());
5529 Parameter.Modifier mod = idx >= expected_par.Count ? 0 : expected_par.FixedParameters[idx].ModFlags;
5531 string index = (idx + 1).ToString ();
5532 if (((mod & Parameter.Modifier.RefOutMask) ^ (a.Modifier & Parameter.Modifier.RefOutMask)) != 0) {
5533 if ((mod & Parameter.Modifier.RefOutMask) == 0)
5534 ec.Report.Error (1615, a.Expr.Location, "Argument `#{0}' does not require `{1}' modifier. Consider removing `{1}' modifier",
5535 index, Parameter.GetModifierSignature (a.Modifier));
5537 ec.Report.Error (1620, a.Expr.Location, "Argument `#{0}' is missing `{1}' modifier",
5538 index, Parameter.GetModifierSignature (mod));
5540 string p1 = a.GetSignatureForError ();
5541 string p2 = paramType.GetSignatureForError ();
5544 p1 = a.Type.GetSignatureForErrorIncludingAssemblyName ();
5545 p2 = paramType.GetSignatureForErrorIncludingAssemblyName ();
5548 if ((mod & Parameter.Modifier.RefOutMask) != 0) {
5549 p1 = Parameter.GetModifierSignature (a.Modifier) + " " + p1;
5550 p2 = Parameter.GetModifierSignature (a.Modifier) + " " + p2;
5553 ec.Report.Error (1503, a.Expr.Location,
5554 "Argument `#{0}' cannot convert `{1}' expression to type `{2}'", index, p1, p2);
5559 // We have failed to find exact match so we return error info about the closest match
5561 void ReportOverloadError (ResolveContext rc, MemberSpec best_candidate, IParametersMember pm, Arguments args, bool params_expanded)
5563 int ta_count = type_arguments == null ? 0 : type_arguments.Count;
5564 int arg_count = args == null ? 0 : args.Count;
5566 if (ta_count != best_candidate.Arity && (ta_count > 0 || ((IParametersMember) best_candidate).Parameters.IsEmpty)) {
5567 var mg = new MethodGroupExpr (new [] { best_candidate }, best_candidate.DeclaringType, loc);
5568 mg.Error_TypeArgumentsCannotBeUsed (rc, best_candidate, loc);
5572 if (lambda_conv_msgs != null && lambda_conv_msgs.Merge (rc.Report.Printer)) {
5577 if ((best_candidate.Modifiers & (Modifiers.PROTECTED | Modifiers.STATIC)) == Modifiers.PROTECTED &&
5578 InstanceQualifier != null && !InstanceQualifier.CheckProtectedMemberAccess (rc, best_candidate)) {
5579 MemberExpr.Error_ProtectedMemberAccess (rc, best_candidate, InstanceQualifier.InstanceType, loc);
5583 // For candidates which match on parameters count report more details about incorrect arguments
5586 if (pm.Parameters.Count == arg_count || params_expanded || HasUnfilledParams (best_candidate, pm, args)) {
5587 // Reject any inaccessible member
5588 if (!best_candidate.IsAccessible (rc) || !best_candidate.DeclaringType.IsAccessible (rc)) {
5589 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5590 Expression.ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
5594 var ms = best_candidate as MethodSpec;
5595 if (ms != null && ms.IsGeneric) {
5596 bool constr_ok = true;
5597 if (ms.TypeArguments != null)
5598 constr_ok = new ConstraintChecker (rc.MemberContext).CheckAll (ms.GetGenericMethodDefinition (), ms.TypeArguments, ms.Constraints, loc);
5600 if (ta_count == 0 && ms.TypeArguments == null) {
5601 if (custom_errors != null && custom_errors.TypeInferenceFailed (rc, best_candidate))
5605 rc.Report.Error (411, loc,
5606 "The type arguments for method `{0}' cannot be inferred from the usage. Try specifying the type arguments explicitly",
5607 ms.GetGenericMethodDefinition ().GetSignatureForError ());
5614 VerifyArguments (rc, ref args, best_candidate, pm, params_expanded);
5620 // We failed to find any method with correct argument count, report best candidate
5622 if (custom_errors != null && custom_errors.NoArgumentMatch (rc, best_candidate))
5625 if (best_candidate.Kind == MemberKind.Constructor) {
5626 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5627 Error_ConstructorMismatch (rc, best_candidate.DeclaringType, arg_count, loc);
5628 } else if (IsDelegateInvoke) {
5629 rc.Report.SymbolRelatedToPreviousError (DelegateType);
5630 rc.Report.Error (1593, loc, "Delegate `{0}' does not take `{1}' arguments",
5631 DelegateType.GetSignatureForError (), arg_count.ToString ());
5633 string name = best_candidate.Kind == MemberKind.Indexer ? "this" : best_candidate.Name;
5634 rc.Report.SymbolRelatedToPreviousError (best_candidate);
5635 rc.Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5636 name, arg_count.ToString ());
5640 static bool HasUnfilledParams (MemberSpec best_candidate, IParametersMember pm, Arguments args)
5642 var p = ((IParametersMember)best_candidate).Parameters;
5647 for (int i = p.Count - 1; i != 0; --i) {
5648 var fp = p.FixedParameters [i];
5649 if ((fp.ModFlags & Parameter.Modifier.PARAMS) == 0)
5659 foreach (var arg in args) {
5660 var na = arg as NamedArgument;
5664 if (na.Name == name) {
5673 return args.Count + 1 == pm.Parameters.Count;
5676 bool VerifyArguments (ResolveContext ec, ref Arguments args, MemberSpec member, IParametersMember pm, bool chose_params_expanded)
5678 var pd = pm.Parameters;
5679 var cpd = ((IParametersMember) member).Parameters;
5680 var ptypes = cpd.Types;
5682 Parameter.Modifier p_mod = 0;
5684 int a_idx = 0, a_pos = 0;
5686 ArrayInitializer params_initializers = null;
5687 bool has_unsafe_arg = pm.MemberType.IsPointer;
5688 int arg_count = args == null ? 0 : args.Count;
5690 for (; a_idx < arg_count; a_idx++, ++a_pos) {
5695 if (p_mod != Parameter.Modifier.PARAMS) {
5696 p_mod = cpd.FixedParameters [a_idx].ModFlags;
5698 has_unsafe_arg |= pt.IsPointer;
5700 if (p_mod == Parameter.Modifier.PARAMS) {
5701 if (chose_params_expanded) {
5702 params_initializers = new ArrayInitializer (arg_count - a_idx, a.Expr.Location);
5703 pt = TypeManager.GetElementType (pt);
5709 // Types have to be identical when ref or out modifer is used
5711 if (((a.Modifier | p_mod) & Parameter.Modifier.RefOutMask) != 0) {
5712 if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
5715 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
5721 NamedArgument na = a as NamedArgument;
5723 int name_index = pd.GetParameterIndexByName (na.Name);
5724 if (name_index < 0 || name_index >= pd.Count) {
5725 if (IsDelegateInvoke) {
5726 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5727 ec.Report.Error (1746, na.Location,
5728 "The delegate `{0}' does not contain a parameter named `{1}'",
5729 DelegateType.GetSignatureForError (), na.Name);
5731 ec.Report.SymbolRelatedToPreviousError (member);
5732 ec.Report.Error (1739, na.Location,
5733 "The best overloaded method match for `{0}' does not contain a parameter named `{1}'",
5734 TypeManager.CSharpSignature (member), na.Name);
5736 } else if (args[name_index] != a && args[name_index] != null) {
5737 if (IsDelegateInvoke)
5738 ec.Report.SymbolRelatedToPreviousError (DelegateType);
5740 ec.Report.SymbolRelatedToPreviousError (member);
5742 ec.Report.Error (1744, na.Location,
5743 "Named argument `{0}' cannot be used for a parameter which has positional argument specified",
5748 if (a.Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
5751 if ((restrictions & Restrictions.CovariantDelegate) != 0 && !Delegate.IsTypeCovariant (ec, a.Expr.Type, pt)) {
5752 custom_errors.NoArgumentMatch (ec, member);
5757 if (a.IsExtensionType) {
5758 if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt)) {
5761 conv = Convert.ImplicitReferenceConversion (a.Expr, pt, false);
5763 conv = Convert.ImplicitBoxingConversion (a.Expr, a.Expr.Type, pt);
5766 conv = Convert.ImplicitConversion (ec, a.Expr, pt, loc);
5773 // Convert params arguments to an array initializer
5775 if (params_initializers != null) {
5776 // we choose to use 'a.Expr' rather than 'conv' so that
5777 // we don't hide the kind of expression we have (esp. CompoundAssign.Helper)
5778 params_initializers.Add (a.Expr);
5779 args.RemoveAt (a_idx--);
5785 // Update the argument with the implicit conversion
5789 if (a_idx != arg_count) {
5790 ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
5795 // Fill not provided arguments required by params modifier
5797 if (params_initializers == null && arg_count + 1 == pd.Count) {
5799 args = new Arguments (1);
5801 pt = ptypes[pd.Count - 1];
5802 pt = TypeManager.GetElementType (pt);
5803 has_unsafe_arg |= pt.IsPointer;
5804 params_initializers = new ArrayInitializer (0, loc);
5808 // Append an array argument with all params arguments
5810 if (params_initializers != null) {
5811 args.Add (new Argument (
5812 new ArrayCreation (new TypeExpression (pt, loc), params_initializers, loc).Resolve (ec)));
5816 if (has_unsafe_arg && !ec.IsUnsafe) {
5817 Expression.UnsafeError (ec, loc);
5821 // We could infer inaccesible type arguments
5823 if (type_arguments == null && member.IsGeneric) {
5824 var ms = (MethodSpec) member;
5825 foreach (var ta in ms.TypeArguments) {
5826 if (!ta.IsAccessible (ec)) {
5827 ec.Report.SymbolRelatedToPreviousError (ta);
5828 Expression.ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
5838 public class ConstantExpr : MemberExpr
5840 readonly ConstSpec constant;
5842 public ConstantExpr (ConstSpec constant, Location loc)
5844 this.constant = constant;
5848 public override string Name {
5849 get { throw new NotImplementedException (); }
5852 public override string KindName {
5853 get { return "constant"; }
5856 public override bool IsInstance {
5857 get { return !IsStatic; }
5860 public override bool IsStatic {
5861 get { return true; }
5864 protected override TypeSpec DeclaringType {
5865 get { return constant.DeclaringType; }
5868 public override Expression CreateExpressionTree (ResolveContext ec)
5870 throw new NotSupportedException ("ET");
5873 protected override Expression DoResolve (ResolveContext rc)
5875 ResolveInstanceExpression (rc, null);
5876 DoBestMemberChecks (rc, constant);
5878 var c = constant.GetConstant (rc);
5880 // Creates reference expression to the constant value
5881 return Constant.CreateConstantFromValue (constant.MemberType, c.GetValue (), loc);
5884 public override void Emit (EmitContext ec)
5886 throw new NotSupportedException ();
5889 public override string GetSignatureForError ()
5891 return constant.GetSignatureForError ();
5894 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
5896 Error_TypeArgumentsCannotBeUsed (ec, "constant", GetSignatureForError (), loc);
5901 // Fully resolved expression that references a Field
5903 public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
5905 protected FieldSpec spec;
5906 VariableInfo variable_info;
5908 LocalTemporary temp;
5911 protected FieldExpr (Location l)
5916 public FieldExpr (FieldSpec spec, Location loc)
5921 type = spec.MemberType;
5924 public FieldExpr (FieldBase fi, Location l)
5931 public override string Name {
5937 public bool IsHoisted {
5939 IVariableReference hv = InstanceExpression as IVariableReference;
5940 return hv != null && hv.IsHoisted;
5944 public override bool IsInstance {
5946 return !spec.IsStatic;
5950 public override bool IsStatic {
5952 return spec.IsStatic;
5956 public override string KindName {
5957 get { return "field"; }
5960 public FieldSpec Spec {
5966 protected override TypeSpec DeclaringType {
5968 return spec.DeclaringType;
5972 public VariableInfo VariableInfo {
5974 return variable_info;
5980 public override string GetSignatureForError ()
5982 return spec.GetSignatureForError ();
5985 public bool IsMarshalByRefAccess (ResolveContext rc)
5987 // Checks possible ldflda of field access expression
5988 return !spec.IsStatic && TypeSpec.IsValueType (spec.MemberType) && !(InstanceExpression is This) &&
5989 rc.Module.PredefinedTypes.MarshalByRefObject.Define () &&
5990 TypeSpec.IsBaseClass (spec.DeclaringType, rc.Module.PredefinedTypes.MarshalByRefObject.TypeSpec, false);
5993 public void SetHasAddressTaken ()
5995 IVariableReference vr = InstanceExpression as IVariableReference;
5997 vr.SetHasAddressTaken ();
6001 protected override void CloneTo (CloneContext clonectx, Expression target)
6003 var t = (FieldExpr) target;
6005 if (InstanceExpression != null)
6006 t.InstanceExpression = InstanceExpression.Clone (clonectx);
6009 public override Expression CreateExpressionTree (ResolveContext ec)
6011 if (ConditionalAccess) {
6012 Error_NullShortCircuitInsideExpressionTree (ec);
6015 return CreateExpressionTree (ec, true);
6018 public Expression CreateExpressionTree (ResolveContext ec, bool convertInstance)
6021 Expression instance;
6023 if (InstanceExpression == null) {
6024 instance = new NullLiteral (loc);
6025 } else if (convertInstance) {
6026 instance = InstanceExpression.CreateExpressionTree (ec);
6028 args = new Arguments (1);
6029 args.Add (new Argument (InstanceExpression));
6030 instance = CreateExpressionFactoryCall (ec, "Constant", args);
6033 args = Arguments.CreateForExpressionTree (ec, null,
6035 CreateTypeOfExpression ());
6037 return CreateExpressionFactoryCall (ec, "Field", args);
6040 public Expression CreateTypeOfExpression ()
6042 return new TypeOfField (spec, loc);
6045 protected override Expression DoResolve (ResolveContext ec)
6047 spec.MemberDefinition.SetIsUsed ();
6049 return DoResolve (ec, null);
6052 Expression DoResolve (ResolveContext ec, Expression rhs)
6054 bool lvalue_instance = rhs != null && IsInstance && spec.DeclaringType.IsStruct;
6057 ResolveConditionalAccessReceiver (ec);
6059 if (ResolveInstanceExpression (ec, rhs)) {
6060 // Resolve the field's instance expression while flow analysis is turned
6061 // off: when accessing a field "a.b", we must check whether the field
6062 // "a.b" is initialized, not whether the whole struct "a" is initialized.
6064 if (lvalue_instance) {
6065 bool out_access = rhs == EmptyExpression.OutAccess || rhs == EmptyExpression.LValueMemberOutAccess;
6067 Expression right_side =
6068 out_access ? EmptyExpression.LValueMemberOutAccess : EmptyExpression.LValueMemberAccess;
6070 InstanceExpression = InstanceExpression.ResolveLValue (ec, right_side);
6072 InstanceExpression = InstanceExpression.Resolve (ec, ResolveFlags.VariableOrValue);
6075 if (InstanceExpression == null)
6079 DoBestMemberChecks (ec, spec);
6081 if (conditional_access_receiver)
6082 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6085 var fb = spec as FixedFieldSpec;
6086 IVariableReference var = InstanceExpression as IVariableReference;
6089 IFixedExpression fe = InstanceExpression as IFixedExpression;
6090 if (!ec.HasSet (ResolveContext.Options.FixedInitializerScope) && (fe == null || !fe.IsFixed)) {
6091 ec.Report.Error (1666, loc, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
6094 if (InstanceExpression.eclass != ExprClass.Variable) {
6095 ec.Report.SymbolRelatedToPreviousError (spec);
6096 ec.Report.Error (1708, loc, "`{0}': Fixed size buffers can only be accessed through locals or fields",
6097 TypeManager.GetFullNameSignature (spec));
6098 } else if (var != null && var.IsHoisted) {
6099 AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
6102 return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
6106 // Set flow-analysis variable info for struct member access. It will be check later
6107 // for precise error reporting
6109 if (var != null && var.VariableInfo != null && InstanceExpression.Type.IsStruct) {
6110 variable_info = var.VariableInfo.GetStructFieldInfo (Name);
6113 if (ConditionalAccess) {
6114 if (conditional_access_receiver)
6115 type = LiftMemberType (ec, type);
6117 if (InstanceExpression.IsNull)
6118 return Constant.CreateConstantFromValue (type, null, loc);
6121 eclass = ExprClass.Variable;
6125 public void SetFieldAssigned (FlowAnalysisContext fc)
6130 bool lvalue_instance = spec.DeclaringType.IsStruct;
6131 if (lvalue_instance) {
6132 var var = InstanceExpression as IVariableReference;
6133 if (var != null && var.VariableInfo != null) {
6134 fc.SetStructFieldAssigned (var.VariableInfo, Name);
6138 var fe = InstanceExpression as FieldExpr;
6140 Expression instance;
6143 instance = fe.InstanceExpression;
6144 var fe_instance = instance as FieldExpr;
6145 if ((fe_instance != null && !fe_instance.IsStatic) || instance is LocalVariableReference) {
6146 if (TypeSpec.IsReferenceType (fe.Type) && instance.Type.IsStruct) {
6147 var var = InstanceExpression as IVariableReference;
6148 if (var != null && var.VariableInfo == null) {
6149 var var_inst = instance as IVariableReference;
6150 if (var_inst == null || (var_inst.VariableInfo != null && !fc.IsDefinitelyAssigned (var_inst.VariableInfo)))
6151 fc.Report.Warning (1060, 1, fe.loc, "Use of possibly unassigned field `{0}'", fe.Name);
6155 if (fe_instance != null) {
6164 if (instance != null && TypeSpec.IsReferenceType (instance.Type))
6165 instance.FlowAnalysis (fc);
6167 if (TypeSpec.IsReferenceType (InstanceExpression.Type))
6168 InstanceExpression.FlowAnalysis (fc);
6172 Expression Error_AssignToReadonly (ResolveContext rc, Expression right_side)
6174 // The return value is always null. Returning a value simplifies calling code.
6176 if (right_side == EmptyExpression.OutAccess) {
6178 rc.Report.Error (199, loc, "A static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6179 GetSignatureForError ());
6181 rc.Report.Error (192, loc, "A readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6182 GetSignatureForError ());
6188 if (right_side == EmptyExpression.LValueMemberAccess) {
6189 // Already reported as CS1648/CS1650
6193 if (right_side == EmptyExpression.LValueMemberOutAccess) {
6195 rc.Report.Error (1651, loc, "Fields of static readonly field `{0}' cannot be passed ref or out (except in a static constructor)",
6196 GetSignatureForError ());
6198 rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
6199 GetSignatureForError ());
6205 rc.Report.Error (198, loc, "A static readonly field `{0}' cannot be assigned to (except in a static constructor or a variable initializer)",
6206 GetSignatureForError ());
6208 rc.Report.Error (191, loc, "A readonly field `{0}' cannot be assigned to (except in a constructor or a variable initializer)",
6209 GetSignatureForError ());
6215 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6217 if (ConditionalAccess)
6218 throw new NotSupportedException ("null propagating operator assignment");
6220 if (spec is FixedFieldSpec) {
6221 // It could be much better error message but we want to be error compatible
6222 Error_ValueAssignment (ec, right_side);
6225 Expression e = DoResolve (ec, right_side);
6230 spec.MemberDefinition.SetIsAssigned ();
6232 if ((right_side == EmptyExpression.UnaryAddress || right_side == EmptyExpression.OutAccess) &&
6233 (spec.Modifiers & Modifiers.VOLATILE) != 0) {
6234 ec.Report.Warning (420, 1, loc,
6235 "`{0}': A volatile field references will not be treated as volatile",
6236 spec.GetSignatureForError ());
6239 if (spec.IsReadOnly) {
6240 // InitOnly fields can only be assigned in constructors or initializers
6241 if (!ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.ConstructorScope))
6242 return Error_AssignToReadonly (ec, right_side);
6244 if (ec.HasSet (ResolveContext.Options.ConstructorScope)) {
6246 // InitOnly fields cannot be assigned-to in a different constructor from their declaring type
6247 if (ec.CurrentMemberDefinition.Parent.PartialContainer.Definition != spec.DeclaringType.GetDefinition ())
6248 return Error_AssignToReadonly (ec, right_side);
6249 // static InitOnly fields cannot be assigned-to in an instance constructor
6250 if (IsStatic && !ec.IsStatic)
6251 return Error_AssignToReadonly (ec, right_side);
6252 // instance constructors can't modify InitOnly fields of other instances of the same type
6253 if (!IsStatic && !(InstanceExpression is This))
6254 return Error_AssignToReadonly (ec, right_side);
6258 if (right_side == EmptyExpression.OutAccess && IsMarshalByRefAccess (ec)) {
6259 ec.Report.SymbolRelatedToPreviousError (spec.DeclaringType);
6260 ec.Report.Warning (197, 1, loc,
6261 "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",
6262 GetSignatureForError ());
6265 eclass = ExprClass.Variable;
6269 public override void FlowAnalysis (FlowAnalysisContext fc)
6271 var var = InstanceExpression as IVariableReference;
6273 var vi = var.VariableInfo;
6274 if (vi != null && !fc.IsStructFieldDefinitelyAssigned (vi, Name)) {
6275 fc.Report.Error (170, loc, "Use of possibly unassigned field `{0}'", Name);
6279 if (TypeSpec.IsValueType (InstanceExpression.Type) && InstanceExpression is VariableReference)
6283 base.FlowAnalysis (fc);
6285 if (conditional_access_receiver)
6286 fc.ConditionalAccessEnd ();
6289 public override int GetHashCode ()
6291 return spec.GetHashCode ();
6294 public bool IsFixed {
6297 // A variable of the form V.I is fixed when V is a fixed variable of a struct type
6299 IVariableReference variable = InstanceExpression as IVariableReference;
6300 if (variable != null)
6301 return InstanceExpression.Type.IsStruct && variable.IsFixed;
6303 IFixedExpression fe = InstanceExpression as IFixedExpression;
6304 return fe != null && fe.IsFixed;
6308 public override bool Equals (object obj)
6310 FieldExpr fe = obj as FieldExpr;
6314 if (spec != fe.spec)
6317 if (InstanceExpression == null || fe.InstanceExpression == null)
6320 return InstanceExpression.Equals (fe.InstanceExpression);
6323 public void Emit (EmitContext ec, bool leave_copy)
6325 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6329 ec.Emit (OpCodes.Volatile);
6331 ec.Emit (OpCodes.Ldsfld, spec);
6334 if (conditional_access_receiver)
6335 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6337 EmitInstance (ec, false);
6340 // Optimization for build-in types
6341 if (type.IsStruct && type == ec.CurrentType && InstanceExpression.Type == type) {
6342 ec.EmitLoadFromPtr (type);
6344 var ff = spec as FixedFieldSpec;
6346 ec.Emit (OpCodes.Ldflda, spec);
6347 ec.Emit (OpCodes.Ldflda, ff.Element);
6350 ec.Emit (OpCodes.Volatile);
6352 ec.Emit (OpCodes.Ldfld, spec);
6356 if (conditional_access_receiver) {
6357 ec.CloseConditionalAccess (type.IsNullableType && type != spec.MemberType ? type : null);
6362 ec.Emit (OpCodes.Dup);
6364 temp = new LocalTemporary (this.Type);
6370 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6372 bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
6373 if (isCompound && !(source is DynamicExpressionStatement) && !has_await_source) {
6378 if (ConditionalAccess)
6379 throw new NotImplementedException ("null operator assignment");
6381 if (has_await_source)
6382 source = source.EmitToField (ec);
6384 EmitInstance (ec, prepared);
6389 if (leave_copy || ec.NotifyEvaluatorOnStore) {
6390 ec.Emit (OpCodes.Dup);
6392 temp = new LocalTemporary (this.Type);
6397 if ((spec.Modifiers & Modifiers.VOLATILE) != 0)
6398 ec.Emit (OpCodes.Volatile);
6400 spec.MemberDefinition.SetIsAssigned ();
6403 ec.Emit (OpCodes.Stsfld, spec);
6405 ec.Emit (OpCodes.Stfld, spec);
6407 if (ec.NotifyEvaluatorOnStore) {
6409 throw new NotImplementedException ("instance field write");
6412 ec.Emit (OpCodes.Dup);
6414 ec.Module.Evaluator.EmitValueChangedCallback (ec, Name, type, loc);
6425 // Emits store to field with prepared values on stack
6427 public void EmitAssignFromStack (EmitContext ec)
6430 ec.Emit (OpCodes.Stsfld, spec);
6432 ec.Emit (OpCodes.Stfld, spec);
6436 public override void Emit (EmitContext ec)
6441 public override void EmitSideEffect (EmitContext ec)
6443 bool is_volatile = (spec.Modifiers & Modifiers.VOLATILE) != 0;
6445 if (is_volatile) // || is_marshal_by_ref ())
6446 base.EmitSideEffect (ec);
6449 public virtual void AddressOf (EmitContext ec, AddressOp mode)
6451 if ((mode & AddressOp.Store) != 0)
6452 spec.MemberDefinition.SetIsAssigned ();
6453 if ((mode & AddressOp.Load) != 0)
6454 spec.MemberDefinition.SetIsUsed ();
6457 // Handle initonly fields specially: make a copy and then
6458 // get the address of the copy.
6461 if (spec.IsReadOnly){
6463 if (ec.HasSet (EmitContext.Options.ConstructorScope) && spec.DeclaringType == ec.CurrentType) {
6475 var temp = ec.GetTemporaryLocal (type);
6476 ec.Emit (OpCodes.Stloc, temp);
6477 ec.Emit (OpCodes.Ldloca, temp);
6483 ec.Emit (OpCodes.Ldsflda, spec);
6486 EmitInstance (ec, false);
6487 ec.Emit (OpCodes.Ldflda, spec);
6491 public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6493 return MakeExpression (ctx);
6496 public override SLE.Expression MakeExpression (BuilderContext ctx)
6499 return base.MakeExpression (ctx);
6501 return SLE.Expression.Field (
6502 IsStatic ? null : InstanceExpression.MakeExpression (ctx),
6503 spec.GetMetaInfo ());
6507 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6509 Error_TypeArgumentsCannotBeUsed (ec, "field", GetSignatureForError (), loc);
6515 // Expression that evaluates to a Property.
6517 // This is not an LValue because we need to re-write the expression. We
6518 // can not take data from the stack and store it.
6520 sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
6522 Arguments arguments;
6524 public PropertyExpr (PropertySpec spec, Location l)
6527 best_candidate = spec;
6528 type = spec.MemberType;
6533 protected override Arguments Arguments {
6542 protected override TypeSpec DeclaringType {
6544 return best_candidate.DeclaringType;
6548 public override string Name {
6550 return best_candidate.Name;
6554 public override bool IsInstance {
6560 public override bool IsStatic {
6562 return best_candidate.IsStatic;
6566 public override string KindName {
6567 get { return "property"; }
6570 public PropertySpec PropertyInfo {
6572 return best_candidate;
6578 public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
6580 if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
6583 var args_count = arguments == null ? 0 : arguments.Count;
6584 if (args_count != body.Parameters.Count && args_count == 0)
6587 var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
6588 mg.InstanceExpression = InstanceExpression;
6593 public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
6595 return new PropertyExpr (spec, loc) {
6601 public override Expression CreateExpressionTree (ResolveContext ec)
6603 if (ConditionalAccess) {
6604 Error_NullShortCircuitInsideExpressionTree (ec);
6608 if (IsSingleDimensionalArrayLength ()) {
6609 args = new Arguments (1);
6610 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6611 return CreateExpressionFactoryCall (ec, "ArrayLength", args);
6614 args = new Arguments (2);
6615 if (InstanceExpression == null)
6616 args.Add (new Argument (new NullLiteral (loc)));
6618 args.Add (new Argument (InstanceExpression.CreateExpressionTree (ec)));
6619 args.Add (new Argument (new TypeOfMethod (Getter, loc)));
6620 return CreateExpressionFactoryCall (ec, "Property", args);
6623 public Expression CreateSetterTypeOfExpression (ResolveContext rc)
6625 DoResolveLValue (rc, null);
6626 return new TypeOfMethod (Setter, loc);
6629 public override string GetSignatureForError ()
6631 return best_candidate.GetSignatureForError ();
6634 public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
6637 return base.MakeExpression (ctx);
6639 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo ());
6643 public override SLE.Expression MakeExpression (BuilderContext ctx)
6646 return base.MakeExpression (ctx);
6648 return SLE.Expression.Property (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo ());
6652 void Error_PropertyNotValid (ResolveContext ec)
6654 ec.Report.SymbolRelatedToPreviousError (best_candidate);
6655 ec.Report.Error (1546, loc, "Property or event `{0}' is not supported by the C# language",
6656 GetSignatureForError ());
6659 bool IsSingleDimensionalArrayLength ()
6661 if (best_candidate.DeclaringType.BuiltinType != BuiltinTypeSpec.Type.Array || !best_candidate.HasGet || Name != "Length")
6664 ArrayContainer ac = InstanceExpression.Type as ArrayContainer;
6665 return ac != null && ac.Rank == 1;
6668 public override void Emit (EmitContext ec, bool leave_copy)
6671 // Special case: length of single dimension array property is turned into ldlen
6673 if (IsSingleDimensionalArrayLength ()) {
6674 if (conditional_access_receiver) {
6675 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6678 EmitInstance (ec, false);
6680 ec.Emit (OpCodes.Ldlen);
6681 ec.Emit (OpCodes.Conv_I4);
6683 if (conditional_access_receiver) {
6684 ec.CloseConditionalAccess (type);
6690 base.Emit (ec, leave_copy);
6693 public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
6696 LocalTemporary await_source_arg = null;
6698 if (isCompound && !(source is DynamicExpressionStatement)) {
6699 emitting_compound_assignment = true;
6702 if (has_await_arguments) {
6703 await_source_arg = new LocalTemporary (Type);
6704 await_source_arg.Store (ec);
6706 args = new Arguments (1);
6707 args.Add (new Argument (await_source_arg));
6710 temp = await_source_arg;
6713 has_await_arguments = false;
6718 ec.Emit (OpCodes.Dup);
6719 temp = new LocalTemporary (this.Type);
6724 args = arguments ?? new Arguments (1);
6728 temp = new LocalTemporary (this.Type);
6730 args.Add (new Argument (temp));
6732 args.Add (new Argument (source));
6736 emitting_compound_assignment = false;
6738 var call = new CallEmitter ();
6739 call.InstanceExpression = InstanceExpression;
6741 call.InstanceExpressionOnStack = true;
6743 if (ConditionalAccess) {
6744 call.ConditionalAccess = true;
6748 call.Emit (ec, Setter, args, loc);
6750 call.EmitStatement (ec, Setter, args, loc);
6757 if (await_source_arg != null) {
6758 await_source_arg.Release (ec);
6762 public override void FlowAnalysis (FlowAnalysisContext fc)
6764 base.FlowAnalysis (fc);
6766 if (conditional_access_receiver)
6767 fc.ConditionalAccessEnd ();
6770 protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
6772 eclass = ExprClass.PropertyAccess;
6774 if (best_candidate.IsNotCSharpCompatible) {
6775 Error_PropertyNotValid (rc);
6778 ResolveInstanceExpression (rc, right_side);
6780 if ((best_candidate.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0 && best_candidate.DeclaringType != InstanceExpression.Type) {
6781 var filter = new MemberFilter (best_candidate.Name, 0, MemberKind.Property, null, null);
6782 var p = MemberCache.FindMember (InstanceExpression.Type, filter, BindingRestriction.InstanceOnly | BindingRestriction.OverrideOnly) as PropertySpec;
6784 type = p.MemberType;
6788 DoBestMemberChecks (rc, best_candidate);
6790 // Handling of com-imported properties with any number of default property parameters
6791 if (best_candidate.HasGet && !best_candidate.Get.Parameters.IsEmpty) {
6792 var p = best_candidate.Get.Parameters;
6793 arguments = new Arguments (p.Count);
6794 for (int i = 0; i < p.Count; ++i) {
6795 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6797 } else if (best_candidate.HasSet && best_candidate.Set.Parameters.Count > 1) {
6798 var p = best_candidate.Set.Parameters;
6799 arguments = new Arguments (p.Count - 1);
6800 for (int i = 0; i < p.Count - 1; ++i) {
6801 arguments.Add (new Argument (OverloadResolver.ResolveDefaultValueArgument (rc, p.Types [i], p.FixedParameters [i].DefaultValue, loc)));
6808 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
6810 Error_TypeArgumentsCannotBeUsed (ec, "property", GetSignatureForError (), loc);
6814 abstract class PropertyOrIndexerExpr<T> : MemberExpr, IDynamicAssign where T : PropertySpec
6816 // getter and setter can be different for base calls
6817 MethodSpec getter, setter;
6818 protected T best_candidate;
6820 protected LocalTemporary temp;
6821 protected bool emitting_compound_assignment;
6822 protected bool has_await_arguments;
6824 protected PropertyOrIndexerExpr (Location l)
6831 protected abstract Arguments Arguments { get; set; }
6833 public MethodSpec Getter {
6842 public MethodSpec Setter {
6853 protected override Expression DoResolve (ResolveContext ec)
6855 if (eclass == ExprClass.Unresolved) {
6856 ResolveConditionalAccessReceiver (ec);
6858 var expr = OverloadResolve (ec, null);
6863 return expr.Resolve (ec);
6865 if (conditional_access_receiver) {
6866 type = LiftMemberType (ec, type);
6867 ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
6871 if (!ResolveGetter (ec))
6877 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
6879 if (ConditionalAccess)
6880 throw new NotSupportedException ("null propagating operator assignment");
6882 if (right_side == EmptyExpression.OutAccess) {
6883 // TODO: best_candidate can be null at this point
6884 INamedBlockVariable variable = null;
6885 if (best_candidate != null && ec.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, ec.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
6886 ec.Report.Error (1939, loc, "A range variable `{0}' may not be passes as `ref' or `out' parameter",
6887 best_candidate.Name);
6889 right_side.DoResolveLValue (ec, this);
6894 if (eclass == ExprClass.Unresolved) {
6895 var expr = OverloadResolve (ec, right_side);
6900 return expr.ResolveLValue (ec, right_side);
6902 ResolveInstanceExpression (ec, right_side);
6905 if (!ResolveSetter (ec))
6911 void EmitConditionalAccess (EmitContext ec, ref CallEmitter call, MethodSpec method, Arguments arguments)
6913 ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
6915 call.Emit (ec, method, arguments, loc);
6917 ec.CloseConditionalAccess (method.ReturnType != type && type.IsNullableType ? type : null);
6921 // Implements the IAssignMethod interface for assignments
6923 public virtual void Emit (EmitContext ec, bool leave_copy)
6925 var call = new CallEmitter ();
6926 call.ConditionalAccess = ConditionalAccess;
6927 call.InstanceExpression = InstanceExpression;
6928 if (has_await_arguments)
6929 call.HasAwaitArguments = true;
6931 call.DuplicateArguments = emitting_compound_assignment;
6933 if (conditional_access_receiver)
6934 EmitConditionalAccess (ec, ref call, Getter, Arguments);
6936 call.Emit (ec, Getter, Arguments, loc);
6938 if (call.HasAwaitArguments) {
6939 InstanceExpression = call.InstanceExpression;
6940 Arguments = call.EmittedArguments;
6941 has_await_arguments = true;
6945 ec.Emit (OpCodes.Dup);
6946 temp = new LocalTemporary (Type);
6951 public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
6953 public override void Emit (EmitContext ec)
6958 protected override FieldExpr EmitToFieldSource (EmitContext ec)
6960 has_await_arguments = true;
6965 public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
6967 protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
6969 bool ResolveGetter (ResolveContext rc)
6971 if (!best_candidate.HasGet) {
6972 if (InstanceExpression != EmptyExpression.Null) {
6973 rc.Report.SymbolRelatedToPreviousError (best_candidate);
6974 rc.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
6975 best_candidate.GetSignatureForError ());
6978 } else if (!best_candidate.Get.IsAccessible (rc) || !best_candidate.Get.DeclaringType.IsAccessible (rc)) {
6979 if (best_candidate.HasDifferentAccessibility) {
6980 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6981 rc.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because the get accessor is inaccessible",
6982 TypeManager.CSharpSignature (best_candidate));
6984 rc.Report.SymbolRelatedToPreviousError (best_candidate.Get);
6985 ErrorIsInaccesible (rc, best_candidate.Get.GetSignatureForError (), loc);
6989 if (best_candidate.HasDifferentAccessibility) {
6990 CheckProtectedMemberAccess (rc, best_candidate.Get);
6993 getter = CandidateToBaseOverride (rc, best_candidate.Get);
6997 bool ResolveSetter (ResolveContext rc)
6999 if (!best_candidate.HasSet) {
7000 rc.Report.Error (200, loc, "Property or indexer `{0}' cannot be assigned to (it is read-only)",
7001 GetSignatureForError ());
7005 if (!best_candidate.Set.IsAccessible (rc) || !best_candidate.Set.DeclaringType.IsAccessible (rc)) {
7006 if (best_candidate.HasDifferentAccessibility) {
7007 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7008 rc.Report.Error (272, loc, "The property or indexer `{0}' cannot be used in this context because the set accessor is inaccessible",
7009 GetSignatureForError ());
7011 rc.Report.SymbolRelatedToPreviousError (best_candidate.Set);
7012 ErrorIsInaccesible (rc, best_candidate.GetSignatureForError (), loc);
7016 if (best_candidate.HasDifferentAccessibility)
7017 CheckProtectedMemberAccess (rc, best_candidate.Set);
7019 setter = CandidateToBaseOverride (rc, best_candidate.Set);
7025 /// Fully resolved expression that evaluates to an Event
7027 public class EventExpr : MemberExpr, IAssignMethod
7029 readonly EventSpec spec;
7032 public EventExpr (EventSpec spec, Location loc)
7040 protected override TypeSpec DeclaringType {
7042 return spec.DeclaringType;
7046 public override string Name {
7052 public override bool IsInstance {
7054 return !spec.IsStatic;
7058 public override bool IsStatic {
7060 return spec.IsStatic;
7064 public override string KindName {
7065 get { return "event"; }
7068 public MethodSpec Operator {
7076 public override MemberExpr ResolveMemberAccess (ResolveContext ec, Expression left, SimpleName original)
7079 // If the event is local to this class and we are not lhs of +=/-= we transform ourselves into a FieldExpr
7081 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7082 if (spec.BackingField != null &&
7083 (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition))) {
7085 spec.MemberDefinition.SetIsUsed ();
7087 if (!ec.IsObsolete) {
7088 ObsoleteAttribute oa = spec.GetAttributeObsolete ();
7090 AttributeTester.Report_ObsoleteMessage (oa, spec.GetSignatureForError (), loc, ec.Report);
7093 if ((spec.Modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0)
7094 Error_AssignmentEventOnly (ec);
7096 FieldExpr ml = new FieldExpr (spec.BackingField, loc);
7098 InstanceExpression = null;
7100 return ml.ResolveMemberAccess (ec, left, original);
7104 return base.ResolveMemberAccess (ec, left, original);
7107 public override Expression CreateExpressionTree (ResolveContext ec)
7109 throw new NotSupportedException ("ET");
7112 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7114 if (right_side == EmptyExpression.EventAddition) {
7115 op = spec.AccessorAdd;
7116 } else if (right_side == EmptyExpression.EventSubtraction) {
7117 op = spec.AccessorRemove;
7121 Error_AssignmentEventOnly (ec);
7125 op = CandidateToBaseOverride (ec, op);
7129 protected override Expression DoResolve (ResolveContext ec)
7131 eclass = ExprClass.EventAccess;
7132 type = spec.MemberType;
7134 ResolveInstanceExpression (ec, null);
7136 if (!ec.HasSet (ResolveContext.Options.CompoundAssignmentScope)) {
7137 Error_AssignmentEventOnly (ec);
7140 DoBestMemberChecks (ec, spec);
7144 public override void Emit (EmitContext ec)
7146 throw new NotSupportedException ();
7147 //Error_CannotAssign ();
7150 #region IAssignMethod Members
7152 public void Emit (EmitContext ec, bool leave_copy)
7154 throw new NotImplementedException ();
7157 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
7159 if (leave_copy || !isCompound)
7160 throw new NotImplementedException ("EventExpr::EmitAssign");
7162 Arguments args = new Arguments (1);
7163 args.Add (new Argument (source));
7165 // TODO: Wrong, needs receiver
7166 // if (NullShortCircuit) {
7167 // ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
7170 var call = new CallEmitter ();
7171 call.InstanceExpression = InstanceExpression;
7172 call.ConditionalAccess = ConditionalAccess;
7173 call.EmitStatement (ec, op, args, loc);
7175 // if (NullShortCircuit)
7176 // ec.CloseConditionalAccess (null);
7181 void Error_AssignmentEventOnly (ResolveContext ec)
7183 if (spec.DeclaringType == ec.CurrentType || TypeManager.IsNestedChildOf (ec.CurrentType, spec.DeclaringType.MemberDefinition)) {
7184 ec.Report.Error (79, loc,
7185 "The event `{0}' can only appear on the left hand side of `+=' or `-=' operator",
7186 GetSignatureForError ());
7188 ec.Report.Error (70, loc,
7189 "The event `{0}' can only appear on the left hand side of += or -= when used outside of the type `{1}'",
7190 GetSignatureForError (), spec.DeclaringType.GetSignatureForError ());
7194 protected override void Error_CannotCallAbstractBase (ResolveContext rc, string name)
7196 name = name.Substring (0, name.LastIndexOf ('.'));
7197 base.Error_CannotCallAbstractBase (rc, name);
7200 public override string GetSignatureForError ()
7202 return TypeManager.CSharpSignature (spec);
7205 public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
7207 Error_TypeArgumentsCannotBeUsed (ec, "event", GetSignatureForError (), loc);
7211 public class TemporaryVariableReference : VariableReference
7213 public class Declarator : Statement
7215 TemporaryVariableReference variable;
7217 public Declarator (TemporaryVariableReference variable)
7219 this.variable = variable;
7223 protected override void DoEmit (EmitContext ec)
7225 variable.li.CreateBuilder (ec);
7228 public override void Emit (EmitContext ec)
7230 // Don't create sequence point
7234 protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
7239 protected override void CloneTo (CloneContext clonectx, Statement target)
7247 public TemporaryVariableReference (LocalVariable li, Location loc)
7250 this.type = li.Type;
7254 public override bool IsLockedByStatement {
7262 public LocalVariable LocalInfo {
7268 public static TemporaryVariableReference Create (TypeSpec type, Block block, Location loc)
7270 var li = LocalVariable.CreateCompilerGenerated (type, block, loc);
7271 return new TemporaryVariableReference (li, loc);
7274 protected override Expression DoResolve (ResolveContext ec)
7276 eclass = ExprClass.Variable;
7279 // Don't capture temporary variables except when using
7280 // state machine redirection and block yields
7282 if (ec.CurrentAnonymousMethod is StateMachineInitializer &&
7283 (ec.CurrentBlock.Explicit.HasYield || ec.CurrentBlock.Explicit.HasAwait) &&
7284 ec.IsVariableCapturingRequired) {
7285 AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
7286 storey.CaptureLocalVariable (ec, li);
7292 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
7294 return Resolve (ec);
7297 public override void Emit (EmitContext ec)
7299 li.CreateBuilder (ec);
7304 public void EmitAssign (EmitContext ec, Expression source)
7306 li.CreateBuilder (ec);
7308 EmitAssign (ec, source, false, false);
7311 public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
7313 return li.HoistedVariant;
7316 public override bool IsFixed {
7317 get { return true; }
7320 public override bool IsRef {
7321 get { return false; }
7324 public override string Name {
7325 get { throw new NotImplementedException (); }
7328 public override void SetHasAddressTaken ()
7330 throw new NotImplementedException ();
7333 protected override ILocalVariable Variable {
7337 public override VariableInfo VariableInfo {
7338 get { return null; }
7343 /// Handles `var' contextual keyword; var becomes a keyword only
7344 /// if no type called var exists in a variable scope
7346 class VarExpr : SimpleName
7348 public VarExpr (Location loc)
7353 public bool InferType (ResolveContext ec, Expression right_side)
7356 throw new InternalErrorException ("An implicitly typed local variable could not be redefined");
7358 type = right_side.Type;
7359 if (type == InternalType.NullLiteral || type.Kind == MemberKind.Void || type == InternalType.AnonymousMethod || type == InternalType.MethodGroup) {
7360 ec.Report.Error (815, loc,
7361 "An implicitly typed local variable declaration cannot be initialized with `{0}'",
7362 type.GetSignatureForError ());
7366 eclass = ExprClass.Variable;
7370 protected override void Error_TypeOrNamespaceNotFound (IMemberContext ec)
7372 if (ec.Module.Compiler.Settings.Version < LanguageVersion.V_3)
7373 base.Error_TypeOrNamespaceNotFound (ec);
7375 ec.Module.Compiler.Report.Error (825, loc, "The contextual keyword `var' may only appear within a local variable declaration");